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

Last change on this file since 246 was 245, checked in by epyon, 11 years ago
  • gl library wgl support
  • gl context and window adoption
File size: 13.6 KB
Line 
1// Copyright (C) 2012-2013 Kornel Kisielewicz
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/lib/sdl.hh"
10
11using namespace nv;
12
13void gl_context::clear( const clear_state& cs )
14{
15        // apply_framebuffer
16       
17        apply_scissor_test( cs.scissor_test );
18        apply_color_mask( cs.color_mask );
19        apply_depth_mask( cs.depth_mask );
20        // stencil_mask_separate
21
22        if ( m_clear_color != cs.color )
23        {
24                glClearColor( cs.color.r, cs.color.g, cs.color.b, cs.color.a );
25                m_clear_color = cs.color;
26        }
27
28        if ( m_clear_depth != cs.depth )
29        {
30                glClearDepth( cs.depth );
31                m_clear_depth = cs.depth;
32        }
33
34        if ( m_clear_stencil != cs.stencil )
35        {
36                glClearStencil( cs.stencil );
37                m_clear_stencil = cs.stencil;
38        }
39       
40        glClear( clear_state_buffers_to_mask( cs.buffers ) );
41}
42
43const ivec4& gl_context::get_viewport()
44{
45        return m_viewport;
46}
47
48void gl_context::set_viewport( const ivec4& viewport )
49{
50        if ( viewport.z < 0 || viewport.w < 0 )
51        {
52                NV_THROW( logic_error, "viewport width and height must be greater than zero!");
53        }
54
55        m_viewport = viewport;
56        glViewport( viewport.x, viewport.y, viewport.z, viewport.w );
57}
58
59void gl_context::enable( unsigned int what, bool value )
60{
61        if ( value )
62        {
63                glEnable( what );
64        }
65        else
66        {
67                glDisable( what );
68        }
69}
70
71void gl_context::apply_stencil_test( const stencil_test& stencil )
72{
73        if ( m_render_state.stencil_test.enabled != stencil.enabled )
74        {
75                enable( GL_STENCIL_TEST, stencil.enabled );
76                m_render_state.stencil_test.enabled = stencil.enabled;
77        }
78
79        if ( stencil.enabled )
80        {
81                apply_stencil_face( GL_FRONT, m_render_state.stencil_test.front_face, stencil.front_face );
82                apply_stencil_face( GL_BACK,  m_render_state.stencil_test.back_face,  stencil.back_face );
83        }
84}
85
86void gl_context::apply_stencil_face( unsigned face, stencil_test_face& stencil, const stencil_test_face& new_stencil )
87{
88        if (( stencil.op_fail       != new_stencil.op_fail       ) ||
89                ( stencil.op_depth_fail != new_stencil.op_depth_fail ) ||
90                ( stencil.op_depth_pass != new_stencil.op_depth_pass ) )
91        {
92                glStencilOpSeparate( face,
93                        stencil_operation_to_enum( new_stencil.op_fail ),
94                        stencil_operation_to_enum( new_stencil.op_depth_fail ),
95                        stencil_operation_to_enum( new_stencil.op_depth_pass )
96                );
97
98                stencil.op_fail       = new_stencil.op_fail;
99                stencil.op_depth_fail = new_stencil.op_depth_fail;
100                stencil.op_depth_pass = new_stencil.op_depth_pass;
101        }
102
103        if (( stencil.function  != new_stencil.function ) ||
104                ( stencil.ref_value != new_stencil.ref_value ) ||
105                ( stencil.mask      != new_stencil.mask ))
106        {
107                glStencilFuncSeparate( face,
108                        stencil_function_to_enum( new_stencil.function ),
109                        new_stencil.ref_value,
110                        new_stencil.mask
111                );
112
113                stencil.function  = new_stencil.function;
114                stencil.ref_value = new_stencil.ref_value;
115                stencil.mask      = new_stencil.mask;
116        }
117}
118
119void gl_context::apply_scissor_test( const scissor_test& scissor )
120{
121        if ( m_render_state.scissor_test.enabled != scissor.enabled )
122        {
123                enable( GL_SCISSOR_TEST, scissor.enabled );
124                m_render_state.scissor_test.enabled = scissor.enabled;
125        }
126
127        if ( scissor.dim.x < 0 || scissor.dim.y < 0 )
128        {
129                NV_THROW( logic_error, "scissor_test.rect width and height must be greater than zero!" );
130        }
131
132        if ( scissor.enabled )
133        {
134                if ( m_render_state.scissor_test.dim != scissor.dim || m_render_state.scissor_test.pos != scissor.pos )
135                {
136                        glScissor(
137                                scissor.pos.x, scissor.pos.y,
138                                scissor.dim.x, scissor.dim.y
139                        );
140                        m_render_state.scissor_test.dim = scissor.dim;
141                        m_render_state.scissor_test.pos = scissor.pos;
142                }
143        }
144}
145
146void gl_context::apply_depth_test( const depth_test& depth )
147{
148        if ( m_render_state.depth_test.enabled != depth.enabled )
149        {
150                enable( GL_DEPTH_TEST, depth.enabled );
151                m_render_state.depth_test.enabled = depth.enabled;
152        }
153
154        if ( depth.enabled )
155        {
156                if ( m_render_state.depth_test.function != depth.function )
157                {
158                        glDepthFunc( depth_state_function_to_enum( depth.function ) );
159                        m_render_state.depth_test.function = depth.function;
160                }
161        }
162}
163
164void gl_context::apply_depth_mask( bool mask )
165{
166        if ( m_render_state.depth_mask != mask )
167        {
168                glDepthMask( mask );
169                m_render_state.depth_mask = mask;
170        }
171}
172
173void gl_context::apply_polygon_mode( const polygon_mode& mode )
174{
175        if ( m_render_state.polygon_mode.fill != mode.fill )
176        {
177                glPolygonMode( GL_FRONT_AND_BACK, polygon_mode_fill_to_enum( mode.fill ) );
178                m_render_state.polygon_mode.fill = mode.fill;
179        }
180}
181
182
183void gl_context::apply_depth_range( const depth_range& range )
184{
185        if ( range.near < 0.0 || range.near > 1.0 )
186        {
187                NV_THROW( logic_error, "render_state.depth_range.near must be between zero and one!");
188        }
189        if ( range.far < 0.0 || range.far > 1.0 )
190        {
191                NV_THROW( logic_error, "render_state.depth_range.far must be between zero and one!");
192        }
193
194        if ((m_render_state.depth_range.far  != range.far) ||
195                (m_render_state.depth_range.near != range.near))
196        {
197                glDepthRange( range.near, range.far );
198
199                m_render_state.depth_range.far  = range.far;
200                m_render_state.depth_range.near = range.near;
201        }
202}
203
204void gl_context::apply_color_mask( const color_mask& mask )
205{
206        if ( m_render_state.color_mask != mask )
207        {
208                glColorMask( mask.red, mask.green, mask.blue, mask.alpha );
209                m_render_state.color_mask = mask;
210        }
211}
212
213void gl_context::apply_blending( const blending& blend )
214{
215        if ( m_render_state.blending.enabled != blend.enabled )
216        {
217                enable( GL_BLEND, blend.enabled );
218                m_render_state.blending.enabled = blend.enabled;
219        }
220
221        if ( blend.enabled )
222        {
223                if ((m_render_state.blending.src_rgb_factor   != blend.src_rgb_factor ) ||
224                        (m_render_state.blending.dst_rgb_factor   != blend.dst_rgb_factor ) ||
225                        (m_render_state.blending.src_alpha_factor != blend.src_alpha_factor ) ||
226                        (m_render_state.blending.dst_alpha_factor != blend.dst_alpha_factor ))
227                {
228                        glBlendFuncSeparate(
229                                blending_factor_to_enum( blend.src_rgb_factor ),
230                                blending_factor_to_enum( blend.dst_rgb_factor ),
231                                blending_factor_to_enum( blend.src_alpha_factor ),
232                                blending_factor_to_enum( blend.dst_alpha_factor )
233                        );
234
235                        m_render_state.blending.src_rgb_factor   = blend.src_rgb_factor;
236                        m_render_state.blending.dst_rgb_factor   = blend.dst_rgb_factor;
237                        m_render_state.blending.src_alpha_factor = blend.src_alpha_factor;
238                        m_render_state.blending.dst_alpha_factor = blend.dst_alpha_factor;
239                }
240
241                if ((m_render_state.blending.rgb_equation   != blend.rgb_equation ) ||
242                        (m_render_state.blending.alpha_equation != blend.alpha_equation ))
243                {
244                        glBlendEquationSeparate(
245                                blending_equation_to_enum( blend.rgb_equation ),
246                                blending_equation_to_enum( blend.alpha_equation )
247                        );
248
249                        m_render_state.blending.rgb_equation   = blend.rgb_equation;
250                        m_render_state.blending.alpha_equation = blend.alpha_equation;
251                }
252
253                if (( m_render_state.blending.color != blend.color ))
254                {
255                        glBlendColor( blend.color.r, blend.color.g, blend.color.b, blend.color.a );
256                        m_render_state.blending.color = blend.color;
257                }
258        }
259}
260
261
262void gl_context::apply_culling( const culling& cull )
263{
264        if ( m_render_state.culling.enabled != cull.enabled )
265        {
266                enable( GL_CULL_FACE, cull.enabled );
267                m_render_state.culling.enabled = cull.enabled;
268        }
269
270        if ( cull.enabled )
271        {
272                if ( m_render_state.culling.face != cull.face )
273                {
274                        glCullFace( culling_face_type_to_enum(cull.face) );
275                        m_render_state.culling.face = cull.face;
276                }
277
278                if ( m_render_state.culling.order != cull.order )
279                {
280                        glFrontFace( culling_order_type_to_enum( cull.order ) );
281                        m_render_state.culling.order = cull.order;
282                }
283        }
284}
285
286
287void gl_context::force_apply_render_state( const render_state& state )
288{
289        enable( GL_CULL_FACE, state.culling.enabled );
290        glCullFace( culling_face_type_to_enum( state.culling.face ) );
291        glFrontFace( culling_order_type_to_enum( state.culling.order ) );
292
293        enable( GL_SCISSOR_TEST, state.scissor_test.enabled );
294        glScissor(
295                state.scissor_test.pos.x, state.scissor_test.pos.y,
296                state.scissor_test.dim.x, state.scissor_test.dim.y
297        );
298
299        enable( GL_STENCIL_TEST, state.stencil_test.enabled );
300        force_apply_stencil_face( GL_FRONT, state.stencil_test.front_face );
301        force_apply_stencil_face( GL_BACK,  state.stencil_test.back_face  );
302
303        enable( GL_DEPTH_TEST, state.depth_test.enabled );
304        glDepthFunc( depth_state_function_to_enum( state.depth_test.function ) );
305        glDepthRange( state.depth_range.near, state.depth_range.far );
306
307        enable( GL_BLEND, state.blending.enabled );
308        glBlendFuncSeparate(
309                blending_factor_to_enum( state.blending.src_rgb_factor ),
310                blending_factor_to_enum( state.blending.dst_rgb_factor ),
311                blending_factor_to_enum( state.blending.src_alpha_factor ),
312                blending_factor_to_enum( state.blending.dst_alpha_factor )
313        );
314        glBlendEquationSeparate(
315                blending_equation_to_enum( state.blending.rgb_equation ),
316                blending_equation_to_enum( state.blending.alpha_equation )
317        );
318        glBlendColor(
319                state.blending.color.r, state.blending.color.g,
320                state.blending.color.b, state.blending.color.a
321        );
322
323        glDepthMask( state.depth_mask );
324        glColorMask(
325                state.color_mask.red, state.color_mask.green,
326                state.color_mask.blue, state.color_mask.alpha
327        );
328        glPolygonMode( GL_FRONT_AND_BACK, polygon_mode_fill_to_enum( state.polygon_mode.fill ) );
329}
330
331void gl_context::force_apply_stencil_face( unsigned face, const stencil_test_face& stencil )
332{
333        glStencilOpSeparate( face,
334                stencil_operation_to_enum( stencil.op_fail ),
335                stencil_operation_to_enum( stencil.op_depth_fail ),
336                stencil_operation_to_enum( stencil.op_depth_pass )
337        );
338
339        glStencilFuncSeparate( face,
340                stencil_function_to_enum( stencil.function ),
341                stencil.ref_value,
342                stencil.mask
343        );
344}
345
346
347void gl_context::apply_render_state( const render_state& state )
348{
349        // apply_primitive_restart
350        apply_culling( state.culling );
351        // apply_program_point_size
352        // apply_rasterization_mode
353        apply_scissor_test( state.scissor_test );
354        apply_stencil_test( state.stencil_test );
355        apply_depth_test( state.depth_test );
356        apply_depth_range( state.depth_range );
357        apply_blending( state.blending );
358        apply_color_mask( state.color_mask );
359        apply_depth_mask( state.depth_mask );
360        apply_polygon_mode( state.polygon_mode );
361}
362
363
364gl_context::gl_context( device* a_device )
365        : context( a_device )
366{
367}
368
369
370nv::gl_context::~gl_context()
371{
372}
373
374
375void gl_context::draw( primitive prim, const render_state& rs, program* p, vertex_array* va, size_t count )
376{
377        apply_render_state( rs );
378        if ( count > 0 )
379        {
380                p->bind();
381                va->bind();
382                if ( va->has_index_buffer() )
383                {
384                        glDrawElements( primitive_to_enum(prim), static_cast<GLsizei>( count ), datatype_to_gl_enum( va->get_index_buffer_type() ), 0 );
385                }
386                else
387                {
388                        glDrawArrays( primitive_to_enum(prim), 0, static_cast<GLsizei>( count ) );
389                }
390                va->unbind();
391                p->unbind();
392        }
393}
394
395nv::sdl_gl_context::sdl_gl_context( device* a_device, void* a_sdl_win_handle )
396        : gl_context( a_device ), m_handle( nullptr )
397{
398#if NV_SDL_VERSION == NV_SDL_20
399        m_handle = SDL_GL_CreateContext( static_cast<SDL_Window*>( a_sdl_win_handle ) );
400
401        if ( m_handle == 0 )
402        {
403                NV_LOG( LOG_CRITICAL, "GL Context creation failed: " << SDL_GetError( ) );
404                return; // TODO: Error report
405        }
406#else
407        NV_UNUSED( a_win_handle );
408        NV_UNUSED( m_handle );
409#endif
410
411        nv::load_gl_library();
412        NV_LOG( LOG_INFO, "OpenGL Vendor       : " << glGetString(GL_VENDOR) );
413        NV_LOG( LOG_INFO, "OpenGL Renderer     : " << glGetString(GL_RENDERER) );
414        NV_LOG( LOG_INFO, "OpenGL Version      : " << glGetString(GL_VERSION) );
415        NV_LOG( LOG_INFO, "OpenGL GLSL Version : " << glGetString(GL_SHADING_LANGUAGE_VERSION) );
416#if NV_SDL_VERSION == NV_SDL_20
417        //      SDL_GL_SetSwapInterval(1);
418#endif
419
420        // TODO: do we really need this?
421        glPixelStorei( GL_UNPACK_ALIGNMENT, 1 );
422
423        force_apply_render_state( m_render_state );
424}
425
426nv::sdl_gl_context::~sdl_gl_context()
427{
428#if NV_SDL_VERSION == NV_SDL_20
429        SDL_GL_DeleteContext(static_cast<SDL_GLContext>( m_handle ) );
430#endif
431}
432
433nv::native_gl_context::native_gl_context( device* a_device, void* a_native_win_handle )
434        : gl_context( a_device ), m_handle( nullptr )
435{
436#if NV_PLATFORM == NV_WINDOWS
437
438// TODO: error checking
439        HDC hdc = (HDC)a_native_win_handle;
440
441        const int wgl_attrib_list[] =
442        {
443                WGL_DRAW_TO_WINDOW_ARB, GL_TRUE,
444                WGL_SUPPORT_OPENGL_ARB, GL_TRUE,
445                WGL_ACCELERATION_ARB,   WGL_FULL_ACCELERATION_ARB,
446                WGL_DOUBLE_BUFFER_ARB,  GL_TRUE,
447                WGL_PIXEL_TYPE_ARB,     WGL_TYPE_RGBA_ARB,
448                WGL_COLOR_BITS_ARB,     32,
449                WGL_DEPTH_BITS_ARB,     24,
450                WGL_STENCIL_BITS_ARB,   8,
451                0, 0  //End
452        };
453
454        unsigned int num_formats;
455        int pixel_format;
456        PIXELFORMATDESCRIPTOR pfd;
457
458        if ( FALSE == wglChoosePixelFormatARB(hdc, wgl_attrib_list, NULL, 1, &pixel_format, &num_formats) )
459        {
460                return;
461        }
462
463        if ( FALSE == SetPixelFormat(hdc, pixel_format, &pfd) )
464        {
465                //int err = GetLastError();
466                return;
467        }
468
469        int attribs[] =
470        {
471                WGL_CONTEXT_MAJOR_VERSION_ARB,   2,
472                WGL_CONTEXT_MINOR_VERSION_ARB,   1,
473                WGL_CONTEXT_PROFILE_MASK_ARB,  WGL_CONTEXT_CORE_PROFILE_BIT_ARB,
474                //WGL_CONTEXT_PROFILE_MASK_ARB, WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB,
475                0, 0  //End
476        };
477
478        HGLRC handle;
479        if ( 0 == (handle = wglCreateContextAttribsARB(hdc, 0, attribs) ) )
480        {
481                return;
482        }
483
484        if ( FALSE == dynwglMakeCurrent( hdc, handle ) )
485        {
486                return;
487        }     
488
489        m_handle = (void*)handle;
490#else
491        NV_ASSERT( false, "Native GL context not implemented for this platform!" );
492#endif
493        force_apply_render_state( m_render_state );
494}
495
496nv::native_gl_context::~native_gl_context()
497{
498#if NV_PLATFORM == NV_WINDOWS
499        dynwglDeleteContext( (HGLRC)m_handle );
500#endif
501}
Note: See TracBrowser for help on using the repository browser.