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

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