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

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