IRenderer.cc 49.8 KB
Newer Older
Jan Möbius's avatar
Jan Möbius committed
1
2
3
/*===========================================================================*\
 *                                                                           *
 *                              OpenFlipper                                  *
Jan Möbius's avatar
Jan Möbius committed
4
5
6
7
 *           Copyright (c) 2001-2015, RWTH-Aachen University                 *
 *           Department of Computer Graphics and Multimedia                  *
 *                          All rights reserved.                             *
 *                            www.openflipper.org                            *
Jan Möbius's avatar
Jan Möbius committed
8
9
 *                                                                           *
 *---------------------------------------------------------------------------*
Jan Möbius's avatar
Jan Möbius committed
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
 * This file is part of OpenFlipper.                                         *
 *---------------------------------------------------------------------------*
 *                                                                           *
 * Redistribution and use in source and binary forms, with or without        *
 * modification, are permitted provided that the following conditions        *
 * are met:                                                                  *
 *                                                                           *
 * 1. Redistributions of source code must retain the above copyright notice, *
 *    this list of conditions and the following disclaimer.                  *
 *                                                                           *
 * 2. Redistributions in binary form must reproduce the above copyright      *
 *    notice, this list of conditions and the following disclaimer in the    *
 *    documentation and/or other materials provided with the distribution.   *
 *                                                                           *
 * 3. Neither the name of the copyright holder nor the names of its          *
 *    contributors may be used to endorse or promote products derived from   *
 *    this software without specific prior written permission.               *
 *                                                                           *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS       *
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED *
 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A           *
 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER *
 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,  *
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,       *
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR        *
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF    *
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING      *
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS        *
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.              *
Jan Möbius's avatar
Jan Möbius committed
39
40
41
42
43
44
45
46
47
48
49
 *                                                                           *
\*===========================================================================*/

/*===========================================================================*\
 *                                                                           *
 *   $Revision$                                                       *
 *   $Author$                                                      *
 *   $Date$                   *
 *                                                                           *
\*===========================================================================*/

50
#include <ACG/GL/acg_glew.hh>
51
52
#include <cstdio>
#include <cstring>
Jan Möbius's avatar
Jan Möbius committed
53
#include <iostream>
Jan Möbius's avatar
Jan Möbius committed
54
#include <QFile>
55
#include <QTextStream>
Jan Möbius's avatar
Jan Möbius committed
56
57
58
59
60
61

#include <ACG/GL/gl.hh>

#include <ACG/GL/IRenderer.hh>

#include <ACG/GL/VertexDeclaration.hh>
62
#include <ACG/GL/GLError.hh>
63

Jan Möbius's avatar
Jan Möbius committed
64
#include <ACG/GL/ShaderCache.hh>
65
#include <ACG/GL/ScreenQuad.hh>
66
#include <ACG/GL/FBO.hh>
67
68
#include <ACG/GL/globjects.hh>

Jan Möbius's avatar
Jan Möbius committed
69
70


71
72
73
namespace ACG
{

Jan Möbius's avatar
Jan Möbius committed
74
IRenderer::IRenderer()
75
76
77
78
: numLights_(0), 
renderObjects_(0), 
depthMapUsed_(false), 
curViewerID_(0),
Christopher Tenter's avatar
Christopher Tenter committed
79
80
prevFbo_(0),
prevDrawBuffer_(GL_BACK),
81
82
83
84
prevFboSaved_(false),
depthCopyShader_(0),
errorDetectionLevel_(1),
enableLineThicknessGL42_(false)
Jan Möbius's avatar
Jan Möbius committed
85
{
86
87
88
89
  prevViewport_[0] = 0;
  prevViewport_[1] = 0;
  prevViewport_[2] = 0;
  prevViewport_[3] = 0;
90
91
92

  // set global ambient scale to default OpenGL value
  globalLightModelAmbient_ = ACG::Vec3f(0.2f, 0.2f, 0.2f);
Jan Möbius's avatar
Jan Möbius committed
93
}
Jan Möbius's avatar
Jan Möbius committed
94

95

Jan Möbius's avatar
Jan Möbius committed
96
97
IRenderer::~IRenderer()
{
98
  delete depthCopyShader_;
99
100
101
102

  // free depth map fbos
  for (std::map<int, ACG::FBO*>::iterator it = depthMaps_.begin(); it != depthMaps_.end(); ++it)
    delete it->second;
Jan Möbius's avatar
Jan Möbius committed
103
}
104

Jan Möbius's avatar
Jan Möbius committed
105
106
void IRenderer::addRenderObject(ACG::RenderObject* _renderObject)
{
Christopher Tenter's avatar
Christopher Tenter committed
107
108
109
110
111
112
113
  // avoid null-ptr access
  if (!_renderObject->debugName)
    _renderObject->debugName = "<unnamed>";

  if (_renderObject->name.empty())
    _renderObject->name = _renderObject->debugName;

Jan Möbius's avatar
Jan Möbius committed
114
  // do some more checks for error detection
115
  if (!_renderObject->vertexDecl && !_renderObject->vertexArrayObject)
116
    std::cout << "error: missing vertex declaration in renderobject: " << _renderObject->debugName << std::endl;
Jan Möbius's avatar
Jan Möbius committed
117
118
  else
  {
119
120
121
122
    if (errorDetectionLevel_ > 0)
    {
      // commonly encountered rendering errors

123
124
125
      if (!_renderObject->numIndices)
        std::cout << "warning: numIndices is 0 in renderobject: " << _renderObject->debugName << std::endl;

126
127
      //  Why is my object invisible/black?
      if (!_renderObject->depthWrite && 
128
129
        !_renderObject->colorWriteMask[0] && !_renderObject->colorWriteMask[1] &&
        !_renderObject->colorWriteMask[2] && !_renderObject->colorWriteMask[3])
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
        std::cout << "warning: depth write and color write disabled in renderobject: " << _renderObject->debugName << std::endl;

      if (errorDetectionLevel_ > 1 && _renderObject->shaderDesc.shadeMode == SG_SHADE_UNLIT)
      {
        if (_renderObject->emissive.max() < 1e-3f)
          std::cout << "warning: unlit object rendered with black emissive color: " << _renderObject->debugName << std::endl;
        else
        {
          // rendering with clear color

          float clearColor[4];
          glGetFloatv(GL_COLOR_CLEAR_VALUE, clearColor);

          if (checkEpsilon(clearColor[0] - _renderObject->emissive[0]) &&
            checkEpsilon(clearColor[1] - _renderObject->emissive[1]) &&
            checkEpsilon(clearColor[2] - _renderObject->emissive[2]))
          {
            std::cout << "warning: unlit object rendered with clear color as emissive color: " << _renderObject->debugName << std::endl;
            std::cout << "         Should this be intentional, disable color writing instead via obj->glColorMask(0,0,0,0)" << std::endl;
          }
        }
      }

153
154
155
156
157
158
159
160
161
      if (_renderObject->textures().size())
      {
        // Why are my textures sampled as black?

        // mipmap enabled, but no mipmap chain provided?

        for (std::map<size_t,RenderObject::Texture>::const_iterator it = _renderObject->textures().begin();
          it != _renderObject->textures().end(); ++it)
        {
Christopher Tenter's avatar
Christopher Tenter committed
162
163
164
165
166
#ifdef GL_ARB_texture_buffer_object
          if (it->second.type == GL_TEXTURE_BUFFER)
            continue; // skip texture buffers, for which testing for mipmaps would generate an error
#endif

167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
          glBindTexture(it->second.type, it->second.id);

          GLint minFilter = GL_NONE;
          glGetTexParameteriv(it->second.type, GL_TEXTURE_MIN_FILTER, &minFilter);

          if (minFilter == GL_NEAREST_MIPMAP_LINEAR ||
            minFilter == GL_NEAREST_MIPMAP_NEAREST ||
            minFilter == GL_LINEAR_MIPMAP_LINEAR ||
            minFilter == GL_LINEAR_MIPMAP_NEAREST)
          {
            GLint maxLevel = 0;
            glGetTexParameteriv(it->second.type, GL_TEXTURE_MAX_LEVEL, &maxLevel);

            GLint texWidth = 0;
            glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &texWidth);

            GLint maxLod = -1;
            for (GLint lod = 0; lod < maxLevel && maxLod < 0; ++lod)
            {
              GLint lodWidth;
              glGetTexLevelParameteriv(GL_TEXTURE_2D, lod, GL_TEXTURE_WIDTH, &lodWidth);

              if (lodWidth <= 0 || lodWidth == GL_INVALID_VALUE)
                maxLod = lod-1;
            }

            if (maxLod <= 0 && texWidth > 1)
            {
              std::cout << "warning: texture is sampled with mipmapping, but no mipchain is present: " << _renderObject->debugName << " texid: " << it->second.id << std::endl;
              std::cout << "         automatically disabling mipmapping!!" << std::endl;

              GLint correctedFilter = GL_LINEAR;

              if (minFilter == GL_NEAREST_MIPMAP_LINEAR ||
                minFilter == GL_LINEAR_MIPMAP_LINEAR)
                correctedFilter = GL_LINEAR;
              else
                correctedFilter = GL_NEAREST;

              glTexParameteri(it->second.type, GL_TEXTURE_MIN_FILTER, correctedFilter);
            }
          }
        }

      }
212
213
214
215
216
217
218
219
220
221
222
223
224

      if (errorDetectionLevel_ > 1)
      {
        // Why is there nothing written to the depth-buffer?
        // this might very well be intentional, so put it in higher level

        if (_renderObject->depthWrite && !_renderObject->depthTest)
        {
          std::cout << "warning: trying to write to depth buffer with depth-testing disabled does not work in: " << _renderObject->debugName << std::endl;
          std::cout << "         If depth-writing was intended, enable depth-testing and set depth-func to GL_ALWAYS" << std::endl;
        }
      }

225
      if (!_renderObject->vertexArrayObject)
226
      {
227
228
229
230
231
        // Why are there gl errors and/or nothing gets drawn?
        if (_renderObject->shaderDesc.shadeMode != SG_SHADE_UNLIT)
        {
          // check for normals
          if (!_renderObject->vertexDecl->findElementByUsage(VERTEX_USAGE_NORMAL))
Christopher Tenter's avatar
Christopher Tenter committed
232
233
            std::cout << "warning: missing normals for lighting in renderobject: " << _renderObject->debugName << std::endl
                      << "         Set shadeMode to SG_SHADE_UNLIT or provide normals!" << std::endl;
234
        }
235

236
237
238
239
240
241
        if (_renderObject->shaderDesc.textured())
        {
          // check for texcoords
          if (!_renderObject->vertexDecl->findElementByUsage(VERTEX_USAGE_TEXCOORD))
            std::cout << "warning: missing texcoords for textured mode in renderobject: " << _renderObject->debugName << std::endl;
        }
242

243
244
245
246
247
248
        if (_renderObject->shaderDesc.vertexColors)
        {
          // check for vertex colors
          if (!_renderObject->vertexDecl->findElementByUsage(VERTEX_USAGE_COLOR))
            std::cout << "warning: missing colors for vertexcolor mode in renderobject: " << _renderObject->debugName << std::endl;
        }
249
250
251
252
253
254
      }


      // Why is alpha blending not work?
      if (fabsf(_renderObject->alpha - 1.0f) > 1e-3f && !(_renderObject->alphaTest || _renderObject->blending))
        std::cout << "warning: alpha value != 1 but no alpha blending or testing enabled in renderobject: " << _renderObject->debugName << std::endl;
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301


#ifdef GL_ARB_tessellation_shader
      // Trying to render with tessellation shaders?
      const bool tessellationActive = !_renderObject->shaderDesc.tessControlTemplateFile.isEmpty() || !_renderObject->shaderDesc.tessEvaluationTemplateFile.isEmpty();
      bool tryToFixPatchInfo = false;
      if (tessellationActive && _renderObject->primitiveMode != GL_PATCHES)
      {
        std::cout << "error: tessellation shaders are not used with GL_PATCHES primitiveType in renderobject: " << _renderObject->debugName << std::endl;
        tryToFixPatchInfo = true;
      }

      if (tessellationActive && !_renderObject->patchVertices)
      {
        std::cout << "error: undefined patch size for tessellation in renderobject: " << _renderObject->debugName << std::endl;
        tryToFixPatchInfo = true;
      }

      if (tryToFixPatchInfo)
      {
        if (_renderObject->primitiveMode == GL_POINTS)
        {
          _renderObject->primitiveMode = GL_PATCHES;
          _renderObject->patchVertices = 1;
          std::cout << "warning: attempting to draw with patchVertices = 1 for tessellation in renderobject: " << _renderObject->debugName << std::endl;
        }
        else if (_renderObject->primitiveMode == GL_LINES)
        {
          _renderObject->primitiveMode = GL_PATCHES;
          _renderObject->patchVertices = 2;
          std::cout << "warning: attempting to draw with patchVertices = 2 for tessellation in renderobject: " << _renderObject->debugName << std::endl;
        }
        else if (_renderObject->primitiveMode == GL_TRIANGLES)
        {
          _renderObject->primitiveMode = GL_PATCHES;
          _renderObject->patchVertices = 3;
          std::cout << "warning: attempting to draw with patchVertices = 3 for tessellation in renderobject: " << _renderObject->debugName << std::endl;
        }
        else if (_renderObject->primitiveMode == GL_QUADS)
        {
          _renderObject->primitiveMode = GL_PATCHES;
          _renderObject->patchVertices = 4;
          std::cout << "warning: attempting to draw with patchVertices = 4 for tessellation in renderobject: " << _renderObject->debugName << std::endl;
        }
      }

#endif
302
    }
303
304


Jan Möbius's avatar
Jan Möbius committed
305
    renderObjects_.push_back(*_renderObject);
Jan Möbius's avatar
Jan Möbius committed
306
307


Jan Möbius's avatar
Jan Möbius committed
308
    ACG::RenderObject* p = &renderObjects_.back();
309

Jan Möbius's avatar
Jan Möbius committed
310
311
    if (!p->shaderDesc.numLights)
      p->shaderDesc.numLights = numLights_;
Jan Möbius's avatar
Jan Möbius committed
312

Jan Möbius's avatar
Jan Möbius committed
313
314
    else if (p->shaderDesc.numLights < 0 || p->shaderDesc.numLights >= SG_MAX_SHADER_LIGHTS)
      p->shaderDesc.numLights = 0;
Jan Möbius's avatar
Jan Möbius committed
315

Jan Möbius's avatar
Jan Möbius committed
316
    p->internalFlags_ = 0;
Jan Möbius's avatar
Jan Möbius committed
317

Jan Möbius's avatar
Jan Möbius committed
318
    // precompile shader
319
#ifdef GL_GEOMETRY_INPUT_TYPE
320
    GLSL::Program* shaderProg = ACG::ShaderCache::getInstance()->getProgram(&p->shaderDesc);
Jan Möbius's avatar
Jan Möbius committed
321
#endif
322
323
324
325
326


    // check primitive type and geometry shader
    if (errorDetectionLevel_ > 1 && p->shaderDesc.geometryTemplateFile.length())
    {
327
#ifdef GL_GEOMETRY_INPUT_TYPE
328
329
330
331
      GLint geomInputType = 0;
      glGetProgramiv(shaderProg->getProgramId(), GL_GEOMETRY_INPUT_TYPE, &geomInputType);


Christopher Tenter's avatar
Christopher Tenter committed
332
      if (geomInputType != GLint(p->primitiveMode))
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
      {

        switch (geomInputType)
        {
        case GL_POINTS: std::cout << "warning: primitive mode is incompatible with points-geometryshader in renderobject: " << _renderObject->debugName << std::endl; break;
        
        case GL_LINES: 
          {
            if (p->primitiveMode != GL_LINE_STRIP && p->primitiveMode != GL_LINE_LOOP)
              std::cout << "warning: primitive mode is incompatible with lines-geometryshader in renderobject: " << _renderObject->debugName << std::endl;
          } break;

        case GL_LINES_ADJACENCY:
          {
            if (p->primitiveMode != GL_LINE_STRIP_ADJACENCY)
              std::cout << "warning: primitive mode is incompatible with lines_adjacency-geometryshader in renderobject: " << _renderObject->debugName << std::endl;
          } break;

        case GL_TRIANGLES:
          {
            if (p->primitiveMode != GL_TRIANGLE_STRIP && p->primitiveMode != GL_TRIANGLE_FAN)
              std::cout << "warning: primitive mode is incompatible with triangles-geometryshader in renderobject: " << _renderObject->debugName << std::endl;
          } break;
          
        case GL_TRIANGLES_ADJACENCY:
          {
            if (p->primitiveMode != GL_TRIANGLE_STRIP_ADJACENCY)
              std::cout << "warning: primitive mode is incompatible with triangles_adjacency-geometryshader in renderobject: " << _renderObject->debugName << std::endl;
          } break;

        default: std::cout << "warning: unknown input_type for geometryshader in renderobject: " << _renderObject->debugName << std::endl;
        }
        
        

      }


#else
      if (_renderObject->isDefaultLineObject())
      {
        if (_renderObject->primitiveMode != GL_LINES && _renderObject->primitiveMode != GL_LINE_STRIP && _renderObject->primitiveMode != GL_LINE_LOOP)
          std::cout << "warning: primitive mode is incompatible with lines-geometryshader in renderobject: " << _renderObject->debugName << std::endl;
      }
      else if (_renderObject->isDefaultPointObject())
      {
        if (_renderObject->primitiveMode != GL_POINTS)
          std::cout << "warning: primitive mode is incompatible with points-geometryshader in renderobject: " << _renderObject->debugName << std::endl;
      }
#endif
    }
Jan Möbius's avatar
Jan Möbius committed
384

Jan Möbius's avatar
Jan Möbius committed
385
386
  }
}
Jan Möbius's avatar
Jan Möbius committed
387
388
389



Jan Möbius's avatar
Jan Möbius committed
390
391
392
393
394
395
396

void IRenderer::collectRenderObjects( ACG::GLState* _glState, ACG::SceneGraph::DrawModes::DrawMode _drawMode, ACG::SceneGraph::BaseNode* _sceneGraphRoot )
{
  // collect light sources
//  collectLightNodes(_sceneGraphRoot);
  numLights_ = 0; // reset light counter

397
398
399
400
401
//  // flush render objects
//  for (size_t i = 0; i < renderObjects_.size(); ++i)
//  {
//    renderObjects_[i].uniformPool_.clear();
//  }
Jan Möbius's avatar
Jan Möbius committed
402
403
404
405
406
407
408
409
410
411
412
413
414
415
  renderObjects_.resize(0);


  // default material needed
  ACG::SceneGraph::Material defMat;
  defMat.baseColor(ACG::Vec4f(0.0f, 0.0f, 0.0f, 1.0f));
  defMat.ambientColor(ACG::Vec4f(0.2f, 0.2f, 0.2f, 1.0f));
  defMat.diffuseColor(ACG::Vec4f(0.6f, 0.6f, 0.6f, 1.0f));
  defMat.specularColor(ACG::Vec4f(0.0f, 0.0f, 0.0f, 1.0f));
  defMat.shininess(1.0f);
  //  defMat.alphaValue(1.0f);

  // collect renderables
  traverseRenderableNodes(_glState, _drawMode, _sceneGraphRoot, &defMat);
Jan Möbius's avatar
Jan Möbius committed
416
}
Jan Möbius's avatar
Jan Möbius committed
417

Jan Möbius's avatar
Jan Möbius committed
418
419
420
421
422




void IRenderer::traverseRenderableNodes( ACG::GLState* _glState, ACG::SceneGraph::DrawModes::DrawMode _drawMode, ACG::SceneGraph::BaseNode* _node, const ACG::SceneGraph::Material* _mat )
423
{
Jan Möbius's avatar
Jan Möbius committed
424
  if (_node)
425
  {
Jan Möbius's avatar
Jan Möbius committed
426
427
428
429
430
431
432
433
434
435
436
437
438
    ACG::SceneGraph::BaseNode::StatusMode status(_node->status());

    ACG::SceneGraph::DrawModes::DrawMode nodeDM = _node->drawMode();

    if (nodeDM == ACG::SceneGraph::DrawModes::DEFAULT)
      nodeDM = _drawMode;


    // If the subtree is hidden, ignore this node and its children while rendering
    if (status != ACG::SceneGraph::BaseNode::HideSubtree)
    {

      if ( _node->status() != ACG::SceneGraph::BaseNode::HideNode )
439
        _node->enter(*_glState, nodeDM);
Jan Möbius's avatar
Jan Möbius committed
440
441
442
443
444
445
446
447
448
449
450


      // fetch material (Node itself can be a material node, so we have to
      // set that in front of the nodes own rendering
      ACG::SceneGraph::MaterialNode* matNode = dynamic_cast<ACG::SceneGraph::MaterialNode*>(_node);
      if (matNode)
        _mat = &matNode->material();

      if (_node->status() != ACG::SceneGraph::BaseNode::HideNode)
        _node->getRenderObjects(this, *_glState, nodeDM, _mat);

Jan Möbius's avatar
Jan Möbius committed
451
452
      // Process children?
      if (status != ACG::SceneGraph::BaseNode::HideChildren)
Jan Möbius's avatar
Jan Möbius committed
453
454
455
456
457
458
459
460
      {

        ACG::SceneGraph::BaseNode::ChildIter cIt, cEnd(_node->childrenEnd());

        // Process all children which are not second pass
        for (cIt = _node->childrenBegin(); cIt != cEnd; ++cIt)
          if (~(*cIt)->traverseMode() & ACG::SceneGraph::BaseNode::SecondPass)
            traverseRenderableNodes( _glState, _drawMode, *cIt, _mat);
461

Jan Möbius's avatar
Jan Möbius committed
462
463
464
465
        // Process all children which are second pass
        for (cIt = _node->childrenBegin(); cIt != cEnd; ++cIt)
          if ((*cIt)->traverseMode() & ACG::SceneGraph::BaseNode::SecondPass)
            traverseRenderableNodes( _glState, _drawMode, *cIt, _mat);
466

Jan Möbius's avatar
Jan Möbius committed
467
468
469
470
471
472
      }


      if (_node->status() != ACG::SceneGraph::BaseNode::HideNode )
        _node->leave(*_glState, nodeDM);
    }
473
474
475
  }
}

Jan Möbius's avatar
Jan Möbius committed
476
477

int IRenderer::cmpPriority(const void* _a, const void* _b)
478
{
Jan Möbius's avatar
Jan Möbius committed
479
480
481
482
  const ACG::RenderObject* a = *(const ACG::RenderObject**)_a;
  const ACG::RenderObject* b = *(const ACG::RenderObject**)_b;

  return a->priority - b->priority;
483
484
485
}


Jan Möbius's avatar
Jan Möbius committed
486
487
void IRenderer::prepareRenderingPipeline(ACG::GLState* _glState, ACG::SceneGraph::DrawModes::DrawMode _drawMode, ACG::SceneGraph::BaseNode* _scenegraphRoot)
{
488
489
490
491
492
493
494
495
  // grab view transform from glstate
  viewMatrix_ = _glState->modelview();
  camPosWS_ = Vec3f( viewMatrix_(0,3), viewMatrix_(1,3), viewMatrix_(2,3) );
  camDirWS_ = Vec3f( viewMatrix_(0,2), viewMatrix_(1,2), -viewMatrix_(2,2) ); // mind the z flip

//   printf("pos: %f %f %f\ndir: %f %f %f\n", camPosWS_[0], camPosWS_[1], camPosWS_[2],
//     camDirWS_[0], camDirWS_[1], camDirWS_[2]);

Jan Möbius's avatar
Jan Möbius committed
496
497
498
499
500
501
502
503
504
  // First, all render objects get collected.
  collectRenderObjects(_glState, _drawMode, _scenegraphRoot);

  // Check if there is anything to render
  if (renderObjects_.empty())
    return;

  // ==========================================================
  // Sort renderable objects based on their priority
505
  // Filter for overlay, lines etc.
Jan Möbius's avatar
Jan Möbius committed
506
507
  // ==========================================================

508
  const size_t numRenderObjects = getNumRenderObjects(),
509
510
    numOverlayObjects = getNumOverlayObjects(),
    numLineObjects = getNumLineGL42Objects();
Jan Möbius's avatar
Jan Möbius committed
511
512
513
514
515

  // sort for priority
  if (sortedObjects_.size() < numRenderObjects)
    sortedObjects_.resize(numRenderObjects);

516
517
518
  if (overlayObjects_.size() < numOverlayObjects)
    overlayObjects_.resize(numOverlayObjects);

519
520
521
  if (lineGL42Objects_.size() < numLineObjects)
    lineGL42Objects_.resize(numLineObjects);

Jan Möbius's avatar
Jan Möbius committed
522
  // init sorted objects array
523
  size_t sceneObjectOffset = 0, overlayObjectOffset = 0, lineObjectOffset = 0;
524
525
526
527
  for (size_t i = 0; i < renderObjects_.size(); ++i)
  {
    if (renderObjects_[i].overlay)
      overlayObjects_[overlayObjectOffset++] = &renderObjects_[i];
528
529
530
531
532
533
534
535
536
537
538
    else if (enableLineThicknessGL42_ && numLineObjects && renderObjects_[i].isDefaultLineObject())
    {
      renderObjects_[i].shaderDesc.geometryTemplateFile = "Wireframe/gl42/geometry.tpl";
      renderObjects_[i].shaderDesc.fragmentTemplateFile = "Wireframe/gl42/fragment.tpl";

      // disable color write to fbo, but allow RenderObject to control depth write
      renderObjects_[i].glColorMask(0,0,0,0);

//      sortedObjects_[sceneObjectOffset++] = &renderObjects_[i];
      lineGL42Objects_[lineObjectOffset++] = &renderObjects_[i];
    }
539
540
541
    else
      sortedObjects_[sceneObjectOffset++] = &renderObjects_[i];
  }
Jan Möbius's avatar
Jan Möbius committed
542
543
544

  sortRenderObjects();

545

Jan Möbius's avatar
Jan Möbius committed
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
  // ---------------------------
  // Initialize the render state
  // ---------------------------
  // gl cleanup

  glDisableClientState(GL_VERTEX_ARRAY);
  glDisableClientState(GL_COLOR_ARRAY);
  glDisableClientState(GL_NORMAL_ARRAY);
  glDisableClientState(GL_TEXTURE_COORD_ARRAY);
  glDisableClientState(GL_INDEX_ARRAY);


  glEnable(GL_CULL_FACE);
  glEnable(GL_DEPTH_TEST);
  glDepthFunc(GL_LESS);
  glDepthMask(GL_TRUE);
562
563
564

  // save active fbo and viewport
  saveInputFbo();
565
566
567
568
569
570


  // get global ambient factor
  GLfloat lightModelAmbient[4];
  glGetFloatv(GL_LIGHT_MODEL_AMBIENT, lightModelAmbient);
  globalLightModelAmbient_ = ACG::Vec3f(lightModelAmbient[0], lightModelAmbient[1], lightModelAmbient[2]);
571
572
573
574
575


  // search list of render object for objects requiring the scene depth map
  bool requiresSceneDepths = false;

576
  for (size_t i = 0; i < renderObjects_.size(); ++i)
577
  {
578
    if (renderObjects_[i].depthMapUniformName)
579
580
581
582
583
584
      requiresSceneDepths = true;
  }

  // render scene depth map
  if (requiresSceneDepths)
    renderDepthMap(curViewerID_, _glState->viewport_width(), _glState->viewport_height());
Jan Möbius's avatar
Jan Möbius committed
585
586
587
588
}



589
void IRenderer::finishRenderingPipeline(bool _drawOverlay)
Jan Möbius's avatar
Jan Möbius committed
590
{
591
592
593
594
#ifdef GL_ARB_vertex_array_object
  glBindVertexArray(0);
#endif

595
596
597
598
  // draw thick lines
  if (enableLineThicknessGL42_)
    renderLineThicknessGL42();

599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
  if (_drawOverlay)
  {
    const int numOverlayObj = getNumOverlayObjects();
    // two-pass overlay rendering:
    // 1. clear depth buffer at pixels of overlay objects
    // 2. render overlay with correct depth-testing

    // 1. pass: clear depth to max value at overlay footprint
    for (int i = 0; i < numOverlayObj; ++i)
    {
      RenderObject* obj = getOverlayRenderObject(i);

      if (obj->depthTest && obj->depthFunc != GL_ALWAYS)
      {
        float depthMax = 1.0f;

        if (obj->depthFunc == GL_GREATER || obj->depthFunc == GL_GEQUAL)
          depthMax = 0.0f;

        // save depth setting of renderobject
        Vec2f depthRange = obj->depthRange;
        bool depthWrite = obj->depthWrite;
        GLenum depthFunc = obj->depthFunc;

        // reset depth to maximal distance by using depth range
        obj->depthRange = Vec2f(depthMax, depthMax);
        obj->depthWrite = true;
        obj->depthFunc = GL_ALWAYS;

        renderObject(obj);

        // restore depth setting
        obj->depthRange = depthRange;
        obj->depthWrite = depthWrite;
        obj->depthFunc = depthFunc;
      }

    }

    // 2. render overlay with correct depth-testing
    for (int i = 0; i < numOverlayObj; ++i)
    {
      RenderObject* obj = getOverlayRenderObject(i);
      renderObject(obj);
    }

  }

647
648
649
650
#ifdef GL_ARB_vertex_array_object
  glBindVertexArray(0);
#endif

Jan Möbius's avatar
Jan Möbius committed
651
652
  glDepthMask(1);
  glColorMask(1,1,1,1);
653

Jan Möbius's avatar
Jan Möbius committed
654
  glUseProgram(0);
655

Jan Möbius's avatar
Jan Möbius committed
656
657
  glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
  glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0);
658
659
660

  // Renderer check:
  // Print a warning if the currently active fbo / viewport is not the same as the saved fbo.
661
  // Restore to previous fbo and viewport if not done already.
662
663
664

  GLint curFbo;
  GLint curViewport[4];
Christopher Tenter's avatar
Christopher Tenter committed
665
  GLint curDrawBuf;
666
667
  glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &curFbo);
  glGetIntegerv(GL_VIEWPORT, curViewport);
Christopher Tenter's avatar
Christopher Tenter committed
668
  glGetIntegerv(GL_DRAW_BUFFER, &curDrawBuf);
669
670
671
672
673
674
675
  
  if (curFbo != prevFbo_)
  {
    std::cout << "warning: input and output fbo are not the same in renderer implementation" << std::endl;
    restoreInputFbo();
  }

Christopher Tenter's avatar
Christopher Tenter committed
676
677
678
679
680
681
  if (curDrawBuf != prevDrawBuffer_)
  {
    std::cout << "warning: input and output draw-buffer are not the same in renderer implementation" << std::endl;
    restoreInputFbo();
  }

682
683
684
685
686
687
688
689
690
691
692
693
694
695
  if (curViewport[0] != prevViewport_[0] ||
    curViewport[1] != prevViewport_[1] ||
    curViewport[2] != prevViewport_[2] ||
    curViewport[3] != prevViewport_[3])
  {
    std::cout << "warning: input and output viewport are not the same in renderer implementation" << std::endl;
    restoreInputFbo();
  }
}


void IRenderer::saveInputFbo()
{
  // save active fbo
Christopher Tenter's avatar
Christopher Tenter committed
696
  saveActiveFbo(&prevFbo_, prevViewport_, &prevDrawBuffer_);
697
698
699
700
701
702
  prevFboSaved_ = true;
}

void IRenderer::restoreInputFbo()
{
  if (prevFboSaved_)
Christopher Tenter's avatar
Christopher Tenter committed
703
    restoreFbo(prevFbo_, prevViewport_, prevDrawBuffer_);
704
705
}

Christopher Tenter's avatar
Christopher Tenter committed
706
void IRenderer::saveActiveFbo( GLint* _outFboId, GLint* _outViewport, GLint* _outDrawBuffer ) const
707
708
709
710
{
  // save active fbo
  glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, _outFboId);
  glGetIntegerv(GL_VIEWPORT, _outViewport);
Christopher Tenter's avatar
Christopher Tenter committed
711
  glGetIntegerv(GL_DRAW_BUFFER, _outDrawBuffer);
712
713
}

Christopher Tenter's avatar
Christopher Tenter committed
714
void IRenderer::restoreFbo( GLint _fboId, const GLint* _outViewport, GLint _drawBuffer ) const
715
716
{
  glBindFramebuffer(GL_FRAMEBUFFER, _fboId);
Christopher Tenter's avatar
Christopher Tenter committed
717
  glDrawBuffer(_drawBuffer);
Jan Möbius's avatar
Jan Möbius committed
718
  glViewport(_outViewport[0], _outViewport[1], _outViewport[2], _outViewport[3]);
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
}

void IRenderer::clearInputFbo( const ACG::Vec4f& clearColor )
{
  glClearColor(clearColor[0], clearColor[1], clearColor[2], 1.0f);

  // glClear will affect the whole back buffer, not only the area in viewport.
  // Temporarily use glScissor to only clear the viewport area in the back buffer.
  if (!prevFboSaved_)
  {
    GLint oldViewport[4];
    glGetIntegerv(GL_VIEWPORT, oldViewport);
    glScissor(oldViewport[0], oldViewport[1], oldViewport[2], oldViewport[3]);
  }
  else
    glScissor(prevViewport_[0], prevViewport_[1], prevViewport_[2], prevViewport_[3]);

  glEnable(GL_SCISSOR_TEST);
  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

  // disable scissors again, draw calls only affect the area in glViewport anyway
  glDisable(GL_SCISSOR_TEST);
741
742
}

Jan Möbius's avatar
Jan Möbius committed
743
744
745

void IRenderer::sortRenderObjects()
{
746
747
748
  if (!sortedObjects_.empty())
    qsort(&sortedObjects_[0], getNumRenderObjects(), sizeof(ACG::RenderObject*), cmpPriority);
  if (!overlayObjects_.empty())
749
    qsort(&overlayObjects_[0], getNumOverlayObjects(), sizeof(ACG::RenderObject*), cmpPriority);
Jan Möbius's avatar
Jan Möbius committed
750
751
752
753
754
755
}



void IRenderer::bindObjectVBO(ACG::RenderObject* _obj,
                                       GLSL::Program*     _prog)
756
{
Jan Möbius's avatar
Jan Möbius committed
757
758
759
  _prog->use();


760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
#ifdef GL_ARB_vertex_array_object
  glBindVertexArray(_obj->vertexArrayObject);
#endif

  if (!_obj->vertexArrayObject)
  {
    //////////////////////////////////////////////////////////////////////////
    // NOTE:
    //  always bind buffers before glVertexAttribPointer calls!!
    //  freeze in glDrawElements guaranteed (with no error message whatsoever)
    glBindBufferARB(GL_ARRAY_BUFFER_ARB, _obj->vertexBuffer);
    glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, _obj->indexBuffer);


    // activate vertex declaration
    _obj->vertexDecl->activateShaderPipeline(_prog);
Jan Möbius's avatar
Jan Möbius committed
776

777
  }
778
}
779

Jan Möbius's avatar
Jan Möbius committed
780
781

void IRenderer::bindObjectUniforms( ACG::RenderObject* _obj, GLSL::Program* _prog )
782
{
Jan Möbius's avatar
Jan Möbius committed
783
784
785
786
787
788
789
790
791
792
793
  // transforms
  ACG::GLMatrixf mvp = _obj->proj * _obj->modelview;
  ACG::GLMatrixf mvIT = _obj->modelview;
  mvIT.invert();
  mvIT.transpose();

  _prog->setUniform("g_mWVP", mvp);
  _prog->setUniform("g_mWV", _obj->modelview);
  _prog->setUniformMat3("g_mWVIT", mvIT);
  _prog->setUniform("g_mP", _obj->proj);

794
795
  _prog->setUniform("g_vCamPos", camPosWS_);
  _prog->setUniform("g_vCamDir", camDirWS_);
Jan Möbius's avatar
Jan Möbius committed
796
797

  // material
798
  
799
  _prog->setUniform("g_cEmissive", _obj->emissive);
800

Jan Möbius's avatar
Jan Möbius committed
801
802
803
804
805
806
807
  _prog->setUniform("g_cDiffuse", _obj->diffuse);
  _prog->setUniform("g_cAmbient", _obj->ambient);
  _prog->setUniform("g_cSpecular", _obj->specular);

  ACG::Vec4f materialParams(_obj->shininess, _obj->alpha, 0.0f, 0.0f);
  _prog->setUniform("g_vMaterial", materialParams);

808
  _prog->setUniform("g_cLightModelAmbient", globalLightModelAmbient_);
Jan Möbius's avatar
Jan Möbius committed
809

810
  // Additional Uniforms defined in the render Object
811
812
  if ( !_obj->uniformPool_.empty() )
    _obj->uniformPool_.bind(_prog);
Jan Möbius's avatar
Jan Möbius committed
813

814
815
816
817
818
819
820
  // textures:

  // maybe consider using bindless textures some time in the future
  // to get rid of the old and problematic glActiveTexture(), glBindTexture() state machine usage:
  // https://www.opengl.org/registry/specs/ARB/bindless_texture.txt

  int maxTextureStage = 0;
Jan Möbius's avatar
Jan Möbius committed
821
  for (std::map<size_t,RenderObject::Texture>::const_iterator iter = _obj->textures().begin();
822
823
824
      iter != _obj->textures().end();++iter)
  {
    //check for valid texture id
Jan Möbius's avatar
Jan Möbius committed
825
    const size_t texture_stage = iter->first;
826
827
828
829
    const RenderObject::Texture tex = iter->second;
    if (!tex.id)
      continue;

Matthias Möller's avatar
Matthias Möller committed
830
    glActiveTexture(GL_TEXTURE0 + (GLenum)texture_stage);
831
832
    glBindTexture(iter->second.type, tex.id);
    _prog->setUniform(QString("g_Texture%1").arg(texture_stage).toStdString().c_str(), (int)texture_stage);
833
834
835
836
837
838
839
840
841
842
843
844
845
846

    maxTextureStage = std::max(maxTextureStage, (int)texture_stage);
  }


  // scene depth texture
  if (_obj->depthMapUniformName)
  {
    // bind to (hopefully) unused texture stage
    int depthMapSlot = maxTextureStage + 1;

    _prog->setUniform(_obj->depthMapUniformName, depthMapSlot);
    glActiveTexture(GL_TEXTURE0 + depthMapSlot);
    glBindTexture(GL_TEXTURE_2D, depthMaps_[curViewerID_]->getAttachment(GL_COLOR_ATTACHMENT0));
847
  }
848

Jan Möbius's avatar
Jan Möbius committed
849
850
851

  // lights
  for (int i = 0; i < numLights_; ++i)
852
  {
Jan Möbius's avatar
Jan Möbius committed
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
    LightData* lgt = lights_ + i;

    char szUniformName[256];

    sprintf(szUniformName, "g_cLightDiffuse_%d", i);
    _prog->setUniform(szUniformName, lgt->diffuse);

    sprintf(szUniformName, "g_cLightAmbient_%d", i);
    _prog->setUniform(szUniformName, lgt->ambient);

    sprintf(szUniformName, "g_cLightSpecular_%d", i);
    _prog->setUniform(szUniformName, lgt->specular);


    if (lgt->ltype == ACG::SG_LIGHT_POINT || lgt->ltype == ACG::SG_LIGHT_SPOT)
    {
      sprintf(szUniformName, "g_vLightPos_%d", i);
      _prog->setUniform(szUniformName, lgt->pos);

      sprintf(szUniformName, "g_vLightAtten_%d", i);
      _prog->setUniform(szUniformName, lgt->atten);
    }

    if (lgt->ltype == ACG::SG_LIGHT_DIRECTIONAL || lgt->ltype == ACG::SG_LIGHT_SPOT)
    {
      sprintf(szUniformName, "g_vLightDir_%d", i);
      _prog->setUniform(szUniformName, lgt->dir);
    }

    if (lgt->ltype == ACG::SG_LIGHT_SPOT)
    {
      sprintf(szUniformName, "g_vLightAngleExp_%d", i);
      _prog->setUniform(szUniformName, lgt->spotCutoffExponent);
    }
  }
}

void IRenderer::bindObjectRenderStates(ACG::RenderObject* _obj)
{
  if (_obj->culling)
    glEnable(GL_CULL_FACE);
  else
    glDisable(GL_CULL_FACE);

  if (_obj->blending)
    glEnable(GL_BLEND);
  else
    glDisable(GL_BLEND);

  if (_obj->alphaTest)
903
  {
Jan Möbius's avatar
Jan Möbius committed
904
    glEnable(GL_ALPHA_TEST);
905
906
    glAlphaFunc(_obj->alphaFunc, _obj->alphaRef);
  }
Jan Möbius's avatar
Jan Möbius committed
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
  else
    glDisable(GL_ALPHA_TEST);

  if (_obj->depthTest)
    glEnable(GL_DEPTH_TEST);
  else
    glDisable(GL_DEPTH_TEST);


  glDepthMask(_obj->depthWrite ? GL_TRUE : GL_FALSE);

  glColorMask(_obj->colorWriteMask[0], _obj->colorWriteMask[1], _obj->colorWriteMask[2], _obj->colorWriteMask[3]);

  glDepthFunc(_obj->depthFunc);

922
923
  glDepthRange(_obj->depthRange[0], _obj->depthRange[1]);

Jan Möbius's avatar
Jan Möbius committed
924
925
  //  ACG::GLState::shadeModel(_obj->shadeModel);

926
  ACG::GLState::blendFunc(_obj->blendSrc, _obj->blendDest);
Jan Möbius's avatar
Jan Möbius committed
927
928
929
930
931
}

void IRenderer::drawObject(ACG::RenderObject* _obj)
{
  if (_obj->numIndices)
932
  {
Jan Möbius's avatar
Jan Möbius committed
933
934
935
936
937
938
    // indexed drawing?
    bool noIndices = true;
    if (_obj->indexBuffer || _obj->sysmemIndexBuffer)
      noIndices = false;

    glPolygonMode(GL_FRONT_AND_BACK, _obj->fillMode);
939

940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
    // tessellation info
    bool tessellationActive = !(_obj->shaderDesc.tessControlTemplateFile.isEmpty() && _obj->shaderDesc.tessEvaluationTemplateFile.isEmpty());
#ifdef GL_ARB_tessellation_shader
    if (tessellationActive)
    {
      glPatchParameteri(GL_PATCH_VERTICES, _obj->patchVertices);

      if (_obj->shaderDesc.tessControlTemplateFile.isEmpty())
      {
        glPatchParameterfv(GL_PATCH_DEFAULT_INNER_LEVEL, _obj->patchDefaultInnerLevel.data());
        glPatchParameterfv(GL_PATCH_DEFAULT_OUTER_LEVEL, _obj->patchDefaultOuterLevel.data());
      }
    }
#else
    if (tessellationActive)
      std::cout << "error: tessellation shaders cannot be used with the outdated glew version" << std::endl;
#endif

958
    if (noIndices) {
959
960
961
962
      if (_obj->numInstances <= 0)
        glDrawArrays(_obj->primitiveMode, _obj->indexOffset, _obj->numIndices);
      else
        glDrawArraysInstanced(_obj->primitiveMode, _obj->indexOffset, _obj->numIndices, _obj->numInstances);
963
    }
Jan Möbius's avatar
Jan Möbius committed
964
965
966
967
968
969
970
971
972
973
974
975
    else
    {
      // ------------------------------------------
      // index offset stuff not tested
      int indexSize = 0;
      switch (_obj->indexType)
      {
      case GL_UNSIGNED_INT: indexSize = 4; break;
      case GL_UNSIGNED_SHORT: indexSize = 2; break;
      default: indexSize = 1; break;
      }

976
977
978
979
980
981
      if (_obj->numInstances <= 0)
        glDrawElements(_obj->primitiveMode, _obj->numIndices, _obj->indexType,
          ((const char*)_obj->sysmemIndexBuffer) + _obj->indexOffset * indexSize);
      else
        glDrawElementsInstanced(_obj->primitiveMode, _obj->numIndices, _obj->indexType,
          ((const char*)_obj->sysmemIndexBuffer) + _obj->indexOffset * indexSize, _obj->numInstances);
Jan Möbius's avatar
Jan Möbius committed
982
983
984
985
986
987
    }
  }
}

void IRenderer::renderObject(ACG::RenderObject* _obj, 
                                      GLSL::Program* _prog,
988
                                      bool _constRenderStates,
989
                                      const std::vector<unsigned int>* _shaderModifiers)
Jan Möbius's avatar
Jan Möbius committed
990
991
{
  // select shader from cache
992
  GLSL::Program* prog = _prog ? _prog : ACG::ShaderCache::getInstance()->getProgram(&_obj->shaderDesc, _shaderModifiers);
Jan Möbius's avatar
Jan Möbius committed
993
994
995
996
997
998


  bindObjectVBO(_obj, prog);

  // ---------------------------------------
  // set shader uniforms
999

Jan Möbius's avatar
Jan Möbius committed
1000
  bindObjectUniforms(_obj, prog);
1001

Jan Möbius's avatar
Jan Möbius committed
1002
  // render states
1003

Jan Möbius's avatar
Jan Möbius committed
1004
1005
  if (!_constRenderStates)
    bindObjectRenderStates(_obj);
1006

Jan Möbius's avatar
Jan Möbius committed
1007
1008
  // ----------------------------
  // OpenGL draw call
1009

Jan Möbius's avatar
Jan Möbius committed
1010
  drawObject(_obj);
1011

1012

Jan Möbius's avatar
Jan Möbius committed
1013
  ACG::glCheckErrors();
1014

1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
  if (_obj->vertexDecl)
  {
    // deactivate vertex declaration to avoid errors
    _obj->vertexDecl->deactivateShaderPipeline(prog);
  }


#ifdef GL_ARB_vertex_array_object
  if (_obj->vertexArrayObject)
    glBindVertexArray(0);
#endif
1026

Jan Möbius's avatar
Jan Möbius committed
1027
}
1028
1029


Jan Möbius's avatar
Jan Möbius committed
1030
1031
1032
void IRenderer::addLight(const LightData& _light)
{
  if (numLights_ < SG_MAX_SHADER_LIGHTS)
1033
1034
1035
1036
1037
1038
1039
1040
1041
  {
    lights_[numLights_] = _light;

    // normalize direction
    if (_light.ltype != SG_LIGHT_POINT)
      lights_[numLights_].dir.normalize();

    ++numLights_;
  }
Jan Möbius's avatar
Jan Möbius committed
1042
}
1043
1044


Jan Möbius's avatar
Jan Möbius committed
1045
1046
int IRenderer::getNumRenderObjects() const
{
1047
1048
  int n = 0;
  for (size_t i = 0; i < renderObjects_.size(); ++i)
1049
1050
    if (!renderObjects_[i].overlay && !(renderObjects_[i].isDefaultLineObject() && enableLineThicknessGL42_))
//    if (!renderObjects_[i].overlay)
1051
1052
1053
      ++n;

  return n;
Jan Möbius's avatar
Jan Möbius committed
1054
}
1055

1056
1057
1058
1059
1060
1061
1062
1063
1064
int IRenderer::getNumOverlayObjects() const
{
  int n = 0;
  for (size_t i = 0; i < renderObjects_.size(); ++i)
    if (renderObjects_[i].overlay)
      ++n;

  return n;
}
1065

1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
int IRenderer::getNumLineGL42Objects() const
{
  int n = 0;

  if (enableLineThicknessGL42_)
  {
    for (size_t i = 0; i < renderObjects_.size(); ++i)
      if (renderObjects_[i].isDefaultLineObject())
        ++n;
  }

  return n;
}

1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
int IRenderer::getNumLights() const
{
  return numLights_;
}


ACG::RenderObject* IRenderer::getRenderObject( int i )
{
  if (sortedObjects_.empty())
    return &renderObjects_[i];
  
  return sortedObjects_[i];
}

1094
1095
1096
1097
1098
1099
1100
1101
ACG::RenderObject* IRenderer::getOverlayRenderObject( int i )
{
  if (overlayObjects_.empty())
    return &renderObjects_[i];

  return overlayObjects_[i];
}

1102
1103
1104
1105
1106
1107
1108
1109
ACG::RenderObject* IRenderer::getLineGL42RenderObject( int i )
{
  if (lineGL42Objects_.empty())
    return 0;

  return lineGL42Objects_[i];
}

1110
1111
1112
1113
1114
1115
IRenderer::LightData* IRenderer::getLight( int i )
{
  return &lights_[i];
}


1116
void IRenderer::dumpRenderObjectsToFile(const char* _fileName, ACG::RenderObject** _sortedList) const
Jan Möbius's avatar
Jan Möbius committed
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
{
  QFile fileOut(_fileName);
  if (fileOut.open(QFile::WriteOnly | QFile::Truncate))
  {
    QTextStream outStrm(&fileOut);
    for (int i = 0; i < getNumRenderObjects(); ++i)
    {
      if (_sortedList)
        outStrm << "\n" << _sortedList[i]->toString();
      else
        outStrm << "\n" << renderObjects_[i].toString();
    }
1129

Jan Möbius's avatar
Jan Möbius committed
1130
1131
1132
    fileOut.close();
  }
}
1133
1134


1135
QString IRenderer::dumpCurrentRenderObjectsToString(ACG::RenderObject** _list, bool _outputShaders, std::vector<ACG::ShaderModifier*>* _modifiers) {
1136

1137
  QString objectString;
1138

1139
  QTextStream outStrm(&objectString);
1140

1141
1142
  for (int i = 0; i < getNumRenderObjects(); ++i)
  {
1143
1144
1145
1146
    const RenderObject* obj = _list ? _list[i] : &renderObjects_[i];

    if (obj) {
      outStrm << "\n" << obj->toString();
1147
1148
1149
1150
1151

      if ( _outputShaders ) {

        outStrm << "\n";

1152
        outStrm << obj->shaderDesc.toString();
1153

1154
        ShaderProgGenerator progGen(&(obj->shaderDesc), _modifiers);
1155
1156
1157
1158
1159
1160

        outStrm << "\n---------------------vertex-shader--------------------\n\n";
        for (int i = 0; i < progGen.getVertexShaderCode().size(); ++i)
          outStrm << progGen.getVertexShaderCode()[i] << "\n";
        outStrm << "\n---------------------end-vertex-shader--------------------\n\n";

1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
        if (progGen.hasTessControlShader())
        {
          outStrm << "\n---------------------tesscontrol-shader--------------------\n\n";
          for (int i = 0; i < progGen.getTessControlShaderCode().size(); ++i)
            outStrm << progGen.getTessControlShaderCode()[i] << "\n";
          outStrm << "\n---------------------end-tesscontrol-shader--------------------\n\n";
        }

        if (progGen.hasTessControlShader())
        {
          outStrm << "\n---------------------tesseval-shader--------------------\n\n";
          if (progGen.hasTessEvaluationShader())
            for (int i = 0; i < progGen.getTessEvaluationShaderCode().size(); ++i)
              outStrm << progGen.getTessEvaluationShaderCode()[i] << "\n";
          outStrm << "\n---------------------end-tesseval-shader--------------------\n\n";
        }

        if (progGen.hasGeometryShader())
        {
          outStrm << "\n---------------------geometry-shader--------------------\n\n";
1181
          for (int i = 0; i < progGen.getGeometryShaderCode().size(); ++i)
1182
            outStrm << progGen.getGeometryShaderCode()[i] << "\n";
1183
1184
          outStrm << "\n---------------------end-geometry-shader--------------------\n\n";
        }
1185
1186


1187
1188
1189
1190
1191
1192
        outStrm << "\n---------------------fragment-shader--------------------\n\n";
        for (int i = 0; i < progGen.getFragmentShaderCode().size(); ++i)
          outStrm << progGen.getFragmentShaderCode()[i] << "\n";
        outStrm << "\n---------------------end-fragment-shader--------------------\n\n";
      }

1193
    } 
1194

1195
  }
1196

1197
1198
  return objectString;
}
1199

1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
void IRenderer::copyDepthToBackBuffer( GLuint _depthTex, float _scale /*= 1.0f*/ )
{
  if (!_depthTex) return;

  if (!depthCopyShader_)
    depthCopyShader_ = GLSL::loadProgram("ScreenQuad/screenquad.glsl", "ScreenQuad/depth_copy.glsl");


  if (depthCopyShader_)
  {
    // save important opengl states
    GLint curFbo;
    GLint curViewport[4];
Christopher Tenter's avatar
Christopher Tenter committed
1213
1214
    GLint curDrawBuffer;
    saveActiveFbo(&curFbo, curViewport, &curDrawBuffer);
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249

    GLboolean colorMask[4], depthMask;
    glGetBooleanv(GL_COLOR_WRITEMASK, colorMask);
    glGetBooleanv(GL_DEPTH_WRITEMASK, &depthMask);

    GLboolean depthTestEnable;
    GLint depthFunc;
    glGetBooleanv(GL_DEPTH_TEST, &depthTestEnable);
    glGetIntegerv(GL_DEPTH_FUNC, &depthFunc);

    // write to depth buffer of input fbo
    restoreInputFbo();

    depthCopyShader_->use();
    depthCopyShader_->setUniform("offset", ACG::Vec2f(0.0f, 0.0f));
    depthCopyShader_->setUniform("size", ACG::Vec2f(1.0f, 1.0f));
    depthCopyShader_->setUniform("DepthTex", 0); // depth tex at texture slot 0
    depthCopyShader_->setUniform("DepthSign", _scale);

    // write to depth buffer only, disable writing to color buffer
    glColorMask(0,0,0,0);
    glDepthMask(1);

    // depth test enabled + pass always 
    glEnable(GL_DEPTH_TEST);
    glDepthFunc(GL_ALWAYS);

    glActiveTexture(GL_TEXTURE0);
    glBindTexture(GL_TEXTURE_2D, _depthTex);

    ACG::ScreenQuad::draw(depthCopyShader_);


    // restore important opengl states

Christopher Tenter's avatar
Christopher Tenter committed
1250
    restoreFbo(curFbo, curViewport, curDrawBuffer);
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263

    glColorMask(colorMask[0], colorMask[1], colorMask[2], colorMask[3]);
    glDepthMask(depthMask);

    if (!depthTestEnable)
      glDisable(GL_DEPTH_TEST);

    if (depthFunc != GL_ALWAYS)
      glDepthFunc(depthFunc);

    glBindTexture(GL_TEXTURE_2D, 0);
  }
}
1264

1265

1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
// depth map computation with a modifier

IRenderer::DepthMapPass IRenderer::DepthMapPass::instance;

void IRenderer::DepthMapPass::modifyFragmentEndCode(QStringList* _code)
{
  _code->push_back("outFragment = gl_FragCoord.zzzz;");
}

void IRenderer::renderDepthMap(int _viewerID, int _width, int _height)
{
  ACG::FBO* fbo = depthMaps_[_viewerID];

  // setup fbo for depth map
  if (!fbo)
  {
    fbo = depthMaps_[_viewerID] = new ACG::FBO();

    fbo->bind();
    fbo->attachTexture2D(GL_COLOR_ATTACHMENT0, _width, _height, GL_R32F, GL_RED);
    fbo->addDepthBuffer(_width, _height);
  }
  else
  {
    fbo->bind();
    fbo->resize(_width, _height);
  }

  // make sure modifier is registered
  ACG::ShaderProgGenerator::registerModifier(&DepthMapPass::instance);

  /* note: 
    It is possible to directly read the depth buffer if it was attached as a texture.
    Then, we would disable the color write mask and just write to the depth buffer in this function.

    However, doing this has shown that the actual depth values written to the depth buffer highly depend on the gpu driver.
    Or, at least sampling from a texture with format GL_DEPTH_COMPONENT returns driver dependent values.
    For instance, in the amd-gl driver sampling the depth texture returns the value of gl_FragDepth (as expected).
    But in the nvidia driver, sampling directly from the depth buffer returns something different!

    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.
  */

  fbo->bind();
  glDrawBuffer(GL_COLOR_ATTACHMENT0);
  glViewport(0, 0, _width, _height);

  // set depth to max
  glColorMask(1,1,1,1);
  glDepthMask(1);

  glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

  // render z-prepass
  for (int i = 0; i < getNumRenderObjects(); ++i)
  {
    RenderObject* obj = getRenderObject(i);

    if (obj->inZPrePass)
    {
      // apply depth map modifier to get the depth pass shader
      GLSL::Program* depthPassShader = ShaderCache::getInstance()->getProgram(&obj->shaderDesc, DepthMapPass::instance);

      // temporarily prevent read/write access to the same texture (the depth map)
      const char* depthMapUniformName = obj->depthMapUniformName;
      obj->depthMapUniformName = 0;

      if (depthMapUniformName)
      {
        depthPassShader->use();
        depthPassShader->setUniform(depthMapUniformName, 0);
        glActiveTexture(GL_TEXTURE0);
        glBindTexture(GL_TEXTURE_2D, 0);
      }

      // we are interested in the depth value only, so temporarily modify the write mask to allow writing to the red channel
      // (for instance, an object might not write a color value, but a depth value)
      const GLboolean redWriteMask = obj->colorWriteMask[0];
      obj->colorWriteMask[0] = obj->depthWrite;

      renderObject(obj, depthPassShader);

      // reset modified render object states
      obj->depthMapUniformName = depthMapUniformName;
      obj->colorWriteMask[0]= redWriteMask;
    }
  }

  // restore input fbo state

  fbo->unbind();

  restoreInputFbo();
}


void IRenderer::setViewerID(int _viewerID)
{
  curViewerID_ = _viewerID;
}


1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
void IRenderer::renderLineThicknessGL42()
{
#ifdef GL_ARB_shader_image_load_store
  // quad extrusion has depth clipping issue
  // GL4.2 method: manually rasterize thick lines into load/store texture, thereby avoiding clipping

  // experimental technique, needs some improvements for rasterization
  /* possible improvement: 
    0. init depth buffer with scene objects
    1. extract visible line object (startpos, endpos) into imageBuffer after depth-test in fragment shader
    1a. line segment id can be found via atomic counter in geometry shader
    1b. use imageAtomicMin/max to find start and end pixel pos of each line segment
         atomic ops work with uint only, thus each segment has 4 texels in the imageBuffer,  offsets are segmentID * 4 + {0,1,2,3}
    2. read imageBuffer in geometry shader and do usual quad extrusion, now without depth testing
        => get hw rasterization and msaa
  */

  //  using image2D does not work: texture always reads 0, even with glGetTexImage2D
  //  imageBuffer works
  //  - check with different gpu

  const int numLines = getNumLineGL42Objects();

  // configs
  const bool useBufferTexture = true;  // imageBuffer or image2D
  const bool useIntegerTexture = true; // color as R32U or RGBA32F



  if (numLines)
  {

    // macro configs for shader
    QStringList macros;

    if (useBufferTexture)
      macros.push_back("#define IMAGE_BUFFER");
    if (useIntegerTexture)
      macros.push_back("#define FMT_UINT");


    // get random access write buffer
    //  32bit uint per viewport pixel, stores rgba8
    Texture2D* lineColorImg2D = 0;
    TextureBuffer* lineColorImgBuf = 0;

    GLsizei w = prevViewport_[2], h = prevViewport_[3];
    GLsizei lineBPP = useIntegerTexture ? 4 : 16; // bytes per pixel


    if (useBufferTexture)
    {
      lineColorImgBuf = dynamic_cast<TextureBuffer*>(lineColorBuffers_[curViewerID_]);

      if (!lineColorImgBuf)
      {
        lineColorImgBuf = new TextureBuffer(GL_TEXTURE0);
        lineColorBuffers_[curViewerID_] = lineColorImgBuf;
      }

      // resize
      if (lineColorImgBuf->getBufferSize() != w * h * lineBPP)
        lineColorImgBuf->setBufferData(w*h*lineBPP, 0, GL_R32UI, GL_DYNAMIC_DRAW);
    }
    else
    {
      lineColorImg2D = dynamic_cast<Texture2D*>(lineColorBuffers_[curViewerID_]);

      if (!lineColorImg2D)
      {
        // allocate and store in map
        lineColorImg2D = new Texture2D(GL_TEXTURE0);
        lineColorBuffers_[curViewerID_] = lineColorImg2D;
      }

      // resize
      if (lineColorImg2D->getWidth() != w || lineColorImg2D->getHeight() != h)
        lineColorImg2D->setData(0,
          useIntegerTexture ? GL_R32UI : GL_RGBA32F,
          w, h, 
          useIntegerTexture ? GL_RED_INTEGER : GL_RGBA, 
          useIntegerTexture ? GL_UNSIGNED_INT : GL_FLOAT, 
          0);  
    }
    

    


    glViewport(0, 0, w, h);



    // ---------------------------
    //  clear line color buffer
1464

1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
    glColorMask(0,0,0,0);
    glDepthMask(0);
    glDisable(GL_DEPTH_TEST);

    // image binding is set to slot 0 in shader already
    if (useBufferTexture)
      lineColorImgBuf->bindAsImage(0, GL_WRITE_ONLY);
    else
      lineColorImg2D->bindAsImage(0, GL_WRITE_ONLY);

    GLSL::Program* shaderClear = ShaderCache::getInstance()->getProgram("ScreenQuad/screenquad.glsl", "Wireframe/gl42/clear.glsl", &macros);

    shaderClear->use();
//     shaderClear->setUniform("offset", Vec2f(0,0));
//     shaderClear->setUniform("size", Vec2f(1,1));
    shaderClear->setUniform("screenSize", Vec2f(w,h));

    ScreenQuad::draw(shaderClear);

    glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT | GL_SHADER_IMAGE_ACCESS_BARRIER_BIT);
//    GLDebug::dumpTexture2D(lineColorBuf->id(), 0, lineColorBuf->getFormat(), lineColorBuf->getType(), lineBPP*w*h, "c:/dbg/lines_clear.dds");
//    GLDebug::dumpBufferData(GL_TEXTURE_BUFFER, lineColorBuf2->getBufferId(), "c:/dbg/lines_clear.bin");

    // ---------------------------
    // 1. pass
    //  render into line color buffer via imageStore,

    for (int i = 0; i < numLines; ++i)
    {
      RenderObject* obj = getLineGL42RenderObject(i);

      renderObject(obj);
    }

    glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT | GL_SHADER_IMAGE_ACCESS_BARRIER_BIT);
//    GLDebug::dumpTexture2D(lineColorBuf->id(), 0, lineColorBuf->getFormat(), lineColorBuf->getType(), lineBPP*w*h, "c:/dbg/lines_image.dds");
//    GLDebug::dumpBufferData(GL_TEXTURE_BUFFER, lineColorBuf2->getBufferId(), "c:/dbg/lines_image.bin");


    // ---------------------------
    // 2. pass
    //  composition of line colors and fbo

    restoreInputFbo();

    // image binding is set to slot 0 in shader already
    if (useBufferTexture)
      lineColorImgBuf->bindAsImage(0, GL_READ_ONLY);
    else
      lineColorImg2D->bindAsImage(0, GL_READ_ONLY);


    glColorMask(1,1,1,1);
    glDisable(GL_DEPTH_TEST);

    // enable alpha blending
    glEnable(GL_BLEND);
1522
    ACG::GLState::blendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552

    GLSL::Program* shaderComposite = ShaderCache::getInstance()->getProgram("ScreenQuad/screenquad.glsl", "Wireframe/gl42/composite.glsl", &macros);

    shaderComposite->use();
//     shaderComposite->setUniform("offset", Vec2f(0,0));
//     shaderComposite->setUniform("size", Vec2f(1,1));
    shaderComposite->setUniform("screenSize", Vec2f(w,h));

    ScreenQuad::draw(shaderComposite);


  }
#endif
}

void IRenderer::setLineThicknessRenderingGL42( bool _enable )
{
  if (Texture::supportsImageLoadStore() && Texture::supportsTextureBuffer())
    enableLineThicknessGL42_ = _enable;
}

void IRenderer::setErrorDetectionLevel( int _level )
{
  errorDetectionLevel_ = std::max(_level, 0); // clamp to [0,n]
}

int IRenderer::getErrorDetectionLevel() const
{
  return errorDetectionLevel_;
}
1553

Jan Möbius's avatar
Jan Möbius committed
1554
1555
} // namespace ACG end