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

Last change on this file since 550 was 550, checked in by epyon, 8 years ago
  • ECS and windowing updates
File size: 36.5 KB
RevLine 
[534]1// Copyright (C) 2012-2017 ChaosForge Ltd
[395]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.
[37]6
7#include "nv/gl/gl_context.hh"
8
9#include "nv/gl/gl_enum.hh"
10#include "nv/lib/gl.hh"
[301]11#include "nv/gl/gl_device.hh"
[365]12#include "nv/core/logger.hh"
[37]13
14using namespace nv;
15
[491]16nv::vertex_array nv::gl_context::create_vertex_array( const vertex_array_desc& desc )
[313]17{
18        vertex_array result = m_vertex_arrays.create();
[491]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 ),
[550]49                        vba.interpolate ? GL_TRUE : GL_FALSE,
[491]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        glBindVertexArray( 0 );
69
70        if ( info->index.is_valid() )
71        {
72                glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, 0 );
73        }
74
[492]75//      for ( uint32 i = 0; i < info->count; ++i )
76//      {
77//              glDisableVertexAttribArray( static_cast<uint32>( info->attr[i].location ) );
78//      }
[491]79
80
[313]81        return result;
82}
83
[492]84nv::framebuffer nv::gl_context::create_framebuffer( uint32 temp_samples )
[313]85{
[491]86        unsigned glid   = 0;
87        glGenFramebuffers( 1, &glid );
88        framebuffer result = m_framebuffers.create();
89        gl_framebuffer_info* info = m_framebuffers.get( result );
90        info->glid = glid;
91        info->depth_rb_glid = 0;
92        info->color_attachment_count = 0;
[492]93        info->sample_count = temp_samples;
[491]94        return result;
[313]95}
96
97void nv::gl_context::release( vertex_array va )
98{
[543]99        if ( gl_vertex_array_info* info = m_vertex_arrays.get( va ) )
100        {
101                release( info );
102                m_vertex_arrays.destroy( va );
103        }
104}
105
106void nv::gl_context::release( gl_vertex_array_info* info )
107{
[313]108        if ( info )
109        {
110                for ( uint32 i = 0; i < info->count; ++i )
111                {
[543]112                        if ( info->attr[i].owner )
[501]113                                release( info->attr[i].vbuffer );
[313]114                }
[543]115                if ( info->index.is_valid() && info->index_owner ) release( info->index );
[491]116                glDeleteVertexArrays( 1, &info->glid );
[313]117        }
118}
119
120void nv::gl_context::release( framebuffer f )
121{
[543]122        if ( gl_framebuffer_info* info = m_framebuffers.get( f ) )
123        {
124                release( info );
125                m_framebuffers.destroy( f );
126        }
127}
128
129void nv::gl_context::release( gl_framebuffer_info* info )
130{
[313]131        if ( info )
132        {
133                // TODO: release textures?
[331]134                glBindFramebuffer( GL_FRAMEBUFFER, 0 );
135                glBindRenderbuffer( GL_RENDERBUFFER, 0 );
136                if ( info->depth_rb_glid == 0 )
137                        glDeleteRenderbuffers( 1, &info->depth_rb_glid );
138                glDeleteFramebuffers( 1, &info->glid );
[313]139        }
140}
141
[535]142nv::image_data* nv::gl_context::dump_image( pixel_format format, image_data* reuse )
[520]143{
[535]144        NV_ASSERT_ALWAYS( format == nv::RGB8 || format == nv::RGBA8, "Bad format passed to dump" );
[520]145        glPixelStorei( GL_PACK_ALIGNMENT, 1 );
146        image_data* result = reuse;
[535]147        datatype type = get_pixel_format_info( format ).type;
148        if ( !result ) result = new image_data( format, ivec2( m_viewport.z, m_viewport.w ) );
149        glReadPixels( 0, 0, m_viewport.z, m_viewport.w, format == nv::RGB8 ? GL_RGB : GL_RGBA, datatype_to_gl_enum( type ), const_cast< uint8* >( result->get_data() ) );
[520]150        return result;
151}
152
153
[313]154const framebuffer_info* nv::gl_context::get_framebuffer_info( framebuffer f ) const
155{
156        return m_framebuffers.get( f );
157}
158
[500]159void nv::gl_context::attach( framebuffer f, output_slot slot, texture t, int layer /* = -1*/ )
[331]160{
161        // TODO: framebuffer variable, so no re-binding?
162        // TODO: support 1d, 3d textures, cubemaps or layers?
163        // TODO: support GL_READ_FRAMEBUFFER?
164        const gl_framebuffer_info* info  = m_framebuffers.get( f );
[406]165        const gl_texture_info*     tinfo = static_cast< const gl_texture_info* >( m_device->get_texture_info( t ) );
[331]166        if ( info )
167        {
168                glBindFramebuffer( GL_FRAMEBUFFER, info->glid );
169                unsigned gl_type = texture_type_to_enum( tinfo->type );
[500]170                unsigned tglid = tinfo ? tinfo->glid : 0;
[313]171
[500]172                if ( layer >= 0 )
[331]173                {
[500]174                        glFramebufferTextureLayer( GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + unsigned( slot ), tglid, 0, layer );
[331]175                }
176                else
177                {
[500]178                        glFramebufferTexture2D( GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + unsigned( slot ), gl_type, tglid, 0 );
[331]179                }
180
181        }
182}
183
[463]184void nv::gl_context::attach( framebuffer f, texture depth, int layer /*= -1*/ )
[331]185{
186        // TODO: framebuffer variable, so no re-binding?
187        // TODO: support GL_READ_FRAMEBUFFER?
188        const gl_framebuffer_info* info  = m_framebuffers.get( f );
[406]189        const gl_texture_info*     tinfo = static_cast< const gl_texture_info* >( m_device->get_texture_info( depth ) );
[331]190        if ( info )
191        {
192                glBindFramebuffer( GL_FRAMEBUFFER, info->glid );
193                unsigned gl_type = texture_type_to_enum( tinfo->type );
[463]194                unsigned glid = ( tinfo ? tinfo->glid : 0 );
195                if ( layer >= 0 )
[331]196                {
[500]197                        glFramebufferTextureLayer( GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, glid, 0, layer );
[331]198                }
199                else
200                {
[463]201                        glFramebufferTexture2D( GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, gl_type, glid, 0 );
[331]202                }
203        }
[463]204
[331]205}
206
207void nv::gl_context::attach( framebuffer f, ivec2 size )
208{
209        // TODO: framebuffer variable, so no re-binding?
210        // TODO: support GL_READ_FRAMEBUFFER?
211        gl_framebuffer_info* info  = m_framebuffers.get( f );
212        if ( info )
213        {
214                glBindFramebuffer( GL_FRAMEBUFFER, info->glid );
[462]215                if ( info->depth_rb_glid )
216                        glDeleteRenderbuffers( 1, &(info->depth_rb_glid) );
[331]217                glGenRenderbuffers( 1, &(info->depth_rb_glid) );
218                glBindRenderbuffer( GL_RENDERBUFFER, info->depth_rb_glid );
[492]219                if ( info->sample_count > 1 )
220                        glRenderbufferStorageMultisample( GL_RENDERBUFFER, info->sample_count, GL_DEPTH_COMPONENT16, size.x, size.y );
221                else
222                        glRenderbufferStorage( GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, size.x, size.y );
[331]223                glFramebufferRenderbuffer( GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, info->depth_rb_glid );
224                glBindRenderbuffer( GL_RENDERBUFFER, 0 );
225        }
226
227}
228
[523]229void nv::gl_context::attach_depth( framebuffer source, framebuffer target )
230{
231        gl_framebuffer_info* sinfo = m_framebuffers.get( source );
232        gl_framebuffer_info* tinfo = m_framebuffers.get( target );
233
234        if ( sinfo && tinfo )
235        {
236                glBindFramebuffer( GL_FRAMEBUFFER, tinfo->glid );
237                // TODO: do we need to bind the renderbuffer at all?
238                glBindRenderbuffer( GL_RENDERBUFFER, sinfo->depth_rb_glid );
239                glFramebufferRenderbuffer( GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, sinfo->depth_rb_glid );
240                glBindRenderbuffer( GL_RENDERBUFFER, 0 );
241                glBindRenderbuffer( GL_FRAMEBUFFER, 0 );
242        }
243
244}
245
246
[503]247void nv::gl_context::blit( framebuffer f, buffer_mask mask, ivec2 src1, ivec2 src2, ivec2 dst1, ivec2 dst2 )
[331]248{
249        gl_framebuffer_info* info  = m_framebuffers.get( f );
250        if ( info )
251        {
252                glBindFramebuffer( GL_FRAMEBUFFER, info->glid );
[503]253                unsigned filter = mask == buffer_mask::COLOR_BUFFER ? GL_LINEAR : GL_NEAREST;
[331]254                glBlitFramebuffer( src1.x, src1.y, src2.x, src2.y, dst1.x, dst1.y, dst2.x, dst2.y, clear_state_buffers_to_mask( mask ), filter );
255        }
256}
257
258
[503]259void nv::gl_context::blit( framebuffer from, framebuffer to, buffer_mask mask, ivec2 src1, ivec2 src2, ivec2 dst1, ivec2 dst2 )
[492]260{
261        gl_framebuffer_info* finfo = m_framebuffers.get( from );
262        gl_framebuffer_info* tinfo = m_framebuffers.get( to );
263        if ( finfo )
264        {
265                glBindFramebuffer( GL_READ_FRAMEBUFFER, finfo->glid );
266                glBindFramebuffer( GL_DRAW_FRAMEBUFFER, tinfo ? tinfo->glid : 0 );
[503]267                unsigned filter = mask == buffer_mask::COLOR_BUFFER ? GL_LINEAR : GL_NEAREST;
[492]268                glBlitFramebuffer( src1.x, src1.y, src2.x, src2.y, dst1.x, dst1.y, dst2.x, dst2.y, clear_state_buffers_to_mask( mask ), filter );
269                glBindFramebuffer( GL_READ_FRAMEBUFFER, 0 );
270                if ( tinfo ) glBindFramebuffer( GL_DRAW_FRAMEBUFFER, 0 );
271        }
272}
273
[331]274bool nv::gl_context::check( framebuffer_slot ft )
275{
[462]276        glDrawBuffer( 0 );
277        glReadBuffer( 0 );
[491]278
279        unsigned result = glCheckFramebufferStatus( framebuffer_slot_to_enum(ft) );
280        if ( result == GL_FRAMEBUFFER_COMPLETE ) return true;
281        switch ( result )
[331]282        {
[492]283        case GL_FRAMEBUFFER_UNDEFINED                     : NV_LOG_ERROR( "gl_context::check : Framebuffer undefined!" ); break;
284        case GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE        : NV_LOG_ERROR( "gl_context::check : Incomplete multisample!" ); break;
285        case GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS      : NV_LOG_ERROR( "gl_context::check : Incomplete layer targets!" ); break;
[491]286        case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT         : NV_LOG_ERROR( "gl_context::check : Framebuffer incomplete attachment!" ); break;
287        case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT : NV_LOG_ERROR( "gl_context::check : Framebuffer missing attachment!" ); break;
[466]288//              case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS         : NV_LOG_ERROR( "gl_context::check : Framebuffer incomplete dimensions!" ); break;
289//              case GL_FRAMEBUFFER_INCOMPLETE_FORMATS            : NV_LOG_ERROR( "gl_context::check : Framebuffer incomplete formats!" ); break;
[491]290        case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER        : NV_LOG_ERROR( "gl_context::check : Framebuffer incomplete draw buffer!" ); break;
291        case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER        : NV_LOG_ERROR( "gl_context::check : Framebuffer incomplete read buffer!" ); break;
292        case GL_FRAMEBUFFER_UNSUPPORTED                   : NV_LOG_ERROR( "gl_context::check : Framebuffer format combination unsupported!" ); break;
293        default: NV_LOG_ERROR( "gl_context::check : Unknown Framebuffer error! (", result, ")" ); break;
[331]294        }
[462]295        glDrawBuffer( GL_BACK );
296        glReadBuffer( GL_BACK );
[331]297        return false;
298}
299
300void nv::gl_context::bind( framebuffer f, framebuffer_slot ft /*= FRAMEBUFFER_BOTH */ )
301{
302        const gl_framebuffer_info* info = m_framebuffers.get( f );
303        if ( info )
304        {
305                glBindFramebuffer( framebuffer_slot_to_enum(ft), info->glid );
306        }
307        else
308        {
309                glBindFramebuffer( framebuffer_slot_to_enum(ft), 0 );
310        }
311}
312
[501]313
[491]314void nv::gl_context::bind( buffer b, texture t )
315{
316        const gl_buffer_info*  binfo = static_cast< const gl_buffer_info* >( m_device->get_buffer_info( b ) );
317        const gl_texture_info* tinfo = static_cast< const gl_texture_info* >( m_device->get_texture_info( t ) );
318        NV_ASSERT( binfo && tinfo, "Bad buffer or texture passed to create_texture" );
319        if ( binfo && tinfo )
320        {
321                NV_ASSERT_ALWAYS( binfo->type == TEXTURE_BUFFER && tinfo->type == TEXTURE_1D_BUFFER, "bad texture or buffer type!" );
[492]322                bind( t, TEXTURE_0 );
[535]323                glTexBuffer( GL_TEXTURE_BUFFER, image_format_to_internal_enum( tinfo->format ), binfo->glid );
[491]324        }
325}
326
[534]327void nv::gl_context::bind( buffer b, uint32 index, uint32 offset /*= 0*/, uint32 size /*= 0 */ )
[473]328{
329        const gl_buffer_info* info = static_cast< const gl_buffer_info* >( m_device->get_buffer_info( b ) );
330        if ( info )
331        {
332                if ( size == 0 )
333                        glBindBufferBase( buffer_type_to_enum( info->type ), index, info->glid );
334                else
[487]335                        glBindBufferRange( buffer_type_to_enum( info->type ), index, info->glid, static_cast<GLintptr>( offset ), static_cast<GLsizeiptr>( size ) );
[473]336        }
337}
338
[301]339void gl_context::bind( texture t, texture_slot slot )
[299]340{
[492]341        if ( m_bound_textures[ slot ] != t )
[301]342        {
[492]343                const gl_texture_info* info = static_cast< const gl_texture_info* >( m_device->get_texture_info( t ) );
344                if ( info )
345                {
346                        set_active_texture( slot );
347                        glBindTexture( texture_type_to_enum( info->type ), info->glid );
[501]348                        m_bound_textures[slot] = t;
[492]349                }
[301]350        }
[299]351}
352
[303]353void nv::gl_context::bind( program p )
[299]354{
[406]355        gl_device* gdevice    = static_cast<gl_device*>( m_device );
356        gl_program_info* info = gdevice->m_programs.get( p );
[303]357        if ( info )
358        {
[501]359                if ( m_bound_program != p )
360                        glUseProgram( info->glid );
[406]361                gdevice->update_uniforms( info );
[493]362                if ( !info->validated )
363                {
364                        validate_program( p );
365                }
[501]366                m_bound_program = p;
[303]367        }
[299]368}
369
[493]370bool nv::gl_context::validate_program( program p )
371{
372        gl_device* gdevice = static_cast<gl_device*>( m_device );
373        gl_program_info* info = gdevice->m_programs.get( p );
374        if ( info )
375        {
376                info->validated = true;
377                const uint32 buffer_size = 1024;
378                char buffer[buffer_size] = { 0 };
379                int length;
380                int status;
381                glValidateProgram( info->glid );
382                glGetProgramiv( info->glid, GL_VALIDATE_STATUS, &status );
383
384                if ( status == GL_FALSE )
385                {
386                        glGetProgramInfoLog( info->glid, buffer_size, &length, buffer );
387                        NV_LOG_ERROR( "Program #", info->glid, " validation error : ", buffer );
388                        return false;
389                }
390                return true;
391        }
392        return false;
393}
394
395
[313]396// void nv::gl_context::bind( buffer b )
397// {
398//      const gl_buffer_info* info = static_cast< const gl_buffer_info* >( m_device->get_buffer_info( b ) );
399//      if ( info )
400//      {
401//              glBindBuffer( buffer_type_to_enum( info->type ), info->glid );
402//      }
403// }
[299]404
[302]405void nv::gl_context::bind( vertex_array va )
[299]406{
[491]407        gl_vertex_array_info* info = m_vertex_arrays.get( va );
[302]408        if ( info )
[299]409        {
[491]410                glBindVertexArray( info->glid );
[299]411        }
412}
413
[313]414void nv::gl_context::unbind( program )
415{
[501]416        if ( m_bound_program )
417                glUseProgram( 0 );
418        m_bound_program = program();
[313]419}
420
[492]421void nv::gl_context::set_active_texture( texture_slot slot )
422{
423        if ( slot != m_active_slot )
[501]424        {
[492]425                glActiveTexture( GL_TEXTURE0 + static_cast<GLenum>( slot ) );
[501]426                m_active_slot = slot;
427        }
[492]428}
429
[313]430// void nv::gl_context::unbind( buffer b )
431// {
432//      const gl_buffer_info* info = static_cast< const gl_buffer_info* >( m_device->get_buffer_info( b ) );
433//      if ( info )
434//      {
435//              glBindBuffer( buffer_type_to_enum( info->type ), 0 );
436//      }
437// }
438
[302]439void nv::gl_context::unbind( vertex_array va )
[299]440{
[313]441        const vertex_array_info* info = m_vertex_arrays.get( va );
[302]442        if ( info )
[299]443        {
[491]444                glBindVertexArray( 0 );
[299]445        }
446}
447
[313]448void nv::gl_context::unbind( framebuffer f )
449{
450        // this way we are sure that the extension is loaded
451        const gl_framebuffer_info* info = m_framebuffers.get( f );
452        if ( info )
453        {
454                glBindFramebuffer( GL_FRAMEBUFFER, 0 );
455        }
[331]456        glDrawBuffer( GL_BACK );
457        glReadBuffer( GL_BACK );
[313]458}
459
[406]460void nv::gl_context::update( texture t, const void* data )
[299]461{
[301]462        const gl_texture_info* info = static_cast< const gl_texture_info* >( m_device->get_texture_info( t ) );
[491]463        NV_ASSERT_ALWAYS( info->type != TEXTURE_1D_BUFFER, "Buffer texture passed to update!" );
[492]464        NV_ASSERT_ALWAYS( info->type != TEXTURE_2D_MULTISAMPLE, "Multisample texture passed to update!" );
[301]465        if ( info )
466        {
[535]467                pixel_format format  = info->format;
468                datatype     type    = get_pixel_format_info( format ).type;
[463]469                ivec3        size    = info->size;
[331]470                unsigned     gl_type = texture_type_to_enum( info->type );
[299]471
[501]472                bind( t, texture_slot::TEXTURE_0 );
[463]473                if ( info->type == TEXTURE_3D || info->type == TEXTURE_2D_ARRAY )
[535]474//                      glTexImage3D( gl_type, 0, static_cast<GLint>( nv::image_format_to_internal_enum( format ) ), size.x, size.y, size.z, 0, nv::image_format_to_enum( format ), nv::datatype_to_gl_enum( type ), data );
475                        glTexSubImage3D( gl_type, 0, 0, 0, 0, size.x, size.y, size.z, nv::image_format_to_enum( format ), nv::datatype_to_gl_enum( type ), data );
[463]476                else
[535]477//                      glTexImage2D( gl_type, 0, static_cast<GLint>( nv::image_format_to_internal_enum(format) ), size.x, size.y, 0, nv::image_format_to_enum(format), nv::datatype_to_gl_enum(type), data );
478                        glTexSubImage2D( gl_type, 0, 0, 0, size.x, size.y, nv::image_format_to_enum( format ), nv::datatype_to_gl_enum( type ), data );
[301]479        }
[299]480}
481
[534]482void* nv::gl_context::map_buffer( buffer b, buffer_access ba, uint32 offset, uint32 length )
[499]483{
484        const gl_buffer_info* info = static_cast<const gl_buffer_info*>( m_device->get_buffer_info( b ) );
485        unsigned int glenum = buffer_type_to_enum( info->type );
486        glBindBuffer( glenum, info->glid );
487        void* result = glMapBufferRange( glenum, GLintptr( offset ), GLsizeiptr( length ), buffer_access_to_bitfield( ba ) );
488        if ( result == nullptr )
489        {
490                while ( GLenum err = glGetError() )
491                switch ( err )
492                {
493                case GL_INVALID_VALUE     : NV_LOG_ERROR( "map_buffer failed : GL_INVALID_VALUE" ) break;
494                case GL_INVALID_OPERATION : NV_LOG_ERROR( "map_buffer failed : GL_INVALID_OPERATION " ) break;
495                case GL_OUT_OF_MEMORY     : NV_LOG_ERROR( "map_buffer failed : GL_OUT_OF_MEMORY " ) break;
[500]496                default:
[499]497                        break;
498                }
499        }
500        return result;
501}
502
503void nv::gl_context::unmap_buffer( buffer b )
504{
505        const gl_buffer_info* info = static_cast<const gl_buffer_info*>( m_device->get_buffer_info( b ) );
506        glUnmapBuffer( buffer_type_to_enum( info->type ) );
507}
508
[534]509// void nv::gl_context::update( buffer b, uint32 index, const void* data, uint32 offset, uint32 size )
[485]510// {
511//      const gl_buffer_info* info = static_cast<const gl_buffer_info*>( m_device->get_buffer_info( b ) );
512//      if ( info )
513//      {
514//              GLenum glenum = buffer_type_to_enum( info->type );
515//              if ( size == 0 )
516//                      glBindBufferBase( glenum, index, info->glid );
517//              else
518//                      glBindBufferRange( glenum, index, info->glid, offset, size );
519//              glBufferSubData( glenum, GLintptr( offset ), GLsizeiptr( size ), data );
520//      }
521// }
[473]522
[534]523void gl_context::update( buffer b, const void* data, nv::uint32 offset, nv::uint32 size )
[299]524{
[302]525        const gl_buffer_info* info = static_cast< const gl_buffer_info* >( m_device->get_buffer_info( b ) );
526        if ( info )
527        {
[313]528                GLenum glenum = buffer_type_to_enum( info->type );
529                glBindBuffer( glenum, info->glid );
[406]530                glBufferSubData( glenum, GLintptr( offset ), GLsizeiptr( size ), data );
[302]531        }
[299]532}
533
[37]534void gl_context::clear( const clear_state& cs )
535{
536        // apply_framebuffer
[44]537       
[37]538        apply_scissor_test( cs.scissor_test );
539        apply_color_mask( cs.color_mask );
540        apply_depth_mask( cs.depth_mask );
541        // stencil_mask_separate
542
543        if ( m_clear_color != cs.color )
544        {
545                glClearColor( cs.color.r, cs.color.g, cs.color.b, cs.color.a );
546                m_clear_color = cs.color;
547        }
548
549        if ( m_clear_depth != cs.depth )
550        {
551                glClearDepth( cs.depth );
552                m_clear_depth = cs.depth;
553        }
554
555        if ( m_clear_stencil != cs.stencil )
556        {
557                glClearStencil( cs.stencil );
558                m_clear_stencil = cs.stencil;
559        }
[44]560       
561        glClear( clear_state_buffers_to_mask( cs.buffers ) );
[37]562}
563
564const ivec4& gl_context::get_viewport()
565{
566        return m_viewport;
567}
568
569void gl_context::set_viewport( const ivec4& viewport )
570{
[501]571        if ( m_viewport != viewport )
572        {
573                NV_ASSERT_ALWAYS( viewport.z > 0 && viewport.w > 0, "viewport dimensions must be greater than zero!" );
574                m_viewport = viewport;
575                glViewport( viewport.x, viewport.y, viewport.z, viewport.w );
576        }
[37]577}
578
579void gl_context::enable( unsigned int what, bool value )
580{
581        if ( value )
582        {
583                glEnable( what );
584        }
585        else
586        {
587                glDisable( what );
588        }
589}
590
591void gl_context::apply_stencil_test( const stencil_test& stencil )
592{
593        if ( m_render_state.stencil_test.enabled != stencil.enabled )
594        {
595                enable( GL_STENCIL_TEST, stencil.enabled );
596                m_render_state.stencil_test.enabled = stencil.enabled;
597        }
[331]598       
[37]599        if ( stencil.enabled )
600        {
601                apply_stencil_face( GL_FRONT, m_render_state.stencil_test.front_face, stencil.front_face );
602                apply_stencil_face( GL_BACK,  m_render_state.stencil_test.back_face,  stencil.back_face );
603        }
604}
605
[121]606void gl_context::apply_stencil_face( unsigned face, stencil_test_face& stencil, const stencil_test_face& new_stencil )
[37]607{
608        if (( stencil.op_fail       != new_stencil.op_fail       ) ||
609                ( stencil.op_depth_fail != new_stencil.op_depth_fail ) ||
610                ( stencil.op_depth_pass != new_stencil.op_depth_pass ) )
611        {
612                glStencilOpSeparate( face,
613                        stencil_operation_to_enum( new_stencil.op_fail ),
614                        stencil_operation_to_enum( new_stencil.op_depth_fail ),
615                        stencil_operation_to_enum( new_stencil.op_depth_pass )
616                );
617
618                stencil.op_fail       = new_stencil.op_fail;
619                stencil.op_depth_fail = new_stencil.op_depth_fail;
620                stencil.op_depth_pass = new_stencil.op_depth_pass;
621        }
622
623        if (( stencil.function  != new_stencil.function ) ||
624                ( stencil.ref_value != new_stencil.ref_value ) ||
625                ( stencil.mask      != new_stencil.mask ))
626        {
627                glStencilFuncSeparate( face,
628                        stencil_function_to_enum( new_stencil.function ),
629                        new_stencil.ref_value,
630                        new_stencil.mask
631                );
632
633                stencil.function  = new_stencil.function;
634                stencil.ref_value = new_stencil.ref_value;
635                stencil.mask      = new_stencil.mask;
636        }
637}
638
639void gl_context::apply_scissor_test( const scissor_test& scissor )
640{
641        if ( m_render_state.scissor_test.enabled != scissor.enabled )
642        {
643                enable( GL_SCISSOR_TEST, scissor.enabled );
644                m_render_state.scissor_test.enabled = scissor.enabled;
645        }
646
647
648        if ( scissor.enabled )
649        {
[403]650                NV_ASSERT_ALWAYS( scissor.dim.x > 0 && scissor.dim.y > 0, "scissor_test.rect dimension equal to zero!" );
651
[37]652                if ( m_render_state.scissor_test.dim != scissor.dim || m_render_state.scissor_test.pos != scissor.pos )
653                {
654                        glScissor(
655                                scissor.pos.x, scissor.pos.y,
656                                scissor.dim.x, scissor.dim.y
657                        );
658                        m_render_state.scissor_test.dim = scissor.dim;
659                        m_render_state.scissor_test.pos = scissor.pos;
660                }
661        }
662}
663
664void gl_context::apply_depth_test( const depth_test& depth )
665{
666        if ( m_render_state.depth_test.enabled != depth.enabled )
667        {
668                enable( GL_DEPTH_TEST, depth.enabled );
669                m_render_state.depth_test.enabled = depth.enabled;
670        }
671
672        if ( depth.enabled )
673        {
674                if ( m_render_state.depth_test.function != depth.function )
675                {
676                        glDepthFunc( depth_state_function_to_enum( depth.function ) );
677                        m_render_state.depth_test.function = depth.function;
678                }
679        }
680}
681
682void gl_context::apply_depth_mask( bool mask )
683{
684        if ( m_render_state.depth_mask != mask )
685        {
686                glDepthMask( mask );
687                m_render_state.depth_mask = mask;
688        }
689}
690
[492]691void gl_context::apply_multisample( bool multisample )
692{
693        if ( m_render_state.multisample != multisample )
694        {
[550]695                enable( GL_MULTISAMPLE, multisample );
[492]696                m_render_state.multisample = multisample;
697        }
698}
699
[233]700void gl_context::apply_polygon_mode( const polygon_mode& mode )
701{
702        if ( m_render_state.polygon_mode.fill != mode.fill )
703        {
704                glPolygonMode( GL_FRONT_AND_BACK, polygon_mode_fill_to_enum( mode.fill ) );
705                m_render_state.polygon_mode.fill = mode.fill;
706        }
707}
708
709
[37]710void gl_context::apply_depth_range( const depth_range& range )
711{
[403]712        NV_ASSERT_ALWAYS( range.near >= 0.0 && range.near <= 1.0, "render_state.depth_range.near must be between zero and one!" );
713        NV_ASSERT_ALWAYS( range.far  >= 0.0 && range.far  <= 1.0, "render_state.depth_range.far must be between zero and one!" );
[37]714
715        if ((m_render_state.depth_range.far  != range.far) ||
716                (m_render_state.depth_range.near != range.near))
717        {
718                glDepthRange( range.near, range.far );
719
720                m_render_state.depth_range.far  = range.far;
721                m_render_state.depth_range.near = range.near;
722        }
723}
724
725void gl_context::apply_color_mask( const color_mask& mask )
726{
727        if ( m_render_state.color_mask != mask )
728        {
729                glColorMask( mask.red, mask.green, mask.blue, mask.alpha );
730                m_render_state.color_mask = mask;
731        }
732}
733
734void gl_context::apply_blending( const blending& blend )
735{
736        if ( m_render_state.blending.enabled != blend.enabled )
737        {
738                enable( GL_BLEND, blend.enabled );
739                m_render_state.blending.enabled = blend.enabled;
740        }
741
742        if ( blend.enabled )
743        {
744                if ((m_render_state.blending.src_rgb_factor   != blend.src_rgb_factor ) ||
745                        (m_render_state.blending.dst_rgb_factor   != blend.dst_rgb_factor ) ||
746                        (m_render_state.blending.src_alpha_factor != blend.src_alpha_factor ) ||
747                        (m_render_state.blending.dst_alpha_factor != blend.dst_alpha_factor ))
748                {
749                        glBlendFuncSeparate(
750                                blending_factor_to_enum( blend.src_rgb_factor ),
751                                blending_factor_to_enum( blend.dst_rgb_factor ),
752                                blending_factor_to_enum( blend.src_alpha_factor ),
753                                blending_factor_to_enum( blend.dst_alpha_factor )
754                        );
755
756                        m_render_state.blending.src_rgb_factor   = blend.src_rgb_factor;
757                        m_render_state.blending.dst_rgb_factor   = blend.dst_rgb_factor;
758                        m_render_state.blending.src_alpha_factor = blend.src_alpha_factor;
759                        m_render_state.blending.dst_alpha_factor = blend.dst_alpha_factor;
760                }
761
762                if ((m_render_state.blending.rgb_equation   != blend.rgb_equation ) ||
763                        (m_render_state.blending.alpha_equation != blend.alpha_equation ))
764                {
765                        glBlendEquationSeparate(
766                                blending_equation_to_enum( blend.rgb_equation ),
767                                blending_equation_to_enum( blend.alpha_equation )
768                        );
769
770                        m_render_state.blending.rgb_equation   = blend.rgb_equation;
771                        m_render_state.blending.alpha_equation = blend.alpha_equation;
772                }
773
774                if (( m_render_state.blending.color != blend.color ))
775                {
776                        glBlendColor( blend.color.r, blend.color.g, blend.color.b, blend.color.a );
777                        m_render_state.blending.color = blend.color;
778                }
779        }
780}
781
782
783void gl_context::apply_culling( const culling& cull )
784{
785        if ( m_render_state.culling.enabled != cull.enabled )
786        {
787                enable( GL_CULL_FACE, cull.enabled );
788                m_render_state.culling.enabled = cull.enabled;
789        }
790
791        if ( cull.enabled )
792        {
793                if ( m_render_state.culling.face != cull.face )
794                {
[462]795                        glCullFace( culling_face_type_to_enum( cull.face ) );
[37]796                        m_render_state.culling.face = cull.face;
797                }
[462]798        }
[37]799
[462]800        if ( m_render_state.culling.order != cull.order )
801        {
802                glFrontFace( culling_order_type_to_enum( cull.order ) );
803                m_render_state.culling.order = cull.order;
[37]804        }
805}
806
807
808void gl_context::force_apply_render_state( const render_state& state )
809{
810        enable( GL_CULL_FACE, state.culling.enabled );
811        glCullFace( culling_face_type_to_enum( state.culling.face ) );
812        glFrontFace( culling_order_type_to_enum( state.culling.order ) );
813
814        enable( GL_SCISSOR_TEST, state.scissor_test.enabled );
815        glScissor(
816                state.scissor_test.pos.x, state.scissor_test.pos.y,
817                state.scissor_test.dim.x, state.scissor_test.dim.y
818        );
819
820        enable( GL_STENCIL_TEST, state.stencil_test.enabled );
821        force_apply_stencil_face( GL_FRONT, state.stencil_test.front_face );
822        force_apply_stencil_face( GL_BACK,  state.stencil_test.back_face  );
823
824        enable( GL_DEPTH_TEST, state.depth_test.enabled );
825        glDepthFunc( depth_state_function_to_enum( state.depth_test.function ) );
826        glDepthRange( state.depth_range.near, state.depth_range.far );
827
828        enable( GL_BLEND, state.blending.enabled );
829        glBlendFuncSeparate(
830                blending_factor_to_enum( state.blending.src_rgb_factor ),
831                blending_factor_to_enum( state.blending.dst_rgb_factor ),
832                blending_factor_to_enum( state.blending.src_alpha_factor ),
833                blending_factor_to_enum( state.blending.dst_alpha_factor )
834        );
835        glBlendEquationSeparate(
836                blending_equation_to_enum( state.blending.rgb_equation ),
837                blending_equation_to_enum( state.blending.alpha_equation )
838        );
839        glBlendColor(
840                state.blending.color.r, state.blending.color.g,
841                state.blending.color.b, state.blending.color.a
842        );
843
844        glDepthMask( state.depth_mask );
845        glColorMask(
846                state.color_mask.red, state.color_mask.green,
847                state.color_mask.blue, state.color_mask.alpha
848        );
[233]849        glPolygonMode( GL_FRONT_AND_BACK, polygon_mode_fill_to_enum( state.polygon_mode.fill ) );
[37]850}
851
[121]852void gl_context::force_apply_stencil_face( unsigned face, const stencil_test_face& stencil )
[37]853{
854        glStencilOpSeparate( face,
855                stencil_operation_to_enum( stencil.op_fail ),
856                stencil_operation_to_enum( stencil.op_depth_fail ),
857                stencil_operation_to_enum( stencil.op_depth_pass )
858        );
859
860        glStencilFuncSeparate( face,
861                stencil_function_to_enum( stencil.function ),
862                stencil.ref_value,
863                stencil.mask
864        );
865}
866
867
868void gl_context::apply_render_state( const render_state& state )
869{
870        // apply_primitive_restart
871        apply_culling( state.culling );
872        // apply_program_point_size
873        // apply_rasterization_mode
874        apply_scissor_test( state.scissor_test );
875        apply_stencil_test( state.stencil_test );
876        apply_depth_test( state.depth_test );
877        apply_depth_range( state.depth_range );
878        apply_blending( state.blending );
879        apply_color_mask( state.color_mask );
880        apply_depth_mask( state.depth_mask );
[492]881        apply_multisample( state.multisample );
[233]882        apply_polygon_mode( state.polygon_mode );
[37]883}
884
[44]885
[326]886gl_context::gl_context( device* a_device, void* a_handle )
887        : context( a_device ), m_handle( a_handle )
[44]888{
[331]889        // TODO: configurable:
[491]890//      load_gl_extensions( GL_EXT_FRAMEBUFFER_BLIT | GL_EXT_FRAMEBUFFER_OBJECT | GL_EXT_TEXTURE_ARRAY );
[492]891        m_active_slot = texture_slot( -1 );
[326]892        force_apply_render_state( m_render_state );
[550]893        glHint( GL_POLYGON_SMOOTH_HINT, GL_NICEST );
[245]894}
895
896nv::gl_context::~gl_context()
897{
[543]898        for ( auto& info : m_framebuffers )
899                release( &info );
900        for ( auto& info : m_vertex_arrays )
901                release( &info );
[245]902}
903
[303]904void nv::gl_context::apply_engine_uniforms( program p, const scene_state& s )
[245]905{
[406]906        gl_program_info* info = static_cast<gl_device*>( m_device )->m_programs.get( p );
[303]907        if ( info )
908        {
[392]909                for ( auto& u : *info->m_engine_uniforms )
[303]910                {
911                        u->set( this, &s );
912                }
913        }
914}
915
[535]916nv::texture nv::gl_context::create_texture( texture_type type, ivec2 size, pixel_format aformat, sampler asampler, const void* data /*= nullptr */ )
[501]917{
[535]918        texture result = create_texture( type, aformat );
[501]919        gl_texture_info* info = static_cast<gl_device*>( m_device )->get_full_texture_info( result );
920        bind( result, texture_slot::TEXTURE_0 );
921        unsigned glid = info->glid;
922        unsigned gl_type = texture_type_to_enum( type );
[535]923        GLenum gl_internal = GLenum( image_format_to_internal_enum( aformat ) );
924        unsigned gl_enum = image_format_to_enum( aformat );
[501]925
[535]926        bool is_depth = aformat == DEPTH16 || aformat == DEPTH24 || aformat == DEPTH32;
[501]927
928        // Detect if mipmapping was requested
929        //      if ( gl_type == GL_TEXTURE_2D && gl_enum != GL_RED_INTEGER && asampler.filter_min != sampler::LINEAR && asampler.filter_min != sampler::NEAREST )
930        //      {
931        //              // TODO: This should not be done if we use framebuffers!
932        //              glTexParameteri( gl_type, GL_GENERATE_MIPMAP, GL_TRUE);
933        //      }
934
935        if ( asampler.filter_max != sampler::NEAREST )
936        {
937                asampler.filter_max = sampler::LINEAR;
938        }
939
940        if ( gl_type != GL_TEXTURE_2D_MULTISAMPLE )
941        {
942                glTexParameteri( gl_type, GL_TEXTURE_MIN_FILTER, GLint( nv::sampler_filter_to_enum( asampler.filter_min ) ) );
943                glTexParameteri( gl_type, GL_TEXTURE_MAG_FILTER, GLint( nv::sampler_filter_to_enum( asampler.filter_max ) ) );
944        }
945
946        if ( gl_type != GL_TEXTURE_2D_MULTISAMPLE && gl_enum != GL_RED_INTEGER )
947        {
948                glTexParameteri( gl_type, GL_TEXTURE_WRAP_S, GLint( nv::sampler_wrap_to_enum( asampler.wrap_s ) ) );
949                glTexParameteri( gl_type, GL_TEXTURE_WRAP_T, GLint( nv::sampler_wrap_to_enum( asampler.wrap_t ) ) );
950        }
951
952        if ( is_depth )
953        {
954                //              glTexParameteri( gl_type, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
955                //              glTexParameteri( gl_type, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
956
957                // This is to allow usage of shadow2DProj function in the shader
958                glTexParameteri( gl_type, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_REF_TO_TEXTURE );
959                glTexParameteri( gl_type, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL );
960        }
961
962        // #define GL_TEXTURE_MAX_ANISOTROPY_EXT 0x84FE
963        // #define GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT 0x84FF
964        //
965        //      float aniso = 0.0f;
966        //      glGetFloatv( GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &aniso );
967        //      NV_LOG_INFO( "Anisotropy at ", aniso, " (", int( aniso ), " ) " );
968        //      glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, aniso );
969
970        if ( gl_type != GL_TEXTURE_2D_MULTISAMPLE )
[535]971                glTexImage2D( gl_type, 0, gl_internal, size.x, size.y, 0, gl_enum, nv::datatype_to_gl_enum( get_pixel_format_info( aformat ).type ), data );
[501]972        else
973                glTexImage2DMultisample( gl_type, 4, gl_internal, size.x, size.y, 1 );
974
975        if ( gl_type == GL_TEXTURE_2D && gl_enum != GL_RED_INTEGER && asampler.filter_min != sampler::LINEAR && asampler.filter_min != sampler::NEAREST )
976        {
977                // TODO: This should not be done if we use framebuffers!
978                glGenerateMipmap( gl_type );
979        }
980
981        bind( texture(), texture_slot::TEXTURE_0 );
982
983        info->type = type;
984        info->format = aformat;
985        info->tsampler = asampler;
986        info->size = ivec3( size.x, size.y, 1 );
987        info->glid = glid;
988
989        return result;
990}
991
[535]992nv::texture nv::gl_context::create_texture( texture_type type, ivec3 size, pixel_format aformat, sampler asampler, const void* data /*= nullptr */ )
[501]993{
[535]994        texture result = create_texture( type, aformat );
[501]995        gl_texture_info* info = static_cast<gl_device*>( m_device )->get_full_texture_info( result );
996        bind( result, texture_slot::TEXTURE_0 );
997        unsigned glid = info->glid;
998
999        unsigned gl_type = texture_type_to_enum( type );
1000
[535]1001        bool is_depth = aformat == DEPTH16 || aformat == DEPTH24 || aformat == DEPTH32;
[501]1002
1003        if ( asampler.filter_max != sampler::NEAREST )
1004        {
1005                asampler.filter_max = sampler::LINEAR;
1006        }
1007
1008        glTexParameteri( gl_type, GL_TEXTURE_MIN_FILTER, GLint( nv::sampler_filter_to_enum( asampler.filter_min ) ) );
1009        glTexParameteri( gl_type, GL_TEXTURE_MAG_FILTER, GLint( nv::sampler_filter_to_enum( asampler.filter_max ) ) );
1010        glTexParameteri( gl_type, GL_TEXTURE_WRAP_S, GLint( nv::sampler_wrap_to_enum( asampler.wrap_s ) ) );
1011        glTexParameteri( gl_type, GL_TEXTURE_WRAP_T, GLint( nv::sampler_wrap_to_enum( asampler.wrap_t ) ) );
[515]1012        glTexParameteri( gl_type, GL_TEXTURE_WRAP_R, GLint( nv::sampler_wrap_to_enum( asampler.wrap_r ) ) );
[501]1013
1014        if ( is_depth )
1015        {
1016                glTexParameteri( gl_type, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
1017                glTexParameteri( gl_type, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
1018
1019                // This is to allow usage of shadow2DProj function in the shader
1020                glTexParameteri( gl_type, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_REF_TO_TEXTURE );
1021                glTexParameteri( gl_type, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL );
1022        }
1023
1024        //glTexStorage3D( GL_TEXTURE_2D_ARRAY, mipLevelCount, GL_RGBA8, width, height, layerCount );
[535]1025        glTexImage3D( gl_type, 0, GLint( nv::image_format_to_internal_enum( aformat ) ), size.x, size.y, size.z, 0, nv::image_format_to_enum( aformat ), nv::datatype_to_gl_enum( get_pixel_format_info( aformat ).type ), data );
[501]1026
1027        bind( texture(), texture_slot::TEXTURE_0 );
1028
1029        info->type = type;
1030        info->format = aformat;
1031        info->tsampler = asampler;
1032        info->size = size;
1033        info->glid = glid;
1034
1035        return result;
1036}
1037
[534]1038nv::buffer nv::gl_context::create_buffer( buffer_type type, buffer_hint hint, uint32 size, const void* source /*= nullptr */ )
[501]1039{
1040        buffer result = static_cast<gl_device*>( m_device )->create_buffer( type, hint );
1041        if ( size > 0 ) create_buffer( result, size, source );
1042        return result;
1043}
1044
[534]1045void nv::gl_context::create_buffer( buffer b, uint32 size, const void* source /*= nullptr */ )
[501]1046{
1047        gl_buffer_info* info = static_cast<gl_device*>( m_device )->get_full_buffer_info( b );
1048        if ( info )
1049        {
1050                unsigned glenum = buffer_type_to_enum( info->type );
1051                glBindBuffer( glenum, info->glid );
1052                glBufferData( glenum, GLsizeiptr( size ), source, buffer_hint_to_enum( info->hint ) );
1053                glBindBuffer( glenum, 0 );
1054        }
1055}
1056
[342]1057void nv::gl_context::set_draw_buffers( uint32 count, const output_slot* slots )
[331]1058{
[342]1059        if ( count == 0 ) return;
1060        if ( count == 1 )
1061        {
1062                set_draw_buffer( slots[0] );
1063                return;
1064        }
[331]1065        unsigned int buffers[8];
[398]1066        count = nv::min<uint32>( count, 8 );
[331]1067        for ( uint32 i = 0; i < count; ++i )
1068        {
1069                buffers[i] = output_slot_to_enum( slots[i] );
1070                if ( slots[i] > OUTPUT_7 ) buffers[i] = 0;
1071        }
[406]1072        glDrawBuffers( GLsizei( count ), buffers );
[331]1073}
1074
1075void nv::gl_context::set_draw_buffer( output_slot slot )
1076{
1077        glDrawBuffer( output_slot_to_enum(slot) );
1078}
1079
1080void nv::gl_context::set_read_buffer( output_slot slot )
1081{
1082        glReadBuffer( output_slot_to_enum(slot) );
1083}
1084
[534]1085void gl_context::draw( primitive prim, const render_state& rs, program p, vertex_array va, nv::uint32 count, nv::uint32 first )
[303]1086{
[245]1087        apply_render_state( rs );
[313]1088        const vertex_array_info* info = m_vertex_arrays.get( va );
[302]1089        if ( count > 0 && info )
[245]1090        {
[299]1091                bind( p );
1092                bind( va );
[302]1093                if ( info->index.is_valid() )
[245]1094                {
[534]1095                        glDrawElements( primitive_to_enum(prim), static_cast<GLsizei>( count ), datatype_to_gl_enum( info->index_type ), reinterpret_cast< const void* >( size_t( get_datatype_info( info->index_type ).size * first ) ) );
[245]1096                }
1097                else
1098                {
[487]1099                        glDrawArrays( primitive_to_enum(prim), static_cast<GLint>( first ), static_cast<GLsizei>( count ) );
[245]1100                }
[299]1101                unbind( va );
1102                //unbind( p );
[245]1103        }
1104}
[502]1105
[534]1106void nv::gl_context::draw_instanced( primitive prim, const render_state& rs, program p, uint32 instances, vertex_array va, uint32 count, uint32 first /*= 0 */ )
[502]1107{
1108        apply_render_state( rs );
1109        const vertex_array_info* info = m_vertex_arrays.get( va );
1110        if ( count > 0 && info )
1111        {
1112                bind( p );
1113                bind( va );
1114                if ( info->index.is_valid() )
1115                {
[534]1116                        glDrawElementsInstanced( primitive_to_enum( prim ), static_cast<GLsizei>( count ), datatype_to_gl_enum( info->index_type ), reinterpret_cast<const void*>( size_t( get_datatype_info( info->index_type ).size * first ) ), instances );
[502]1117                }
1118                else
1119                {
1120                        glDrawArraysInstanced( primitive_to_enum( prim ), static_cast<GLint>( first ), static_cast<GLsizei>( count ), instances );
1121                }
1122                unbind( va );
1123                //unbind( p );
1124        }
1125}
Note: See TracBrowser for help on using the repository browser.