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

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