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

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