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

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