source: trunk/src/gl/gl_context.cc @ 299

Last change on this file since 299 was 299, checked in by epyon, 11 years ago
  • all bind and update function for graphics objects are done via context (will simplify directx device, and allow for handles instead of objects)
File size: 16.5 KB
Line 
1// Copyright (C) 2012-2013 Kornel Kisielewicz
2// This file is part of NV Libraries.
3// For conditions of distribution and use, see copyright notice in nv.hh
4
5#include "nv/gl/gl_context.hh"
6
7#include "nv/gl/gl_enum.hh"
8#include "nv/lib/gl.hh"
9#include "nv/lib/sdl.hh"
10#include "nv/gl/gl_texture2d.hh"
11#include "nv/gl/gl_program.hh"
12#include "nv/gl/gl_vertex_buffer.hh"
13
14using namespace nv;
15
16void gl_context::bind( texture2d* texture, texture_slot slot )
17{
18        GLuint id = static_cast< gl_texture2d* >( texture )->m_name.get_value();
19        glActiveTexture( GL_TEXTURE0 + static_cast< GLenum >( slot ) );
20        glBindTexture( GL_TEXTURE_2D, id );
21}
22
23void nv::gl_context::bind( program* p )
24{
25        gl_program* glp = static_cast< gl_program* >( p );
26        glUseProgram( glp->m_name.get_value() );
27        glp->update_uniforms();
28}
29
30void nv::gl_context::bind( vertex_buffer* b )
31{
32        GLuint id = static_cast< gl_vertex_buffer* >( b )->m_name.get_value();
33        glBindBuffer( GL_ARRAY_BUFFER, id );
34}
35
36void nv::gl_context::bind( index_buffer* b )
37{
38        GLuint id = static_cast< gl_index_buffer* >( b )->m_name.get_value();
39        glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, id );
40}
41
42void nv::gl_context::bind( vertex_array* va )
43{
44        for ( vertex_buffer_attribute_map::iterator i = va->m_map.begin();      i != va->m_map.end(); ++i )
45        {
46                uint32 location             = static_cast<uint32>( i->first );
47                vertex_buffer_attribute* va = i->second;
48                vertex_buffer*           vb = va->get_buffer();
49                glEnableVertexAttribArray( location );
50                bind( vb );
51                glVertexAttribPointer(
52                        location,
53                        static_cast<GLint>( va->get_components() ),
54                        nv::datatype_to_gl_enum( va->get_datatype() ),
55                        GL_FALSE,
56                        static_cast<GLsizei>( va->get_stride() ),
57                        (void*)va->get_offset()
58                        );
59                unbind( vb );
60        }
61
62        if ( va->m_index )
63        {
64                bind( va->m_index );
65        }
66}
67
68void nv::gl_context::unbind( program* )
69{
70        glUseProgram( 0 );
71}
72
73void nv::gl_context::unbind( vertex_buffer* )
74{
75        glBindBuffer( GL_ARRAY_BUFFER, 0 );
76}
77
78void nv::gl_context::unbind( index_buffer* )
79{
80        glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, 0 );
81}
82
83void nv::gl_context::unbind( vertex_array* va )
84{
85        if ( va->m_index )
86        {
87                unbind( va->m_index );
88        }
89
90        for ( vertex_buffer_attribute_map::iterator i = va->m_map.begin();      i != va->m_map.end(); ++i )
91        {
92                glDisableVertexAttribArray( static_cast<uint32>( i->first ) );
93        }
94}
95
96void gl_context::update( texture2d* texture, void* data )
97{
98        GLuint id = static_cast< gl_texture2d* >( texture )->m_name.get_value();
99        image_format format = texture->get_format();
100        ivec2        size   = texture->get_size();
101
102        glBindTexture( GL_TEXTURE_2D, id );
103        glTexImage2D( GL_TEXTURE_2D, 0, (GLint)nv::image_format_to_enum(format.format), size.x, size.y, 0, nv::image_format_to_enum(format.format), nv::datatype_to_gl_enum(format.type), data );
104}
105
106void gl_context::update( vertex_buffer* b, const void* data, size_t offset, size_t size )
107{
108        bind( b );
109        glBufferSubData( GL_ARRAY_BUFFER, (GLintptr)offset, (GLsizeiptr)size, data );
110}
111
112void gl_context::update( index_buffer* b, const void* data, size_t offset, size_t size )
113{
114        bind( b );
115        glBufferSubData( GL_ELEMENT_ARRAY_BUFFER, (GLintptr)offset, (GLsizeiptr)size, data );
116}
117
118void gl_context::clear( const clear_state& cs )
119{
120        // apply_framebuffer
121       
122        apply_scissor_test( cs.scissor_test );
123        apply_color_mask( cs.color_mask );
124        apply_depth_mask( cs.depth_mask );
125        // stencil_mask_separate
126
127        if ( m_clear_color != cs.color )
128        {
129                glClearColor( cs.color.r, cs.color.g, cs.color.b, cs.color.a );
130                m_clear_color = cs.color;
131        }
132
133        if ( m_clear_depth != cs.depth )
134        {
135                glClearDepth( cs.depth );
136                m_clear_depth = cs.depth;
137        }
138
139        if ( m_clear_stencil != cs.stencil )
140        {
141                glClearStencil( cs.stencil );
142                m_clear_stencil = cs.stencil;
143        }
144       
145        glClear( clear_state_buffers_to_mask( cs.buffers ) );
146}
147
148const ivec4& gl_context::get_viewport()
149{
150        return m_viewport;
151}
152
153void gl_context::set_viewport( const ivec4& viewport )
154{
155        if ( viewport.z < 0 || viewport.w < 0 )
156        {
157                NV_THROW( logic_error, "viewport width and height must be greater than zero!");
158        }
159
160        m_viewport = viewport;
161        glViewport( viewport.x, viewport.y, viewport.z, viewport.w );
162}
163
164void gl_context::enable( unsigned int what, bool value )
165{
166        if ( value )
167        {
168                glEnable( what );
169        }
170        else
171        {
172                glDisable( what );
173        }
174}
175
176void gl_context::apply_stencil_test( const stencil_test& stencil )
177{
178        if ( m_render_state.stencil_test.enabled != stencil.enabled )
179        {
180                enable( GL_STENCIL_TEST, stencil.enabled );
181                m_render_state.stencil_test.enabled = stencil.enabled;
182        }
183
184        if ( stencil.enabled )
185        {
186                apply_stencil_face( GL_FRONT, m_render_state.stencil_test.front_face, stencil.front_face );
187                apply_stencil_face( GL_BACK,  m_render_state.stencil_test.back_face,  stencil.back_face );
188        }
189}
190
191void gl_context::apply_stencil_face( unsigned face, stencil_test_face& stencil, const stencil_test_face& new_stencil )
192{
193        if (( stencil.op_fail       != new_stencil.op_fail       ) ||
194                ( stencil.op_depth_fail != new_stencil.op_depth_fail ) ||
195                ( stencil.op_depth_pass != new_stencil.op_depth_pass ) )
196        {
197                glStencilOpSeparate( face,
198                        stencil_operation_to_enum( new_stencil.op_fail ),
199                        stencil_operation_to_enum( new_stencil.op_depth_fail ),
200                        stencil_operation_to_enum( new_stencil.op_depth_pass )
201                );
202
203                stencil.op_fail       = new_stencil.op_fail;
204                stencil.op_depth_fail = new_stencil.op_depth_fail;
205                stencil.op_depth_pass = new_stencil.op_depth_pass;
206        }
207
208        if (( stencil.function  != new_stencil.function ) ||
209                ( stencil.ref_value != new_stencil.ref_value ) ||
210                ( stencil.mask      != new_stencil.mask ))
211        {
212                glStencilFuncSeparate( face,
213                        stencil_function_to_enum( new_stencil.function ),
214                        new_stencil.ref_value,
215                        new_stencil.mask
216                );
217
218                stencil.function  = new_stencil.function;
219                stencil.ref_value = new_stencil.ref_value;
220                stencil.mask      = new_stencil.mask;
221        }
222}
223
224void gl_context::apply_scissor_test( const scissor_test& scissor )
225{
226        if ( m_render_state.scissor_test.enabled != scissor.enabled )
227        {
228                enable( GL_SCISSOR_TEST, scissor.enabled );
229                m_render_state.scissor_test.enabled = scissor.enabled;
230        }
231
232        if ( scissor.dim.x < 0 || scissor.dim.y < 0 )
233        {
234                NV_THROW( logic_error, "scissor_test.rect width and height must be greater than zero!" );
235        }
236
237        if ( scissor.enabled )
238        {
239                if ( m_render_state.scissor_test.dim != scissor.dim || m_render_state.scissor_test.pos != scissor.pos )
240                {
241                        glScissor(
242                                scissor.pos.x, scissor.pos.y,
243                                scissor.dim.x, scissor.dim.y
244                        );
245                        m_render_state.scissor_test.dim = scissor.dim;
246                        m_render_state.scissor_test.pos = scissor.pos;
247                }
248        }
249}
250
251void gl_context::apply_depth_test( const depth_test& depth )
252{
253        if ( m_render_state.depth_test.enabled != depth.enabled )
254        {
255                enable( GL_DEPTH_TEST, depth.enabled );
256                m_render_state.depth_test.enabled = depth.enabled;
257        }
258
259        if ( depth.enabled )
260        {
261                if ( m_render_state.depth_test.function != depth.function )
262                {
263                        glDepthFunc( depth_state_function_to_enum( depth.function ) );
264                        m_render_state.depth_test.function = depth.function;
265                }
266        }
267}
268
269void gl_context::apply_depth_mask( bool mask )
270{
271        if ( m_render_state.depth_mask != mask )
272        {
273                glDepthMask( mask );
274                m_render_state.depth_mask = mask;
275        }
276}
277
278void gl_context::apply_polygon_mode( const polygon_mode& mode )
279{
280        if ( m_render_state.polygon_mode.fill != mode.fill )
281        {
282                glPolygonMode( GL_FRONT_AND_BACK, polygon_mode_fill_to_enum( mode.fill ) );
283                m_render_state.polygon_mode.fill = mode.fill;
284        }
285}
286
287
288void gl_context::apply_depth_range( const depth_range& range )
289{
290        if ( range.near < 0.0 || range.near > 1.0 )
291        {
292                NV_THROW( logic_error, "render_state.depth_range.near must be between zero and one!");
293        }
294        if ( range.far < 0.0 || range.far > 1.0 )
295        {
296                NV_THROW( logic_error, "render_state.depth_range.far must be between zero and one!");
297        }
298
299        if ((m_render_state.depth_range.far  != range.far) ||
300                (m_render_state.depth_range.near != range.near))
301        {
302                glDepthRange( range.near, range.far );
303
304                m_render_state.depth_range.far  = range.far;
305                m_render_state.depth_range.near = range.near;
306        }
307}
308
309void gl_context::apply_color_mask( const color_mask& mask )
310{
311        if ( m_render_state.color_mask != mask )
312        {
313                glColorMask( mask.red, mask.green, mask.blue, mask.alpha );
314                m_render_state.color_mask = mask;
315        }
316}
317
318void gl_context::apply_blending( const blending& blend )
319{
320        if ( m_render_state.blending.enabled != blend.enabled )
321        {
322                enable( GL_BLEND, blend.enabled );
323                m_render_state.blending.enabled = blend.enabled;
324        }
325
326        if ( blend.enabled )
327        {
328                if ((m_render_state.blending.src_rgb_factor   != blend.src_rgb_factor ) ||
329                        (m_render_state.blending.dst_rgb_factor   != blend.dst_rgb_factor ) ||
330                        (m_render_state.blending.src_alpha_factor != blend.src_alpha_factor ) ||
331                        (m_render_state.blending.dst_alpha_factor != blend.dst_alpha_factor ))
332                {
333                        glBlendFuncSeparate(
334                                blending_factor_to_enum( blend.src_rgb_factor ),
335                                blending_factor_to_enum( blend.dst_rgb_factor ),
336                                blending_factor_to_enum( blend.src_alpha_factor ),
337                                blending_factor_to_enum( blend.dst_alpha_factor )
338                        );
339
340                        m_render_state.blending.src_rgb_factor   = blend.src_rgb_factor;
341                        m_render_state.blending.dst_rgb_factor   = blend.dst_rgb_factor;
342                        m_render_state.blending.src_alpha_factor = blend.src_alpha_factor;
343                        m_render_state.blending.dst_alpha_factor = blend.dst_alpha_factor;
344                }
345
346                if ((m_render_state.blending.rgb_equation   != blend.rgb_equation ) ||
347                        (m_render_state.blending.alpha_equation != blend.alpha_equation ))
348                {
349                        glBlendEquationSeparate(
350                                blending_equation_to_enum( blend.rgb_equation ),
351                                blending_equation_to_enum( blend.alpha_equation )
352                        );
353
354                        m_render_state.blending.rgb_equation   = blend.rgb_equation;
355                        m_render_state.blending.alpha_equation = blend.alpha_equation;
356                }
357
358                if (( m_render_state.blending.color != blend.color ))
359                {
360                        glBlendColor( blend.color.r, blend.color.g, blend.color.b, blend.color.a );
361                        m_render_state.blending.color = blend.color;
362                }
363        }
364}
365
366
367void gl_context::apply_culling( const culling& cull )
368{
369        if ( m_render_state.culling.enabled != cull.enabled )
370        {
371                enable( GL_CULL_FACE, cull.enabled );
372                m_render_state.culling.enabled = cull.enabled;
373        }
374
375        if ( cull.enabled )
376        {
377                if ( m_render_state.culling.face != cull.face )
378                {
379                        glCullFace( culling_face_type_to_enum(cull.face) );
380                        m_render_state.culling.face = cull.face;
381                }
382
383                if ( m_render_state.culling.order != cull.order )
384                {
385                        glFrontFace( culling_order_type_to_enum( cull.order ) );
386                        m_render_state.culling.order = cull.order;
387                }
388        }
389}
390
391
392void gl_context::force_apply_render_state( const render_state& state )
393{
394        enable( GL_CULL_FACE, state.culling.enabled );
395        glCullFace( culling_face_type_to_enum( state.culling.face ) );
396        glFrontFace( culling_order_type_to_enum( state.culling.order ) );
397
398        enable( GL_SCISSOR_TEST, state.scissor_test.enabled );
399        glScissor(
400                state.scissor_test.pos.x, state.scissor_test.pos.y,
401                state.scissor_test.dim.x, state.scissor_test.dim.y
402        );
403
404        enable( GL_STENCIL_TEST, state.stencil_test.enabled );
405        force_apply_stencil_face( GL_FRONT, state.stencil_test.front_face );
406        force_apply_stencil_face( GL_BACK,  state.stencil_test.back_face  );
407
408        enable( GL_DEPTH_TEST, state.depth_test.enabled );
409        glDepthFunc( depth_state_function_to_enum( state.depth_test.function ) );
410        glDepthRange( state.depth_range.near, state.depth_range.far );
411
412        enable( GL_BLEND, state.blending.enabled );
413        glBlendFuncSeparate(
414                blending_factor_to_enum( state.blending.src_rgb_factor ),
415                blending_factor_to_enum( state.blending.dst_rgb_factor ),
416                blending_factor_to_enum( state.blending.src_alpha_factor ),
417                blending_factor_to_enum( state.blending.dst_alpha_factor )
418        );
419        glBlendEquationSeparate(
420                blending_equation_to_enum( state.blending.rgb_equation ),
421                blending_equation_to_enum( state.blending.alpha_equation )
422        );
423        glBlendColor(
424                state.blending.color.r, state.blending.color.g,
425                state.blending.color.b, state.blending.color.a
426        );
427
428        glDepthMask( state.depth_mask );
429        glColorMask(
430                state.color_mask.red, state.color_mask.green,
431                state.color_mask.blue, state.color_mask.alpha
432        );
433        glPolygonMode( GL_FRONT_AND_BACK, polygon_mode_fill_to_enum( state.polygon_mode.fill ) );
434}
435
436void gl_context::force_apply_stencil_face( unsigned face, const stencil_test_face& stencil )
437{
438        glStencilOpSeparate( face,
439                stencil_operation_to_enum( stencil.op_fail ),
440                stencil_operation_to_enum( stencil.op_depth_fail ),
441                stencil_operation_to_enum( stencil.op_depth_pass )
442        );
443
444        glStencilFuncSeparate( face,
445                stencil_function_to_enum( stencil.function ),
446                stencil.ref_value,
447                stencil.mask
448        );
449}
450
451
452void gl_context::apply_render_state( const render_state& state )
453{
454        // apply_primitive_restart
455        apply_culling( state.culling );
456        // apply_program_point_size
457        // apply_rasterization_mode
458        apply_scissor_test( state.scissor_test );
459        apply_stencil_test( state.stencil_test );
460        apply_depth_test( state.depth_test );
461        apply_depth_range( state.depth_range );
462        apply_blending( state.blending );
463        apply_color_mask( state.color_mask );
464        apply_depth_mask( state.depth_mask );
465        apply_polygon_mode( state.polygon_mode );
466}
467
468
469gl_context::gl_context( device* a_device )
470        : context( a_device )
471{
472}
473
474
475nv::gl_context::~gl_context()
476{
477}
478
479void gl_context::draw( primitive prim, const render_state& rs, program* p, vertex_array* va, size_t count )
480{
481        apply_render_state( rs );
482        if ( count > 0 )
483        {
484                bind( p );
485                bind( va );
486                if ( va->has_index_buffer() )
487                {
488                        glDrawElements( primitive_to_enum(prim), static_cast<GLsizei>( count ), datatype_to_gl_enum( va->get_index_buffer_type() ), 0 );
489                }
490                else
491                {
492                        glDrawArrays( primitive_to_enum(prim), 0, static_cast<GLsizei>( count ) );
493                }
494                unbind( va );
495                //unbind( p );
496        }
497}
498
499nv::sdl_gl_context::sdl_gl_context( device* a_device, void* a_sdl_win_handle )
500        : gl_context( a_device ), m_handle( nullptr )
501{
502#if NV_SDL_VERSION == NV_SDL_20
503        m_handle = SDL_GL_CreateContext( static_cast<SDL_Window*>( a_sdl_win_handle ) );
504
505        if ( m_handle == 0 )
506        {
507                NV_LOG( LOG_CRITICAL, "GL Context creation failed: " << SDL_GetError( ) );
508                return; // TODO: Error report
509        }
510#else
511        NV_UNUSED( a_win_handle );
512        NV_UNUSED( m_handle );
513#endif
514
515        nv::load_gl_library();
516        NV_LOG( LOG_INFO, "OpenGL Vendor       : " << glGetString(GL_VENDOR) );
517        NV_LOG( LOG_INFO, "OpenGL Renderer     : " << glGetString(GL_RENDERER) );
518        NV_LOG( LOG_INFO, "OpenGL Version      : " << glGetString(GL_VERSION) );
519        NV_LOG( LOG_INFO, "OpenGL GLSL Version : " << glGetString(GL_SHADING_LANGUAGE_VERSION) );
520#if NV_SDL_VERSION == NV_SDL_20
521        //      SDL_GL_SetSwapInterval(1);
522#endif
523
524        // TODO: do we really need this?
525        glPixelStorei( GL_UNPACK_ALIGNMENT, 1 );
526
527        force_apply_render_state( m_render_state );
528}
529
530nv::sdl_gl_context::~sdl_gl_context()
531{
532#if NV_SDL_VERSION == NV_SDL_20
533        SDL_GL_DeleteContext(static_cast<SDL_GLContext>( m_handle ) );
534#endif
535}
536
537nv::native_gl_context::native_gl_context( device* a_device, void* a_native_win_handle )
538        : gl_context( a_device ), m_handle( nullptr )
539{
540#if NV_PLATFORM == NV_WINDOWS
541
542// TODO: error checking
543        HDC hdc = (HDC)a_native_win_handle;
544
545        const int wgl_attrib_list[] =
546        {
547                WGL_DRAW_TO_WINDOW_ARB, GL_TRUE,
548                WGL_SUPPORT_OPENGL_ARB, GL_TRUE,
549                WGL_ACCELERATION_ARB,   WGL_FULL_ACCELERATION_ARB,
550                WGL_DOUBLE_BUFFER_ARB,  GL_TRUE,
551                WGL_PIXEL_TYPE_ARB,     WGL_TYPE_RGBA_ARB,
552                WGL_COLOR_BITS_ARB,     32,
553                WGL_DEPTH_BITS_ARB,     24,
554                WGL_STENCIL_BITS_ARB,   8,
555                0, 0  //End
556        };
557
558        unsigned int num_formats;
559        int pixel_format;
560        PIXELFORMATDESCRIPTOR pfd;
561
562        if ( FALSE == wglChoosePixelFormatARB(hdc, wgl_attrib_list, NULL, 1, &pixel_format, &num_formats) )
563        {
564                return;
565        }
566
567        if ( FALSE == SetPixelFormat(hdc, pixel_format, &pfd) )
568        {
569                //int err = GetLastError();
570                return;
571        }
572
573        int attribs[] =
574        {
575                WGL_CONTEXT_MAJOR_VERSION_ARB,   2,
576                WGL_CONTEXT_MINOR_VERSION_ARB,   1,
577                WGL_CONTEXT_PROFILE_MASK_ARB,  WGL_CONTEXT_CORE_PROFILE_BIT_ARB,
578                //WGL_CONTEXT_PROFILE_MASK_ARB, WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB,
579                0, 0  //End
580        };
581
582        HGLRC handle;
583        if ( 0 == (handle = wglCreateContextAttribsARB(hdc, 0, attribs) ) )
584        {
585                return;
586        }
587
588        if ( FALSE == dynwglMakeCurrent( hdc, handle ) )
589        {
590                return;
591        }     
592
593        m_handle = (void*)handle;
594#else
595        NV_ASSERT( false, "Native GL context not implemented for this platform!" );
596#endif
597        force_apply_render_state( m_render_state );
598}
599
600nv::native_gl_context::~native_gl_context()
601{
602#if NV_PLATFORM == NV_WINDOWS
603        dynwglDeleteContext( (HGLRC)m_handle );
604#endif
605}
Note: See TracBrowser for help on using the repository browser.