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

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