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

Last change on this file since 469 was 469, checked in by epyon, 10 years ago
  • stl/short_string - minor fix
  • stl/utility - max for 3 arguments
  • stl/math length_sq
  • interface/context - proper handling of buffer ownage in va's
  • wx/canvas - sleep added
File size: 23.1 KB
RevLine 
[395]1// Copyright (C) 2012-2015 ChaosForge Ltd
2// http://chaosforge.org/
3//
4// This file is part of Nova libraries.
5// For conditions of distribution and use, see copying.txt file in root folder.
[37]6
7#include "nv/gl/gl_context.hh"
8
9#include "nv/gl/gl_enum.hh"
10#include "nv/lib/gl.hh"
[301]11#include "nv/gl/gl_device.hh"
[365]12#include "nv/core/logger.hh"
[37]13
14using namespace nv;
15
[313]16nv::vertex_array nv::gl_context::create_vertex_array()
17{
18        vertex_array result = m_vertex_arrays.create();
19        vertex_array_info* info = m_vertex_arrays.get( result );
20        info->count       = 0;
21        info->index       = buffer();
22        info->index_owner = false;
23        info->index_type  = USHORT;
24        return result;
25}
26
27nv::framebuffer nv::gl_context::create_framebuffer()
28{
[331]29        if ( is_gl_extension_loaded( GL_EXT_FRAMEBUFFER_OBJECT ) && is_gl_extension_loaded( GL_EXT_FRAMEBUFFER_BLIT ) )
[313]30        {
31                unsigned glid   = 0;
32                glGenFramebuffers( 1, &glid );
33                framebuffer result = m_framebuffers.create();
34                gl_framebuffer_info* info = m_framebuffers.get( result );
35                info->glid = glid;
[331]36                info->depth_rb_glid = 0;
[313]37                info->color_attachment_count = 0;
38                return result;
39        }
40        else return framebuffer();
41}
42
43void nv::gl_context::release( vertex_array va )
44{
45        vertex_array_info* info = m_vertex_arrays.get( va );
46        if ( info )
47        {
48                for ( uint32 i = 0; i < info->count; ++i )
49                {
[469]50                        if ( info->attr[i].owner )
51                                m_device->release( info->attr[i].vbuffer );
[313]52                }
53                if ( info->index.is_valid() && info->index_owner) m_device->release( info->index );
54                m_vertex_arrays.destroy( va );
55        }
56}
57
58void nv::gl_context::release( framebuffer f )
59{
60        gl_framebuffer_info* info = m_framebuffers.get( f );
61        if ( info )
62        {
63                // TODO: release textures?
[331]64                glBindFramebuffer( GL_FRAMEBUFFER, 0 );
65                glBindRenderbuffer( GL_RENDERBUFFER, 0 );
66                if ( info->depth_rb_glid == 0 )
67                        glDeleteRenderbuffers( 1, &info->depth_rb_glid );
68                glDeleteFramebuffers( 1, &info->glid );
[335]69                m_framebuffers.destroy( f );
[313]70        }
71}
72
73const vertex_array_info* nv::gl_context::get_vertex_array_info( vertex_array va ) const
74{
75        return m_vertex_arrays.get( va );
76}
77
78const framebuffer_info* nv::gl_context::get_framebuffer_info( framebuffer f ) const
79{
80        return m_framebuffers.get( f );
81}
82
83vertex_array_info* nv::gl_context::get_vertex_array_info_mutable( vertex_array va )
84{
85        return m_vertex_arrays.get( va );
86}
87
[331]88void nv::gl_context::attach( framebuffer f, output_slot slot, texture t )
89{
90        // TODO: framebuffer variable, so no re-binding?
91        // TODO: support 1d, 3d textures, cubemaps or layers?
92        // TODO: support GL_READ_FRAMEBUFFER?
93        const gl_framebuffer_info* info  = m_framebuffers.get( f );
[406]94        const gl_texture_info*     tinfo = static_cast< const gl_texture_info* >( m_device->get_texture_info( t ) );
[331]95        if ( info )
96        {
97                glBindFramebuffer( GL_FRAMEBUFFER, info->glid );
98                unsigned gl_type = texture_type_to_enum( tinfo->type );
[313]99
[331]100                if ( tinfo )
101                {
102                        //              if ( tinfo->size.y == 0 )
103                                //                      glFramebufferTexture1D( GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0+(unsigned)slot, GL_TEXTURE_1D, tinfo->glid, 0 );
[406]104                        glFramebufferTexture2D( GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0+unsigned( slot ), gl_type, tinfo->glid, 0 );
[331]105                }
106                else
107                {
[406]108                        glFramebufferTexture2D( GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0+unsigned( slot ), gl_type, 0, 0 );
[331]109                }
110
111        }
112}
113
[463]114void nv::gl_context::attach( framebuffer f, texture depth, int layer /*= -1*/ )
[331]115{
116        // TODO: framebuffer variable, so no re-binding?
117        // TODO: support GL_READ_FRAMEBUFFER?
118        const gl_framebuffer_info* info  = m_framebuffers.get( f );
[406]119        const gl_texture_info*     tinfo = static_cast< const gl_texture_info* >( m_device->get_texture_info( depth ) );
[331]120        if ( info )
121        {
122                glBindFramebuffer( GL_FRAMEBUFFER, info->glid );
123                unsigned gl_type = texture_type_to_enum( tinfo->type );
[463]124                unsigned glid = ( tinfo ? tinfo->glid : 0 );
125                if ( layer >= 0 )
[331]126                {
[463]127                        glFramebufferTextureLayer( GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, tinfo->glid, 0, layer );
[331]128                }
129                else
130                {
[463]131                        glFramebufferTexture2D( GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, gl_type, glid, 0 );
[331]132                }
133        }
[463]134
[331]135}
136
137void nv::gl_context::attach( framebuffer f, ivec2 size )
138{
139        // TODO: framebuffer variable, so no re-binding?
140        // TODO: support GL_READ_FRAMEBUFFER?
141        gl_framebuffer_info* info  = m_framebuffers.get( f );
142        if ( info )
143        {
144                glBindFramebuffer( GL_FRAMEBUFFER, info->glid );
[462]145                if ( info->depth_rb_glid )
146                        glDeleteRenderbuffers( 1, &(info->depth_rb_glid) );
[331]147                glGenRenderbuffers( 1, &(info->depth_rb_glid) );
148                glBindRenderbuffer( GL_RENDERBUFFER, info->depth_rb_glid );
149                glRenderbufferStorage( GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, size.x, size.y );
150                glFramebufferRenderbuffer( GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, info->depth_rb_glid );
151                glBindRenderbuffer( GL_RENDERBUFFER, 0 );
152        }
153
154}
155
156void nv::gl_context::blit( framebuffer f, clear_state::buffers_type mask, ivec2 src1, ivec2 src2, ivec2 dst1, ivec2 dst2 )
157{
158        gl_framebuffer_info* info  = m_framebuffers.get( f );
159        if ( info )
160        {
161                glBindFramebuffer( GL_FRAMEBUFFER, info->glid );
162                unsigned filter = mask == clear_state::COLOR_BUFFER ? GL_LINEAR : GL_NEAREST;
163                glBlitFramebuffer( src1.x, src1.y, src2.x, src2.y, dst1.x, dst1.y, dst2.x, dst2.y, clear_state_buffers_to_mask( mask ), filter );
164        }
165}
166
167
168bool nv::gl_context::check( framebuffer_slot ft )
169{
[462]170        glDrawBuffer( 0 );
171        glReadBuffer( 0 );
[331]172        if ( is_gl_extension_loaded( GL_EXT_FRAMEBUFFER_OBJECT ) && is_gl_extension_loaded( GL_EXT_FRAMEBUFFER_BLIT ) )
173        {
174                unsigned result = glCheckFramebufferStatus( framebuffer_slot_to_enum(ft) );
175                if ( result == GL_FRAMEBUFFER_COMPLETE ) return true;
176                switch ( result )
177                {
[365]178                case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT         : NV_LOG_ERROR( "gl_context::check : Framebuffer incomplete attachment!" ); break;
179                case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT : NV_LOG_ERROR( "gl_context::check : Framebuffer missing attachment!" ); break;
[466]180//              case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS         : NV_LOG_ERROR( "gl_context::check : Framebuffer incomplete dimensions!" ); break;
181//              case GL_FRAMEBUFFER_INCOMPLETE_FORMATS            : NV_LOG_ERROR( "gl_context::check : Framebuffer incomplete formats!" ); break;
[365]182                case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER        : NV_LOG_ERROR( "gl_context::check : Framebuffer incomplete draw buffer!" ); break;
183                case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER        : NV_LOG_ERROR( "gl_context::check : Framebuffer incomplete read buffer!" ); break;
184                case GL_FRAMEBUFFER_UNSUPPORTED                   : NV_LOG_ERROR( "gl_context::check : Framebuffer format combination unsupported!" ); break;
185                default: NV_LOG_ERROR( "gl_context::check : Unknown Framebuffer error! (", result, ")" ); break;
[331]186                }
187        }
188        else
189        {
[365]190                NV_LOG_ERROR( "gl_context::check : Framebuffer extensions not loaded!" );
[331]191        }
[462]192        glDrawBuffer( GL_BACK );
193        glReadBuffer( GL_BACK );
[331]194        return false;
195}
196
197void nv::gl_context::bind( framebuffer f, framebuffer_slot ft /*= FRAMEBUFFER_BOTH */ )
198{
199        const gl_framebuffer_info* info = m_framebuffers.get( f );
200        if ( info )
201        {
202                glBindFramebuffer( framebuffer_slot_to_enum(ft), info->glid );
203        }
204        else
205        {
206                glBindFramebuffer( framebuffer_slot_to_enum(ft), 0 );
207        }
208}
209
[301]210void gl_context::bind( texture t, texture_slot slot )
[299]211{
[301]212        const gl_texture_info* info = static_cast< const gl_texture_info* >( m_device->get_texture_info( t ) );
213        if ( info )
214        {
215                glActiveTexture( GL_TEXTURE0 + static_cast< GLenum >( slot ) );
[331]216                glBindTexture( texture_type_to_enum( info->type ), info->glid );
[301]217        }
[299]218}
219
[303]220void nv::gl_context::bind( program p )
[299]221{
[406]222        gl_device* gdevice    = static_cast<gl_device*>( m_device );
223        gl_program_info* info = gdevice->m_programs.get( p );
[303]224        if ( info )
225        {
226                glUseProgram( info->glid );
[406]227                gdevice->update_uniforms( info );
[303]228        }
[299]229}
230
[313]231// void nv::gl_context::bind( buffer b )
232// {
233//      const gl_buffer_info* info = static_cast< const gl_buffer_info* >( m_device->get_buffer_info( b ) );
234//      if ( info )
235//      {
236//              glBindBuffer( buffer_type_to_enum( info->type ), info->glid );
237//      }
238// }
[299]239
[302]240void nv::gl_context::bind( vertex_array va )
[299]241{
[313]242        const vertex_array_info* info = m_vertex_arrays.get( va );
[302]243        if ( info )
[299]244        {
[302]245                for ( uint32 i = 0; i < info->count; ++i )
246                {
247                        const vertex_buffer_attribute& vba = info->attr[i];
248                        uint32 location                    = static_cast<uint32>( vba.location );
249                        glEnableVertexAttribArray( location );
[313]250                        const gl_buffer_info* vinfo = static_cast< const gl_buffer_info* >( m_device->get_buffer_info( vba.vbuffer ) );
251                        if ( vinfo && vinfo->type == VERTEX_BUFFER )
252                                glBindBuffer( GL_ARRAY_BUFFER, vinfo->glid );
253                        else
254                        {
255                                // TODO: report error
256                        }
257
[406]258                        glVertexAttribPointer(
259                                location,
260                                static_cast<GLint>( vba.components ),
[302]261                                nv::datatype_to_gl_enum( vba.dtype ),
262                                GL_FALSE,
263                                static_cast<GLsizei>( vba.stride ),
[406]264                                reinterpret_cast<void*>( vba.offset )
[302]265                                );
266                }
[313]267                glBindBuffer( GL_ARRAY_BUFFER, 0 );
[299]268
[302]269                if ( info->index.is_valid() )
270                {
[313]271                        const gl_buffer_info* iinfo = static_cast< const gl_buffer_info* >( m_device->get_buffer_info( info->index ) );
272                        if ( iinfo && iinfo->type == INDEX_BUFFER )
273                        {
274                                glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, iinfo->glid );
275                        }
276                        else
277                        {
278                                // TODO: report error
279                        }
[302]280                }
[299]281        }
282}
283
[313]284void nv::gl_context::unbind( program )
285{
286        glUseProgram( 0 );
287}
288
289// void nv::gl_context::unbind( buffer b )
290// {
291//      const gl_buffer_info* info = static_cast< const gl_buffer_info* >( m_device->get_buffer_info( b ) );
292//      if ( info )
293//      {
294//              glBindBuffer( buffer_type_to_enum( info->type ), 0 );
295//      }
296// }
297
[302]298void nv::gl_context::unbind( vertex_array va )
[299]299{
[313]300        const vertex_array_info* info = m_vertex_arrays.get( va );
[302]301        if ( info )
[299]302        {
[302]303                if ( info->index.is_valid() )
304                {
[313]305                        glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, 0 );
[302]306                }
[299]307
[302]308                for ( uint32 i = 0; i < info->count; ++i )
309                {
310                        glDisableVertexAttribArray( static_cast<uint32>( info->attr[i].location ) );
311                }
[299]312        }
313}
314
[313]315void nv::gl_context::unbind( framebuffer f )
316{
317        // this way we are sure that the extension is loaded
318        const gl_framebuffer_info* info = m_framebuffers.get( f );
319        if ( info )
320        {
321                glBindFramebuffer( GL_FRAMEBUFFER, 0 );
322        }
[331]323        glDrawBuffer( GL_BACK );
324        glReadBuffer( GL_BACK );
[313]325}
326
[406]327void nv::gl_context::update( texture t, const void* data )
[299]328{
[301]329        const gl_texture_info* info = static_cast< const gl_texture_info* >( m_device->get_texture_info( t ) );
330        if ( info )
331        {
[331]332                image_format format  = info->format;
[463]333                ivec3        size    = info->size;
[331]334                unsigned     gl_type = texture_type_to_enum( info->type );
[299]335
[331]336                glBindTexture( gl_type, info->glid );
[463]337                if ( info->type == TEXTURE_3D || info->type == TEXTURE_2D_ARRAY )
338                        glTexImage3D( gl_type, 0, static_cast<GLint>( nv::image_format_to_internal_enum( format.format ) ), size.x, size.y, size.z, 0, nv::image_format_to_enum( format.format ), nv::datatype_to_gl_enum( format.type ), data );
339                else
340                        glTexImage2D( gl_type, 0, static_cast<GLint>( nv::image_format_to_internal_enum(format.format) ), size.x, size.y, 0, nv::image_format_to_enum(format.format), nv::datatype_to_gl_enum(format.type), data );
[301]341        }
[299]342}
343
[376]344void gl_context::update( buffer b, const void* data, nv::size_t offset, nv::size_t size )
[299]345{
[302]346        const gl_buffer_info* info = static_cast< const gl_buffer_info* >( m_device->get_buffer_info( b ) );
347        if ( info )
348        {
[313]349                GLenum glenum = buffer_type_to_enum( info->type );
350                glBindBuffer( glenum, info->glid );
[406]351                glBufferSubData( glenum, GLintptr( offset ), GLsizeiptr( size ), data );
[302]352        }
[299]353}
354
[37]355void gl_context::clear( const clear_state& cs )
356{
357        // apply_framebuffer
[44]358       
[37]359        apply_scissor_test( cs.scissor_test );
360        apply_color_mask( cs.color_mask );
361        apply_depth_mask( cs.depth_mask );
362        // stencil_mask_separate
363
364        if ( m_clear_color != cs.color )
365        {
366                glClearColor( cs.color.r, cs.color.g, cs.color.b, cs.color.a );
367                m_clear_color = cs.color;
368        }
369
370        if ( m_clear_depth != cs.depth )
371        {
372                glClearDepth( cs.depth );
373                m_clear_depth = cs.depth;
374        }
375
376        if ( m_clear_stencil != cs.stencil )
377        {
378                glClearStencil( cs.stencil );
379                m_clear_stencil = cs.stencil;
380        }
[44]381       
382        glClear( clear_state_buffers_to_mask( cs.buffers ) );
[37]383}
384
385const ivec4& gl_context::get_viewport()
386{
387        return m_viewport;
388}
389
390void gl_context::set_viewport( const ivec4& viewport )
391{
[403]392        NV_ASSERT_ALWAYS( viewport.z > 0 && viewport.w > 0, "viewport dimensions must be greater than zero!" );
[37]393        m_viewport = viewport;
394        glViewport( viewport.x, viewport.y, viewport.z, viewport.w );
395}
396
397void gl_context::enable( unsigned int what, bool value )
398{
399        if ( value )
400        {
401                glEnable( what );
402        }
403        else
404        {
405                glDisable( what );
406        }
407}
408
409void gl_context::apply_stencil_test( const stencil_test& stencil )
410{
411        if ( m_render_state.stencil_test.enabled != stencil.enabled )
412        {
413                enable( GL_STENCIL_TEST, stencil.enabled );
414                m_render_state.stencil_test.enabled = stencil.enabled;
415        }
[331]416       
[37]417        if ( stencil.enabled )
418        {
419                apply_stencil_face( GL_FRONT, m_render_state.stencil_test.front_face, stencil.front_face );
420                apply_stencil_face( GL_BACK,  m_render_state.stencil_test.back_face,  stencil.back_face );
421        }
422}
423
[121]424void gl_context::apply_stencil_face( unsigned face, stencil_test_face& stencil, const stencil_test_face& new_stencil )
[37]425{
426        if (( stencil.op_fail       != new_stencil.op_fail       ) ||
427                ( stencil.op_depth_fail != new_stencil.op_depth_fail ) ||
428                ( stencil.op_depth_pass != new_stencil.op_depth_pass ) )
429        {
430                glStencilOpSeparate( face,
431                        stencil_operation_to_enum( new_stencil.op_fail ),
432                        stencil_operation_to_enum( new_stencil.op_depth_fail ),
433                        stencil_operation_to_enum( new_stencil.op_depth_pass )
434                );
435
436                stencil.op_fail       = new_stencil.op_fail;
437                stencil.op_depth_fail = new_stencil.op_depth_fail;
438                stencil.op_depth_pass = new_stencil.op_depth_pass;
439        }
440
441        if (( stencil.function  != new_stencil.function ) ||
442                ( stencil.ref_value != new_stencil.ref_value ) ||
443                ( stencil.mask      != new_stencil.mask ))
444        {
445                glStencilFuncSeparate( face,
446                        stencil_function_to_enum( new_stencil.function ),
447                        new_stencil.ref_value,
448                        new_stencil.mask
449                );
450
451                stencil.function  = new_stencil.function;
452                stencil.ref_value = new_stencil.ref_value;
453                stencil.mask      = new_stencil.mask;
454        }
455}
456
457void gl_context::apply_scissor_test( const scissor_test& scissor )
458{
459        if ( m_render_state.scissor_test.enabled != scissor.enabled )
460        {
461                enable( GL_SCISSOR_TEST, scissor.enabled );
462                m_render_state.scissor_test.enabled = scissor.enabled;
463        }
464
465
466        if ( scissor.enabled )
467        {
[403]468                NV_ASSERT_ALWAYS( scissor.dim.x > 0 && scissor.dim.y > 0, "scissor_test.rect dimension equal to zero!" );
469
[37]470                if ( m_render_state.scissor_test.dim != scissor.dim || m_render_state.scissor_test.pos != scissor.pos )
471                {
472                        glScissor(
473                                scissor.pos.x, scissor.pos.y,
474                                scissor.dim.x, scissor.dim.y
475                        );
476                        m_render_state.scissor_test.dim = scissor.dim;
477                        m_render_state.scissor_test.pos = scissor.pos;
478                }
479        }
480}
481
482void gl_context::apply_depth_test( const depth_test& depth )
483{
484        if ( m_render_state.depth_test.enabled != depth.enabled )
485        {
486                enable( GL_DEPTH_TEST, depth.enabled );
487                m_render_state.depth_test.enabled = depth.enabled;
488        }
489
490        if ( depth.enabled )
491        {
492                if ( m_render_state.depth_test.function != depth.function )
493                {
494                        glDepthFunc( depth_state_function_to_enum( depth.function ) );
495                        m_render_state.depth_test.function = depth.function;
496                }
497        }
498}
499
500void gl_context::apply_depth_mask( bool mask )
501{
502        if ( m_render_state.depth_mask != mask )
503        {
504                glDepthMask( mask );
505                m_render_state.depth_mask = mask;
506        }
507}
508
[233]509void gl_context::apply_polygon_mode( const polygon_mode& mode )
510{
511        if ( m_render_state.polygon_mode.fill != mode.fill )
512        {
513                glPolygonMode( GL_FRONT_AND_BACK, polygon_mode_fill_to_enum( mode.fill ) );
514                m_render_state.polygon_mode.fill = mode.fill;
515        }
516}
517
518
[37]519void gl_context::apply_depth_range( const depth_range& range )
520{
[403]521        NV_ASSERT_ALWAYS( range.near >= 0.0 && range.near <= 1.0, "render_state.depth_range.near must be between zero and one!" );
522        NV_ASSERT_ALWAYS( range.far  >= 0.0 && range.far  <= 1.0, "render_state.depth_range.far must be between zero and one!" );
[37]523
524        if ((m_render_state.depth_range.far  != range.far) ||
525                (m_render_state.depth_range.near != range.near))
526        {
527                glDepthRange( range.near, range.far );
528
529                m_render_state.depth_range.far  = range.far;
530                m_render_state.depth_range.near = range.near;
531        }
532}
533
534void gl_context::apply_color_mask( const color_mask& mask )
535{
536        if ( m_render_state.color_mask != mask )
537        {
538                glColorMask( mask.red, mask.green, mask.blue, mask.alpha );
539                m_render_state.color_mask = mask;
540        }
541}
542
543void gl_context::apply_blending( const blending& blend )
544{
545        if ( m_render_state.blending.enabled != blend.enabled )
546        {
547                enable( GL_BLEND, blend.enabled );
548                m_render_state.blending.enabled = blend.enabled;
549        }
550
551        if ( blend.enabled )
552        {
553                if ((m_render_state.blending.src_rgb_factor   != blend.src_rgb_factor ) ||
554                        (m_render_state.blending.dst_rgb_factor   != blend.dst_rgb_factor ) ||
555                        (m_render_state.blending.src_alpha_factor != blend.src_alpha_factor ) ||
556                        (m_render_state.blending.dst_alpha_factor != blend.dst_alpha_factor ))
557                {
558                        glBlendFuncSeparate(
559                                blending_factor_to_enum( blend.src_rgb_factor ),
560                                blending_factor_to_enum( blend.dst_rgb_factor ),
561                                blending_factor_to_enum( blend.src_alpha_factor ),
562                                blending_factor_to_enum( blend.dst_alpha_factor )
563                        );
564
565                        m_render_state.blending.src_rgb_factor   = blend.src_rgb_factor;
566                        m_render_state.blending.dst_rgb_factor   = blend.dst_rgb_factor;
567                        m_render_state.blending.src_alpha_factor = blend.src_alpha_factor;
568                        m_render_state.blending.dst_alpha_factor = blend.dst_alpha_factor;
569                }
570
571                if ((m_render_state.blending.rgb_equation   != blend.rgb_equation ) ||
572                        (m_render_state.blending.alpha_equation != blend.alpha_equation ))
573                {
574                        glBlendEquationSeparate(
575                                blending_equation_to_enum( blend.rgb_equation ),
576                                blending_equation_to_enum( blend.alpha_equation )
577                        );
578
579                        m_render_state.blending.rgb_equation   = blend.rgb_equation;
580                        m_render_state.blending.alpha_equation = blend.alpha_equation;
581                }
582
583                if (( m_render_state.blending.color != blend.color ))
584                {
585                        glBlendColor( blend.color.r, blend.color.g, blend.color.b, blend.color.a );
586                        m_render_state.blending.color = blend.color;
587                }
588        }
589}
590
591
592void gl_context::apply_culling( const culling& cull )
593{
594        if ( m_render_state.culling.enabled != cull.enabled )
595        {
596                enable( GL_CULL_FACE, cull.enabled );
597                m_render_state.culling.enabled = cull.enabled;
598        }
599
600        if ( cull.enabled )
601        {
602                if ( m_render_state.culling.face != cull.face )
603                {
[462]604                        glCullFace( culling_face_type_to_enum( cull.face ) );
[37]605                        m_render_state.culling.face = cull.face;
606                }
[462]607        }
[37]608
[462]609        if ( m_render_state.culling.order != cull.order )
610        {
611                glFrontFace( culling_order_type_to_enum( cull.order ) );
612                m_render_state.culling.order = cull.order;
[37]613        }
614}
615
616
617void gl_context::force_apply_render_state( const render_state& state )
618{
619        enable( GL_CULL_FACE, state.culling.enabled );
620        glCullFace( culling_face_type_to_enum( state.culling.face ) );
621        glFrontFace( culling_order_type_to_enum( state.culling.order ) );
622
623        enable( GL_SCISSOR_TEST, state.scissor_test.enabled );
624        glScissor(
625                state.scissor_test.pos.x, state.scissor_test.pos.y,
626                state.scissor_test.dim.x, state.scissor_test.dim.y
627        );
628
629        enable( GL_STENCIL_TEST, state.stencil_test.enabled );
630        force_apply_stencil_face( GL_FRONT, state.stencil_test.front_face );
631        force_apply_stencil_face( GL_BACK,  state.stencil_test.back_face  );
632
633        enable( GL_DEPTH_TEST, state.depth_test.enabled );
634        glDepthFunc( depth_state_function_to_enum( state.depth_test.function ) );
635        glDepthRange( state.depth_range.near, state.depth_range.far );
636
637        enable( GL_BLEND, state.blending.enabled );
638        glBlendFuncSeparate(
639                blending_factor_to_enum( state.blending.src_rgb_factor ),
640                blending_factor_to_enum( state.blending.dst_rgb_factor ),
641                blending_factor_to_enum( state.blending.src_alpha_factor ),
642                blending_factor_to_enum( state.blending.dst_alpha_factor )
643        );
644        glBlendEquationSeparate(
645                blending_equation_to_enum( state.blending.rgb_equation ),
646                blending_equation_to_enum( state.blending.alpha_equation )
647        );
648        glBlendColor(
649                state.blending.color.r, state.blending.color.g,
650                state.blending.color.b, state.blending.color.a
651        );
652
653        glDepthMask( state.depth_mask );
654        glColorMask(
655                state.color_mask.red, state.color_mask.green,
656                state.color_mask.blue, state.color_mask.alpha
657        );
[233]658        glPolygonMode( GL_FRONT_AND_BACK, polygon_mode_fill_to_enum( state.polygon_mode.fill ) );
[37]659}
660
[121]661void gl_context::force_apply_stencil_face( unsigned face, const stencil_test_face& stencil )
[37]662{
663        glStencilOpSeparate( face,
664                stencil_operation_to_enum( stencil.op_fail ),
665                stencil_operation_to_enum( stencil.op_depth_fail ),
666                stencil_operation_to_enum( stencil.op_depth_pass )
667        );
668
669        glStencilFuncSeparate( face,
670                stencil_function_to_enum( stencil.function ),
671                stencil.ref_value,
672                stencil.mask
673        );
674}
675
676
677void gl_context::apply_render_state( const render_state& state )
678{
679        // apply_primitive_restart
680        apply_culling( state.culling );
681        // apply_program_point_size
682        // apply_rasterization_mode
683        apply_scissor_test( state.scissor_test );
684        apply_stencil_test( state.stencil_test );
685        apply_depth_test( state.depth_test );
686        apply_depth_range( state.depth_range );
687        apply_blending( state.blending );
688        apply_color_mask( state.color_mask );
689        apply_depth_mask( state.depth_mask );
[233]690        apply_polygon_mode( state.polygon_mode );
[37]691}
692
[44]693
[326]694gl_context::gl_context( device* a_device, void* a_handle )
695        : context( a_device ), m_handle( a_handle )
[44]696{
[331]697        // TODO: configurable:
[463]698        load_gl_extensions( GL_EXT_FRAMEBUFFER_BLIT | GL_EXT_FRAMEBUFFER_OBJECT | GL_EXT_TEXTURE_ARRAY );
[326]699        force_apply_render_state( m_render_state );
[462]700
[245]701}
702
703
704nv::gl_context::~gl_context()
705{
[313]706        while ( m_framebuffers.size() > 0 )
707                release( m_framebuffers.get_handle(0) );
708        while ( m_vertex_arrays.size() > 0 )
709                release( m_vertex_arrays.get_handle(0) );
[245]710}
711
[303]712void nv::gl_context::apply_engine_uniforms( program p, const scene_state& s )
[245]713{
[406]714        gl_program_info* info = static_cast<gl_device*>( m_device )->m_programs.get( p );
[303]715        if ( info )
716        {
[392]717                for ( auto& u : *info->m_engine_uniforms )
[303]718                {
719                        u->set( this, &s );
720                }
721        }
722}
723
[342]724void nv::gl_context::set_draw_buffers( uint32 count, const output_slot* slots )
[331]725{
[342]726        if ( count == 0 ) return;
727        if ( count == 1 )
728        {
729                set_draw_buffer( slots[0] );
730                return;
731        }
[331]732        unsigned int buffers[8];
[398]733        count = nv::min<uint32>( count, 8 );
[331]734        for ( uint32 i = 0; i < count; ++i )
735        {
736                buffers[i] = output_slot_to_enum( slots[i] );
737                if ( slots[i] > OUTPUT_7 ) buffers[i] = 0;
738        }
[406]739        glDrawBuffers( GLsizei( count ), buffers );
[331]740}
741
742void nv::gl_context::set_draw_buffer( output_slot slot )
743{
744        glDrawBuffer( output_slot_to_enum(slot) );
745}
746
747void nv::gl_context::set_read_buffer( output_slot slot )
748{
749        glReadBuffer( output_slot_to_enum(slot) );
750}
751
[376]752void gl_context::draw( primitive prim, const render_state& rs, program p, vertex_array va, nv::size_t count )
[303]753{
[245]754        apply_render_state( rs );
[313]755        const vertex_array_info* info = m_vertex_arrays.get( va );
[302]756        if ( count > 0 && info )
[245]757        {
[299]758                bind( p );
759                bind( va );
[302]760                if ( info->index.is_valid() )
[245]761                {
[302]762                        glDrawElements( primitive_to_enum(prim), static_cast<GLsizei>( count ), datatype_to_gl_enum( info->index_type ), 0 );
[245]763                }
764                else
765                {
766                        glDrawArrays( primitive_to_enum(prim), 0, static_cast<GLsizei>( count ) );
767                }
[299]768                unbind( va );
769                //unbind( p );
[245]770        }
771}
Note: See TracBrowser for help on using the repository browser.