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

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