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

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