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

Last change on this file since 326 was 326, checked in by epyon, 11 years ago
  • window_manager interface added
  • input interface added
  • sdl::window_manager and sdl::input added
  • gl_device/gl_window/gl_context made oblivious to sdl
  • currently some setup is required, application class needed
File size: 17.0 KB
Line 
1// Copyright (C) 2012-2014 ChaosForge Ltd
2// This file is part of NV Libraries.
3// For conditions of distribution and use, see copyright notice in nv.hh
4
5#include "nv/gl/gl_context.hh"
6
7#include "nv/gl/gl_enum.hh"
8#include "nv/lib/gl.hh"
9#include "nv/gl/gl_device.hh"
10
11using namespace nv;
12
13nv::vertex_array nv::gl_context::create_vertex_array()
14{
15        vertex_array result = m_vertex_arrays.create();
16        vertex_array_info* info = m_vertex_arrays.get( result );
17        info->count       = 0;
18        info->index       = buffer();
19        info->index_owner = false;
20        info->index_type  = USHORT;
21        return result;
22}
23
24nv::framebuffer nv::gl_context::create_framebuffer()
25{
26        if ( is_gl_extension_loaded( GL_EXT_FRAMEBUFFER_OBJECT ) )
27        {
28                unsigned glid   = 0;
29                glGenFramebuffers( 1, &glid );
30                framebuffer result = m_framebuffers.create();
31                gl_framebuffer_info* info = m_framebuffers.get( result );
32                info->glid = glid;
33                info->color_attachment_count = 0;
34                return result;
35        }
36        else return framebuffer();
37}
38
39void nv::gl_context::release( vertex_array va )
40{
41        vertex_array_info* info = m_vertex_arrays.get( va );
42        if ( info )
43        {
44                for ( uint32 i = 0; i < info->count; ++i )
45                {
46                        if ( info->attr[i].owner ) m_device->release( info->attr[i].vbuffer );
47                }
48                if ( info->index.is_valid() && info->index_owner) m_device->release( info->index );
49                m_vertex_arrays.destroy( va );
50        }
51}
52
53void nv::gl_context::release( framebuffer f )
54{
55        gl_framebuffer_info* info = m_framebuffers.get( f );
56        if ( info )
57        {
58                // TODO: release textures?
59                glBindFramebuffer(GL_FRAMEBUFFER, 0);
60                glDeleteFramebuffers(1, &info->glid);
61        }
62}
63
64const vertex_array_info* nv::gl_context::get_vertex_array_info( vertex_array va ) const
65{
66        return m_vertex_arrays.get( va );
67}
68
69const framebuffer_info* nv::gl_context::get_framebuffer_info( framebuffer f ) const
70{
71        return m_framebuffers.get( f );
72}
73
74vertex_array_info* nv::gl_context::get_vertex_array_info_mutable( vertex_array va )
75{
76        return m_vertex_arrays.get( va );
77}
78
79
80void gl_context::bind( texture t, texture_slot slot )
81{
82        const gl_texture_info* info = static_cast< const gl_texture_info* >( m_device->get_texture_info( t ) );
83        if ( info )
84        {
85                glActiveTexture( GL_TEXTURE0 + static_cast< GLenum >( slot ) );
86                glBindTexture( GL_TEXTURE_2D, info->glid );
87        }
88}
89
90void nv::gl_context::bind( program p )
91{
92        gl_program_info* info = ((gl_device*)m_device)->m_programs.get( p );
93        if ( info )
94        {
95                glUseProgram( info->glid );
96                ((gl_device*)m_device)->update_uniforms( info );
97        }
98}
99
100// void nv::gl_context::bind( buffer b )
101// {
102//      const gl_buffer_info* info = static_cast< const gl_buffer_info* >( m_device->get_buffer_info( b ) );
103//      if ( info )
104//      {
105//              glBindBuffer( buffer_type_to_enum( info->type ), info->glid );
106//      }
107// }
108
109void nv::gl_context::bind( vertex_array va )
110{
111        const vertex_array_info* info = m_vertex_arrays.get( va );
112        if ( info )
113        {
114                for ( uint32 i = 0; i < info->count; ++i )
115                {
116                        const vertex_buffer_attribute& vba = info->attr[i];
117                        uint32 location                    = static_cast<uint32>( vba.location );
118                        glEnableVertexAttribArray( location );
119                        const gl_buffer_info* vinfo = static_cast< const gl_buffer_info* >( m_device->get_buffer_info( vba.vbuffer ) );
120                        if ( vinfo && vinfo->type == VERTEX_BUFFER )
121                                glBindBuffer( GL_ARRAY_BUFFER, vinfo->glid );
122                        else
123                        {
124                                // TODO: report error
125                        }
126
127                        glVertexAttribPointer(
128                                location,
129                                static_cast<GLint>( vba.components ),
130                                nv::datatype_to_gl_enum( vba.dtype ),
131                                GL_FALSE,
132                                static_cast<GLsizei>( vba.stride ),
133                                (void*)vba.offset
134                                );
135                }
136                glBindBuffer( GL_ARRAY_BUFFER, 0 );
137
138                if ( info->index.is_valid() )
139                {
140                        const gl_buffer_info* iinfo = static_cast< const gl_buffer_info* >( m_device->get_buffer_info( info->index ) );
141                        if ( iinfo && iinfo->type == INDEX_BUFFER )
142                        {
143                                glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, iinfo->glid );
144                        }
145                        else
146                        {
147                                // TODO: report error
148                        }
149                }
150        }
151}
152
153void nv::gl_context::bind( framebuffer f )
154{
155        const gl_framebuffer_info* info = m_framebuffers.get( f );
156        if ( info )
157        {
158                glBindFramebuffer( GL_FRAMEBUFFER, info->glid );
159        }
160}
161
162void nv::gl_context::unbind( program )
163{
164        glUseProgram( 0 );
165}
166
167// void nv::gl_context::unbind( buffer b )
168// {
169//      const gl_buffer_info* info = static_cast< const gl_buffer_info* >( m_device->get_buffer_info( b ) );
170//      if ( info )
171//      {
172//              glBindBuffer( buffer_type_to_enum( info->type ), 0 );
173//      }
174// }
175
176void nv::gl_context::unbind( vertex_array va )
177{
178        const vertex_array_info* info = m_vertex_arrays.get( va );
179        if ( info )
180        {
181                if ( info->index.is_valid() )
182                {
183                        glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, 0 );
184                }
185
186                for ( uint32 i = 0; i < info->count; ++i )
187                {
188                        glDisableVertexAttribArray( static_cast<uint32>( info->attr[i].location ) );
189                }
190        }
191}
192
193void nv::gl_context::unbind( framebuffer f )
194{
195        // this way we are sure that the extension is loaded
196        const gl_framebuffer_info* info = m_framebuffers.get( f );
197        if ( info )
198        {
199                glBindFramebuffer( GL_FRAMEBUFFER, 0 );
200        }
201}
202
203void nv::gl_context::update( texture t, void* data )
204{
205        const gl_texture_info* info = static_cast< const gl_texture_info* >( m_device->get_texture_info( t ) );
206        if ( info )
207        {
208                image_format format = info->format;
209                ivec2        size   = info->size;
210
211                glBindTexture( GL_TEXTURE_2D, info->glid );
212                glTexImage2D( GL_TEXTURE_2D, 0, (GLint)nv::image_format_to_enum(format.format), size.x, size.y, 0, nv::image_format_to_enum(format.format), nv::datatype_to_gl_enum(format.type), data );
213        }
214}
215
216void gl_context::update( buffer b, const void* data, size_t offset, size_t size )
217{
218        const gl_buffer_info* info = static_cast< const gl_buffer_info* >( m_device->get_buffer_info( b ) );
219        if ( info )
220        {
221                GLenum glenum = buffer_type_to_enum( info->type );
222                glBindBuffer( glenum, info->glid );
223                glBufferSubData( glenum, (GLintptr)offset, (GLsizeiptr)size, data );
224        }
225}
226
227void gl_context::clear( const clear_state& cs )
228{
229        // apply_framebuffer
230       
231        apply_scissor_test( cs.scissor_test );
232        apply_color_mask( cs.color_mask );
233        apply_depth_mask( cs.depth_mask );
234        // stencil_mask_separate
235
236        if ( m_clear_color != cs.color )
237        {
238                glClearColor( cs.color.r, cs.color.g, cs.color.b, cs.color.a );
239                m_clear_color = cs.color;
240        }
241
242        if ( m_clear_depth != cs.depth )
243        {
244                glClearDepth( cs.depth );
245                m_clear_depth = cs.depth;
246        }
247
248        if ( m_clear_stencil != cs.stencil )
249        {
250                glClearStencil( cs.stencil );
251                m_clear_stencil = cs.stencil;
252        }
253       
254        glClear( clear_state_buffers_to_mask( cs.buffers ) );
255}
256
257const ivec4& gl_context::get_viewport()
258{
259        return m_viewport;
260}
261
262void gl_context::set_viewport( const ivec4& viewport )
263{
264        if ( viewport.z < 0 || viewport.w < 0 )
265        {
266                NV_THROW( logic_error, "viewport width and height must be greater than zero!");
267        }
268
269        m_viewport = viewport;
270        glViewport( viewport.x, viewport.y, viewport.z, viewport.w );
271}
272
273void gl_context::enable( unsigned int what, bool value )
274{
275        if ( value )
276        {
277                glEnable( what );
278        }
279        else
280        {
281                glDisable( what );
282        }
283}
284
285void gl_context::apply_stencil_test( const stencil_test& stencil )
286{
287        if ( m_render_state.stencil_test.enabled != stencil.enabled )
288        {
289                enable( GL_STENCIL_TEST, stencil.enabled );
290                m_render_state.stencil_test.enabled = stencil.enabled;
291        }
292
293        if ( stencil.enabled )
294        {
295                apply_stencil_face( GL_FRONT, m_render_state.stencil_test.front_face, stencil.front_face );
296                apply_stencil_face( GL_BACK,  m_render_state.stencil_test.back_face,  stencil.back_face );
297        }
298}
299
300void gl_context::apply_stencil_face( unsigned face, stencil_test_face& stencil, const stencil_test_face& new_stencil )
301{
302        if (( stencil.op_fail       != new_stencil.op_fail       ) ||
303                ( stencil.op_depth_fail != new_stencil.op_depth_fail ) ||
304                ( stencil.op_depth_pass != new_stencil.op_depth_pass ) )
305        {
306                glStencilOpSeparate( face,
307                        stencil_operation_to_enum( new_stencil.op_fail ),
308                        stencil_operation_to_enum( new_stencil.op_depth_fail ),
309                        stencil_operation_to_enum( new_stencil.op_depth_pass )
310                );
311
312                stencil.op_fail       = new_stencil.op_fail;
313                stencil.op_depth_fail = new_stencil.op_depth_fail;
314                stencil.op_depth_pass = new_stencil.op_depth_pass;
315        }
316
317        if (( stencil.function  != new_stencil.function ) ||
318                ( stencil.ref_value != new_stencil.ref_value ) ||
319                ( stencil.mask      != new_stencil.mask ))
320        {
321                glStencilFuncSeparate( face,
322                        stencil_function_to_enum( new_stencil.function ),
323                        new_stencil.ref_value,
324                        new_stencil.mask
325                );
326
327                stencil.function  = new_stencil.function;
328                stencil.ref_value = new_stencil.ref_value;
329                stencil.mask      = new_stencil.mask;
330        }
331}
332
333void gl_context::apply_scissor_test( const scissor_test& scissor )
334{
335        if ( m_render_state.scissor_test.enabled != scissor.enabled )
336        {
337                enable( GL_SCISSOR_TEST, scissor.enabled );
338                m_render_state.scissor_test.enabled = scissor.enabled;
339        }
340
341        if ( scissor.dim.x < 0 || scissor.dim.y < 0 )
342        {
343                NV_THROW( logic_error, "scissor_test.rect width and height must be greater than zero!" );
344        }
345
346        if ( scissor.enabled )
347        {
348                if ( m_render_state.scissor_test.dim != scissor.dim || m_render_state.scissor_test.pos != scissor.pos )
349                {
350                        glScissor(
351                                scissor.pos.x, scissor.pos.y,
352                                scissor.dim.x, scissor.dim.y
353                        );
354                        m_render_state.scissor_test.dim = scissor.dim;
355                        m_render_state.scissor_test.pos = scissor.pos;
356                }
357        }
358}
359
360void gl_context::apply_depth_test( const depth_test& depth )
361{
362        if ( m_render_state.depth_test.enabled != depth.enabled )
363        {
364                enable( GL_DEPTH_TEST, depth.enabled );
365                m_render_state.depth_test.enabled = depth.enabled;
366        }
367
368        if ( depth.enabled )
369        {
370                if ( m_render_state.depth_test.function != depth.function )
371                {
372                        glDepthFunc( depth_state_function_to_enum( depth.function ) );
373                        m_render_state.depth_test.function = depth.function;
374                }
375        }
376}
377
378void gl_context::apply_depth_mask( bool mask )
379{
380        if ( m_render_state.depth_mask != mask )
381        {
382                glDepthMask( mask );
383                m_render_state.depth_mask = mask;
384        }
385}
386
387void gl_context::apply_polygon_mode( const polygon_mode& mode )
388{
389        if ( m_render_state.polygon_mode.fill != mode.fill )
390        {
391                glPolygonMode( GL_FRONT_AND_BACK, polygon_mode_fill_to_enum( mode.fill ) );
392                m_render_state.polygon_mode.fill = mode.fill;
393        }
394}
395
396
397void gl_context::apply_depth_range( const depth_range& range )
398{
399        if ( range.near < 0.0 || range.near > 1.0 )
400        {
401                NV_THROW( logic_error, "render_state.depth_range.near must be between zero and one!");
402        }
403        if ( range.far < 0.0 || range.far > 1.0 )
404        {
405                NV_THROW( logic_error, "render_state.depth_range.far must be between zero and one!");
406        }
407
408        if ((m_render_state.depth_range.far  != range.far) ||
409                (m_render_state.depth_range.near != range.near))
410        {
411                glDepthRange( range.near, range.far );
412
413                m_render_state.depth_range.far  = range.far;
414                m_render_state.depth_range.near = range.near;
415        }
416}
417
418void gl_context::apply_color_mask( const color_mask& mask )
419{
420        if ( m_render_state.color_mask != mask )
421        {
422                glColorMask( mask.red, mask.green, mask.blue, mask.alpha );
423                m_render_state.color_mask = mask;
424        }
425}
426
427void gl_context::apply_blending( const blending& blend )
428{
429        if ( m_render_state.blending.enabled != blend.enabled )
430        {
431                enable( GL_BLEND, blend.enabled );
432                m_render_state.blending.enabled = blend.enabled;
433        }
434
435        if ( blend.enabled )
436        {
437                if ((m_render_state.blending.src_rgb_factor   != blend.src_rgb_factor ) ||
438                        (m_render_state.blending.dst_rgb_factor   != blend.dst_rgb_factor ) ||
439                        (m_render_state.blending.src_alpha_factor != blend.src_alpha_factor ) ||
440                        (m_render_state.blending.dst_alpha_factor != blend.dst_alpha_factor ))
441                {
442                        glBlendFuncSeparate(
443                                blending_factor_to_enum( blend.src_rgb_factor ),
444                                blending_factor_to_enum( blend.dst_rgb_factor ),
445                                blending_factor_to_enum( blend.src_alpha_factor ),
446                                blending_factor_to_enum( blend.dst_alpha_factor )
447                        );
448
449                        m_render_state.blending.src_rgb_factor   = blend.src_rgb_factor;
450                        m_render_state.blending.dst_rgb_factor   = blend.dst_rgb_factor;
451                        m_render_state.blending.src_alpha_factor = blend.src_alpha_factor;
452                        m_render_state.blending.dst_alpha_factor = blend.dst_alpha_factor;
453                }
454
455                if ((m_render_state.blending.rgb_equation   != blend.rgb_equation ) ||
456                        (m_render_state.blending.alpha_equation != blend.alpha_equation ))
457                {
458                        glBlendEquationSeparate(
459                                blending_equation_to_enum( blend.rgb_equation ),
460                                blending_equation_to_enum( blend.alpha_equation )
461                        );
462
463                        m_render_state.blending.rgb_equation   = blend.rgb_equation;
464                        m_render_state.blending.alpha_equation = blend.alpha_equation;
465                }
466
467                if (( m_render_state.blending.color != blend.color ))
468                {
469                        glBlendColor( blend.color.r, blend.color.g, blend.color.b, blend.color.a );
470                        m_render_state.blending.color = blend.color;
471                }
472        }
473}
474
475
476void gl_context::apply_culling( const culling& cull )
477{
478        if ( m_render_state.culling.enabled != cull.enabled )
479        {
480                enable( GL_CULL_FACE, cull.enabled );
481                m_render_state.culling.enabled = cull.enabled;
482        }
483
484        if ( cull.enabled )
485        {
486                if ( m_render_state.culling.face != cull.face )
487                {
488                        glCullFace( culling_face_type_to_enum(cull.face) );
489                        m_render_state.culling.face = cull.face;
490                }
491
492                if ( m_render_state.culling.order != cull.order )
493                {
494                        glFrontFace( culling_order_type_to_enum( cull.order ) );
495                        m_render_state.culling.order = cull.order;
496                }
497        }
498}
499
500
501void gl_context::force_apply_render_state( const render_state& state )
502{
503        enable( GL_CULL_FACE, state.culling.enabled );
504        glCullFace( culling_face_type_to_enum( state.culling.face ) );
505        glFrontFace( culling_order_type_to_enum( state.culling.order ) );
506
507        enable( GL_SCISSOR_TEST, state.scissor_test.enabled );
508        glScissor(
509                state.scissor_test.pos.x, state.scissor_test.pos.y,
510                state.scissor_test.dim.x, state.scissor_test.dim.y
511        );
512
513        enable( GL_STENCIL_TEST, state.stencil_test.enabled );
514        force_apply_stencil_face( GL_FRONT, state.stencil_test.front_face );
515        force_apply_stencil_face( GL_BACK,  state.stencil_test.back_face  );
516
517        enable( GL_DEPTH_TEST, state.depth_test.enabled );
518        glDepthFunc( depth_state_function_to_enum( state.depth_test.function ) );
519        glDepthRange( state.depth_range.near, state.depth_range.far );
520
521        enable( GL_BLEND, state.blending.enabled );
522        glBlendFuncSeparate(
523                blending_factor_to_enum( state.blending.src_rgb_factor ),
524                blending_factor_to_enum( state.blending.dst_rgb_factor ),
525                blending_factor_to_enum( state.blending.src_alpha_factor ),
526                blending_factor_to_enum( state.blending.dst_alpha_factor )
527        );
528        glBlendEquationSeparate(
529                blending_equation_to_enum( state.blending.rgb_equation ),
530                blending_equation_to_enum( state.blending.alpha_equation )
531        );
532        glBlendColor(
533                state.blending.color.r, state.blending.color.g,
534                state.blending.color.b, state.blending.color.a
535        );
536
537        glDepthMask( state.depth_mask );
538        glColorMask(
539                state.color_mask.red, state.color_mask.green,
540                state.color_mask.blue, state.color_mask.alpha
541        );
542        glPolygonMode( GL_FRONT_AND_BACK, polygon_mode_fill_to_enum( state.polygon_mode.fill ) );
543}
544
545void gl_context::force_apply_stencil_face( unsigned face, const stencil_test_face& stencil )
546{
547        glStencilOpSeparate( face,
548                stencil_operation_to_enum( stencil.op_fail ),
549                stencil_operation_to_enum( stencil.op_depth_fail ),
550                stencil_operation_to_enum( stencil.op_depth_pass )
551        );
552
553        glStencilFuncSeparate( face,
554                stencil_function_to_enum( stencil.function ),
555                stencil.ref_value,
556                stencil.mask
557        );
558}
559
560
561void gl_context::apply_render_state( const render_state& state )
562{
563        // apply_primitive_restart
564        apply_culling( state.culling );
565        // apply_program_point_size
566        // apply_rasterization_mode
567        apply_scissor_test( state.scissor_test );
568        apply_stencil_test( state.stencil_test );
569        apply_depth_test( state.depth_test );
570        apply_depth_range( state.depth_range );
571        apply_blending( state.blending );
572        apply_color_mask( state.color_mask );
573        apply_depth_mask( state.depth_mask );
574        apply_polygon_mode( state.polygon_mode );
575}
576
577
578gl_context::gl_context( device* a_device, void* a_handle )
579        : context( a_device ), m_handle( a_handle )
580{
581        force_apply_render_state( m_render_state );
582}
583
584
585nv::gl_context::~gl_context()
586{
587        while ( m_framebuffers.size() > 0 )
588                release( m_framebuffers.get_handle(0) );
589        while ( m_vertex_arrays.size() > 0 )
590                release( m_vertex_arrays.get_handle(0) );
591}
592
593void nv::gl_context::apply_engine_uniforms( program p, const scene_state& s )
594{
595        gl_program_info* info = ((gl_device*)m_device)->m_programs.get( p );
596        if ( info )
597        {
598                for ( auto u : info->m_engine_uniforms )
599                {
600                        u->set( this, &s );
601                }
602        }
603}
604
605void gl_context::draw( primitive prim, const render_state& rs, program p, vertex_array va, size_t count )
606{
607        apply_render_state( rs );
608        const vertex_array_info* info = m_vertex_arrays.get( va );
609        if ( count > 0 && info )
610        {
611                bind( p );
612                bind( va );
613                if ( info->index.is_valid() )
614                {
615                        glDrawElements( primitive_to_enum(prim), static_cast<GLsizei>( count ), datatype_to_gl_enum( info->index_type ), 0 );
616                }
617                else
618                {
619                        glDrawArrays( primitive_to_enum(prim), 0, static_cast<GLsizei>( count ) );
620                }
621                unbind( va );
622                //unbind( p );
623        }
624}
Note: See TracBrowser for help on using the repository browser.