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#include <ACG/GL/acg_glew.hh>
45#include <cstdio>
46#include <cstring>
47#include <iostream>
48#include <algorithm>
49#include <QFile>
50#include <QTextStream>
51
52#include <ACG/GL/gl.hh>
53
54#include <ACG/GL/IRenderer.hh>
55
56#include <ACG/GL/VertexDeclaration.hh>
57#include <ACG/GL/GLError.hh>
58
59#include <ACG/GL/ShaderCache.hh>
60#include <ACG/GL/ScreenQuad.hh>
61#include <ACG/GL/FBO.hh>
62#include <ACG/GL/globjects.hh>
63
64
65
66namespace ACG
67{
68
70
71IRenderer::IRenderer()
72: numLights_(0),
73renderObjects_(0),
74depthMapUsed_(false),
75curViewerID_(0),
76prevFbo_(0),
77prevDrawBuffer_(GL_BACK),
78prevFboSaved_(false),
79prevVAO_(0),
80depthCopyShader_(0),
81errorDetectionLevel_(1),
82coreProfile_(false),
83enableLineThicknessGL42_(false)
84{
85 prevViewport_[0] = 0;
86 prevViewport_[1] = 0;
87 prevViewport_[2] = 0;
88 prevViewport_[3] = 0;
89
90 // set global ambient scale to default OpenGL value
91 globalLightModelAmbient_ = ACG::Vec3f(0.2f, 0.2f, 0.2f);
92}
93
94
95IRenderer::~IRenderer()
96{
97 delete depthCopyShader_;
98
99 // free depth map fbos
100 for (std::map<int, ACG::FBO*>::iterator it = depthMaps_.begin(); it != depthMaps_.end(); ++it)
101 delete it->second;
102}
103
104void IRenderer::addRenderObject(ACG::RenderObject* _renderObject)
105{
106 // avoid null-ptr access
107 if (_renderObject->debugName.empty())
108 _renderObject->debugName = "<unnamed>";
109
110 if (_renderObject->name.empty())
111 _renderObject->name = _renderObject->debugName;
112
113 // do some more checks for error detection
114 if (!_renderObject->vertexDecl && !_renderObject->vertexArrayObject)
115 std::cout << "error: missing vertex declaration in renderobject: " << _renderObject->debugName << std::endl;
116 else
117 {
118 if (errorDetectionLevel_ > 0)
119 {
120 // commonly encountered rendering errors
121
122 if (!_renderObject->numIndices)
123 std::cout << "warning: numIndices is 0 in renderobject: " << _renderObject->debugName << std::endl;
124
125 // Why is my object invisible/black?
126 if (!_renderObject->depthWrite &&
127 !_renderObject->colorWriteMask[0] && !_renderObject->colorWriteMask[1] &&
128 !_renderObject->colorWriteMask[2] && !_renderObject->colorWriteMask[3])
129 std::cout << "warning: depth write and color write disabled in renderobject: " << _renderObject->debugName << std::endl;
130
131 // Why is gl_PointSize not working in shader?
132#ifndef GL_PROGRAM_POINT_SIZE
133 if (_renderObject->programPointSize)
134 std::cout << "warning: GL_PROGRAM_POINT_SIZE requested but missing in opengl headers!" << std::endl;
135#endif
136
137 if (errorDetectionLevel_ > 1 && _renderObject->shaderDesc.shadeMode == SG_SHADE_UNLIT)
138 {
139 if (_renderObject->emissive.max() < 1e-3f)
140 std::cout << "warning: unlit object rendered with black emissive color: " << _renderObject->debugName << std::endl;
141 else
142 {
143 // rendering with clear color
144
145 float clearColor[4];
146 glGetFloatv(GL_COLOR_CLEAR_VALUE, clearColor);
147
148 if (checkEpsilon(clearColor[0] - _renderObject->emissive[0]) &&
149 checkEpsilon(clearColor[1] - _renderObject->emissive[1]) &&
150 checkEpsilon(clearColor[2] - _renderObject->emissive[2]))
151 {
152 std::cout << "warning: unlit object rendered with clear color as emissive color: " << _renderObject->debugName << std::endl;
153 std::cout << " Should this be intentional, disable color writing instead via obj->glColorMask(0,0,0,0)" << std::endl;
154 }
155 }
156 }
157
158 if (_renderObject->textures().size())
159 {
160 // Why are my textures sampled as black?
161
162 // mipmap enabled, but no mipmap chain provided?
163
164 for (std::map<size_t,RenderObject::Texture>::const_iterator it = _renderObject->textures().begin();
165 it != _renderObject->textures().end(); ++it)
166 {
167 if (it->second.type == GL_TEXTURE_BUFFER)
168 continue; // skip texture buffers, for which testing for mipmaps would generate an error
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
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
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
402void IRenderer::collectRenderObjects( ACG::GLState* _glState, ACG::SceneGraph::DrawModes::DrawMode _drawMode, ACG::SceneGraph::BaseNode* _sceneGraphRoot )
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
432namespace {
433class 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
447void IRenderer::traverseRenderableNodes( ACG::GLState* _glState, ACG::SceneGraph::DrawModes::DrawMode _drawMode, ACG::SceneGraph::BaseNode &_node, const ACG::SceneGraph::Material &_mat )
448{
449 renderObjectSource_.clear();
450 overlayObjectSource_.clear();
451
453 return;
454
455 std::vector<ScenegraphTraversalStackEl> stack;
456 // That's roughly the minimum size every scenegraph requries.
457 stack.reserve(32);
458 stack.push_back(ScenegraphTraversalStackEl(&_node, &_mat));
459 while (!stack.empty()) {
460 ScenegraphTraversalStackEl &cur = stack.back();
461 auto cur_idx = stack.size() - 1;
462 ACG::SceneGraph::DrawModes::DrawMode nodeDM = cur.node->drawMode();
464 nodeDM = _drawMode;
465
466 if (!cur.leave) {
467 /*
468 * Stuff that happens before processing cur.node's children.
469 */
470 if ( cur.node->status() != ACG::SceneGraph::BaseNode::HideNode )
471 cur.node->enter(this, *_glState, nodeDM);
472
473 cur.subtree_index_start = renderObjects_.size();
474
475 // fetch material (Node itself can be a material node, so we have to
476 // set that in front of the nodes own rendering
478 dynamic_cast<ACG::SceneGraph::MaterialNode*>(cur.node);
479 if (matNode)
480 cur.material = &matNode->material();
481
482 if (cur.node->status() != ACG::SceneGraph::BaseNode::HideNode)
483 cur.node->getRenderObjects(this, *_glState, nodeDM, cur.material);
484
485 // keep track of which node added objects
486 size_t numAddedObjects = renderObjects_.size() - renderObjectSource_.size();
487 renderObjectSource_.insert(renderObjectSource_.end(), numAddedObjects, cur.node);
488
489 auto cur_mat = cur.material; // make a copy so we can avoid use-after-free on stack.push_back
490 // Process children?
491 if (cur.node->status() != ACG::SceneGraph::BaseNode::HideChildren) {
492 // Process all children which are second pass
494 cIt = cur.node->childrenBegin(),
495 cEnd = cur.node->childrenEnd(); cIt != cEnd; ++cIt) {
496 if (((*cIt)->traverseMode() &
498 (*cIt)->status() != ACG::SceneGraph::BaseNode::HideSubtree)
499 stack.emplace_back(*cIt, cur_mat);
500 }
501
502 // Process all children which are not second pass
504 cIt = cur.node->childrenBegin(),
505 cEnd = cur.node->childrenEnd(); cIt != cEnd; ++cIt) {
506 if ((~(*cIt)->traverseMode() &
508 (*cIt)->status() != ACG::SceneGraph::BaseNode::HideSubtree)
509 stack.emplace_back(*cIt, cur_mat);
510 }
511 }
512
513 // Next time process the other branch of this if statement.
514 // 'cur' is now invalidated due to push_back, access via stack
515 stack[cur_idx].leave = true;
516
517 } else {
518 /*
519 * Stuff that happens after processing cur.node's children.
520 */
521 current_subtree_objects_ = RenderObjectRange(
522 renderObjects_.begin() + cur.subtree_index_start,
523 renderObjects_.end());
524
525 if (cur.node->status() != ACG::SceneGraph::BaseNode::HideNode )
526 cur.node->leave(this, *_glState, nodeDM);
527 stack.pop_back();
528 }
529 }
530}
531
532void IRenderer::prepareRenderingPipeline(ACG::GLState* _glState, ACG::SceneGraph::DrawModes::DrawMode _drawMode, ACG::SceneGraph::BaseNode* _scenegraphRoot)
533{
534 // save default VAO
535#ifdef GL_ARB_vertex_array_object
536 glGetIntegerv(GL_VERTEX_ARRAY_BINDING, &prevVAO_);
537#endif
538
539 coreProfile_ = !_glState->compatibilityProfile();
540
541 // grab view transform from glstate
542 viewMatrix_ = _glState->modelview();
543 camPosWS_ = Vec3f( viewMatrix_(0,3), viewMatrix_(1,3), viewMatrix_(2,3) );
544 camDirWS_ = Vec3f( viewMatrix_(0,2), viewMatrix_(1,2), -viewMatrix_(2,2) ); // mind the z flip
545
546// printf("pos: %f %f %f\ndir: %f %f %f\n", camPosWS_[0], camPosWS_[1], camPosWS_[2],
547// camDirWS_[0], camDirWS_[1], camDirWS_[2]);
548
549 // First, all render objects get collected.
550 collectRenderObjects(_glState, _drawMode, _scenegraphRoot);
551
552 // ==========================================================
553 // Sort renderable objects based on their priority
554 // Filter for overlay, lines etc.
555 // ==========================================================
556
557 size_t numRenderObjects = 0,
558 numOverlayObjects = 0,
559 numLineObjects = 0;
560
561 for (std::vector<ACG::RenderObject>::const_iterator it = renderObjects_.begin();
562 it != renderObjects_.end(); ++it) {
563 if (!it->overlay && !(it->isDefaultLineObject() && enableLineThicknessGL42_))
564 numRenderObjects++;
565 if (it->overlay)
566 numOverlayObjects++;
567 if (enableLineThicknessGL42_ && it->isDefaultLineObject())
568 numLineObjects++;
569 }
570
571 /*
572 * Neither clear() nor resize() ever decreases the capacity of
573 * a vector. So it has no adverse impact on performance to clear
574 * the vectors here.
575 */
576 sortedObjects_.clear();
577 sortedObjects_.reserve(numRenderObjects);
578
579 overlayObjects_.clear();
580 overlayObjects_.reserve(numOverlayObjects);
581
582 lineGL42Objects_.clear();
583 lineGL42Objects_.reserve(numLineObjects);
584
585
586 sortListObjects_.clear();
587 sortListObjects_.reserve(numRenderObjects);
588
589 sortListOverlays_.clear();
590 sortListOverlays_.reserve(numOverlayObjects);
591
592 // init sorted objects array
593 for (size_t i = 0; i < renderObjects_.size(); ++i)
594 {
595 if (renderObjects_[i].overlay)
596 {
597 overlayObjects_.push_back(&renderObjects_[i]);
598 sortListOverlays_.push_back(i);
599 }
600 else if (enableLineThicknessGL42_ && numLineObjects && renderObjects_[i].isDefaultLineObject())
601 {
602 renderObjects_[i].shaderDesc.geometryTemplateFile = "Wireframe/gl42/geometry.tpl";
603 renderObjects_[i].shaderDesc.fragmentTemplateFile = "Wireframe/gl42/fragment.tpl";
604
605 // disable color write to fbo, but allow RenderObject to control depth write
606 renderObjects_[i].glColorMask(0,0,0,0);
607
608// sortedObjects_[sceneObjectOffset++] = &renderObjects_[i];
609 lineGL42Objects_.push_back(&renderObjects_[i]);
610 }
611 else
612 {
613 sortedObjects_.push_back(&renderObjects_[i]);
614 sortListObjects_.push_back(i);
615 }
616 }
617
618 sortRenderObjects();
619
620
621 // ---------------------------
622 // Initialize the render state
623 // ---------------------------
624 // gl cleanup
625
626 if (_glState->compatibilityProfile())
627 {
628 glDisableClientState(GL_VERTEX_ARRAY);
629 glDisableClientState(GL_COLOR_ARRAY);
630 glDisableClientState(GL_NORMAL_ARRAY);
631 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
632 glDisableClientState(GL_INDEX_ARRAY);
633 }
634
635 glEnable(GL_CULL_FACE);
636 glEnable(GL_DEPTH_TEST);
637 glDepthFunc(GL_LESS);
638 glDepthMask(GL_TRUE);
639
640 // save active fbo and viewport
641 saveInputFbo();
642
643if(_glState->compatibilityProfile())
644{
645 // get global ambient factor
646 GLfloat lightModelAmbient[4];
647 glGetFloatv(GL_LIGHT_MODEL_AMBIENT, lightModelAmbient);
648 globalLightModelAmbient_ = ACG::Vec3f(lightModelAmbient[0], lightModelAmbient[1], lightModelAmbient[2]);
649}
650
651 // search list of render object for objects requiring the scene depth map
652 bool requiresSceneDepths = false;
653
654 for (size_t i = 0; i < renderObjects_.size(); ++i)
655 {
656 if (renderObjects_[i].depthMapUniformName)
657 requiresSceneDepths = true;
658 }
659
660 // render scene depth map
661 if (requiresSceneDepths)
662 renderDepthMap(curViewerID_, _glState->viewport_width(), _glState->viewport_height());
663}
664
665
666
667void IRenderer::finishRenderingPipeline(bool _drawOverlay)
668{
669#ifdef GL_ARB_vertex_array_object
670 glBindVertexArray(prevVAO_);
671#endif
672
673 // draw thick lines
674 if (enableLineThicknessGL42_)
675 renderLineThicknessGL42();
676
677 if (_drawOverlay)
678 {
679 const int numOverlayObj = overlayObjects_.size();
680 // two-pass overlay rendering:
681 // 1. clear depth buffer at pixels of overlay objects
682 // 2. render overlay with correct depth-testing
683
684 // 1. pass: clear depth to max value at overlay footprint
685 for (int i = 0; i < numOverlayObj; ++i)
686 {
687 RenderObject* obj = getOverlayRenderObject(i);
688
689 if (obj->depthTest && obj->depthFunc != GL_ALWAYS)
690 {
691 float depthMax = 1.0f;
692
693 if (obj->depthFunc == GL_GREATER || obj->depthFunc == GL_GEQUAL)
694 depthMax = 0.0f;
695
696 // save depth setting of renderobject
697 Vec2f depthRange = obj->depthRange;
698 bool depthWrite = obj->depthWrite;
699 GLenum depthFunc = obj->depthFunc;
700
701 // reset depth to maximal distance by using depth range
702 obj->depthRange = Vec2f(depthMax, depthMax);
703 obj->depthWrite = true;
704 obj->depthFunc = GL_ALWAYS;
705
706 renderObject(obj);
707
708 // restore depth setting
709 obj->depthRange = depthRange;
710 obj->depthWrite = depthWrite;
711 obj->depthFunc = depthFunc;
712 }
713
714 }
715
716 // 2. render overlay with correct depth-testing
717 for (int i = 0; i < numOverlayObj; ++i)
718 {
719 RenderObject* obj = getOverlayRenderObject(i);
720 renderObject(obj);
721 }
722
723 }
724
725#ifdef GL_ARB_vertex_array_object
726 glBindVertexArray(prevVAO_);
727#endif
728
729 for (int i = 0; i < maxClipDistances_; ++i)
730 glDisable(GL_CLIP_DISTANCE0 + i);
731
732 glDisable(GL_PROGRAM_POINT_SIZE);
733
734 glDepthMask(1);
735 glColorMask(1,1,1,1);
736
737 glUseProgram(0);
738
739 glBindBuffer(GL_ARRAY_BUFFER, 0);
740 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
741
742 // Renderer check:
743 // Print a warning if the currently active fbo / viewport is not the same as the saved fbo.
744 // Restore to previous fbo and viewport if not done already.
745
746 GLint curFbo;
747 GLint curViewport[4];
748 GLint curDrawBuf;
749 glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &curFbo);
750 glGetIntegerv(GL_VIEWPORT, curViewport);
751 glGetIntegerv(GL_DRAW_BUFFER, &curDrawBuf);
752
753 if (curFbo != prevFbo_)
754 {
755 std::cout << "warning: input and output fbo are not the same in renderer implementation" << std::endl;
756 restoreInputFbo();
757 }
758
759 if (curDrawBuf != prevDrawBuffer_)
760 {
761 std::cout << "warning: input and output draw-buffer are not the same in renderer implementation" << std::endl;
762 restoreInputFbo();
763 }
764
765 if (curViewport[0] != prevViewport_[0] ||
766 curViewport[1] != prevViewport_[1] ||
767 curViewport[2] != prevViewport_[2] ||
768 curViewport[3] != prevViewport_[3])
769 {
770 std::cout << "warning: input and output viewport are not the same in renderer implementation" << std::endl;
771 restoreInputFbo();
772 }
773}
774
775
776void IRenderer::saveInputFbo()
777{
778 // save active fbo
779 saveActiveFbo(&prevFbo_, prevViewport_, &prevDrawBuffer_);
780 prevFboSaved_ = true;
781}
782
783void IRenderer::restoreInputFbo()
784{
785 if (prevFboSaved_)
786 restoreFbo(prevFbo_, prevViewport_, prevDrawBuffer_);
787}
788
789void IRenderer::saveActiveFbo( GLint* _outFboId, GLint* _outViewport, GLint* _outDrawBuffer ) const
790{
791 // save active fbo
792 glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, _outFboId);
793 glGetIntegerv(GL_VIEWPORT, _outViewport);
794 glGetIntegerv(GL_DRAW_BUFFER, _outDrawBuffer);
795}
796
797void IRenderer::restoreFbo( GLint _fboId, const GLint* _outViewport, GLint _drawBuffer ) const
798{
799 glBindFramebuffer(GL_FRAMEBUFFER, _fboId);
800 glDrawBuffer(_drawBuffer);
801 glViewport(_outViewport[0], _outViewport[1], _outViewport[2], _outViewport[3]);
802}
803
804void IRenderer::clearInputFbo( const ACG::Vec4f& clearColor )
805{
806 glClearColor(clearColor[0], clearColor[1], clearColor[2], 1.0f);
807
808 // glClear will affect the whole back buffer, not only the area in viewport.
809 // Temporarily use glScissor to only clear the viewport area in the back buffer.
810 if (!prevFboSaved_)
811 {
812 GLint oldViewport[4];
813 glGetIntegerv(GL_VIEWPORT, oldViewport);
814 glScissor(oldViewport[0], oldViewport[1], oldViewport[2], oldViewport[3]);
815 }
816 else
817 glScissor(prevViewport_[0], prevViewport_[1], prevViewport_[2], prevViewport_[3]);
818
819 glEnable(GL_SCISSOR_TEST);
820 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
821
822 // disable scissors again, draw calls only affect the area in glViewport anyway
823 glDisable(GL_SCISSOR_TEST);
824}
825
826namespace {
827struct RenderObjectComparator {
828 explicit RenderObjectComparator(const std::vector<ACG::RenderObject>& _vec) : vec_(_vec) {
829 }
830
831 bool operator() (int a, int b) {
832 return (vec_[a].priority < vec_[b].priority);
833 }
834
835 const std::vector<ACG::RenderObject>& vec_;
836};
837}
838
839void IRenderer::sortRenderObjects()
840{
841 size_t numObjs = sortListObjects_.size();
842 size_t numOverlays = sortListOverlays_.size();
843
844 RenderObjectComparator cmpOp(renderObjects_);
845
846 std::sort(sortListObjects_.begin(), sortListObjects_.end(), cmpOp);
847 std::sort(sortListOverlays_.begin(), sortListOverlays_.end(), cmpOp);
848
849 // apply sorting list
850 std::vector<ACG::SceneGraph::BaseNode*> temp;
851 renderObjectSource_.swap(temp);
852
853
854 renderObjectSource_.resize(numObjs, 0);
855 overlayObjectSource_.resize(numOverlays, 0);
856
857 for (size_t i = 0; i < numObjs; ++i)
858 {
859 int objID = sortListObjects_[i];
860 sortedObjects_[i] = &renderObjects_[objID];
861
862 renderObjectSource_[i] = temp[objID];
863 }
864
865 for (size_t i = 0; i < numOverlays; ++i)
866 {
867 int objID = sortListOverlays_[i];
868 overlayObjects_[i] = &renderObjects_[objID];
869
870 overlayObjectSource_[i] = temp[objID];
871 }
872}
873
874
875
876void IRenderer::bindObjectVBO(ACG::RenderObject* _obj,
877 GLSL::Program* _prog)
878{
879 _prog->use();
880
881
882#ifdef GL_ARB_vertex_array_object
883 if (_obj->vertexArrayObject)
884 glBindVertexArray(_obj->vertexArrayObject);
885#endif
886
887 if (!_obj->vertexArrayObject)
888 {
890 // NOTE:
891 // always bind buffers before glVertexAttribPointer calls!!
892 // freeze in glDrawElements guaranteed (with no error message whatsoever)
893 glBindBuffer(GL_ARRAY_BUFFER, _obj->vertexBuffer);
894 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _obj->indexBuffer);
895
896
897 // activate vertex declaration
899
900 }
901}
902
903
904void IRenderer::bindObjectUniforms( ACG::RenderObject* _obj, GLSL::Program* _prog )
905{
906 // transforms
907 ACG::GLMatrixf mvp = _obj->proj * _obj->modelview;
908 ACG::GLMatrixf mvIT = _obj->modelview;
909 mvIT.invert();
910 mvIT.transpose();
911
912 _prog->setUniform("g_mWVP", mvp);
913 _prog->setUniform("g_mWV", _obj->modelview);
914 _prog->setUniformMat3("g_mWVIT", mvIT);
915 _prog->setUniform("g_mP", _obj->proj);
916
917 _prog->setUniform("g_vCamPos", camPosWS_);
918 _prog->setUniform("g_vCamDir", camDirWS_);
919
920 // material
921
922 _prog->setUniform("g_cEmissive", _obj->emissive);
923
924 _prog->setUniform("g_cDiffuse", _obj->diffuse);
925 _prog->setUniform("g_cAmbient", _obj->ambient);
926 _prog->setUniform("g_cSpecular", _obj->specular);
927
928
929 float alphaRef = 0.f;
930 if (_obj->alphaTest && _obj->alphaFunc == GL_GREATER) {
931 alphaRef = _obj->alphaRef;
932 }
933 ACG::Vec4f materialParams(_obj->shininess, _obj->alpha, alphaRef, 0.0f);
934 _prog->setUniform("g_vMaterial", materialParams);
935
936 _prog->setUniform("g_cLightModelAmbient", globalLightModelAmbient_);
937
938 // Additional Uniforms defined in the render Object
939 if ( !_obj->uniformPool_.empty() )
940 _obj->uniformPool_.bind(_prog);
941
942 // textures:
943
944 // maybe consider using bindless textures some time in the future
945 // to get rid of the old and problematic glActiveTexture(), glBindTexture() state machine usage:
946 // https://www.opengl.org/registry/specs/ARB/bindless_texture.txt
947
948 int maxTextureStage = 0;
949 for (std::map<size_t,RenderObject::Texture>::const_iterator iter = _obj->textures().begin();
950 iter != _obj->textures().end();++iter)
951 {
952 //check for valid texture id
953 const size_t texture_stage = iter->first;
954 const RenderObject::Texture tex = iter->second;
955 if (!tex.id)
956 continue;
957
958 glActiveTexture(GL_TEXTURE0 + (GLenum)texture_stage);
959 glBindTexture(iter->second.type, tex.id);
960 _prog->setUniform(QString("g_Texture%1").arg(texture_stage).toStdString().c_str(), (int)texture_stage);
961
962 maxTextureStage = std::max(maxTextureStage, (int)texture_stage);
963 }
964
965
966 // scene depth texture
967 if (_obj->depthMapUniformName)
968 {
969 // bind to (hopefully) unused texture stage
970 int depthMapSlot = maxTextureStage + 1;
971
972 _prog->setUniform(_obj->depthMapUniformName, depthMapSlot);
973 glActiveTexture(GL_TEXTURE0 + depthMapSlot);
974 glBindTexture(GL_TEXTURE_2D, depthMaps_[curViewerID_]->getAttachment(GL_COLOR_ATTACHMENT0));
975 }
976
977
978 // lights
979 for (int i = 0; i < numLights_; ++i)
980 {
981 LightData* lgt = lights_ + i;
982
983 auto idx_str = std::to_string(i);
984
985 _prog->setUniform(("g_cLightDiffuse_" + idx_str).c_str(), lgt->diffuse);
986 _prog->setUniform(("g_cLightAmbient_" + idx_str).c_str(), lgt->ambient);
987 _prog->setUniform(("g_cLightSpecular_" + idx_str).c_str(), lgt->specular);
988
989 if (lgt->ltype == ACG::SG_LIGHT_POINT || lgt->ltype == ACG::SG_LIGHT_SPOT)
990 {
991 _prog->setUniform(("g_vLightPos_" + idx_str).c_str(), lgt->pos);
992 _prog->setUniform(("g_vLightAtten_" + idx_str).c_str(), lgt->atten);
993 }
994
995 if (lgt->ltype == ACG::SG_LIGHT_DIRECTIONAL || lgt->ltype == ACG::SG_LIGHT_SPOT)
996 {
997 _prog->setUniform(("g_vLightDir_" + idx_str).c_str(), lgt->dir);
998 }
999
1000 if (lgt->ltype == ACG::SG_LIGHT_SPOT)
1001 {
1002 _prog->setUniform(("g_vLightAngleExp_" + idx_str).c_str(), lgt->spotCutoffExponent);
1003 }
1004 }
1005}
1006
1007void IRenderer::bindObjectRenderStates(ACG::RenderObject* _obj)
1008{
1009 if (_obj->culling)
1010 glEnable(GL_CULL_FACE);
1011 else
1012 glDisable(GL_CULL_FACE);
1013
1014 if (_obj->blending)
1015 glEnable(GL_BLEND);
1016 else
1017 glDisable(GL_BLEND);
1018
1019 if (!coreProfile_)
1020 {
1021 if (_obj->alphaTest)
1022 {
1023 glEnable(GL_ALPHA_TEST);
1024 glAlphaFunc(_obj->alphaFunc, _obj->alphaRef);
1025 }
1026 else
1027 glDisable(GL_ALPHA_TEST);
1028 }
1029
1030 if (_obj->depthTest)
1031 glEnable(GL_DEPTH_TEST);
1032 else
1033 glDisable(GL_DEPTH_TEST);
1034
1035
1036 glDepthMask(_obj->depthWrite ? GL_TRUE : GL_FALSE);
1037
1038 glColorMask(_obj->colorWriteMask[0], _obj->colorWriteMask[1], _obj->colorWriteMask[2], _obj->colorWriteMask[3]);
1039
1040 glDepthFunc(_obj->depthFunc);
1041
1042 glDepthRange(_obj->depthRange[0], _obj->depthRange[1]);
1043
1044 // ACG::GLState::shadeModel(_obj->shadeModel);
1045
1046 ACG::GLState::blendFunc(_obj->blendSrc, _obj->blendDest);
1047
1048 if (maxClipDistances_ < 0)
1049 {
1050 glGetIntegerv(GL_MAX_CLIP_DISTANCES, &maxClipDistances_);
1051 maxClipDistances_ = std::min(maxClipDistances_, 32); // clamp to 32 bits
1052 }
1053
1054 for (int i = 0; i < maxClipDistances_; ++i)
1055 {
1056 if (_obj->clipDistanceMask & (1 << i))
1057 glEnable(GL_CLIP_DISTANCE0 + i);
1058 else
1059 glDisable(GL_CLIP_DISTANCE0 + i);
1060 }
1061
1062#ifdef GL_PROGRAM_POINT_SIZE
1063 if (_obj->programPointSize)
1064 glEnable(GL_PROGRAM_POINT_SIZE);
1065 else
1066 glDisable(GL_PROGRAM_POINT_SIZE);
1067#endif
1068
1069 glPointSize(_obj->pointSize);
1070}
1071
1072void IRenderer::drawObject(ACG::RenderObject* _obj)
1073{
1074 if (_obj->numIndices)
1075 {
1076 // indexed drawing?
1077 bool noIndices = true;
1078 if (_obj->indexBuffer || _obj->sysmemIndexBuffer)
1079 noIndices = false;
1080
1081 glPolygonMode(GL_FRONT_AND_BACK, _obj->fillMode);
1082
1083 // tessellation info
1084 bool tessellationActive = !(_obj->shaderDesc.tessControlTemplateFile.isEmpty() && _obj->shaderDesc.tessEvaluationTemplateFile.isEmpty());
1085#ifdef GL_ARB_tessellation_shader
1086 if (tessellationActive)
1087 {
1088 glPatchParameteri(GL_PATCH_VERTICES, _obj->patchVertices);
1089
1090 if (_obj->shaderDesc.tessControlTemplateFile.isEmpty())
1091 {
1092 glPatchParameterfv(GL_PATCH_DEFAULT_INNER_LEVEL, _obj->patchDefaultInnerLevel.data());
1093 glPatchParameterfv(GL_PATCH_DEFAULT_OUTER_LEVEL, _obj->patchDefaultOuterLevel.data());
1094 }
1095 }
1096#else
1097 if (tessellationActive)
1098 std::cout << "error: tessellation shaders cannot be used with the outdated glew version" << std::endl;
1099#endif
1100
1101 if (noIndices) {
1102 if (_obj->numInstances <= 0)
1103 glDrawArrays(_obj->primitiveMode, _obj->indexOffset, _obj->numIndices);
1104 else
1105 glDrawArraysInstanced(_obj->primitiveMode, _obj->indexOffset, _obj->numIndices, _obj->numInstances);
1106 }
1107 else
1108 {
1109 // ------------------------------------------
1110 // index offset stuff not tested
1111 int indexSize = 0;
1112 switch (_obj->indexType)
1113 {
1114 case GL_UNSIGNED_INT: indexSize = 4; break;
1115 case GL_UNSIGNED_SHORT: indexSize = 2; break;
1116 default: indexSize = 1; break;
1117 }
1118
1119 if (_obj->numInstances <= 0)
1120 glDrawElements(_obj->primitiveMode, _obj->numIndices, _obj->indexType,
1121 ((const char*)_obj->sysmemIndexBuffer) + _obj->indexOffset * indexSize);
1122 else
1123 glDrawElementsInstanced(_obj->primitiveMode, _obj->numIndices, _obj->indexType,
1124 ((const char*)_obj->sysmemIndexBuffer) + _obj->indexOffset * indexSize, _obj->numInstances);
1125 }
1126 }
1127}
1128
1129void IRenderer::renderObject(ACG::RenderObject* _obj,
1130 GLSL::Program* _prog,
1131 bool _constRenderStates,
1132 const std::vector<unsigned int>* _shaderModifiers)
1133{
1134 // select shader from cache
1135 GLSL::Program* prog = _prog ? _prog : ACG::ShaderCache::getInstance()->getProgram(&_obj->shaderDesc, _shaderModifiers);
1136
1137
1138 bindObjectVBO(_obj, prog);
1139
1140 // ---------------------------------------
1141 // set shader uniforms
1142
1143 bindObjectUniforms(_obj, prog);
1144
1145 // render states
1146
1147 if (!_constRenderStates)
1148 bindObjectRenderStates(_obj);
1149
1150 // ----------------------------
1151 // OpenGL draw call
1152
1153 drawObject(_obj);
1154
1155
1157
1158 if (_obj->vertexDecl)
1159 {
1160 // deactivate vertex declaration to avoid errors
1162 }
1163
1164
1165#ifdef GL_ARB_vertex_array_object
1166 if (_obj->vertexArrayObject)
1167 glBindVertexArray(prevVAO_);
1168#endif
1169
1170}
1171
1172
1173void IRenderer::addLight(const LightData& _light)
1174{
1175 if (numLights_ < SG_MAX_SHADER_LIGHTS)
1176 {
1177 lights_[numLights_] = _light;
1178
1179 // normalize direction
1180 if (_light.ltype != SG_LIGHT_POINT)
1181 lights_[numLights_].dir.normalize();
1182
1183 ++numLights_;
1184 }
1185}
1186
1187void IRenderer::addRenderObjectModifier(RenderObjectModifier* _mod)
1188{
1189 renderObjectModifiers_.push_back(_mod);
1190}
1191
1192void IRenderer::removeRenderObjectModifier(RenderObjectModifier* _mod)
1193{
1194 for (int i = int(renderObjectModifiers_.size()) - 1; i >= 0; --i)
1195 {
1196 if (renderObjectModifiers_[i] == _mod)
1197 renderObjectModifiers_.erase(renderObjectModifiers_.begin() + i);
1198 }
1199}
1200
1201int IRenderer::getNumRenderObjects() const {
1202 return sortedObjects_.size();
1203}
1204
1205int IRenderer::getNumLights() const
1206{
1207 return numLights_;
1208}
1209
1210
1211ACG::RenderObject* IRenderer::getRenderObject( int i )
1212{
1213 if (sortedObjects_.empty())
1214 return &renderObjects_[i];
1215
1216 return sortedObjects_[i];
1217}
1218
1219ACG::RenderObject* IRenderer::getOverlayRenderObject( int i )
1220{
1221 if (overlayObjects_.empty())
1222 return &renderObjects_[i];
1223
1224 return overlayObjects_[i];
1225}
1226
1227
1228ACG::SceneGraph::BaseNode* IRenderer::getRenderObjectNode( int i )
1229{
1230 return renderObjectSource_[i];
1231}
1232
1233ACG::SceneGraph::BaseNode* IRenderer::getOverlayRenderObjectNode( int i )
1234{
1235 return overlayObjectSource_[i];
1236}
1237
1238
1239ACG::RenderObject* IRenderer::getLineGL42RenderObject( int i )
1240{
1241 if (lineGL42Objects_.empty())
1242 return 0;
1243
1244 return lineGL42Objects_[i];
1245}
1246
1247IRenderer::LightData* IRenderer::getLight( int i )
1248{
1249 return &lights_[i];
1250}
1251
1252
1253void IRenderer::dumpRenderObjectsToFile(const char* _fileName, ACG::RenderObject** _sortedList) const
1254{
1255 QFile fileOut(_fileName);
1256 if (fileOut.open(QFile::WriteOnly | QFile::Truncate))
1257 {
1258 QTextStream outStrm(&fileOut);
1259 for (int i = 0; i < getNumRenderObjects(); ++i)
1260 {
1261 if (_sortedList)
1262 outStrm << "\n" << _sortedList[i]->toString();
1263 else
1264 outStrm << "\n" << renderObjects_[i].toString();
1265 }
1266
1267 fileOut.close();
1268 }
1269}
1270
1271
1272QString IRenderer::dumpCurrentRenderObjectsToString(ACG::RenderObject** _list, bool _outputShaders, std::vector<ACG::ShaderModifier*>* _modifiers) {
1273
1274 QString objectString;
1275
1276 QTextStream outStrm(&objectString);
1277
1278 for (int i = 0; i < getNumRenderObjects(); ++i)
1279 {
1280 const RenderObject* obj = _list ? _list[i] : &renderObjects_[i];
1281
1282 if (obj) {
1283 outStrm << "\n" << obj->toString();
1284
1285 if ( _outputShaders ) {
1286
1287 outStrm << "\n";
1288
1289 outStrm << obj->shaderDesc.toString();
1290
1291 ShaderProgGenerator progGen(&(obj->shaderDesc), _modifiers);
1292
1293 outStrm << "\n---------------------vertex-shader--------------------\n\n";
1294 for (int nr = 0; nr < progGen.getVertexShaderCode().size(); ++nr)
1295 outStrm << progGen.getVertexShaderCode()[nr] << "\n";
1296 outStrm << "\n---------------------end-vertex-shader--------------------\n\n";
1297
1298 if (progGen.hasTessControlShader())
1299 {
1300 outStrm << "\n---------------------tesscontrol-shader--------------------\n\n";
1301 for (int nr = 0; nr < progGen.getTessControlShaderCode().size(); ++nr)
1302 outStrm << progGen.getTessControlShaderCode()[nr] << "\n";
1303 outStrm << "\n---------------------end-tesscontrol-shader--------------------\n\n";
1304 }
1305
1306 if (progGen.hasTessControlShader())
1307 {
1308 outStrm << "\n---------------------tesseval-shader--------------------\n\n";
1309 if (progGen.hasTessEvaluationShader())
1310 for (int nr = 0; nr < progGen.getTessEvaluationShaderCode().size(); ++nr)
1311 outStrm << progGen.getTessEvaluationShaderCode()[nr] << "\n";
1312 outStrm << "\n---------------------end-tesseval-shader--------------------\n\n";
1313 }
1314
1315 if (progGen.hasGeometryShader())
1316 {
1317 outStrm << "\n---------------------geometry-shader--------------------\n\n";
1318 for (int nr = 0; nr < progGen.getGeometryShaderCode().size(); ++nr)
1319 outStrm << progGen.getGeometryShaderCode()[nr] << "\n";
1320 outStrm << "\n---------------------end-geometry-shader--------------------\n\n";
1321 }
1322
1323
1324 outStrm << "\n---------------------fragment-shader--------------------\n\n";
1325 for (int nr = 0; nr < progGen.getFragmentShaderCode().size(); ++nr)
1326 outStrm << progGen.getFragmentShaderCode()[nr] << "\n";
1327 outStrm << "\n---------------------end-fragment-shader--------------------\n\n";
1328 }
1329
1330 }
1331
1332 }
1333
1334 return objectString;
1335}
1336
1337void IRenderer::copyDepthToBackBuffer( GLuint _depthTex, float _scale /*= 1.0f*/ )
1338{
1339 if (!_depthTex) return;
1340#ifdef __APPLE__
1341 if(ACG::openGLVersion(3,3))
1342 {
1343 if (!depthCopyShader_)
1344 depthCopyShader_ = GLSL::loadProgram("ScreenQuad/screenquad.glsl", "ScreenQuad/depth_copy_330.glsl");
1345 }
1346 else
1347#endif
1348 {
1349 if (!depthCopyShader_)
1350 depthCopyShader_ = GLSL::loadProgram("ScreenQuad/screenquad.glsl", "ScreenQuad/depth_copy.glsl");
1351 }
1352
1353 if (depthCopyShader_)
1354 {
1355 // save important opengl states
1356 GLint curFbo;
1357 GLint curViewport[4];
1358 GLint curDrawBuffer;
1359 saveActiveFbo(&curFbo, curViewport, &curDrawBuffer);
1360
1361 GLboolean colorMask[4], depthMask;
1362 glGetBooleanv(GL_COLOR_WRITEMASK, colorMask);
1363 glGetBooleanv(GL_DEPTH_WRITEMASK, &depthMask);
1364
1365 GLboolean depthTestEnable;
1366 GLint depthFunc;
1367 glGetBooleanv(GL_DEPTH_TEST, &depthTestEnable);
1368 glGetIntegerv(GL_DEPTH_FUNC, &depthFunc);
1369
1370 // write to depth buffer of input fbo
1371 restoreInputFbo();
1372
1373 depthCopyShader_->use();
1374 depthCopyShader_->setUniform("offset", ACG::Vec2f(0.0f, 0.0f));
1375 depthCopyShader_->setUniform("size", ACG::Vec2f(1.0f, 1.0f));
1376 depthCopyShader_->setUniform("DepthTex", 0); // depth tex at texture slot 0
1377 depthCopyShader_->setUniform("DepthSign", _scale);
1378
1379 // write to depth buffer only, disable writing to color buffer
1380 glColorMask(0,0,0,0);
1381 glDepthMask(1);
1382
1383 // depth test enabled + pass always
1384 glEnable(GL_DEPTH_TEST);
1385 glDepthFunc(GL_ALWAYS);
1386
1387 glActiveTexture(GL_TEXTURE0);
1388 glBindTexture(GL_TEXTURE_2D, _depthTex);
1389
1390 ACG::ScreenQuad::draw(depthCopyShader_);
1391
1392
1393 // restore important opengl states
1394
1395 restoreFbo(curFbo, curViewport, curDrawBuffer);
1396
1397 glColorMask(colorMask[0], colorMask[1], colorMask[2], colorMask[3]);
1398 glDepthMask(depthMask);
1399
1400 if (!depthTestEnable)
1401 glDisable(GL_DEPTH_TEST);
1402
1403 if (depthFunc != GL_ALWAYS)
1404 glDepthFunc(depthFunc);
1405
1406 glBindTexture(GL_TEXTURE_2D, 0);
1407 }
1408}
1409
1410
1411// depth map computation with a modifier
1412
1413IRenderer::DepthMapPass IRenderer::DepthMapPass::instance;
1414
1415void IRenderer::DepthMapPass::modifyFragmentEndCode(QStringList* _code)
1416{
1417 _code->push_back("outFragment = gl_FragCoord.zzzz;");
1418}
1419
1420void IRenderer::renderDepthMap(int _viewerID, int _width, int _height)
1421{
1422 ACG::FBO* fbo = depthMaps_[_viewerID];
1423
1424 // setup fbo for depth map
1425 if (!fbo)
1426 {
1427 fbo = depthMaps_[_viewerID] = new ACG::FBO();
1428
1429 fbo->bind();
1430 fbo->attachTexture2D(GL_COLOR_ATTACHMENT0, _width, _height, GL_R32F, GL_RED);
1431 fbo->addDepthBuffer(_width, _height);
1432 }
1433 else
1434 {
1435 fbo->bind();
1436 fbo->resize(_width, _height);
1437 }
1438
1439 // make sure modifier is registered
1440 ACG::ShaderProgGenerator::registerModifier(&DepthMapPass::instance);
1441
1442 /* note:
1443 It is possible to directly read the depth buffer if it was attached as a texture.
1444 Then, we would disable the color write mask and just write to the depth buffer in this function.
1445
1446 However, doing this has shown that the actual depth values written to the depth buffer highly depend on the gpu driver.
1447 Or, at least sampling from a texture with format GL_DEPTH_COMPONENT returns driver dependent values.
1448 For instance, in the amd-gl driver sampling the depth texture returns the value of gl_FragDepth (as expected).
1449 But in the nvidia driver, sampling directly from the depth buffer returns something different!
1450
1451 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.
1452 */
1453
1454 fbo->bind();
1455 glDrawBuffer(GL_COLOR_ATTACHMENT0);
1456 glViewport(0, 0, _width, _height);
1457
1458 // set depth to max
1459 glColorMask(1,1,1,1);
1460 glDepthMask(1);
1461
1462 glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
1463 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
1464
1465 // render z-prepass
1466 for (int i = 0; i < getNumRenderObjects(); ++i)
1467 {
1468 RenderObject* obj = getRenderObject(i);
1469
1470 if (obj->inZPrePass)
1471 {
1472 // apply depth map modifier to get the depth pass shader
1473 GLSL::Program* depthPassShader = ShaderCache::getInstance()->getProgram(&obj->shaderDesc, DepthMapPass::instance);
1474
1475 // temporarily prevent read/write access to the same texture (the depth map)
1476 const char* depthMapUniformName = obj->depthMapUniformName;
1477 obj->depthMapUniformName = 0;
1478
1479 if (depthMapUniformName)
1480 {
1481 depthPassShader->use();
1482 depthPassShader->setUniform(depthMapUniformName, 0);
1483 glActiveTexture(GL_TEXTURE0);
1484 glBindTexture(GL_TEXTURE_2D, 0);
1485 }
1486
1487 // we are interested in the depth value only, so temporarily modify the write mask to allow writing to the red channel
1488 // (for instance, an object might not write a color value, but a depth value)
1489 const GLboolean redWriteMask = obj->colorWriteMask[0];
1490 obj->colorWriteMask[0] = obj->depthWrite;
1491
1492 renderObject(obj, depthPassShader);
1493
1494 // reset modified render object states
1495 obj->depthMapUniformName = depthMapUniformName;
1496 obj->colorWriteMask[0]= redWriteMask;
1497 }
1498 }
1499
1500 // restore input fbo state
1501
1502 fbo->unbind();
1503
1504 restoreInputFbo();
1505}
1506
1507
1508void IRenderer::setViewerID(int _viewerID)
1509{
1510 curViewerID_ = _viewerID;
1511}
1512
1513
1514void IRenderer::renderLineThicknessGL42()
1515{
1516#ifdef GL_ARB_shader_image_load_store
1517 // quad extrusion has depth clipping issue
1518 // GL4.2 method: manually rasterize thick lines into load/store texture, thereby avoiding clipping
1519
1520 // experimental technique, needs some improvements for rasterization
1521 /* possible improvement:
1522 0. init depth buffer with scene objects
1523 1. extract visible line object (startpos, endpos) into imageBuffer after depth-test in fragment shader
1524 1a. line segment id can be found via atomic counter in geometry shader
1525 1b. use imageAtomicMin/max to find start and end pixel pos of each line segment
1526 atomic ops work with uint only, thus each segment has 4 texels in the imageBuffer, offsets are segmentID * 4 + {0,1,2,3}
1527 2. read imageBuffer in geometry shader and do usual quad extrusion, now without depth testing
1528 => get hw rasterization and msaa
1529 */
1530
1531 // using image2D does not work: texture always reads 0, even with glGetTexImage2D
1532 // imageBuffer works
1533 // - check with different gpu
1534
1535 const int numLines = lineGL42Objects_.size();
1536
1537 // configs
1538 const bool useBufferTexture = true; // imageBuffer or image2D
1539 const bool useIntegerTexture = true; // color as R32U or RGBA32F
1540
1541
1542
1543 if (numLines)
1544 {
1545
1546 // macro configs for shader
1547 QStringList macros;
1548
1549 if (useBufferTexture)
1550 macros.push_back("#define IMAGE_BUFFER");
1551 if (useIntegerTexture)
1552 macros.push_back("#define FMT_UINT");
1553
1554
1555 // get random access write buffer
1556 // 32bit uint per viewport pixel, stores rgba8
1557 Texture2D* lineColorImg2D = 0;
1558 TextureBuffer* lineColorImgBuf = 0;
1559
1560 size_t w = static_cast<size_t>(prevViewport_[2]), h = static_cast<size_t>(prevViewport_[3]);
1561 size_t lineBPP = static_cast<size_t>(useIntegerTexture ? 4 : 16); // bytes per pixel
1562
1563
1564 if (useBufferTexture)
1565 {
1566 lineColorImgBuf = dynamic_cast<TextureBuffer*>(lineColorBuffers_[curViewerID_]);
1567
1568 if (!lineColorImgBuf)
1569 {
1570 lineColorImgBuf = new TextureBuffer(GL_TEXTURE0);
1571 lineColorBuffers_[curViewerID_] = lineColorImgBuf;
1572 }
1573
1574 // resize
1575 if (lineColorImgBuf->getBufferSize() != w * h * lineBPP)
1576 lineColorImgBuf->setBufferData(w*h*lineBPP, 0, GL_R32UI, GL_DYNAMIC_DRAW);
1577 }
1578 else
1579 {
1580 lineColorImg2D = dynamic_cast<Texture2D*>(lineColorBuffers_[curViewerID_]);
1581
1582 if (!lineColorImg2D)
1583 {
1584 // allocate and store in map
1585 lineColorImg2D = new Texture2D(GL_TEXTURE0);
1586 lineColorBuffers_[curViewerID_] = lineColorImg2D;
1587 }
1588
1589 // resize
1590 if (lineColorImg2D->getWidth() != static_cast<int>(w) || lineColorImg2D->getHeight() != static_cast<int>(h))
1591 lineColorImg2D->setData(0,
1592 useIntegerTexture ? GL_R32UI : GL_RGBA32F,
1593 w, h,
1594 useIntegerTexture ? GL_RED_INTEGER : GL_RGBA,
1595 useIntegerTexture ? GL_UNSIGNED_INT : GL_FLOAT,
1596 0);
1597 }
1598
1599
1600
1601
1602
1603 glViewport(0, 0, w, h);
1604
1605
1606
1607 // ---------------------------
1608 // clear line color buffer
1609
1610 glColorMask(0,0,0,0);
1611 glDepthMask(0);
1612 glDisable(GL_DEPTH_TEST);
1613
1614 // image binding is set to slot 0 in shader already
1615 if (useBufferTexture)
1616 lineColorImgBuf->bindAsImage(0, GL_WRITE_ONLY);
1617 else
1618 lineColorImg2D->bindAsImage(0, GL_WRITE_ONLY);
1619
1620 GLSL::Program* shaderClear = ShaderCache::getInstance()->getProgram("ScreenQuad/screenquad.glsl", "Wireframe/gl42/clear.glsl", &macros);
1621
1622 shaderClear->use();
1623// shaderClear->setUniform("offset", Vec2f(0,0));
1624// shaderClear->setUniform("size", Vec2f(1,1));
1625 shaderClear->setUniform("screenSize", Vec2f(w,h));
1626
1627 ScreenQuad::draw(shaderClear);
1628
1629 glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT | GL_SHADER_IMAGE_ACCESS_BARRIER_BIT);
1630// GLDebug::dumpTexture2D(lineColorBuf->id(), 0, lineColorBuf->getFormat(), lineColorBuf->getType(), lineBPP*w*h, "c:/dbg/lines_clear.dds");
1631// GLDebug::dumpBufferData(GL_TEXTURE_BUFFER, lineColorBuf2->getBufferId(), "c:/dbg/lines_clear.bin");
1632
1633 // ---------------------------
1634 // 1. pass
1635 // render into line color buffer via imageStore,
1636
1637 for (int i = 0; i < numLines; ++i)
1638 {
1639 RenderObject* obj = getLineGL42RenderObject(i);
1640
1641 renderObject(obj);
1642 }
1643
1644 glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT | GL_SHADER_IMAGE_ACCESS_BARRIER_BIT);
1645// GLDebug::dumpTexture2D(lineColorBuf->id(), 0, lineColorBuf->getFormat(), lineColorBuf->getType(), lineBPP*w*h, "c:/dbg/lines_image.dds");
1646// GLDebug::dumpBufferData(GL_TEXTURE_BUFFER, lineColorBuf2->getBufferId(), "c:/dbg/lines_image.bin");
1647
1648
1649 // ---------------------------
1650 // 2. pass
1651 // composition of line colors and fbo
1652
1653 restoreInputFbo();
1654
1655 // image binding is set to slot 0 in shader already
1656 if (useBufferTexture)
1657 lineColorImgBuf->bindAsImage(0, GL_READ_ONLY);
1658 else
1659 lineColorImg2D->bindAsImage(0, GL_READ_ONLY);
1660
1661
1662 glColorMask(1,1,1,1);
1663 glDisable(GL_DEPTH_TEST);
1664
1665 // enable alpha blending
1666 glEnable(GL_BLEND);
1667 ACG::GLState::blendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1668
1669 GLSL::Program* shaderComposite = ShaderCache::getInstance()->getProgram("ScreenQuad/screenquad.glsl", "Wireframe/gl42/composite.glsl", &macros);
1670
1671 shaderComposite->use();
1672// shaderComposite->setUniform("offset", Vec2f(0,0));
1673// shaderComposite->setUniform("size", Vec2f(1,1));
1674 shaderComposite->setUniform("screenSize", Vec2f(w,h));
1675
1676 ScreenQuad::draw(shaderComposite);
1677
1678
1679 }
1680#endif
1681}
1682
1683void IRenderer::setLineThicknessRenderingGL42( bool _enable )
1684{
1685 if (Texture::supportsImageLoadStore() && Texture::supportsTextureBuffer())
1686 enableLineThicknessGL42_ = _enable;
1687}
1688
1689void IRenderer::setErrorDetectionLevel( int _level )
1690{
1691 errorDetectionLevel_ = std::max(_level, 0); // clamp to [0,n]
1692}
1693
1694int IRenderer::getErrorDetectionLevel() const
1695{
1696 return errorDetectionLevel_;
1697}
1698
1699} // namespace ACG end
1700
Definition: FBO.hh:72
void resize(GLsizei _width, GLsizei _height, bool _forceResize=false)
resize function (if textures created by this class)
Definition: FBO.cc:550
bool bind()
bind the fbo and sets it as rendertarget
Definition: FBO.cc:458
void addDepthBuffer(GLuint _width, GLuint _height)
function to add a depth renderbuffer to the fbo
Definition: FBO.cc:350
void unbind()
unbind fbo, go to normal rendering mode
Definition: FBO.cc:481
void attachTexture2D(GLenum _attachment, GLsizei _width, GLsizei _height, GLuint _internalFmt, GLenum _format, GLint _wrapMode=GL_CLAMP_TO_EDGE, GLint _minFilter=GL_NEAREST, GLint _magFilter=GL_NEAREST)
function to attach a texture to fbo
Definition: FBO.cc:207
const GLMatrixd & modelview() const
get modelview matrix
Definition: GLState.hh:816
int viewport_width() const
get viewport width
Definition: GLState.hh:847
static void blendFunc(GLenum _sfactor, GLenum _dfactor)
replaces glBlendFunc, supports locking
Definition: GLState.hh:307
int viewport_height() const
get viewport height
Definition: GLState.hh:849
static int maxClipDistances_
max number of clip distance outputs in a vertex shader
Definition: IRenderer.hh:580
bool invert()
matrix inversion (returns true on success)
void transpose()
transpose matrix
Interface for modifying render objects.
@ HideNode
Hide this node, but draw children.
Definition: BaseNode.hh:394
@ HideChildren
Draw this node, but hide children.
Definition: BaseNode.hh:396
@ HideSubtree
Hide this node and its children.
Definition: BaseNode.hh:398
@ SecondPass
Draw node in second pass.
Definition: BaseNode.hh:445
std::vector< BaseNode * >::iterator ChildIter
allows to iterate over children
Definition: BaseNode.hh:286
StatusMode status() const
Get node's status.
Definition: BaseNode.hh:401
ACG::SceneGraph::Material & material()
Get material object reference.
void shininess(float _s)
set shininess
void baseColor(const Vec4f &_c)
set the base color (Sets the baseColor which is the same as the emission(const Vec4f& _c) )
void specularColor(const Vec4f &_s)
set the specular color
void ambientColor(const Vec4f &_a)
set the ambient color.
void diffuseColor(const Vec4f &_d)
set the diffuse color.
static void draw(GLSL::Program *_prog=0)
Draw the screen quad.
Definition: ScreenQuad.cc:138
static ShaderCache * getInstance()
Return instance of the ShaderCache singleton.
Definition: ShaderCache.cc:84
GLSL::Program * getProgram(const ShaderGenDesc *_desc, const std::vector< unsigned int > &_mods)
Query a dynamically generated program from cache.
Definition: ShaderCache.cc:102
QString toString() const
convert ShaderGenDesc to string format for debugging
const QStringList & getTessEvaluationShaderCode()
Returns generated tessellation control shader code.
const QStringList & getTessControlShaderCode()
Returns generated vertex shader code.
bool hasTessEvaluationShader() const
check whether there is a tess-evaluation shader present
const QStringList & getGeometryShaderCode()
Returns generated tessellation evaluation shader code.
bool hasGeometryShader() const
check whether there is a geometry shader present
bool hasTessControlShader() const
check whether there is a tess-control shader present
static unsigned int registerModifier(ShaderModifier *_modifier)
Shader modifiers have to be registered before they can be used. They also must remain allocated for t...
const QStringList & getFragmentShaderCode()
Returns generated fragment shader code.
const QStringList & getVertexShaderCode()
Returns generated vertex shader code.
void deactivateShaderPipeline(GLSL::Program *_prog) const
const VertexElement * findElementByUsage(VERTEX_USAGE _usage) const
void activateShaderPipeline(GLSL::Program *_prog) const
GLSL program class.
Definition: GLSLShader.hh:211
GLuint getProgramId()
Returns opengl id.
Definition: GLSLShader.cc:376
void setUniformMat3(const char *_name, const ACG::GLMatrixf &_value, bool _transposed=false)
Set 3x3fMatrix uniform to specified value.
Definition: GLSLShader.cc:663
void use()
Enables the program object for using.
Definition: GLSLShader.cc:345
void setUniform(const char *_name, GLint _value)
Set int uniform to specified value.
Definition: GLSLShader.cc:385
bool empty() const
returns if the pool is empty
Definition: UniformPool.cc:95
void bind(PtrProgram _prog) const
Send all stored uniforms to program.
Definition: UniformPool.cc:116
Scalar * data()
access to Scalar array
Definition: Vector11T.hh:201
Scalar max() const
return the maximal component
Definition: Vector11T.hh:518
auto normalize() -> decltype(*this/=std::declval< VectorT< S, DIM > >().norm())
Definition: Vector11T.hh:454
DrawMode DEFAULT
use the default (global) draw mode and not the node's own.
Definition: DrawModes.cc:72
Namespace providing different geometric functions concerning angles.
bool openGLVersion(const int _major, const int _minor, bool _verbose)
Definition: gl.cc:129
VectorT< float, 3 > Vec3f
Definition: VectorT.hh:119
@ VERTEX_USAGE_NORMAL
"inNormal"
@ VERTEX_USAGE_COLOR
"inColor"
@ VERTEX_USAGE_TEXCOORD
"inTexCoord"
void glCheckErrors()
Definition: GLError.hh:96
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:1076
Texture to be used.
Interface class between scenegraph and renderer.
Definition: RenderObject.hh:99
const char * depthMapUniformName
Uniform name of the depth map in the used shader.
Vec3f diffuse
material definitions
ShaderGenDesc shaderDesc
Drawmode and other shader params.
bool isDefaultLineObject() const
Test if the object is rendered with one of the default line thickness methods.
GLuint vertexArrayObject
Use vertex array object.
const VertexDeclaration * vertexDecl
Defines the vertex buffer layout, ignored if VAO is provided.
QString toString() const
const void * sysmemIndexBuffer
Use system memory index buffer.
GLuint indexBuffer
Use vertex array object.
unsigned int numIndices
Number indices to render.
GLMatrixd modelview
Modelview transform.
GLMatrixd proj
Projection transform.
std::string name
Name for logging.
bool inZPrePass
Specify whether this object should be rendered in a z-prepass.
unsigned int indexOffset
Offset to first index in the index buffer or vertex buffer respectively.
GLuint vertexBuffer
VBO, IBO ids, ignored if VAO is provided.
bool isDefaultPointObject() const
Test if the object is rendered with one of the default point extension methods.
GLenum primitiveMode
Primitive type.
GLenum alphaFunc
GL_LESS, GL_LEQUAL, GL_GREATER ..
unsigned int patchVertices
patch size if primitiveMode is GL_PATCHES for rendering with tessellation shaders
GLenum blendDest
glBlendFunc: GL_SRC_ALPHA, GL_ZERO, GL_ONE, GL_ONE_MINUS_SRC_ALPHA ...
unsigned int internalFlags_
may be used internally by the renderer
Vec2f depthRange
glDepthRange: (znear, zmax)
GLenum indexType
Index element type.
GLenum depthFunc
GL_LESS, GL_LEQUAL, GL_GREATER ..