Developer Documentation
ClassicDepthPeeling_glew.cc
1 /*===========================================================================*\
2 * *
3 * OpenFlipper *
4  * Copyright (c) 2001-2015, RWTH-Aachen University *
5  * Department of Computer Graphics and Multimedia *
6  * All rights reserved. *
7  * www.openflipper.org *
8  * *
9  *---------------------------------------------------------------------------*
10  * This file is part of OpenFlipper. *
11  *---------------------------------------------------------------------------*
12  * *
13  * Redistribution and use in source and binary forms, with or without *
14  * modification, are permitted provided that the following conditions *
15  * are met: *
16  * *
17  * 1. Redistributions of source code must retain the above copyright notice, *
18  * this list of conditions and the following disclaimer. *
19  * *
20  * 2. Redistributions in binary form must reproduce the above copyright *
21  * notice, this list of conditions and the following disclaimer in the *
22  * documentation and/or other materials provided with the distribution. *
23  * *
24  * 3. Neither the name of the copyright holder nor the names of its *
25  * contributors may be used to endorse or promote products derived from *
26  * this software without specific prior written permission. *
27  * *
28  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS *
29  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED *
30  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A *
31  * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER *
32  * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, *
33  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, *
34  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR *
35  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF *
36  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING *
37  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS *
38  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *
39 * *
40 \*===========================================================================*/
41 
42 /*===========================================================================*\
43 * *
44 * $Revision: $ *
45 * $LastChangedBy: $ *
46 * $Date: $ *
47 * *
48 \*===========================================================================*/
49 
50 #include <ACG/GL/acg_glew.hh>
51 #include "ClassicDepthPeeling.hh"
52 
53 #include <ACG/GL/GLError.hh>
56 
58  // called in constructor and resizeEvent()
59 
61 
62  ViewerResources* p = &viewerRes_[_viewerId];
63 
64  if (!p->glWidth_ || !p->glHeight_) return;
65 
66  destroyResources(_viewerId);
67 
68  // dual depth peeling rt's
69  glGenTextures(7, p->blendDualPeelTexID_);
70  GLint DualPeelIntFmt[] = {GL_RG32F, GL_RG32F, // depth0, depth1
71  GL_RGBA, GL_RGBA, // front blender0, ..._1
72  GL_RGBA, GL_RGBA, // back_temp_tex0, ..._1,
73  GL_RGB}; // back_blender
74 
75  for (int i = 0; i < 7; ++i)
76  {
77  GLint fmt = GL_RGB; // fmt for depth textures
78 
79  if (i >= 2) fmt = GL_RGBA; // fmt for front_blender01 and back_temp01
80  if (i == 6) fmt = GL_RGB; // fmt for back_blender
81 
82  ACG::GLState::bindTexture(GL_TEXTURE_RECTANGLE_EXT, p->blendDualPeelTexID_[i]);
83  // texture access: clamped
84  glTexParameteri(GL_TEXTURE_RECTANGLE_EXT, GL_TEXTURE_WRAP_S, GL_CLAMP);
85  glTexParameteri(GL_TEXTURE_RECTANGLE_EXT, GL_TEXTURE_WRAP_T, GL_CLAMP);
86  // filter: none
87  glTexParameteri(GL_TEXTURE_RECTANGLE_EXT, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
88  glTexParameteri(GL_TEXTURE_RECTANGLE_EXT, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
89 
90  glTexImage2D(GL_TEXTURE_RECTANGLE_EXT, 0, DualPeelIntFmt[i], p->glWidth_, p->glHeight_, 0, fmt, GL_FLOAT, 0);
91 
92 
93 
94 
96  }
97 
98  p->rtWidth_ = p->glWidth_;
99  p->rtHeight_ = p->glHeight_;
100 
101  // dual depth peeling fbo's
102  glGenFramebuffersEXT(1, &p->blendDualPeelFbo_);
103  {
104  // layer_peel fbo
106 
107  // color_attachment order:
108  // depth0, front_blend0, back_temp0, depth1, front_blend1, back_temp1, back_blender_tex_id
109 
110  for (int i = 0; i < 6; ++i)
111  {
112  glFramebufferTexture2DEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0+i,
113  GL_TEXTURE_RECTANGLE_EXT, p->blendDualPeelTexID_[i < 3 ? 2*i : 2*(i-3) +1], 0);
114  }
115 
116  // back_blender_tex_id
117  glFramebufferTexture2DEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT6, GL_TEXTURE_RECTANGLE_EXT,
118  p->blendDualPeelTexID_[6], 0);
119  }
120 
121  ACG::GLState::bindFramebuffer(GL_FRAMEBUFFER, 0);
122 
123 
124  // load shaders
125 
126  const char* ShaderFiles[] = {"Blending/dual_peeling_init_vertex.glsl",
127  "Blending/dual_peeling_init_fragment.glsl",
128  "Blending/dual_peeling_blend_vertex.glsl",
129  "Blending/dual_peeling_blend_fragment.glsl",
130  "Blending/dual_peeling_final_vertex.glsl",
131  "Blending/dual_peeling_final_fragment.glsl"};
132 
133  for (int i = 0; i < 6; ++i)
134  {
135  QString shaderFile = OpenFlipper::Options::shaderDirStr() + QDir::separator() + QString(ShaderFiles[i]);
136 
137  if (blendShaders_[i]) continue;
138 
139  if (i & 1) // alternating vertex/fragment shader
140  blendShaders_[i] = GLSL::loadFragmentShader(shaderFile.toUtf8());
141  else
142  blendShaders_[i] = GLSL::loadVertexShader(shaderFile.toUtf8());
143 
144  if (!blendShaders_[i]) {
145  log(LOGERR, QString(ShaderFiles[i]) + QString(" could not be loaded and compiled"));
146  return;
147  }
148  }
149 
150  // dual depth peeling programs
151 
152  if (!blendDualPeelProg_[0])
153  {
154  for (int i = 0; i < 4; ++i)
155  {
156  if (i != 1)
158  }
159 
160  // init shaders
163  blendDualPeelProg_[0]->link();
164 
165  // blend shaders
168  blendDualPeelProg_[2]->link();
169 
170  // final shaders
173  blendDualPeelProg_[3]->link();
174  }
175 
176  if (!blendQueryID_)
177  glGenQueries(1, &blendQueryID_);
178 
180 }
181 
183 {
184  ViewerResources* p = &viewerRes_[_viewerId];
185 
186  if (p->blendDualPeelFbo_) glDeleteFramebuffersEXT(1, &p->blendDualPeelFbo_);
187  p->blendDualPeelFbo_ = 0;
188 
189  if (p->blendDualPeelTexID_[0]) glDeleteTextures(7, p->blendDualPeelTexID_);
190  memset(p->blendDualPeelTexID_, 0, sizeof(p->blendDualPeelTexID_));
191 }
192 
194  // called in destructor and reloadBlendingTech()
195 
196  if (blendQueryID_)
197  glDeleteQueries(1, &blendQueryID_);
198  blendQueryID_ = 0;
199 
200  for (int i = 0; i < 4; ++i)
201  {
202  delete blendDualPeelProg_[i]; blendDualPeelProg_[i] = 0;
203  }
204 
205  for (unsigned int i = 0; i < sizeof(blendShaders_) / sizeof(blendShaders_[0]); ++i)
206  {
207  delete blendShaders_[i];
208  blendShaders_[i] = 0;
209  }
210 
211  for (unsigned int i = 0; i < sizeof(peelShaders_) / sizeof(peelShaders_[0]); ++i)
212  {
213  delete peelShaders_[i]; peelShaders_[i] = 0;
214  }
215 
216  for (unsigned int i = 0; i < sizeof(peelProgs_) / sizeof(peelProgs_[0]); ++i)
217  {
218  delete peelProgs_[i]; peelProgs_[i] = 0;
219  }
220 
221  // free all viewer specific resources
222  std::map<int, ViewerResources>::iterator resIt = viewerRes_.begin();
223  for (; resIt != viewerRes_.end(); ++resIt)
224  destroyResources(resIt->first);
225 }
226 
227 void DepthPeelingPlugin::render(ACG::GLState* _glState, Viewer::ViewerProperties& _properties)
228 {
229  glStateTmp_ = _glState;
230 
231  glPushAttrib(GL_ALL_ATTRIB_BITS);
232 
233  const GLuint targetFbo = ACG::GLState::getFramebufferDraw();
234 
235  int viewerId = _properties.viewerId();
236 
237  ViewerResources* pViewer = &viewerRes_[viewerId];
238  pViewer->glWidth_ = _glState->viewport_width();
239  pViewer->glHeight_ = _glState->viewport_height();
240 
241  if (pViewer->glWidth_ != pViewer->rtWidth_ || pViewer->glHeight_ != pViewer->rtHeight_)
242  reloadResources(viewerId);
243 
244 // updatePeelingShaderSet(viewerId, _properties.drawMode());
247 
248  ACG::GLState::depthFunc(GL_LESS);
249 
250 
251  ACG::GLState::disable(GL_CULL_FACE);
252  ACG::GLState::disable(GL_LIGHTING);
253  ACG::GLState::disable(GL_NORMALIZE);
254 
255  ACG::GLState::lockDepthFunc();
256  ACG::GLState::lockState(GL_CULL_FACE);
257  ACG::GLState::lockState(GL_LIGHTING);
258  ACG::GLState::lockState(GL_NORMALIZE);
259 
260  // from nvidia demo code:
261  // needed some minor adjustments
262 
263  GLenum drawBuffers[] = {GL_COLOR_ATTACHMENT0_EXT,
264  GL_COLOR_ATTACHMENT1_EXT,
265  GL_COLOR_ATTACHMENT2_EXT,
266  GL_COLOR_ATTACHMENT3_EXT,
267  GL_COLOR_ATTACHMENT4_EXT,
268  GL_COLOR_ATTACHMENT5_EXT,
269  GL_COLOR_ATTACHMENT6_EXT};
270 
271  // the farthest depth value possible in the depth buffer
272  const float maxDepth = 1.0f;
273 
274  ACG::GLState::disable(GL_DEPTH_TEST);
275  ACG::GLState::enable(GL_BLEND);
276 
277  ACG::GLState::lockState(GL_DEPTH_TEST);
278  ACG::GLState::lockState(GL_BLEND);
279 
280 
281 
282  /* FIXED: VIEWPORT BUG
283 
284  log-window causes viewport shift by 16 units upward in window's y axis
285  therefore the scene gets rendered only in the upper part of the viewport:
286  -> glViewport(0, 16, glWidht, glHeight_)
287 
288  glHeight_() is NOT the height of the back buffer (i.e. glViewer window),
289  but the height of scene target view
290  -> glHeight_() is 16 units less than the back buffer
291 
292  -> all render targets are 16 units less in height than back buffer
293 
294  since the scene has to use the full render targets size,
295  use glViewport(0, 0, glWidth_, glHeight_) for all offscreen rendering
296 
297  in the final pass, shift the viewport up by 16 units and use the shift amount
298  in the shader (uniform g_Offset), to finally get the correct sampling coordinates
299 
300 
301  note: shift amount is not hardcoded, but fetched from glGetIntegerv(GL_VIEWPORT)
302  */
303 
304 
305  GLint old_viewport[4];
306  glGetIntegerv(GL_VIEWPORT, old_viewport);
307  glViewport(0, 0, pViewer->glWidth_, pViewer->glHeight_);
308 
309  for (int i = 0; i < 6; ++i)
310  {
311  ACG::GLState::activeTexture(GL_TEXTURE0 + i);
312  ACG::GLState::bindTexture(GL_TEXTURE_RECTANGLE_EXT, 0);
313  }
314 
315 
316  // ---------------------------------------------------------------------
317  // 1. Initialize Min-Max Depth Buffer
318  // ---------------------------------------------------------------------
319 
320  ACG::GLState::bindFramebuffer(GL_FRAMEBUFFER_EXT, pViewer->blendDualPeelFbo_);
321 
322  // Render targets 1 and 2 store the front and back colors
323  // Clear to 0.0 and use MAX blending to filter written color
324  // At most one front color and one back color can be written every pass
325  ACG::GLState::drawBuffers(2, &drawBuffers[1]);
326  glClearColor(0, 0, 0, 0);
327  glClear(GL_COLOR_BUFFER_BIT);
328 
329  // Render target 0 stores (-minDepth, maxDepth, alphaMultiplier)
330  ACG::GLState::drawBuffer(drawBuffers[0]);
331  glClearColor(-maxDepth, -maxDepth, 0, 0);
332  glClear(GL_COLOR_BUFFER_BIT);
333  ACG::GLState::blendEquation(GL_MAX_EXT);
335 
336  blendDualPeelProg_[0]->use();
338  drawScenePass(_glState, _properties.drawMode(), sceneGraphRoot);
340 
341 
342 
343  int currId = 0;
344 
345  // ---------------------------------------------------------------------
346  // 2. Dual Depth Peeling + Blending
347  // ---------------------------------------------------------------------
348 
349  // Since we cannot blend the back colors in the geometry passes,
350  // we use another render target to do the alpha blending
351  //glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, g_dualBackBlenderFboId);
352  ACG::GLState::drawBuffer(drawBuffers[6]);
353  glClearColor(_glState->clear_color()[0], _glState->clear_color()[1], _glState->clear_color()[2], 0);
354 
355  glClear(GL_COLOR_BUFFER_BIT);
356 
357  // Geometry layers are peeled until the sample query returns 0
358  GLuint sampleCount = 1;
359  for (int pass = 1; sampleCount; ++pass)
360  {
361  currId = pass % 2;
362  int prevId = 1 - currId;
363  int bufId = currId * 3;
364 
365  ACG::GLState::drawBuffers(2, &drawBuffers[bufId+1]);
366  glClearColor(0, 0, 0, 0);
367  glClear(GL_COLOR_BUFFER_BIT);
368 
369  ACG::GLState::drawBuffer(drawBuffers[bufId+0]);
370  glClearColor(-maxDepth, -maxDepth, 0, 0);
371  glClear(GL_COLOR_BUFFER_BIT);
372 
373  // Render target 0: RG32F MAX blending
374  // Render target 1: RGBA MAX blending
375  // Render target 2: RGBA MAX blending
376  ACG::GLState::drawBuffers(3, &drawBuffers[bufId+0]);
378  ACG::GLState::blendEquation(GL_MAX_EXT);
380 
381  ACG::GLState::activeTexture(GL_TEXTURE5); // front_blender_tex base_offset: 2
382  ACG::GLState::bindTexture(GL_TEXTURE_RECTANGLE_EXT, pViewer->blendDualPeelTexID_[2 + prevId]);
383 
384  ACG::GLState::activeTexture(GL_TEXTURE4); // depth_tex base_offset: 0
385  ACG::GLState::bindTexture(GL_TEXTURE_RECTANGLE_EXT, pViewer->blendDualPeelTexID_[0 + prevId]);
386 
387 
388  // scene geometry peeling pass
389  // note that the peel shader is set right before rendering in the traverser, based on a node's drawmode
390  ACG::GLState::activeTexture(GL_TEXTURE0);
391 
392  ACG::GLState::shadeModel(GL_SMOOTH); // flat shading is emulated in Geometry Shader, which only works with interpolated vertex shader output
394  drawScenePeelPass(_glState, _properties.drawMode(), sceneGraphRoot, pass);
396 
397 
398  // Full screen pass to alpha-blend the back color
399  ACG::GLState::drawBuffer(drawBuffers[6]);
400 
402  ACG::GLState::blendEquation(GL_FUNC_ADD);
404  ACG::GLState::blendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
405 
406  // start samples counter query
407  glBeginQuery(GL_SAMPLES_PASSED_ARB, blendQueryID_);
408 
409  blendDualPeelProg_[2]->use();
410  blendDualPeelProg_[2]->setUniform("TempTex", 4);
411 
412  ACG::GLState::activeTexture(GL_TEXTURE4); // back_temp_tex base_offset: 4
413  ACG::GLState::bindTexture(GL_TEXTURE_RECTANGLE_EXT, pViewer->blendDualPeelTexID_[4 + currId]);
414 
415  drawQuadProj(); // full screen quad, already projected
416 
417  glEndQuery(GL_SAMPLES_PASSED_ARB);
418  glGetQueryObjectuiv(blendQueryID_, GL_QUERY_RESULT_ARB, &sampleCount);
419  }
420 
422 
423  ACG::GLState::unlockState(GL_BLEND);
424  ACG::GLState::disable(GL_BLEND);
425 
426 
427 
428  // ---------------------------------------------------------------------
429  // 3. Final Pass
430  // operates on screen pixels only
431  // ---------------------------------------------------------------------
432 
433  // enable back buffer
434  ACG::GLState::bindFramebuffer(GL_FRAMEBUFFER_EXT, targetFbo);
435  ACG::GLState::drawBuffer(GL_BACK);
436 
437  // program id 3
438  blendDualPeelProg_[3]->use();
439  blendDualPeelProg_[3]->setUniform("FrontBlenderTex", 4);
440  blendDualPeelProg_[3]->setUniform("BackBlenderTex", 5);
441 
442  // bugfix for multiple viewports:
443  // gl_FragCoord represents the screen space coordinate of a pixel into the back buffer
444  // this has to be back-shifted by the upper left viewport coordinate to get correct texture coordinates
445  blendDualPeelProg_[3]->setUniform("ViewportOffset", ACG::Vec2f(old_viewport[0], old_viewport[1]));
446 
447  ACG::GLState::activeTexture(GL_TEXTURE5); // back_blender: offset 6
448  ACG::GLState::bindTexture(GL_TEXTURE_RECTANGLE_EXT, pViewer->blendDualPeelTexID_[6]);
449 
450 
451  ACG::GLState::activeTexture(GL_TEXTURE4); // front_blender_tex base_offset: 2
452  ACG::GLState::bindTexture(GL_TEXTURE_RECTANGLE_EXT, pViewer->blendDualPeelTexID_[2 + currId]);
453 
454 
455  glViewport(old_viewport[0], old_viewport[1], old_viewport[2], old_viewport[3]);
456  drawQuadProj(-1.0f, 1.0f, 2.0f, 2.0f);
457 
458 
460 
461 
462 
464 
465 
466  // unlock states
467  ACG::GLState::unlockDepthFunc();
468  ACG::GLState::unlockState(GL_CULL_FACE);
469  ACG::GLState::unlockState(GL_LIGHTING);
470  ACG::GLState::unlockState(GL_NORMALIZE);
471 
472  ACG::GLState::unlockState(GL_DEPTH_TEST);
473  ACG::GLState::unlockState(GL_BLEND);
474 
475 
476  glPopAttrib();
477 }
static void enable(GLenum _cap)
replaces glEnable, but supports locking
Definition: GLState.cc:1490
void attach(PtrConstShader _shader)
Attaches a shader object to the program object.
Definition: GLSLShader.cc:298
GLSL::PtrFragmentShader loadFragmentShader(const char *name, const GLSL::StringList *macros, bool verbose)
Loads, compiles and installs a new vertex shader.
Definition: GLSLShader.cc:989
const Vec4f & clear_color() const
get background color
Definition: GLState.hh:924
static void lockBlendEquation()
lock blend equation
Definition: GLState.hh:351
static void blendEquation(GLenum _mode)
replaces glBlendEquation, supports locking
Definition: GLState.cc:1643
static void lockProgram()
lock the program
Definition: GLState.hh:632
void link()
Links the shader objects to the program.
Definition: GLSLShader.cc:332
static void unlockShadeModel()
unlock shade model
Definition: GLState.hh:392
unsigned int rtWidth_
render target width
static void lockState(GLenum _cap)
locks a specific cap state, such that enable() or disable() has no effect
Definition: GLState.cc:1518
GLuint blendDualPeelTexID_[7]
render target textures: {depth0, depth1, front_blend0, front_blend1, back_temp0, back_temp1, back_blend}
int viewport_width() const
get viewport width
Definition: GLState.hh:825
static GLuint getFramebufferDraw()
get current draw framebuffer of a target
Definition: GLState.cc:1994
static void bindFramebuffer(GLenum _target, GLuint _framebuffer)
replaces glBindFramebuffer, supports locking
Definition: GLState.cc:2009
void use()
Enables the program object for using.
Definition: GLSLShader.cc:351
void destroyResources()
free all gl resources
ACG::GLState * glStateTmp_
current glState ptr for hiddenline rendering
const GLenum & depthFunc() const
get glDepthFunc() that is supposed to be active
Definition: GLState.cc:937
void updatePeelingShaderSet()
regenerates peeling shaders based on light nodes in scenegraph
GLuint blendQueryID_
fragment query
static void unlockProgram()
unlock the program
Definition: GLState.hh:634
void setUniform(const char *_name, GLint _value)
Set int uniform to specified value.
Definition: GLSLShader.cc:391
GLSL::Shader * peelShaders_[PEEL_NUM_COMBINATIONS *3]
generated shader set
void drawScenePass(ACG::GLState *_glState, ACG::SceneGraph::DrawModes::DrawMode _drawMode, BaseNode *_sceneGraphRoot)
draw the current scene
unsigned int rtHeight_
render target height
void drawQuadProj(float _x0=-1.0f, float _y0=1.0f, float _w=2.0f, float _h=2.0f)
draw a quad in projection space (only positions)
static void drawBuffers(GLsizei _n, const GLenum *_bufs)
replaces glDrawBuffers, supports locking
Definition: GLState.cc:1968
void reloadResources(int _viewerId)
reload gl resources
static void syncFromGL()
synchronize this class with the OpenGL state machine
Definition: GLState.cc:1227
static void activeTexture(GLenum _texunit)
replaces glActiveTexture, no locking support
Definition: GLState.cc:1801
static void unlockState(GLenum _cap)
unlocks a specific cap state
Definition: GLState.cc:1523
int viewerId()
Get the id of the viewer this viewerproperties belongs to.
static void disable(GLenum _cap)
replaces glDisable, but supports locking
Definition: GLState.cc:1504
GLSL::Shader * blendShaders_[8]
shader resources
GLSL::Program * peelProgs_[PEEL_NUM_COMBINATIONS]
generates shader programs
static void unlockBlendEquation()
unlock blend equation
Definition: GLState.hh:353
void drawMode(ACG::SceneGraph::DrawModes::DrawMode _mode)
set draw mode (No test if this mode is available!)
GLSL::PtrVertexShader loadVertexShader(const char *name, const GLSL::StringList *macros, bool verbose)
Loads, compiles and installs a new vertex shader.
Definition: GLSLShader.cc:975
GLuint blendDualPeelFbo_
depth peeling fbo
unsigned int glWidth_
viewer window width
static void bindTexture(GLenum _target, GLuint _buffer)
replaces glBindTexture, supports locking
Definition: GLState.cc:1812
int viewport_height() const
get viewport height
Definition: GLState.hh:827
ACG::SceneGraph::BaseNode * getSceneGraphRootNode()
get scenegraph root node
GLSL::Program * blendDualPeelProg_[4]
depth peeling programs
static void drawBuffer(GLenum _mode)
replaces glDrawBuffer, supports locking
Definition: GLState.cc:1953
void disable()
Resets to standard rendering pipeline.
Definition: GLSLShader.cc:361
GLSL program class.
Definition: GLSLShader.hh:217
unsigned int glHeight_
viewer window height
void glCheckErrors()
Definition: GLError.hh:105
static void lockShadeModel()
lock shade model
Definition: GLState.hh:390
static void blendFunc(GLenum _sfactor, GLenum _dfactor)
replaces glBlendFunc, supports locking
Definition: GLState.hh:314
static void shadeModel(GLenum _mode)
replaces glShadeModel, supports locking
Definition: GLState.cc:1700