Developer Documentation
IRenderer.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  * $Author$ *
46  * $Date$ *
47  * *
48 \*===========================================================================*/
49 
50 #include <ACG/GL/acg_glew.hh>
51 #include <cstdio>
52 #include <cstring>
53 #include <iostream>
54 #include <algorithm>
55 #include <QFile>
56 #include <QTextStream>
57 
58 #include <ACG/GL/gl.hh>
59 
60 #include <ACG/GL/IRenderer.hh>
61 
62 #include <ACG/GL/VertexDeclaration.hh>
63 #include <ACG/GL/GLError.hh>
64 
65 #include <ACG/GL/ShaderCache.hh>
66 #include <ACG/GL/ScreenQuad.hh>
67 #include <ACG/GL/FBO.hh>
68 #include <ACG/GL/globjects.hh>
69 
70 
71 
72 namespace ACG
73 {
74 
76 
77 IRenderer::IRenderer()
78 : numLights_(0),
79 renderObjects_(0),
80 depthMapUsed_(false),
81 curViewerID_(0),
82 prevFbo_(0),
83 prevDrawBuffer_(GL_BACK),
84 prevFboSaved_(false),
85 depthCopyShader_(0),
86 errorDetectionLevel_(1),
87 enableLineThicknessGL42_(false)
88 {
89  prevViewport_[0] = 0;
90  prevViewport_[1] = 0;
91  prevViewport_[2] = 0;
92  prevViewport_[3] = 0;
93 
94  // set global ambient scale to default OpenGL value
95  globalLightModelAmbient_ = ACG::Vec3f(0.2f, 0.2f, 0.2f);
96 }
97 
98 
99 IRenderer::~IRenderer()
100 {
101  delete depthCopyShader_;
102 
103  // free depth map fbos
104  for (std::map<int, ACG::FBO*>::iterator it = depthMaps_.begin(); it != depthMaps_.end(); ++it)
105  delete it->second;
106 }
107 
109 {
110  // avoid null-ptr access
111  if (!_renderObject->debugName)
112  _renderObject->debugName = "<unnamed>";
113 
114  if (_renderObject->name.empty())
115  _renderObject->name = _renderObject->debugName;
116 
117  // do some more checks for error detection
118  if (!_renderObject->vertexDecl && !_renderObject->vertexArrayObject)
119  std::cout << "error: missing vertex declaration in renderobject: " << _renderObject->debugName << std::endl;
120  else
121  {
122  if (errorDetectionLevel_ > 0)
123  {
124  // commonly encountered rendering errors
125 
126  if (!_renderObject->numIndices)
127  std::cout << "warning: numIndices is 0 in renderobject: " << _renderObject->debugName << std::endl;
128 
129  // Why is my object invisible/black?
130  if (!_renderObject->depthWrite &&
131  !_renderObject->colorWriteMask[0] && !_renderObject->colorWriteMask[1] &&
132  !_renderObject->colorWriteMask[2] && !_renderObject->colorWriteMask[3])
133  std::cout << "warning: depth write and color write disabled in renderobject: " << _renderObject->debugName << std::endl;
134 
135  if (errorDetectionLevel_ > 1 && _renderObject->shaderDesc.shadeMode == SG_SHADE_UNLIT)
136  {
137  if (_renderObject->emissive.max() < 1e-3f)
138  std::cout << "warning: unlit object rendered with black emissive color: " << _renderObject->debugName << std::endl;
139  else
140  {
141  // rendering with clear color
142 
143  float clearColor[4];
144  glGetFloatv(GL_COLOR_CLEAR_VALUE, clearColor);
145 
146  if (checkEpsilon(clearColor[0] - _renderObject->emissive[0]) &&
147  checkEpsilon(clearColor[1] - _renderObject->emissive[1]) &&
148  checkEpsilon(clearColor[2] - _renderObject->emissive[2]))
149  {
150  std::cout << "warning: unlit object rendered with clear color as emissive color: " << _renderObject->debugName << std::endl;
151  std::cout << " Should this be intentional, disable color writing instead via obj->glColorMask(0,0,0,0)" << std::endl;
152  }
153  }
154  }
155 
156  if (_renderObject->textures().size())
157  {
158  // Why are my textures sampled as black?
159 
160  // mipmap enabled, but no mipmap chain provided?
161 
162  for (std::map<size_t,RenderObject::Texture>::const_iterator it = _renderObject->textures().begin();
163  it != _renderObject->textures().end(); ++it)
164  {
165 #ifdef GL_ARB_texture_buffer_object
166  if (it->second.type == GL_TEXTURE_BUFFER)
167  continue; // skip texture buffers, for which testing for mipmaps would generate an error
168 #endif
169 
170  glBindTexture(it->second.type, it->second.id);
171 
172  GLint minFilter = GL_NONE;
173  glGetTexParameteriv(it->second.type, GL_TEXTURE_MIN_FILTER, &minFilter);
174 
175  if (minFilter == GL_NEAREST_MIPMAP_LINEAR ||
176  minFilter == GL_NEAREST_MIPMAP_NEAREST ||
177  minFilter == GL_LINEAR_MIPMAP_LINEAR ||
178  minFilter == GL_LINEAR_MIPMAP_NEAREST)
179  {
180  GLint maxLevel = 0;
181  glGetTexParameteriv(it->second.type, GL_TEXTURE_MAX_LEVEL, &maxLevel);
182 
183  GLint texWidth = 0;
184  glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &texWidth);
185 
186  GLint maxLod = -1;
187  for (GLint lod = 0; lod < maxLevel && maxLod < 0; ++lod)
188  {
189  GLint lodWidth;
190  glGetTexLevelParameteriv(GL_TEXTURE_2D, lod, GL_TEXTURE_WIDTH, &lodWidth);
191 
192  if (lodWidth <= 0 || lodWidth == GL_INVALID_VALUE)
193  maxLod = lod-1;
194  }
195 
196  if (maxLod <= 0 && texWidth > 1)
197  {
198  std::cout << "warning: texture is sampled with mipmapping, but no mipchain is present: " << _renderObject->debugName << " texid: " << it->second.id << std::endl;
199  std::cout << " automatically disabling mipmapping!!" << std::endl;
200 
201  GLint correctedFilter = GL_LINEAR;
202 
203  if (minFilter == GL_NEAREST_MIPMAP_LINEAR ||
204  minFilter == GL_LINEAR_MIPMAP_LINEAR)
205  correctedFilter = GL_LINEAR;
206  else
207  correctedFilter = GL_NEAREST;
208 
209  glTexParameteri(it->second.type, GL_TEXTURE_MIN_FILTER, correctedFilter);
210  }
211  }
212  }
213 
214  }
215 
216  if (errorDetectionLevel_ > 1)
217  {
218  // Why is there nothing written to the depth-buffer?
219  // this might very well be intentional, so put it in higher level
220 
221  if (_renderObject->depthWrite && !_renderObject->depthTest)
222  {
223  std::cout << "warning: trying to write to depth buffer with depth-testing disabled does not work in: " << _renderObject->debugName << std::endl;
224  std::cout << " If depth-writing was intended, enable depth-testing and set depth-func to GL_ALWAYS" << std::endl;
225  }
226  }
227 
228  if (!_renderObject->vertexArrayObject)
229  {
230  // Why are there gl errors and/or nothing gets drawn?
231  if (_renderObject->shaderDesc.shadeMode != SG_SHADE_UNLIT)
232  {
233  // check for normals
234  if (!_renderObject->vertexDecl->findElementByUsage(VERTEX_USAGE_NORMAL))
235  std::cout << "warning: missing normals for lighting in renderobject: " << _renderObject->debugName << std::endl
236  << " Set shadeMode to SG_SHADE_UNLIT or provide normals!" << std::endl;
237  }
238 
239  if (_renderObject->shaderDesc.textured())
240  {
241  // check for texcoords
243  std::cout << "warning: missing texcoords for textured mode in renderobject: " << _renderObject->debugName << std::endl;
244  }
245 
246  if (_renderObject->shaderDesc.vertexColors)
247  {
248  // check for vertex colors
249  if (!_renderObject->vertexDecl->findElementByUsage(VERTEX_USAGE_COLOR))
250  std::cout << "warning: missing colors for vertexcolor mode in renderobject: " << _renderObject->debugName << std::endl;
251  }
252  }
253 
254 
255  // Why is alpha blending not work?
256  if (fabsf(_renderObject->alpha - 1.0f) > 1e-3f && !(_renderObject->alphaTest || _renderObject->blending))
257  std::cout << "warning: alpha value != 1 but no alpha blending or testing enabled in renderobject: " << _renderObject->debugName << std::endl;
258 
259 
260 #ifdef GL_ARB_tessellation_shader
261  // Trying to render with tessellation shaders?
262  const bool tessellationActive = !_renderObject->shaderDesc.tessControlTemplateFile.isEmpty() || !_renderObject->shaderDesc.tessEvaluationTemplateFile.isEmpty();
263  bool tryToFixPatchInfo = false;
264  if (tessellationActive && _renderObject->primitiveMode != GL_PATCHES)
265  {
266  std::cout << "error: tessellation shaders are not used with GL_PATCHES primitiveType in renderobject: " << _renderObject->debugName << std::endl;
267  tryToFixPatchInfo = true;
268  }
269 
270  if (tessellationActive && !_renderObject->patchVertices)
271  {
272  std::cout << "error: undefined patch size for tessellation in renderobject: " << _renderObject->debugName << std::endl;
273  tryToFixPatchInfo = true;
274  }
275 
276  if (tryToFixPatchInfo)
277  {
278  if (_renderObject->primitiveMode == GL_POINTS)
279  {
280  _renderObject->primitiveMode = GL_PATCHES;
281  _renderObject->patchVertices = 1;
282  std::cout << "warning: attempting to draw with patchVertices = 1 for tessellation in renderobject: " << _renderObject->debugName << std::endl;
283  }
284  else if (_renderObject->primitiveMode == GL_LINES)
285  {
286  _renderObject->primitiveMode = GL_PATCHES;
287  _renderObject->patchVertices = 2;
288  std::cout << "warning: attempting to draw with patchVertices = 2 for tessellation in renderobject: " << _renderObject->debugName << std::endl;
289  }
290  else if (_renderObject->primitiveMode == GL_TRIANGLES)
291  {
292  _renderObject->primitiveMode = GL_PATCHES;
293  _renderObject->patchVertices = 3;
294  std::cout << "warning: attempting to draw with patchVertices = 3 for tessellation in renderobject: " << _renderObject->debugName << std::endl;
295  }
296  else if (_renderObject->primitiveMode == GL_QUADS)
297  {
298  _renderObject->primitiveMode = GL_PATCHES;
299  _renderObject->patchVertices = 4;
300  std::cout << "warning: attempting to draw with patchVertices = 4 for tessellation in renderobject: " << _renderObject->debugName << std::endl;
301  }
302  }
303 
304 #endif
305  }
306 
307 
308  renderObjects_.push_back(*_renderObject);
309 
310 
311  ACG::RenderObject* p = &renderObjects_.back();
312 
313  // apply modifiers
314  size_t numMods = renderObjectModifiers_.size();
315  for (size_t i = 0; i < numMods; ++i)
316  {
317  if (renderObjectModifiers_[i])
318  renderObjectModifiers_[i]->apply(p);
319  }
320 
321  if (!p->shaderDesc.numLights)
322  p->shaderDesc.numLights = numLights_;
323 
324  else if (p->shaderDesc.numLights < 0 || p->shaderDesc.numLights >= SG_MAX_SHADER_LIGHTS)
325  p->shaderDesc.numLights = 0;
326 
327  p->internalFlags_ = 0;
328 
329  // precompile shader
330 #ifdef GL_VERSION_3_2
332 #endif
333 
334 
335  // check primitive type and geometry shader
336  if (errorDetectionLevel_ > 1 && p->shaderDesc.geometryTemplateFile.length())
337  {
338 #ifdef GL_VERSION_3_2
339  GLint geomInputType = 0;
340  glGetProgramiv(shaderProg->getProgramId(), GL_GEOMETRY_INPUT_TYPE, &geomInputType);
341 
342 
343  if (geomInputType != GLint(p->primitiveMode))
344  {
345 
346  switch (geomInputType)
347  {
348  case GL_POINTS: std::cout << "warning: primitive mode is incompatible with points-geometryshader in renderobject: " << _renderObject->debugName << std::endl; break;
349 
350  case GL_LINES:
351  {
352  if (p->primitiveMode != GL_LINE_STRIP && p->primitiveMode != GL_LINE_LOOP)
353  std::cout << "warning: primitive mode is incompatible with lines-geometryshader in renderobject: " << _renderObject->debugName << std::endl;
354  } break;
355 
356  case GL_LINES_ADJACENCY:
357  {
358  if (p->primitiveMode != GL_LINE_STRIP_ADJACENCY)
359  std::cout << "warning: primitive mode is incompatible with lines_adjacency-geometryshader in renderobject: " << _renderObject->debugName << std::endl;
360  } break;
361 
362  case GL_TRIANGLES:
363  {
364  if (p->primitiveMode != GL_TRIANGLE_STRIP && p->primitiveMode != GL_TRIANGLE_FAN)
365  std::cout << "warning: primitive mode is incompatible with triangles-geometryshader in renderobject: " << _renderObject->debugName << std::endl;
366  } break;
367 
368  case GL_TRIANGLES_ADJACENCY:
369  {
370  if (p->primitiveMode != GL_TRIANGLE_STRIP_ADJACENCY)
371  std::cout << "warning: primitive mode is incompatible with triangles_adjacency-geometryshader in renderobject: " << _renderObject->debugName << std::endl;
372  } break;
373 
374  default: std::cout << "warning: unknown input_type for geometryshader in renderobject: " << _renderObject->debugName << std::endl;
375  }
376 
377 
378 
379  }
380 
381 
382 #else
383  if (_renderObject->isDefaultLineObject())
384  {
385  if (_renderObject->primitiveMode != GL_LINES && _renderObject->primitiveMode != GL_LINE_STRIP && _renderObject->primitiveMode != GL_LINE_LOOP)
386  std::cout << "warning: primitive mode is incompatible with lines-geometryshader in renderobject: " << _renderObject->debugName << std::endl;
387  }
388  else if (_renderObject->isDefaultPointObject())
389  {
390  if (_renderObject->primitiveMode != GL_POINTS)
391  std::cout << "warning: primitive mode is incompatible with points-geometryshader in renderobject: " << _renderObject->debugName << std::endl;
392  }
393 #endif
394  }
395 
396  }
397 }
398 
399 
400 
401 
403 {
404  // collect light sources
405 // collectLightNodes(_sceneGraphRoot);
406  numLights_ = 0; // reset light counter
407 
408 // // flush render objects
409 // for (size_t i = 0; i < renderObjects_.size(); ++i)
410 // {
411 // renderObjects_[i].uniformPool_.clear();
412 // }
413  renderObjects_.clear();
414 
415  if (!_sceneGraphRoot) return;
416 
417  // default material needed
419  defMat.baseColor(ACG::Vec4f(0.0f, 0.0f, 0.0f, 1.0f));
420  defMat.ambientColor(ACG::Vec4f(0.2f, 0.2f, 0.2f, 1.0f));
421  defMat.diffuseColor(ACG::Vec4f(0.6f, 0.6f, 0.6f, 1.0f));
422  defMat.specularColor(ACG::Vec4f(0.0f, 0.0f, 0.0f, 1.0f));
423  defMat.shininess(1.0f);
424  // defMat.alphaValue(1.0f);
425 
426  // collect renderables
427  traverseRenderableNodes(_glState, _drawMode, *_sceneGraphRoot, defMat);
428 }
429 
430 
432 namespace {
433 class ScenegraphTraversalStackEl {
434  public:
435  ScenegraphTraversalStackEl(ACG::SceneGraph::BaseNode *_node,
436  const ACG::SceneGraph::Material *_material) :
437  node(_node), material(_material),
438  subtree_index_start(0), leave(false) {}
439 
441  const ACG::SceneGraph::Material* material;
442  size_t subtree_index_start;
443  bool leave;
444 };
445 }
446 
448 {
450  return;
451 
452  std::vector<ScenegraphTraversalStackEl> stack;
453  // That's roughly the minimum size every scenegraph requries.
454  stack.reserve(32);
455  stack.push_back(ScenegraphTraversalStackEl(&_node, &_mat));
456  while (!stack.empty()) {
457  ScenegraphTraversalStackEl &cur = stack.back();
458  ACG::SceneGraph::DrawModes::DrawMode nodeDM = cur.node->drawMode();
460  nodeDM = _drawMode;
461 
462  if (!cur.leave) {
463  /*
464  * Stuff that happens before processing cur.node's children.
465  */
466  if ( cur.node->status() != ACG::SceneGraph::BaseNode::HideNode )
467  cur.node->enter(this, *_glState, nodeDM);
468 
469  cur.subtree_index_start = renderObjects_.size();
470 
471  // fetch material (Node itself can be a material node, so we have to
472  // set that in front of the nodes own rendering
474  dynamic_cast<ACG::SceneGraph::MaterialNode*>(cur.node);
475  if (matNode)
476  cur.material = &matNode->material();
477 
478  if (cur.node->status() != ACG::SceneGraph::BaseNode::HideNode)
479  cur.node->getRenderObjects(this, *_glState, nodeDM, cur.material);
480 
481  // Process children?
482  if (cur.node->status() != ACG::SceneGraph::BaseNode::HideChildren) {
483  // Process all children which are second pass
485  cIt = cur.node->childrenBegin(),
486  cEnd = cur.node->childrenEnd(); cIt != cEnd; ++cIt) {
487  if (((*cIt)->traverseMode() &
489  (*cIt)->status() != ACG::SceneGraph::BaseNode::HideSubtree)
490  stack.push_back(ScenegraphTraversalStackEl(*cIt, cur.material));
491  }
492 
493  // Process all children which are not second pass
495  cIt = cur.node->childrenBegin(),
496  cEnd = cur.node->childrenEnd(); cIt != cEnd; ++cIt) {
497  if ((~(*cIt)->traverseMode() &
499  (*cIt)->status() != ACG::SceneGraph::BaseNode::HideSubtree)
500  stack.push_back(ScenegraphTraversalStackEl(*cIt, cur.material));
501  }
502  }
503 
504  // Next time process the other branch of this if statement.
505  cur.leave = true;
506 
507  } else {
508  /*
509  * Stuff that happens after processing cur.node's children.
510  */
511  current_subtree_objects_ = RenderObjectRange(
512  renderObjects_.begin() + cur.subtree_index_start,
513  renderObjects_.end());
514 
515  if (cur.node->status() != ACG::SceneGraph::BaseNode::HideNode )
516  cur.node->leave(this, *_glState, nodeDM);
517  stack.pop_back();
518  }
519  }
520 }
521 
523 {
524  // grab view transform from glstate
525  viewMatrix_ = _glState->modelview();
526  camPosWS_ = Vec3f( viewMatrix_(0,3), viewMatrix_(1,3), viewMatrix_(2,3) );
527  camDirWS_ = Vec3f( viewMatrix_(0,2), viewMatrix_(1,2), -viewMatrix_(2,2) ); // mind the z flip
528 
529 // printf("pos: %f %f %f\ndir: %f %f %f\n", camPosWS_[0], camPosWS_[1], camPosWS_[2],
530 // camDirWS_[0], camDirWS_[1], camDirWS_[2]);
531 
532  // First, all render objects get collected.
533  collectRenderObjects(_glState, _drawMode, _scenegraphRoot);
534 
535  // ==========================================================
536  // Sort renderable objects based on their priority
537  // Filter for overlay, lines etc.
538  // ==========================================================
539 
540  size_t numRenderObjects = 0,
541  numOverlayObjects = 0,
542  numLineObjects = 0;
543 
544  for (std::vector<ACG::RenderObject>::const_iterator it = renderObjects_.begin();
545  it != renderObjects_.end(); ++it) {
546  if (!it->overlay && !(it->isDefaultLineObject() && enableLineThicknessGL42_))
547  numRenderObjects++;
548  if (it->overlay)
549  numOverlayObjects++;
550  if (enableLineThicknessGL42_ && it->isDefaultLineObject())
551  numLineObjects++;
552  }
553 
554  /*
555  * Neither clear() nor resize() ever decreases the capacity of
556  * a vector. So it has no adverse impact on performance to clear
557  * the vectors here.
558  */
559  sortedObjects_.clear();
560  sortedObjects_.reserve(numRenderObjects);
561 
562  overlayObjects_.clear();
563  overlayObjects_.reserve(numOverlayObjects);
564 
565  lineGL42Objects_.clear();
566  lineGL42Objects_.reserve(numLineObjects);
567 
568  // init sorted objects array
569  for (size_t i = 0; i < renderObjects_.size(); ++i)
570  {
571  if (renderObjects_[i].overlay)
572  overlayObjects_.push_back(&renderObjects_[i]);
573  else if (enableLineThicknessGL42_ && numLineObjects && renderObjects_[i].isDefaultLineObject())
574  {
575  renderObjects_[i].shaderDesc.geometryTemplateFile = "Wireframe/gl42/geometry.tpl";
576  renderObjects_[i].shaderDesc.fragmentTemplateFile = "Wireframe/gl42/fragment.tpl";
577 
578  // disable color write to fbo, but allow RenderObject to control depth write
579  renderObjects_[i].glColorMask(0,0,0,0);
580 
581 // sortedObjects_[sceneObjectOffset++] = &renderObjects_[i];
582  lineGL42Objects_.push_back(&renderObjects_[i]);
583  }
584  else
585  sortedObjects_.push_back(&renderObjects_[i]);
586  }
587 
588  sortRenderObjects();
589 
590 
591  // ---------------------------
592  // Initialize the render state
593  // ---------------------------
594  // gl cleanup
595 
596  glDisableClientState(GL_VERTEX_ARRAY);
597  glDisableClientState(GL_COLOR_ARRAY);
598  glDisableClientState(GL_NORMAL_ARRAY);
599  glDisableClientState(GL_TEXTURE_COORD_ARRAY);
600  glDisableClientState(GL_INDEX_ARRAY);
601 
602 
603  glEnable(GL_CULL_FACE);
604  glEnable(GL_DEPTH_TEST);
605  glDepthFunc(GL_LESS);
606  glDepthMask(GL_TRUE);
607 
608  // save active fbo and viewport
609  saveInputFbo();
610 
611 
612  // get global ambient factor
613  GLfloat lightModelAmbient[4];
614  glGetFloatv(GL_LIGHT_MODEL_AMBIENT, lightModelAmbient);
615  globalLightModelAmbient_ = ACG::Vec3f(lightModelAmbient[0], lightModelAmbient[1], lightModelAmbient[2]);
616 
617 
618  // search list of render object for objects requiring the scene depth map
619  bool requiresSceneDepths = false;
620 
621  for (size_t i = 0; i < renderObjects_.size(); ++i)
622  {
623  if (renderObjects_[i].depthMapUniformName)
624  requiresSceneDepths = true;
625  }
626 
627  // render scene depth map
628  if (requiresSceneDepths)
629  renderDepthMap(curViewerID_, _glState->viewport_width(), _glState->viewport_height());
630 }
631 
632 
633 
634 void IRenderer::finishRenderingPipeline(bool _drawOverlay)
635 {
636 #ifdef GL_ARB_vertex_array_object
637  glBindVertexArray(0);
638 #endif
639 
640  // draw thick lines
641  if (enableLineThicknessGL42_)
642  renderLineThicknessGL42();
643 
644  if (_drawOverlay)
645  {
646  const int numOverlayObj = overlayObjects_.size();
647  // two-pass overlay rendering:
648  // 1. clear depth buffer at pixels of overlay objects
649  // 2. render overlay with correct depth-testing
650 
651  // 1. pass: clear depth to max value at overlay footprint
652  for (int i = 0; i < numOverlayObj; ++i)
653  {
654  RenderObject* obj = getOverlayRenderObject(i);
655 
656  if (obj->depthTest && obj->depthFunc != GL_ALWAYS)
657  {
658  float depthMax = 1.0f;
659 
660  if (obj->depthFunc == GL_GREATER || obj->depthFunc == GL_GEQUAL)
661  depthMax = 0.0f;
662 
663  // save depth setting of renderobject
664  Vec2f depthRange = obj->depthRange;
665  bool depthWrite = obj->depthWrite;
666  GLenum depthFunc = obj->depthFunc;
667 
668  // reset depth to maximal distance by using depth range
669  obj->depthRange = Vec2f(depthMax, depthMax);
670  obj->depthWrite = true;
671  obj->depthFunc = GL_ALWAYS;
672 
673  renderObject(obj);
674 
675  // restore depth setting
676  obj->depthRange = depthRange;
677  obj->depthWrite = depthWrite;
678  obj->depthFunc = depthFunc;
679  }
680 
681  }
682 
683  // 2. render overlay with correct depth-testing
684  for (int i = 0; i < numOverlayObj; ++i)
685  {
686  RenderObject* obj = getOverlayRenderObject(i);
687  renderObject(obj);
688  }
689 
690  }
691 
692 #ifdef GL_ARB_vertex_array_object
693  glBindVertexArray(0);
694 #endif
695 
696  for (int i = 0; i < maxClipDistances_; ++i)
697  glDisable(GL_CLIP_DISTANCE0 + i);
698 
699  glDepthMask(1);
700  glColorMask(1,1,1,1);
701 
702  glUseProgram(0);
703 
704  glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
705  glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0);
706 
707  // Renderer check:
708  // Print a warning if the currently active fbo / viewport is not the same as the saved fbo.
709  // Restore to previous fbo and viewport if not done already.
710 
711  GLint curFbo;
712  GLint curViewport[4];
713  GLint curDrawBuf;
714  glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &curFbo);
715  glGetIntegerv(GL_VIEWPORT, curViewport);
716  glGetIntegerv(GL_DRAW_BUFFER, &curDrawBuf);
717 
718  if (curFbo != prevFbo_)
719  {
720  std::cout << "warning: input and output fbo are not the same in renderer implementation" << std::endl;
721  restoreInputFbo();
722  }
723 
724  if (curDrawBuf != prevDrawBuffer_)
725  {
726  std::cout << "warning: input and output draw-buffer are not the same in renderer implementation" << std::endl;
727  restoreInputFbo();
728  }
729 
730  if (curViewport[0] != prevViewport_[0] ||
731  curViewport[1] != prevViewport_[1] ||
732  curViewport[2] != prevViewport_[2] ||
733  curViewport[3] != prevViewport_[3])
734  {
735  std::cout << "warning: input and output viewport are not the same in renderer implementation" << std::endl;
736  restoreInputFbo();
737  }
738 }
739 
740 
742 {
743  // save active fbo
744  saveActiveFbo(&prevFbo_, prevViewport_, &prevDrawBuffer_);
745  prevFboSaved_ = true;
746 }
747 
749 {
750  if (prevFboSaved_)
751  restoreFbo(prevFbo_, prevViewport_, prevDrawBuffer_);
752 }
753 
754 void IRenderer::saveActiveFbo( GLint* _outFboId, GLint* _outViewport, GLint* _outDrawBuffer ) const
755 {
756  // save active fbo
757  glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, _outFboId);
758  glGetIntegerv(GL_VIEWPORT, _outViewport);
759  glGetIntegerv(GL_DRAW_BUFFER, _outDrawBuffer);
760 }
761 
762 void IRenderer::restoreFbo( GLint _fboId, const GLint* _outViewport, GLint _drawBuffer ) const
763 {
764  glBindFramebuffer(GL_FRAMEBUFFER, _fboId);
765  glDrawBuffer(_drawBuffer);
766  glViewport(_outViewport[0], _outViewport[1], _outViewport[2], _outViewport[3]);
767 }
768 
769 void IRenderer::clearInputFbo( const ACG::Vec4f& clearColor )
770 {
771  glClearColor(clearColor[0], clearColor[1], clearColor[2], 1.0f);
772 
773  // glClear will affect the whole back buffer, not only the area in viewport.
774  // Temporarily use glScissor to only clear the viewport area in the back buffer.
775  if (!prevFboSaved_)
776  {
777  GLint oldViewport[4];
778  glGetIntegerv(GL_VIEWPORT, oldViewport);
779  glScissor(oldViewport[0], oldViewport[1], oldViewport[2], oldViewport[3]);
780  }
781  else
782  glScissor(prevViewport_[0], prevViewport_[1], prevViewport_[2], prevViewport_[3]);
783 
784  glEnable(GL_SCISSOR_TEST);
785  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
786 
787  // disable scissors again, draw calls only affect the area in glViewport anyway
788  glDisable(GL_SCISSOR_TEST);
789 }
790 
791 namespace {
792 struct RenderObjectComparator {
793  bool operator() (ACG::RenderObject *a, ACG::RenderObject * b) {
794  return (a->priority < b->priority);
795  }
796 };
797 }
798 
800 {
801  std::sort(sortedObjects_.begin(), sortedObjects_.end(), RenderObjectComparator());
802  std::sort(overlayObjects_.begin(), overlayObjects_.end(), RenderObjectComparator());
803 }
804 
805 
806 
808  GLSL::Program* _prog)
809 {
810  _prog->use();
811 
812 
813 #ifdef GL_ARB_vertex_array_object
814  glBindVertexArray(_obj->vertexArrayObject);
815 #endif
816 
817  if (!_obj->vertexArrayObject)
818  {
820  // NOTE:
821  // always bind buffers before glVertexAttribPointer calls!!
822  // freeze in glDrawElements guaranteed (with no error message whatsoever)
823  glBindBufferARB(GL_ARRAY_BUFFER_ARB, _obj->vertexBuffer);
824  glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, _obj->indexBuffer);
825 
826 
827  // activate vertex declaration
828  _obj->vertexDecl->activateShaderPipeline(_prog);
829 
830  }
831 }
832 
833 
835 {
836  // transforms
837  ACG::GLMatrixf mvp = _obj->proj * _obj->modelview;
838  ACG::GLMatrixf mvIT = _obj->modelview;
839  mvIT.invert();
840  mvIT.transpose();
841 
842  _prog->setUniform("g_mWVP", mvp);
843  _prog->setUniform("g_mWV", _obj->modelview);
844  _prog->setUniformMat3("g_mWVIT", mvIT);
845  _prog->setUniform("g_mP", _obj->proj);
846 
847  _prog->setUniform("g_vCamPos", camPosWS_);
848  _prog->setUniform("g_vCamDir", camDirWS_);
849 
850  // material
851 
852  _prog->setUniform("g_cEmissive", _obj->emissive);
853 
854  _prog->setUniform("g_cDiffuse", _obj->diffuse);
855  _prog->setUniform("g_cAmbient", _obj->ambient);
856  _prog->setUniform("g_cSpecular", _obj->specular);
857 
858  ACG::Vec4f materialParams(_obj->shininess, _obj->alpha, 0.0f, 0.0f);
859  _prog->setUniform("g_vMaterial", materialParams);
860 
861  _prog->setUniform("g_cLightModelAmbient", globalLightModelAmbient_);
862 
863  // Additional Uniforms defined in the render Object
864  if ( !_obj->uniformPool_.empty() )
865  _obj->uniformPool_.bind(_prog);
866 
867  // textures:
868 
869  // maybe consider using bindless textures some time in the future
870  // to get rid of the old and problematic glActiveTexture(), glBindTexture() state machine usage:
871  // https://www.opengl.org/registry/specs/ARB/bindless_texture.txt
872 
873  int maxTextureStage = 0;
874  for (std::map<size_t,RenderObject::Texture>::const_iterator iter = _obj->textures().begin();
875  iter != _obj->textures().end();++iter)
876  {
877  //check for valid texture id
878  const size_t texture_stage = iter->first;
879  const RenderObject::Texture tex = iter->second;
880  if (!tex.id)
881  continue;
882 
883  glActiveTexture(GL_TEXTURE0 + (GLenum)texture_stage);
884  glBindTexture(iter->second.type, tex.id);
885  _prog->setUniform(QString("g_Texture%1").arg(texture_stage).toStdString().c_str(), (int)texture_stage);
886 
887  maxTextureStage = std::max(maxTextureStage, (int)texture_stage);
888  }
889 
890 
891  // scene depth texture
892  if (_obj->depthMapUniformName)
893  {
894  // bind to (hopefully) unused texture stage
895  int depthMapSlot = maxTextureStage + 1;
896 
897  _prog->setUniform(_obj->depthMapUniformName, depthMapSlot);
898  glActiveTexture(GL_TEXTURE0 + depthMapSlot);
899  glBindTexture(GL_TEXTURE_2D, depthMaps_[curViewerID_]->getAttachment(GL_COLOR_ATTACHMENT0));
900  }
901 
902 
903  // lights
904  for (int i = 0; i < numLights_; ++i)
905  {
906  LightData* lgt = lights_ + i;
907 
908  char szUniformName[256];
909 
910  sprintf(szUniformName, "g_cLightDiffuse_%d", i);
911  _prog->setUniform(szUniformName, lgt->diffuse);
912 
913  sprintf(szUniformName, "g_cLightAmbient_%d", i);
914  _prog->setUniform(szUniformName, lgt->ambient);
915 
916  sprintf(szUniformName, "g_cLightSpecular_%d", i);
917  _prog->setUniform(szUniformName, lgt->specular);
918 
919 
920  if (lgt->ltype == ACG::SG_LIGHT_POINT || lgt->ltype == ACG::SG_LIGHT_SPOT)
921  {
922  sprintf(szUniformName, "g_vLightPos_%d", i);
923  _prog->setUniform(szUniformName, lgt->pos);
924 
925  sprintf(szUniformName, "g_vLightAtten_%d", i);
926  _prog->setUniform(szUniformName, lgt->atten);
927  }
928 
929  if (lgt->ltype == ACG::SG_LIGHT_DIRECTIONAL || lgt->ltype == ACG::SG_LIGHT_SPOT)
930  {
931  sprintf(szUniformName, "g_vLightDir_%d", i);
932  _prog->setUniform(szUniformName, lgt->dir);
933  }
934 
935  if (lgt->ltype == ACG::SG_LIGHT_SPOT)
936  {
937  sprintf(szUniformName, "g_vLightAngleExp_%d", i);
938  _prog->setUniform(szUniformName, lgt->spotCutoffExponent);
939  }
940  }
941 }
942 
944 {
945  if (_obj->culling)
946  glEnable(GL_CULL_FACE);
947  else
948  glDisable(GL_CULL_FACE);
949 
950  if (_obj->blending)
951  glEnable(GL_BLEND);
952  else
953  glDisable(GL_BLEND);
954 
955  if (_obj->alphaTest)
956  {
957  glEnable(GL_ALPHA_TEST);
958  glAlphaFunc(_obj->alphaFunc, _obj->alphaRef);
959  }
960  else
961  glDisable(GL_ALPHA_TEST);
962 
963  if (_obj->depthTest)
964  glEnable(GL_DEPTH_TEST);
965  else
966  glDisable(GL_DEPTH_TEST);
967 
968 
969  glDepthMask(_obj->depthWrite ? GL_TRUE : GL_FALSE);
970 
971  glColorMask(_obj->colorWriteMask[0], _obj->colorWriteMask[1], _obj->colorWriteMask[2], _obj->colorWriteMask[3]);
972 
973  glDepthFunc(_obj->depthFunc);
974 
975  glDepthRange(_obj->depthRange[0], _obj->depthRange[1]);
976 
977  // ACG::GLState::shadeModel(_obj->shadeModel);
978 
979  ACG::GLState::blendFunc(_obj->blendSrc, _obj->blendDest);
980 
981  if (maxClipDistances_ < 0)
982  {
983  glGetIntegerv(GL_MAX_CLIP_DISTANCES, &maxClipDistances_);
984  maxClipDistances_ = std::min(maxClipDistances_, 32); // clamp to 32 bits
985  }
986 
987  for (int i = 0; i < maxClipDistances_; ++i)
988  {
989  if (_obj->clipDistanceMask & (1 << i))
990  glEnable(GL_CLIP_DISTANCE0 + i);
991  else
992  glDisable(GL_CLIP_DISTANCE0 + i);
993  }
994 }
995 
997 {
998  if (_obj->numIndices)
999  {
1000  // indexed drawing?
1001  bool noIndices = true;
1002  if (_obj->indexBuffer || _obj->sysmemIndexBuffer)
1003  noIndices = false;
1004 
1005  glPolygonMode(GL_FRONT_AND_BACK, _obj->fillMode);
1006 
1007  // tessellation info
1008  bool tessellationActive = !(_obj->shaderDesc.tessControlTemplateFile.isEmpty() && _obj->shaderDesc.tessEvaluationTemplateFile.isEmpty());
1009 #ifdef GL_ARB_tessellation_shader
1010  if (tessellationActive)
1011  {
1012  glPatchParameteri(GL_PATCH_VERTICES, _obj->patchVertices);
1013 
1014  if (_obj->shaderDesc.tessControlTemplateFile.isEmpty())
1015  {
1016  glPatchParameterfv(GL_PATCH_DEFAULT_INNER_LEVEL, _obj->patchDefaultInnerLevel.data());
1017  glPatchParameterfv(GL_PATCH_DEFAULT_OUTER_LEVEL, _obj->patchDefaultOuterLevel.data());
1018  }
1019  }
1020 #else
1021  if (tessellationActive)
1022  std::cout << "error: tessellation shaders cannot be used with the outdated glew version" << std::endl;
1023 #endif
1024 
1025  if (noIndices) {
1026  if (_obj->numInstances <= 0)
1027  glDrawArrays(_obj->primitiveMode, _obj->indexOffset, _obj->numIndices);
1028  else
1029  glDrawArraysInstanced(_obj->primitiveMode, _obj->indexOffset, _obj->numIndices, _obj->numInstances);
1030  }
1031  else
1032  {
1033  // ------------------------------------------
1034  // index offset stuff not tested
1035  int indexSize = 0;
1036  switch (_obj->indexType)
1037  {
1038  case GL_UNSIGNED_INT: indexSize = 4; break;
1039  case GL_UNSIGNED_SHORT: indexSize = 2; break;
1040  default: indexSize = 1; break;
1041  }
1042 
1043  if (_obj->numInstances <= 0)
1044  glDrawElements(_obj->primitiveMode, _obj->numIndices, _obj->indexType,
1045  ((const char*)_obj->sysmemIndexBuffer) + _obj->indexOffset * indexSize);
1046  else
1047  glDrawElementsInstanced(_obj->primitiveMode, _obj->numIndices, _obj->indexType,
1048  ((const char*)_obj->sysmemIndexBuffer) + _obj->indexOffset * indexSize, _obj->numInstances);
1049  }
1050  }
1051 }
1052 
1054  GLSL::Program* _prog,
1055  bool _constRenderStates,
1056  const std::vector<unsigned int>* _shaderModifiers)
1057 {
1058  // select shader from cache
1059  GLSL::Program* prog = _prog ? _prog : ACG::ShaderCache::getInstance()->getProgram(&_obj->shaderDesc, _shaderModifiers);
1060 
1061 
1062  bindObjectVBO(_obj, prog);
1063 
1064  // ---------------------------------------
1065  // set shader uniforms
1066 
1067  bindObjectUniforms(_obj, prog);
1068 
1069  // render states
1070 
1071  if (!_constRenderStates)
1072  bindObjectRenderStates(_obj);
1073 
1074  // ----------------------------
1075  // OpenGL draw call
1076 
1077  drawObject(_obj);
1078 
1079 
1081 
1082  if (_obj->vertexDecl)
1083  {
1084  // deactivate vertex declaration to avoid errors
1085  _obj->vertexDecl->deactivateShaderPipeline(prog);
1086  }
1087 
1088 
1089 #ifdef GL_ARB_vertex_array_object
1090  if (_obj->vertexArrayObject)
1091  glBindVertexArray(0);
1092 #endif
1093 
1094 }
1095 
1096 
1097 void IRenderer::addLight(const LightData& _light)
1098 {
1099  if (numLights_ < SG_MAX_SHADER_LIGHTS)
1100  {
1101  lights_[numLights_] = _light;
1102 
1103  // normalize direction
1104  if (_light.ltype != SG_LIGHT_POINT)
1105  lights_[numLights_].dir.normalize();
1106 
1107  ++numLights_;
1108  }
1109 }
1110 
1112 {
1113  renderObjectModifiers_.push_back(_mod);
1114 }
1115 
1117 {
1118  for (int i = int(renderObjectModifiers_.size()) - 1; i >= 0; --i)
1119  {
1120  if (renderObjectModifiers_[i] == _mod)
1121  renderObjectModifiers_.erase(renderObjectModifiers_.begin() + i);
1122  }
1123 }
1124 
1126  return sortedObjects_.size();
1127 }
1128 
1130 {
1131  return numLights_;
1132 }
1133 
1134 
1136 {
1137  if (sortedObjects_.empty())
1138  return &renderObjects_[i];
1139 
1140  return sortedObjects_[i];
1141 }
1142 
1144 {
1145  if (overlayObjects_.empty())
1146  return &renderObjects_[i];
1147 
1148  return overlayObjects_[i];
1149 }
1150 
1152 {
1153  if (lineGL42Objects_.empty())
1154  return 0;
1155 
1156  return lineGL42Objects_[i];
1157 }
1158 
1160 {
1161  return &lights_[i];
1162 }
1163 
1164 
1165 void IRenderer::dumpRenderObjectsToFile(const char* _fileName, ACG::RenderObject** _sortedList) const
1166 {
1167  QFile fileOut(_fileName);
1168  if (fileOut.open(QFile::WriteOnly | QFile::Truncate))
1169  {
1170  QTextStream outStrm(&fileOut);
1171  for (int i = 0; i < getNumRenderObjects(); ++i)
1172  {
1173  if (_sortedList)
1174  outStrm << "\n" << _sortedList[i]->toString();
1175  else
1176  outStrm << "\n" << renderObjects_[i].toString();
1177  }
1178 
1179  fileOut.close();
1180  }
1181 }
1182 
1183 
1184 QString IRenderer::dumpCurrentRenderObjectsToString(ACG::RenderObject** _list, bool _outputShaders, std::vector<ACG::ShaderModifier*>* _modifiers) {
1185 
1186  QString objectString;
1187 
1188  QTextStream outStrm(&objectString);
1189 
1190  for (int i = 0; i < getNumRenderObjects(); ++i)
1191  {
1192  const RenderObject* obj = _list ? _list[i] : &renderObjects_[i];
1193 
1194  if (obj) {
1195  outStrm << "\n" << obj->toString();
1196 
1197  if ( _outputShaders ) {
1198 
1199  outStrm << "\n";
1200 
1201  outStrm << obj->shaderDesc.toString();
1202 
1203  ShaderProgGenerator progGen(&(obj->shaderDesc), _modifiers);
1204 
1205  outStrm << "\n---------------------vertex-shader--------------------\n\n";
1206  for (int i = 0; i < progGen.getVertexShaderCode().size(); ++i)
1207  outStrm << progGen.getVertexShaderCode()[i] << "\n";
1208  outStrm << "\n---------------------end-vertex-shader--------------------\n\n";
1209 
1210  if (progGen.hasTessControlShader())
1211  {
1212  outStrm << "\n---------------------tesscontrol-shader--------------------\n\n";
1213  for (int i = 0; i < progGen.getTessControlShaderCode().size(); ++i)
1214  outStrm << progGen.getTessControlShaderCode()[i] << "\n";
1215  outStrm << "\n---------------------end-tesscontrol-shader--------------------\n\n";
1216  }
1217 
1218  if (progGen.hasTessControlShader())
1219  {
1220  outStrm << "\n---------------------tesseval-shader--------------------\n\n";
1221  if (progGen.hasTessEvaluationShader())
1222  for (int i = 0; i < progGen.getTessEvaluationShaderCode().size(); ++i)
1223  outStrm << progGen.getTessEvaluationShaderCode()[i] << "\n";
1224  outStrm << "\n---------------------end-tesseval-shader--------------------\n\n";
1225  }
1226 
1227  if (progGen.hasGeometryShader())
1228  {
1229  outStrm << "\n---------------------geometry-shader--------------------\n\n";
1230  for (int i = 0; i < progGen.getGeometryShaderCode().size(); ++i)
1231  outStrm << progGen.getGeometryShaderCode()[i] << "\n";
1232  outStrm << "\n---------------------end-geometry-shader--------------------\n\n";
1233  }
1234 
1235 
1236  outStrm << "\n---------------------fragment-shader--------------------\n\n";
1237  for (int i = 0; i < progGen.getFragmentShaderCode().size(); ++i)
1238  outStrm << progGen.getFragmentShaderCode()[i] << "\n";
1239  outStrm << "\n---------------------end-fragment-shader--------------------\n\n";
1240  }
1241 
1242  }
1243 
1244  }
1245 
1246  return objectString;
1247 }
1248 
1249 void IRenderer::copyDepthToBackBuffer( GLuint _depthTex, float _scale /*= 1.0f*/ )
1250 {
1251  if (!_depthTex) return;
1252 
1253  if (!depthCopyShader_)
1254  depthCopyShader_ = GLSL::loadProgram("ScreenQuad/screenquad.glsl", "ScreenQuad/depth_copy.glsl");
1255 
1256 
1257  if (depthCopyShader_)
1258  {
1259  // save important opengl states
1260  GLint curFbo;
1261  GLint curViewport[4];
1262  GLint curDrawBuffer;
1263  saveActiveFbo(&curFbo, curViewport, &curDrawBuffer);
1264 
1265  GLboolean colorMask[4], depthMask;
1266  glGetBooleanv(GL_COLOR_WRITEMASK, colorMask);
1267  glGetBooleanv(GL_DEPTH_WRITEMASK, &depthMask);
1268 
1269  GLboolean depthTestEnable;
1270  GLint depthFunc;
1271  glGetBooleanv(GL_DEPTH_TEST, &depthTestEnable);
1272  glGetIntegerv(GL_DEPTH_FUNC, &depthFunc);
1273 
1274  // write to depth buffer of input fbo
1275  restoreInputFbo();
1276 
1277  depthCopyShader_->use();
1278  depthCopyShader_->setUniform("offset", ACG::Vec2f(0.0f, 0.0f));
1279  depthCopyShader_->setUniform("size", ACG::Vec2f(1.0f, 1.0f));
1280  depthCopyShader_->setUniform("DepthTex", 0); // depth tex at texture slot 0
1281  depthCopyShader_->setUniform("DepthSign", _scale);
1282 
1283  // write to depth buffer only, disable writing to color buffer
1284  glColorMask(0,0,0,0);
1285  glDepthMask(1);
1286 
1287  // depth test enabled + pass always
1288  glEnable(GL_DEPTH_TEST);
1289  glDepthFunc(GL_ALWAYS);
1290 
1291  glActiveTexture(GL_TEXTURE0);
1292  glBindTexture(GL_TEXTURE_2D, _depthTex);
1293 
1294  ACG::ScreenQuad::draw(depthCopyShader_);
1295 
1296 
1297  // restore important opengl states
1298 
1299  restoreFbo(curFbo, curViewport, curDrawBuffer);
1300 
1301  glColorMask(colorMask[0], colorMask[1], colorMask[2], colorMask[3]);
1302  glDepthMask(depthMask);
1303 
1304  if (!depthTestEnable)
1305  glDisable(GL_DEPTH_TEST);
1306 
1307  if (depthFunc != GL_ALWAYS)
1308  glDepthFunc(depthFunc);
1309 
1310  glBindTexture(GL_TEXTURE_2D, 0);
1311  }
1312 }
1313 
1314 
1315 // depth map computation with a modifier
1316 
1317 IRenderer::DepthMapPass IRenderer::DepthMapPass::instance;
1318 
1320 {
1321  _code->push_back("outFragment = gl_FragCoord.zzzz;");
1322 }
1323 
1324 void IRenderer::renderDepthMap(int _viewerID, int _width, int _height)
1325 {
1326  ACG::FBO* fbo = depthMaps_[_viewerID];
1327 
1328  // setup fbo for depth map
1329  if (!fbo)
1330  {
1331  fbo = depthMaps_[_viewerID] = new ACG::FBO();
1332 
1333  fbo->bind();
1334  fbo->attachTexture2D(GL_COLOR_ATTACHMENT0, _width, _height, GL_R32F, GL_RED);
1335  fbo->addDepthBuffer(_width, _height);
1336  }
1337  else
1338  {
1339  fbo->bind();
1340  fbo->resize(_width, _height);
1341  }
1342 
1343  // make sure modifier is registered
1344  ACG::ShaderProgGenerator::registerModifier(&DepthMapPass::instance);
1345 
1346  /* note:
1347  It is possible to directly read the depth buffer if it was attached as a texture.
1348  Then, we would disable the color write mask and just write to the depth buffer in this function.
1349 
1350  However, doing this has shown that the actual depth values written to the depth buffer highly depend on the gpu driver.
1351  Or, at least sampling from a texture with format GL_DEPTH_COMPONENT returns driver dependent values.
1352  For instance, in the amd-gl driver sampling the depth texture returns the value of gl_FragDepth (as expected).
1353  But in the nvidia driver, sampling directly from the depth buffer returns something different!
1354 
1355  Therefore we render the value of gl_FragDepth to a custom floating-point texture bound to a color slot in order to get driver independent behavior.
1356  */
1357 
1358  fbo->bind();
1359  glDrawBuffer(GL_COLOR_ATTACHMENT0);
1360  glViewport(0, 0, _width, _height);
1361 
1362  // set depth to max
1363  glColorMask(1,1,1,1);
1364  glDepthMask(1);
1365 
1366  glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
1367  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
1368 
1369  // render z-prepass
1370  for (int i = 0; i < getNumRenderObjects(); ++i)
1371  {
1372  RenderObject* obj = getRenderObject(i);
1373 
1374  if (obj->inZPrePass)
1375  {
1376  // apply depth map modifier to get the depth pass shader
1377  GLSL::Program* depthPassShader = ShaderCache::getInstance()->getProgram(&obj->shaderDesc, DepthMapPass::instance);
1378 
1379  // temporarily prevent read/write access to the same texture (the depth map)
1380  const char* depthMapUniformName = obj->depthMapUniformName;
1381  obj->depthMapUniformName = 0;
1382 
1383  if (depthMapUniformName)
1384  {
1385  depthPassShader->use();
1386  depthPassShader->setUniform(depthMapUniformName, 0);
1387  glActiveTexture(GL_TEXTURE0);
1388  glBindTexture(GL_TEXTURE_2D, 0);
1389  }
1390 
1391  // we are interested in the depth value only, so temporarily modify the write mask to allow writing to the red channel
1392  // (for instance, an object might not write a color value, but a depth value)
1393  const GLboolean redWriteMask = obj->colorWriteMask[0];
1394  obj->colorWriteMask[0] = obj->depthWrite;
1395 
1396  renderObject(obj, depthPassShader);
1397 
1398  // reset modified render object states
1399  obj->depthMapUniformName = depthMapUniformName;
1400  obj->colorWriteMask[0]= redWriteMask;
1401  }
1402  }
1403 
1404  // restore input fbo state
1405 
1406  fbo->unbind();
1407 
1408  restoreInputFbo();
1409 }
1410 
1411 
1412 void IRenderer::setViewerID(int _viewerID)
1413 {
1414  curViewerID_ = _viewerID;
1415 }
1416 
1417 
1418 void IRenderer::renderLineThicknessGL42()
1419 {
1420 #ifdef GL_ARB_shader_image_load_store
1421  // quad extrusion has depth clipping issue
1422  // GL4.2 method: manually rasterize thick lines into load/store texture, thereby avoiding clipping
1423 
1424  // experimental technique, needs some improvements for rasterization
1425  /* possible improvement:
1426  0. init depth buffer with scene objects
1427  1. extract visible line object (startpos, endpos) into imageBuffer after depth-test in fragment shader
1428  1a. line segment id can be found via atomic counter in geometry shader
1429  1b. use imageAtomicMin/max to find start and end pixel pos of each line segment
1430  atomic ops work with uint only, thus each segment has 4 texels in the imageBuffer, offsets are segmentID * 4 + {0,1,2,3}
1431  2. read imageBuffer in geometry shader and do usual quad extrusion, now without depth testing
1432  => get hw rasterization and msaa
1433  */
1434 
1435  // using image2D does not work: texture always reads 0, even with glGetTexImage2D
1436  // imageBuffer works
1437  // - check with different gpu
1438 
1439  const int numLines = lineGL42Objects_.size();
1440 
1441  // configs
1442  const bool useBufferTexture = true; // imageBuffer or image2D
1443  const bool useIntegerTexture = true; // color as R32U or RGBA32F
1444 
1445 
1446 
1447  if (numLines)
1448  {
1449 
1450  // macro configs for shader
1451  QStringList macros;
1452 
1453  if (useBufferTexture)
1454  macros.push_back("#define IMAGE_BUFFER");
1455  if (useIntegerTexture)
1456  macros.push_back("#define FMT_UINT");
1457 
1458 
1459  // get random access write buffer
1460  // 32bit uint per viewport pixel, stores rgba8
1461  Texture2D* lineColorImg2D = 0;
1462  TextureBuffer* lineColorImgBuf = 0;
1463 
1464  GLsizei w = prevViewport_[2], h = prevViewport_[3];
1465  GLsizei lineBPP = useIntegerTexture ? 4 : 16; // bytes per pixel
1466 
1467 
1468  if (useBufferTexture)
1469  {
1470  lineColorImgBuf = dynamic_cast<TextureBuffer*>(lineColorBuffers_[curViewerID_]);
1471 
1472  if (!lineColorImgBuf)
1473  {
1474  lineColorImgBuf = new TextureBuffer(GL_TEXTURE0);
1475  lineColorBuffers_[curViewerID_] = lineColorImgBuf;
1476  }
1477 
1478  // resize
1479  if (lineColorImgBuf->getBufferSize() != w * h * lineBPP)
1480  lineColorImgBuf->setBufferData(w*h*lineBPP, 0, GL_R32UI, GL_DYNAMIC_DRAW);
1481  }
1482  else
1483  {
1484  lineColorImg2D = dynamic_cast<Texture2D*>(lineColorBuffers_[curViewerID_]);
1485 
1486  if (!lineColorImg2D)
1487  {
1488  // allocate and store in map
1489  lineColorImg2D = new Texture2D(GL_TEXTURE0);
1490  lineColorBuffers_[curViewerID_] = lineColorImg2D;
1491  }
1492 
1493  // resize
1494  if (lineColorImg2D->getWidth() != w || lineColorImg2D->getHeight() != h)
1495  lineColorImg2D->setData(0,
1496  useIntegerTexture ? GL_R32UI : GL_RGBA32F,
1497  w, h,
1498  useIntegerTexture ? GL_RED_INTEGER : GL_RGBA,
1499  useIntegerTexture ? GL_UNSIGNED_INT : GL_FLOAT,
1500  0);
1501  }
1502 
1503 
1504 
1505 
1506 
1507  glViewport(0, 0, w, h);
1508 
1509 
1510 
1511  // ---------------------------
1512  // clear line color buffer
1513 
1514  glColorMask(0,0,0,0);
1515  glDepthMask(0);
1516  glDisable(GL_DEPTH_TEST);
1517 
1518  // image binding is set to slot 0 in shader already
1519  if (useBufferTexture)
1520  lineColorImgBuf->bindAsImage(0, GL_WRITE_ONLY);
1521  else
1522  lineColorImg2D->bindAsImage(0, GL_WRITE_ONLY);
1523 
1524  GLSL::Program* shaderClear = ShaderCache::getInstance()->getProgram("ScreenQuad/screenquad.glsl", "Wireframe/gl42/clear.glsl", &macros);
1525 
1526  shaderClear->use();
1527 // shaderClear->setUniform("offset", Vec2f(0,0));
1528 // shaderClear->setUniform("size", Vec2f(1,1));
1529  shaderClear->setUniform("screenSize", Vec2f(w,h));
1530 
1531  ScreenQuad::draw(shaderClear);
1532 
1533  glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT | GL_SHADER_IMAGE_ACCESS_BARRIER_BIT);
1534 // GLDebug::dumpTexture2D(lineColorBuf->id(), 0, lineColorBuf->getFormat(), lineColorBuf->getType(), lineBPP*w*h, "c:/dbg/lines_clear.dds");
1535 // GLDebug::dumpBufferData(GL_TEXTURE_BUFFER, lineColorBuf2->getBufferId(), "c:/dbg/lines_clear.bin");
1536 
1537  // ---------------------------
1538  // 1. pass
1539  // render into line color buffer via imageStore,
1540 
1541  for (int i = 0; i < numLines; ++i)
1542  {
1543  RenderObject* obj = getLineGL42RenderObject(i);
1544 
1545  renderObject(obj);
1546  }
1547 
1548  glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT | GL_SHADER_IMAGE_ACCESS_BARRIER_BIT);
1549 // GLDebug::dumpTexture2D(lineColorBuf->id(), 0, lineColorBuf->getFormat(), lineColorBuf->getType(), lineBPP*w*h, "c:/dbg/lines_image.dds");
1550 // GLDebug::dumpBufferData(GL_TEXTURE_BUFFER, lineColorBuf2->getBufferId(), "c:/dbg/lines_image.bin");
1551 
1552 
1553  // ---------------------------
1554  // 2. pass
1555  // composition of line colors and fbo
1556 
1557  restoreInputFbo();
1558 
1559  // image binding is set to slot 0 in shader already
1560  if (useBufferTexture)
1561  lineColorImgBuf->bindAsImage(0, GL_READ_ONLY);
1562  else
1563  lineColorImg2D->bindAsImage(0, GL_READ_ONLY);
1564 
1565 
1566  glColorMask(1,1,1,1);
1567  glDisable(GL_DEPTH_TEST);
1568 
1569  // enable alpha blending
1570  glEnable(GL_BLEND);
1571  ACG::GLState::blendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1572 
1573  GLSL::Program* shaderComposite = ShaderCache::getInstance()->getProgram("ScreenQuad/screenquad.glsl", "Wireframe/gl42/composite.glsl", &macros);
1574 
1575  shaderComposite->use();
1576 // shaderComposite->setUniform("offset", Vec2f(0,0));
1577 // shaderComposite->setUniform("size", Vec2f(1,1));
1578  shaderComposite->setUniform("screenSize", Vec2f(w,h));
1579 
1580  ScreenQuad::draw(shaderComposite);
1581 
1582 
1583  }
1584 #endif
1585 }
1586 
1588 {
1589  if (Texture::supportsImageLoadStore() && Texture::supportsTextureBuffer())
1590  enableLineThicknessGL42_ = _enable;
1591 }
1592 
1594 {
1595  errorDetectionLevel_ = std::max(_level, 0); // clamp to [0,n]
1596 }
1597 
1599 {
1600  return errorDetectionLevel_;
1601 }
1602 
1603 } // namespace ACG end
1604 
const VertexElement * findElementByUsage(VERTEX_USAGE _usage) const
VectorT< float, 2 > Vec2f
Definition: VectorT.hh:108
Vec3f diffuse
material definitions
StatusMode status() const
Get node&#39;s status.
Definition: BaseNode.hh:432
void specularColor(const Vec4f &_s)
set the specular color
static void draw(GLSL::Program *_prog=0)
Draw the screen quad.
Definition: ScreenQuad.cc:147
void transpose()
transpose matrix
Definition: Matrix4x4T.cc:272
QString toString() const
convert ShaderGenDesc to string format for debugging
std::vector< BaseNode * >::iterator ChildIter
allows to iterate over children
Definition: BaseNode.hh:317
void activateShaderPipeline(GLSL::Program *_prog) const
DrawMode DEFAULT
use the default (global) draw mode and not the node&#39;s own.
Definition: DrawModes.cc:78
virtual void bindObjectVBO(ACG::RenderObject *_obj, GLSL::Program *_prog)
Binding VBOs (First state function)
Definition: IRenderer.cc:807
static ShaderCache * getInstance()
Return instance of the ShaderCache singleton.
Definition: ShaderCache.cc:90
ACG::SceneGraph::Material & material()
Get material object reference.
bool bind()
bind the fbo and sets it as rendertarget
Definition: FBO.cc:451
GLenum primitiveMode
Primitive type.
virtual void sortRenderObjects()
Sort the renderobjects by priority.
Definition: IRenderer.cc:799
bool isDefaultLineObject() const
Test if the object is rendered with one of the default line thickness methods.
virtual void collectRenderObjects(ACG::GLState *_glState, ACG::SceneGraph::DrawModes::DrawMode _drawMode, ACG::SceneGraph::BaseNode *_sceneGraphRoot)
Traverse the scenegraph to collect render information.
Definition: IRenderer.cc:402
Hide this node and its children.
Definition: BaseNode.hh:429
int priority
Priority to allow sorting of objects.
virtual void renderObject(ACG::RenderObject *_obj, GLSL::Program *_prog=0, bool _constRenderStates=false, const std::vector< unsigned int > *_shaderModifiers=0)
Render one renderobject.
Definition: IRenderer.cc:1053
unsigned int internalFlags_
may be used internally by the renderer
GLuint indexBuffer
Use vertex array object.
const VertexDeclaration * vertexDecl
Defines the vertex buffer layout, ignored if VAO is provided.
void setUniformMat3(const char *_name, const ACG::GLMatrixf &_value, bool _transposed=false)
Set 3x3fMatrix uniform to specified value.
Definition: GLSLShader.cc:669
const void * sysmemIndexBuffer
Use system memory index buffer.
Interface for modifying render objects.
virtual void saveActiveFbo(GLint *_outFboId, GLint *_outViewport, GLint *_outDrawBuffer) const
Save active Fbo configuration (fbo id + viewport)
Definition: IRenderer.cc:754
GLSL::PtrProgram loadProgram(const char *vertexShaderFile, const char *tessControlShaderFile, const char *tessEvaluationShaderFile, const char *geometryShaderFile, const char *fragmentShaderFile, const GLSL::StringList *macros, bool verbose)
Definition: GLSLShader.cc:1082
void traverseRenderableNodes(ACG::GLState *_glState, ACG::SceneGraph::DrawModes::DrawMode _drawMode, ACG::SceneGraph::BaseNode &_node, const ACG::SceneGraph::Material &_mat)
Scene graph traversal for render object collection.
Definition: IRenderer.cc:447
void baseColor(const Vec4f &_c)
set the base color
GLuint vertexArrayObject
Use vertex array object.
void attachTexture2D(GLenum _attachment, GLsizei _width, GLsizei _height, GLuint _internalFmt, GLenum _format, GLint _wrapMode=GL_CLAMP, GLint _minFilter=GL_NEAREST, GLint _magFilter=GL_NEAREST)
function to attach a texture to fbo
Definition: FBO.cc:200
int viewport_width() const
get viewport width
Definition: GLState.hh:825
GLenum indexType
Index element type.
ACG::RenderObject * getRenderObject(int i)
Get render objects in the sorted list by index (not including overlay objects)
Definition: IRenderer.cc:1135
Definition: FBO.hh:83
void bind(PtrProgram _prog) const
Send all stored uniforms to program.
Definition: UniformPool.cc:103
const QStringList & getFragmentShaderCode()
Returns generated fragment shader code.
virtual void drawObject(ACG::RenderObject *_obj)
Executes the opengl draw call for one object (Fourth function)
Definition: IRenderer.cc:996
unsigned int patchVertices
patch size if primitiveMode is GL_PATCHES for rendering with tessellation shaders ...
void use()
Enables the program object for using.
Definition: GLSLShader.cc:351
static int maxClipDistances_
max number of clip distance outputs in a vertex shader
Definition: IRenderer.hh:552
virtual void copyDepthToBackBuffer(GLuint _depthTex, float _scale=1.0f)
Copy texture to depth buffer.
Definition: IRenderer.cc:1249
int getNumLights() const
Get the number of current light sources.
Definition: IRenderer.cc:1129
bool hasGeometryShader() const
check whether there is a geometry shader present
Draw this node, but hide children.
Definition: BaseNode.hh:427
unsigned int numIndices
Number indices to render.
GLMatrixd modelview
Modelview transform.
void ambientColor(const Vec4f &_a)
set the ambient color.
GLenum blendDest
glBlendFunc: GL_SRC_ALPHA, GL_ZERO, GL_ONE, GL_ONE_MINUS_SRC_ALPHA ...
VectorT< float, 3 > Vec3f
Definition: VectorT.hh:125
Texture to be used.
virtual void removeRenderObjectModifier(RenderObjectModifier *_mod)
Callback for the scenegraph nodes, which removes a render object modifier from the renderer...
Definition: IRenderer.cc:1116
unsigned int indexOffset
Offset to first index in the index buffer or vertex buffer respectively.
bool empty() const
returns if the pool is empty
Definition: UniformPool.cc:95
virtual void addRenderObject(RenderObject *_renderObject)
Callback for the scenegraph nodes, which send new render objects via this function.
Definition: IRenderer.cc:108
void addDepthBuffer(GLuint _width, GLuint _height)
function to add a depth renderbuffer to the fbo
Definition: FBO.cc:343
void diffuseColor(const Vec4f &_d)
set the diffuse color.
Hide this node, but draw children.
Definition: BaseNode.hh:425
void setUniform(const char *_name, GLint _value)
Set int uniform to specified value.
Definition: GLSLShader.cc:391
const QStringList & getGeometryShaderCode()
Returns generated tessellation evaluation shader code.
int getNumRenderObjects() const
Get the number of collected render objects (not including overlay objects or gl4.2 line objects) ...
Definition: IRenderer.cc:1125
std::string name
Name for logging.
void dumpRenderObjectsToFile(const char *_fileName, ACG::RenderObject **_sortedList=0) const
Debugging function to dump list of render objects into a file.
Definition: IRenderer.cc:1165
const QStringList & getVertexShaderCode()
Returns generated vertex shader code.
bool hasTessControlShader() const
check whether there is a tess-control shader present
virtual void restoreFbo(GLint _fboId, const GLint *_outViewport, GLint _drawBuffer) const
Restore a previously saved input Fbo configuration (fbo id + viewport)
Definition: IRenderer.cc:762
ACG::RenderObject * getLineGL42RenderObject(int i)
Get render objects in the sorted list by index (only line objects rendered with gl4.2)
Definition: IRenderer.cc:1151
Namespace providing different geometric functions concerning angles.
Definition: DBSCANT.cc:51
void deactivateShaderPipeline(GLSL::Program *_prog) const
void setViewerID(int _viewerID)
Set currently active viewer id.
Definition: IRenderer.cc:1412
void resize(GLsizei _width, GLsizei _height, bool _forceResize=false)
resize function (if textures created by this class)
Definition: FBO.cc:543
const QStringList & getTessEvaluationShaderCode()
Returns generated tessellation control shader code.
int getErrorDetectionLevel() const
Get error detection level.
Definition: IRenderer.cc:1598
virtual void renderDepthMap(int _viewerID, int _width, int _height)
Render the depth map of the scene.
Definition: IRenderer.cc:1324
GLSL::Program * getProgram(const ShaderGenDesc *_desc, const std::vector< unsigned int > &_mods)
Query a dynamically generated program from cache.
Definition: ShaderCache.cc:108
auto normalize() -> decltype(*this/=std::declval< VectorT< S, DIM >>().norm())
Definition: Vector11T.hh:428
LightData * getLight(int i)
Get light by index.
Definition: IRenderer.cc:1159
virtual void addLight(const LightData &_light)
Callback for the scenegraph nodes, which send new lights to the renderer via this function...
Definition: IRenderer.cc:1097
bool invert()
matrix inversion (returns true on success)
Definition: Matrix4x4T.cc:297
GLenum depthFunc
GL_LESS, GL_LEQUAL, GL_GREATER ..
void setErrorDetectionLevel(int _level)
Control error detection for checking render objects.
Definition: IRenderer.cc:1593
Draw node in second pass.
Definition: BaseNode.hh:476
virtual void bindObjectUniforms(ACG::RenderObject *_obj, GLSL::Program *_prog)
Binding Uniforms (Second state function)
Definition: IRenderer.cc:834
void setLineThicknessRenderingGL42(bool _enable)
Definition: IRenderer.cc:1587
ACG::RenderObject * getOverlayRenderObject(int i)
Get render objects in the sorted list by index (only overlay objects)
Definition: IRenderer.cc:1143
const QStringList & getTessControlShaderCode()
Returns generated vertex shader code.
const char * depthMapUniformName
Uniform name of the depth map in the used shader.
void shininess(float _s)
set shininess
GLenum alphaFunc
GL_LESS, GL_LEQUAL, GL_GREATER ..
bool hasTessEvaluationShader() const
check whether there is a tess-evaluation shader present
const GLMatrixd & modelview() const
get modelview matrix
Definition: GLState.hh:794
Scalar max() const
return the maximal component
Definition: Vector11T.hh:492
virtual void finishRenderingPipeline(bool _drawOverlay=true)
Draw overlay objects and reset OpenGL state.
Definition: IRenderer.cc:634
virtual void addRenderObjectModifier(RenderObjectModifier *_mod)
Callback for the scenegraph nodes, which adds a render object modifier to the renderer via this funct...
Definition: IRenderer.cc:1111
bool inZPrePass
Specify whether this object should be rendered in a z-prepass.
void modifyFragmentEndCode(QStringList *_code)
Append code the the fragment shader.
Definition: IRenderer.cc:1319
virtual void clearInputFbo(const ACG::Vec4f &_clearColor)
Clear input Fbo.
Definition: IRenderer.cc:769
virtual void saveInputFbo()
Save input Fbo configuration (fbo id + viewport)
Definition: IRenderer.cc:741
virtual void prepareRenderingPipeline(ACG::GLState *_glState, ACG::SceneGraph::DrawModes::DrawMode _drawMode, ACG::SceneGraph::BaseNode *_scenegraphRoot)
Prepares renderer and OpenGL for any draw-related calls including.
Definition: IRenderer.cc:522
int viewport_height() const
get viewport height
Definition: GLState.hh:827
void unbind()
unbind fbo, go to normal rendering mode
Definition: FBO.cc:474
GLMatrixd proj
Projection transform.
Interface class between scenegraph and renderer.
QString toString() const
static unsigned int registerModifier(ShaderModifier *_modifier)
Shader modifiers have to be registered before they can be used. They also must remain allocated for t...
bool isDefaultPointObject() const
Test if the object is rendered with one of the default point extension methods.
GLuint getProgramId()
Returns opengl id.
Definition: GLSLShader.cc:382
GLuint vertexBuffer
VBO, IBO ids, ignored if VAO is provided.
ShaderGenDesc shaderDesc
Drawmode and other shader params.
GLSL program class.
Definition: GLSLShader.hh:217
virtual void bindObjectRenderStates(ACG::RenderObject *_obj)
Binding Render state (Third state function)
Definition: IRenderer.cc:943
virtual QString dumpCurrentRenderObjectsToString(ACG::RenderObject **_list=0, bool _outputShaders=false, std::vector< ACG::ShaderModifier * > *_modifiers=0)
Outputs the current render objects to the string.
Definition: IRenderer.cc:1184
Scalar * data()
access to Scalar array
Definition: Vector11T.hh:193
Vec2f depthRange
glDepthRange: (znear, zmax)
virtual void restoreInputFbo()
Restore the previously saved input Fbo configuration (fbo id + viewport)
Definition: IRenderer.cc:748
void glCheckErrors()
Definition: GLError.hh:105
static void blendFunc(GLenum _sfactor, GLenum _dfactor)
replaces glBlendFunc, supports locking
Definition: GLState.hh:314