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

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