ShaderGenerator.cc 33.4 KB
Newer Older
1
2
3
4
5
6
7
8
9
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
39
40
41
42
/*===========================================================================*\
 *                                                                           *
 *                              OpenFlipper                                  *
 *      Copyright (C) 2001-2011 by Computer Graphics Group, RWTH Aachen      *
 *                           www.openflipper.org                             *
 *                                                                           *
 *---------------------------------------------------------------------------*
 *  This file is part of OpenFlipper.                                        *
 *                                                                           *
 *  OpenFlipper is free software: you can redistribute it and/or modify      *
 *  it under the terms of the GNU Lesser General Public License as           *
 *  published by the Free Software Foundation, either version 3 of           *
 *  the License, or (at your option) any later version with the              *
 *  following exceptions:                                                    *
 *                                                                           *
 *  If other files instantiate templates or use macros                       *
 *  or inline functions from this file, or you compile this file and         *
 *  link it with other files to produce an executable, this file does        *
 *  not by itself cause the resulting executable to be covered by the        *
 *  GNU Lesser General Public License. This exception does not however       *
 *  invalidate any other reasons why the executable file might be            *
 *  covered by the GNU Lesser General Public License.                        *
 *                                                                           *
 *  OpenFlipper is distributed in the hope that it will be useful,           *
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of           *
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the            *
 *  GNU Lesser General Public License for more details.                      *
 *                                                                           *
 *  You should have received a copy of the GNU LesserGeneral Public          *
 *  License along with OpenFlipper. If not,                                  *
 *  see <http://www.gnu.org/licenses/>.                                      *
 *                                                                           *
\*===========================================================================*/

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

Christopher Tenter's avatar
Christopher Tenter committed
43
#include "ShaderGenerator.hh"
44
45
#include <cstdio>
#include <cstring>
Christopher Tenter's avatar
Christopher Tenter committed
46
47
48
#include <iostream>
#include <algorithm>

49
#include <QFile>
50
51
#include <QFileInfo>
#include <QDir>
52
53
#include <QTextStream>

Christopher Tenter's avatar
Christopher Tenter committed
54
55
56
namespace ACG
{

57
#define LIGHTING_CODE_FILE "ShaderGen/SG_LIGHTING.GLSL"
Christopher Tenter's avatar
Christopher Tenter committed
58

Christopher Tenter's avatar
Christopher Tenter committed
59

60
61
62
63

int ShaderProgGenerator::numModifiers_ = 0;
ShaderModifier* ShaderProgGenerator::modifiers_[32] = {0};

Christopher Tenter's avatar
Christopher Tenter committed
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78


ShaderGenerator::ShaderGenerator()
{
  version_ = "#version 150"; 
}

ShaderGenerator::~ShaderGenerator()
{

}


void ShaderGenerator::initVertexShaderIO(const ShaderGenDesc* _desc)
{
79
80


Christopher Tenter's avatar
Christopher Tenter committed
81
  addInput("vec4 inPosition");
82
  addOutput("vec4 outVertexPosCS");
83

Christopher Tenter's avatar
Christopher Tenter committed
84
85
86
87

  if (_desc->shadeMode != SG_SHADE_UNLIT)
    addInput("vec3 inNormal");

88
  if (_desc->textured())
Christopher Tenter's avatar
Christopher Tenter committed
89
  {
90
91
92
93
94
95
96
97
98
99
100
101

    std::map<size_t,ShaderGenDesc::TextureType>::const_iterator iter = _desc->textureTypes().begin();

    /// TODO Setup for multiple texture coordinates as input
    if (iter->second.type == GL_TEXTURE_3D) {
      addInput("vec3 inTexCoord");
      addOutput("vec3 outVertexTexCoord");
    } else {
      addInput("vec2 inTexCoord");
      addOutput("vec2 outVertexTexCoord");
    }

Christopher Tenter's avatar
Christopher Tenter committed
102
103
104
105
106
107
108
  }
  if (_desc->vertexColors)
    addInput("vec4 inColor");


  if (_desc->shadeMode == SG_SHADE_PHONG)
  {
109
110
    addOutput("vec3 outVertexNormal");
    addOutput("vec4 outVertexPosVS");
Christopher Tenter's avatar
Christopher Tenter committed
111
112
113
114
115
  }


  std::string strColorOut = "";

Jan Möbius's avatar
Jan Möbius committed
116

Christopher Tenter's avatar
Christopher Tenter committed
117
  if (_desc->shadeMode == SG_SHADE_FLAT)
118
    if (_desc->geometryShader)
Jan Möbius's avatar
Jan Möbius committed
119
120
121
122
123
      strColorOut = "vec4 outVertexColor";
    else {
      // Bypass the output setter, as we have to set that directly with the flat.
      addStringToList("vec4 outVertexColor", &outputs_, "flat out ", ";");
    }
124
125
126
  else {
    if (_desc->shadeMode == SG_SHADE_GOURAUD || _desc->vertexColors)
      strColorOut = "vec4 outVertexColor";
Christopher Tenter's avatar
Christopher Tenter committed
127
128
129
130
131
132
  }

  if (strColorOut.size())
    addOutput(strColorOut.c_str());
}

133
134
void ShaderGenerator::initGeometryShaderIO(const ShaderGenDesc* _desc) {

135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
  // Define input of the geometry shader
  switch (_desc->geometryShaderInput) {
    case SG_GEOMETRY_IN_TRIANGLES: // 3 points of the triangle
      addStringToList("layout(triangles)", &inputs_, "", " in;");
      break;
    case SG_GEOMETRY_IN_TRIANGLES_ADJACENCY: // 6 points (defining 3 triangles , one before, current, one after)
      addStringToList("layout(triangles_adjacency)", &inputs_, "", " in;");
      break;
    case SG_GEOMETRY_IN_LINES: // 2 Points describing the line
      addStringToList("layout(lines)", &inputs_, "", " in;");
      break;
    case SG_GEOMETRY_IN_LINES_ADJACENCY: // 4 points ( 1 before, middle two defining line, last one
      addStringToList("layout(lines_adjacency)", &inputs_, "", " in;");
      break;
    case SG_GEOMETRY_IN_POINTS: // Single points
      addStringToList("layout(points)", &inputs_, "", " in;");
      break;
  }
153

154
155
156
157
158
159
160
161
162
163
164
165
  // Define output of geometry shader
  switch (_desc->geometryShaderOutput) {
    case SG_GEOMETRY_OUT_TRIANGLE_STRIP:
      addStringToList("layout(triangle_strip, max_vertices = "+ QString::number(_desc->geometryShaderMaxOutputPrimitives)+ ")", &outputs_, "", " out;");
      break;
    case SG_GEOMETRY_OUT_LINE_STRIP:
      addStringToList("layout(line_strip, max_vertices = "+ QString::number(_desc->geometryShaderMaxOutputPrimitives)+ ")", &outputs_, "", " out;");
      break;
    case SG_GEOMETRY_OUT_POINTS:
      addStringToList("layout(points, max_vertices = "+ QString::number(_desc->geometryShaderMaxOutputPrimitives)+ ")", &outputs_, "", " out;");
      break;
  }
166

167
168
169
  addInput("vec4 outVertexPosCS[]");
  addOutput("vec4 outGeometryPosCS");

170
  if (_desc->textured()) {
171
172
173
174
175
176
177
178
179
180
181
182
183

    std::map<size_t,ShaderGenDesc::TextureType>::const_iterator iter = _desc->textureTypes().begin();

    /// TODO Setup for multiple texture coordinates as input
    if (iter->second.type == GL_TEXTURE_3D)
    {
      addInput("vec3 outVertexTexCoord[]");
      addOutput("vec3 outGeometryTexCoord");
    } else {
      addInput("vec2 outVertexTexCoord[]");
      addOutput("vec2 outGeometryTexCoord");
    }

184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
  }


  if (_desc->shadeMode == SG_SHADE_PHONG)
  {
    addInput("vec3 outVertexNormal[]");
    addInput("vec4 outVertexPosVS[]");

    addOutput("vec3 outGeometryNormal");
    addOutput("vec4 outGeometryPosVS");
  }

  QString strColorOut = "";

  if (_desc->shadeMode == SG_SHADE_FLAT || _desc->shadeMode == SG_SHADE_GOURAUD || _desc->vertexColors) {
    addInput("vec4 outVertexColor[]");


    if (_desc->shadeMode == SG_SHADE_FLAT)
Jan Möbius's avatar
Jan Möbius committed
203
      addStringToList("vec4 outGeometryColor", &outputs_, "flat out ", ";");
204
205
206
207
208
    else {
      if (_desc->shadeMode == SG_SHADE_GOURAUD || _desc->vertexColors)
        strColorOut = "vec4 outGeometryColor";
    }

Jan Möbius's avatar
Jan Möbius committed
209
210
    if ( !strColorOut.isEmpty() )
      addOutput(strColorOut);
211
212
  }

213
214
}

Christopher Tenter's avatar
Christopher Tenter committed
215
216
217
218


void ShaderGenerator::initFragmentShaderIO(const ShaderGenDesc* _desc)
{
219
220
221
222
223
224
225

  QString inputShader = "Vertex";

  if ( _desc->geometryShader )
    inputShader = "Geometry";


226
227
228
229
230
231
232
233
234
235
236
237
  if (_desc->textured()) {

    std::map<size_t,ShaderGenDesc::TextureType>::const_iterator iter = _desc->textureTypes().begin();

    /// TODO Setup for multiple texture coordinates as input
    if (iter->second.type == GL_TEXTURE_3D) {
      addInput("vec3 out"+inputShader+"TexCoord");
    } else {
      addInput("vec2 out"+inputShader+"TexCoord");
    }

  }
Christopher Tenter's avatar
Christopher Tenter committed
238

239
  addInput("vec4 out"+inputShader+"PosCS");
Christopher Tenter's avatar
Christopher Tenter committed
240

241
  QString strColorIn = "";
Christopher Tenter's avatar
Christopher Tenter committed
242
243

  if (_desc->shadeMode == SG_SHADE_FLAT)
Jan Möbius's avatar
Jan Möbius committed
244
    addStringToList("vec4 out"+inputShader+"Color", &inputs_, "flat in ", ";");
Christopher Tenter's avatar
Christopher Tenter committed
245
246
247
248
  else
  {
    if (_desc->shadeMode == SG_SHADE_GOURAUD ||
      _desc->vertexColors)
249
      strColorIn = "vec4 out"+inputShader+"Color";
Christopher Tenter's avatar
Christopher Tenter committed
250
251
  }

252
253
  if (strColorIn.size())
    addInput(strColorIn);
Christopher Tenter's avatar
Christopher Tenter committed
254
255
256
257


  if (_desc->shadeMode == SG_SHADE_PHONG)
  {
258
259
    addInput("vec3 out"+inputShader+"Normal");
    addInput("vec4 out"+inputShader+"PosVS");
Christopher Tenter's avatar
Christopher Tenter committed
260
261
262
263
264
265
266
267
268
269
  }

  addOutput("vec4 outFragment");
}




void ShaderGenerator::initDefaultUniforms()
{
Jan Möbius's avatar
Jan Möbius committed
270
271
272
273
  addUniform("mat4 g_mWVP" , "  // Projection * Modelview");       // Transforms directly from Object space to NDC
  addUniform("mat4 g_mWV" , "   // Modelview matrix");             // Modelview transforms from Object to World to View coordinates
  addUniform("mat3 g_mWVIT" , " // Modelview inverse transposed"); // Modelview inverse transposed, transforms from view across World into Object coordinates
  addUniform("mat4 g_mP", "     // Projection matrix");            // Projection Matrix
Christopher Tenter's avatar
Christopher Tenter committed
274
275
276
277
278
279
280
281
282
283
284
285

  addUniform("vec3 g_vCamPos");
  addUniform("vec3 g_vCamDir");

  addUniform("vec3 g_cDiffuse");
  addUniform("vec3 g_cAmbient");
  addUniform("vec3 g_cEmissive");
  addUniform("vec3 g_cSpecular");
  addUniform("vec4 g_vMaterial");
}


286
#define ADDLIGHT(x) (sz.sprintf(x"_%d", lightIndex_), addUniform(sz))
Christopher Tenter's avatar
Christopher Tenter committed
287
288
289

void ShaderGenerator::addLight(int lightIndex_, ShaderGenLightType _light)
{
290
  QString sz;
Christopher Tenter's avatar
Christopher Tenter committed
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313

  ADDLIGHT("vec3 g_cLightDiffuse");
  ADDLIGHT("vec3 g_cLightAmbient");
  ADDLIGHT("vec3 g_cLightSpecular");

  if (_light == SG_LIGHT_POINT ||
    _light == SG_LIGHT_SPOT)
  {
    ADDLIGHT("vec3 g_vLightPos");
    ADDLIGHT("vec3 g_vLightAtten");
  }

  if (_light == SG_LIGHT_DIRECTIONAL ||
    _light == SG_LIGHT_SPOT)
    ADDLIGHT("vec3 g_vLightDir");


  if (_light == SG_LIGHT_SPOT)
    ADDLIGHT("vec2 g_vLightAngleExp");
}



314
void ShaderGenerator::addStringToList(QString _str, 
315
                                      QStringList* _arr,
Jan Möbius's avatar
Jan Möbius committed
316
317
                                      QString _prefix,
                                      QString _postfix)
Christopher Tenter's avatar
Christopher Tenter committed
318
{
Jan Möbius's avatar
Jan Möbius committed
319
320
  // Construct the whole string
  QString tmp = _prefix + _str + _postfix;
Christopher Tenter's avatar
Christopher Tenter committed
321
322
323

  // normalize string
  //  remove tabs, double whitespace
324
  tmp = tmp.simplified();
Christopher Tenter's avatar
Christopher Tenter committed
325
326

  // avoid duplicates
327
328
  if (!_arr->contains(tmp))
    _arr->push_back(tmp);
Christopher Tenter's avatar
Christopher Tenter committed
329
330
331
332

}


333
void ShaderGenerator::addInput(QString _input)
Christopher Tenter's avatar
Christopher Tenter committed
334
335
336
337
338
339
{
  addStringToList(_input, &inputs_, "in ", ";");
}



340
void ShaderGenerator::addOutput(QString _output)
Christopher Tenter's avatar
Christopher Tenter committed
341
342
343
344
345
{
  addStringToList(_output, &outputs_, "out ", ";");
}


346
void ShaderGenerator::addDefine(QString _def)
Christopher Tenter's avatar
Christopher Tenter committed
347
348
349
350
351
352
353
{
  addStringToList(_def, &genDefines_, "#define ");
}




Jan Möbius's avatar
Jan Möbius committed
354
void ShaderGenerator::addUniform(QString _uniform, QString _comment)
Christopher Tenter's avatar
Christopher Tenter committed
355
{
Jan Möbius's avatar
Jan Möbius committed
356
  addStringToList(_uniform, &uniforms_, "uniform ", "; " + _comment );
Christopher Tenter's avatar
Christopher Tenter committed
357
358
359
360
}



361
void ShaderGenerator::addIOToCode(const QStringList& _cmds)
Christopher Tenter's avatar
Christopher Tenter committed
362
{
363
364
  QString it;
  foreach(it, _cmds)
Christopher Tenter's avatar
Christopher Tenter committed
365
  {
366
    code_.push_back(it);
Christopher Tenter's avatar
Christopher Tenter committed
367
368
    // append ; eventually

369
    if (!it.contains(";"))
Christopher Tenter's avatar
Christopher Tenter committed
370
371
372
373
374
375
      code_.back().append(";");
  }
}



376
void ShaderGenerator::buildShaderCode(QStringList* _pMainCode)
Christopher Tenter's avatar
Christopher Tenter committed
377
378
379
380
{
  code_.push_back(version_);

  // provide defines
381
  QString it;
Christopher Tenter's avatar
Christopher Tenter committed
382

383
384
  foreach(it, genDefines_)
    code_.push_back(it);
Christopher Tenter's avatar
Christopher Tenter committed
385

386
387
388
  // provide imports
  foreach(it, imports_)
    code_.push_back(it);
Christopher Tenter's avatar
Christopher Tenter committed
389

390
  // IO
Christopher Tenter's avatar
Christopher Tenter committed
391
392
393
394
395
  addIOToCode(inputs_);
  addIOToCode(outputs_);
  addIOToCode(uniforms_);

  // main function
396
397
  foreach(it, (*_pMainCode))
    code_.push_back(it);
Christopher Tenter's avatar
Christopher Tenter committed
398
399
400
401
402
403


}



404
void ShaderGenerator::addIncludeFile(QString _fileName)
Christopher Tenter's avatar
Christopher Tenter committed
405
{
406
  QFile file(_fileName);
Christopher Tenter's avatar
Christopher Tenter committed
407

Christopher Tenter's avatar
Christopher Tenter committed
408
  if (file.open(QIODevice::ReadOnly | QIODevice::Text))
Christopher Tenter's avatar
Christopher Tenter committed
409
  {
Christopher Tenter's avatar
Christopher Tenter committed
410
411
412
413
414
    QTextStream fileStream(&file);

    while (!fileStream.atEnd())
    {
      QString tmpLine = fileStream.readLine();
Christopher Tenter's avatar
Christopher Tenter committed
415

Christopher Tenter's avatar
Christopher Tenter committed
416
417
      imports_.push_back(tmpLine.simplified());
    }
Christopher Tenter's avatar
Christopher Tenter committed
418
419
420
421
422
423
424
425
  }

}



void ShaderGenerator::saveToFile(const char* _fileName)
{
426
  QFile file(_fileName);
Christopher Tenter's avatar
Christopher Tenter committed
427
428
429
  if (file.open(QIODevice::WriteOnly | QIODevice::Text))
  {
    QTextStream fileStream(&file);
Christopher Tenter's avatar
Christopher Tenter committed
430

Christopher Tenter's avatar
Christopher Tenter committed
431
432
433
434
    QString it;
    foreach(it, code_)
      fileStream << it << '\n';
  }
Christopher Tenter's avatar
Christopher Tenter committed
435
436
437
438
}



439
const QStringList& ShaderGenerator::getShaderCode()
Christopher Tenter's avatar
Christopher Tenter committed
440
441
442
443
444
445
446
{
  return code_;
}




447
QString ShaderProgGenerator::shaderDir_;
448
QStringList ShaderProgGenerator::lightingCode_;
Christopher Tenter's avatar
Christopher Tenter committed
449

450
451
ShaderProgGenerator::ShaderProgGenerator(const ShaderGenDesc* _desc,
                                         unsigned int _usage)
452
: vertex_(0), geometry_(0), fragment_(0), usage_(_usage)
Christopher Tenter's avatar
Christopher Tenter committed
453
{
454
455
456
457
  if (shaderDir_.isEmpty())
    std::cout << "error: call ShaderProgGenerator::setShaderDir() first!" << std::endl;
  else
  {
458
    desc_ = *_desc;
Christopher Tenter's avatar
Christopher Tenter committed
459

460
461
    // We need at least version 3.2 or higher to support geometry shaders
    desc_.geometryShader &= ACG::openGLVersion(3,2);
462

463
    loadLightingFunctions();
Christopher Tenter's avatar
Christopher Tenter committed
464

465
466
    generateShaders();
  }
Christopher Tenter's avatar
Christopher Tenter committed
467
468
469
470
471
472
473
474
475
476
}

ShaderProgGenerator::~ShaderProgGenerator(void)
{
  delete vertex_;
  delete fragment_;
}



Christopher Tenter's avatar
Christopher Tenter committed
477
void ShaderProgGenerator::loadStringListFromFile(QString _fileName, QStringList* _out)
Christopher Tenter's avatar
Christopher Tenter committed
478
{
479
  QFile file(_fileName);
Christopher Tenter's avatar
Christopher Tenter committed
480

481
482
483
  file.open(QIODevice::ReadOnly | QIODevice::Text);

  if (!file.isReadable())
484
    std::cout << "error: file missing -> \"" << _fileName.toStdString() << "\"" << std::endl;
Christopher Tenter's avatar
Christopher Tenter committed
485
486
487

  else
  {
488
    QTextStream filestream(&file);
Christopher Tenter's avatar
Christopher Tenter committed
489

490
    while (!filestream.atEnd())
Christopher Tenter's avatar
Christopher Tenter committed
491
    {
492
493
      QString szLine = filestream.readLine();
      _out->push_back(szLine.trimmed());
Christopher Tenter's avatar
Christopher Tenter committed
494
495
496
497
498
499
500
501
502
503
    }
  }
}


void ShaderProgGenerator::loadLightingFunctions()
{
  if (lightingCode_.size()) return;

  // load shader code from file
504
  loadStringListFromFile(shaderDir_ + QDir::separator() + QString(LIGHTING_CODE_FILE), &lightingCode_);
Christopher Tenter's avatar
Christopher Tenter committed
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
}



void ShaderProgGenerator::initGenDefines(ShaderGenerator* _gen)
{
  switch (desc_.shadeMode)
  {
  case SG_SHADE_GOURAUD:
    _gen->addDefine("SG_GOURAUD 1"); break;
  case SG_SHADE_FLAT:
    _gen->addDefine("SG_FLAT 1"); break;
  case SG_SHADE_UNLIT:
    _gen->addDefine("SG_UNLIT 1"); break;
  case SG_SHADE_PHONG:
    _gen->addDefine("SG_PHONG 1"); break;

  default:
    std::cout << __FUNCTION__ << " -> unknown shade mode: " << desc_.shadeMode << std::endl;
  }

526
  if (desc_.textured())
Christopher Tenter's avatar
Christopher Tenter committed
527
528
529
530
531
    _gen->addDefine("SG_TEXTURED 1");

  if (desc_.vertexColors)
    _gen->addDefine("SG_VERTEX_COLOR 1");

532
533
534
  if (desc_.shadeMode != SG_SHADE_UNLIT)
    _gen->addDefine("SG_NORMALS 1");

Christopher Tenter's avatar
Christopher Tenter committed
535
  // # lights define
536
537
538
  QString strNumLights;
  strNumLights.sprintf("SG_NUM_LIGHTS %d", desc_.numLights);
  _gen->addDefine(strNumLights);
Christopher Tenter's avatar
Christopher Tenter committed
539
540
541
542
543
544
545
546
547
548
549

  // light types define
  const char* lightTypeNames[] = {"SG_LIGHT_DIRECTIONAL",
    "SG_LIGHT_POINT", "SG_LIGHT_SPOT"};

  for (int i = 0; i < 3; ++i)
    _gen->addDefine(lightTypeNames[i]);


  for (int i = 0; i < desc_.numLights; ++i)
  {
550
551
552
    QString strLightType;
    strLightType.sprintf("SG_LIGHT_TYPE_%d %s", i, lightTypeNames[desc_.lightTypes[i]]);
    _gen->addDefine(strLightType);
Christopher Tenter's avatar
Christopher Tenter committed
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
  }
}




void ShaderProgGenerator::buildVertexShader()
{
  delete vertex_;

  vertex_  = new ShaderGenerator();


//  vertex_->initDefaultVertexShaderIO();
  vertex_->initVertexShaderIO(&desc_);
568

Christopher Tenter's avatar
Christopher Tenter committed
569
570
  vertex_->initDefaultUniforms();

571
572
  vertex_->addUniform("float g_PointSize");

Christopher Tenter's avatar
Christopher Tenter committed
573

574
575
576
577
578
579
580
581
  // apply i/o modifiers
  for (int i = 0; i < numModifiers_; ++i)
  {
    if (usage_ & (1 << i))
      modifiers_[i]->modifyVertexIO(vertex_);
  }


Christopher Tenter's avatar
Christopher Tenter committed
582
583
584
585
  initGenDefines(vertex_);



586
  // IO
Christopher Tenter's avatar
Christopher Tenter committed
587
588
589
590
591
592
593
594
595
596
597

  // when to use vertex lights
  if (desc_.shadeMode == SG_SHADE_GOURAUD ||
    desc_.shadeMode == SG_SHADE_FLAT)
  {
    for (int i = 0; i < desc_.numLights; ++i)
      vertex_->addLight(i, desc_.lightTypes[i]);
  }


  // assemble main function
598
  QStringList mainCode;
Christopher Tenter's avatar
Christopher Tenter committed
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616

  addLightingFunctions(&mainCode);

  if (!vertexTemplate_.size())
  {
    mainCode.push_back("void main()");
    mainCode.push_back("{");

    addVertexBeginCode(&mainCode);
    addVertexEndCode(&mainCode);

    mainCode.push_back("}");
  }
  else
  {
    // interpret loaded shader template:
    //  import #includes and replace SG_VERTEX_BEGIN/END markers

617
618
    QString it;
    foreach(it,vertexTemplate_)
Christopher Tenter's avatar
Christopher Tenter committed
619
    {
620
      if (!checkForIncludes(it, vertex_, getPathName(vertexShaderFile_)))
Christopher Tenter's avatar
Christopher Tenter committed
621
622
623
624
      {
        // str line is no include directive
        // check for SG_ markers

625
        if (it.contains("SG_VERTEX_BEGIN"))
Christopher Tenter's avatar
Christopher Tenter committed
626
627
628
          addVertexBeginCode(&mainCode);
        else
        {
629
          if (it.contains("SG_VERTEX_END"))
Christopher Tenter's avatar
Christopher Tenter committed
630
631
632
633
            addVertexEndCode(&mainCode);
          else
          {
            // no SG marker
634
            mainCode.push_back(it);
Christopher Tenter's avatar
Christopher Tenter committed
635
636
637
638
639
640
641
642
643
644
645
646
647
          }
        }

      }
    }

  }

  vertex_->buildShaderCode(&mainCode);

}


648
void ShaderProgGenerator::addVertexBeginCode(QStringList* _code)
Christopher Tenter's avatar
Christopher Tenter committed
649
{
650
651
652
  // size in pixel of rendered point-lists, set by user via uniform
  _code->push_back("gl_PointSize = g_PointSize;");

Christopher Tenter's avatar
Christopher Tenter committed
653
654
655
  _code->push_back("vec4 sg_vPosPS = g_mWVP * inPosition;");
  _code->push_back("vec4 sg_vPosVS = g_mWV * inPosition;");
  _code->push_back("vec3 sg_vNormalVS = vec3(0.0, 1.0, 0.0);");
656
657

  /// TODO Setup for multiple texture coordinates as input
658
659
660
661
662
663
664
  if (desc_.textured())
  {
    if (desc_.textureTypes().begin()->second.type == GL_TEXTURE_3D) {
      _code->push_back("vec3 sg_vTexCoord = vec3(0.0, 0.0, 0.0);");
    } else {
      _code->push_back("vec2 sg_vTexCoord = vec2(0.0, 0.0);");
    }
665
666
  }

667
  _code->push_back("vec4 sg_cColor = vec4(g_cEmissive, ALPHA);");
Christopher Tenter's avatar
Christopher Tenter committed
668
669

  if (desc_.shadeMode != SG_SHADE_UNLIT)
670
    _code->push_back("sg_vNormalVS = normalize(g_mWVIT * inNormal);");
Christopher Tenter's avatar
Christopher Tenter committed
671

672
  if (desc_.textured())
Christopher Tenter's avatar
Christopher Tenter committed
673
674
675
676
677
678
679
680
681
682
683
684
685
686
    _code->push_back("sg_vTexCoord = inTexCoord;");

  if (desc_.vertexColors)
    _code->push_back("sg_cColor = inColor;");

  if (desc_.shadeMode == SG_SHADE_GOURAUD ||
    desc_.shadeMode == SG_SHADE_FLAT)
  {
    // add lighting code here

    addLightingCode(_code);
  }


687
688
689
690
691
692
693

  // apply modifiers
  for (int i = 0; i < numModifiers_; ++i)
  {
    if (usage_ & (1 << i))
      modifiers_[i]->modifyVertexBeginCode(_code);
  }
Christopher Tenter's avatar
Christopher Tenter committed
694
695
696
}


697
void ShaderProgGenerator::addVertexEndCode(QStringList* _code)
Christopher Tenter's avatar
Christopher Tenter committed
698
699
{
  _code->push_back("gl_Position = sg_vPosPS;");
700
  _code->push_back("outVertexPosCS = sg_vPosPS;");
Christopher Tenter's avatar
Christopher Tenter committed
701

702
  if (desc_.textured())
703
    _code->push_back("outVertexTexCoord = sg_vTexCoord;");
Christopher Tenter's avatar
Christopher Tenter committed
704
705
706
707

  if (desc_.shadeMode == SG_SHADE_GOURAUD ||
    desc_.shadeMode == SG_SHADE_FLAT ||
    desc_.vertexColors)
708
    _code->push_back("outVertexColor = sg_cColor;");
Christopher Tenter's avatar
Christopher Tenter committed
709
710
711

  if (desc_.shadeMode == SG_SHADE_PHONG)
  {
712
713
    _code->push_back("outVertexNormal = sg_vNormalVS;");
    _code->push_back("outVertexPosVS  = sg_vPosVS;");
Christopher Tenter's avatar
Christopher Tenter committed
714
  }
715
716
717
718
719
720
721
722
723



  // apply modifiers
  for (int i = 0; i < numModifiers_; ++i)
  {
    if (usage_ & (1 << i))
      modifiers_[i]->modifyVertexEndCode(_code);
  }
Christopher Tenter's avatar
Christopher Tenter committed
724
725
726
}


727
int ShaderProgGenerator::checkForIncludes(QString _str, ShaderGenerator* _gen, QString _includePath)
Christopher Tenter's avatar
Christopher Tenter committed
728
{
729
  if (_str.contains("#include "))
Christopher Tenter's avatar
Christopher Tenter committed
730
  {
731
    QString strIncludeFile = _str.remove("#include ").remove('\"').remove('<').remove('>').trimmed();
Christopher Tenter's avatar
Christopher Tenter committed
732

733
    if (strIncludeFile.isEmpty())
734
      std::cout << "wrong include syntax: " << _str.toStdString() << std::endl;
Christopher Tenter's avatar
Christopher Tenter committed
735
736
    else
    {
737
      QString fullPathToIncludeFile = _includePath + QDir::separator() + strIncludeFile;
Christopher Tenter's avatar
Christopher Tenter committed
738

739
      _gen->addIncludeFile(fullPathToIncludeFile);
Christopher Tenter's avatar
Christopher Tenter committed
740
741
742
743
744
745
746
747
    }

    return 1;
  }

  return 0;
}

748
749
void ShaderProgGenerator::buildGeometryShader()
{
750
751
752
753
  // Only build a geometry shader if enabled
  if ( !desc_.geometryShader )
    return;

754

755
756
757
  delete geometry_;

  geometry_  = new ShaderGenerator();
758
759
760

  geometry_->initGeometryShaderIO(&desc_);

Jan Möbius's avatar
Jan Möbius committed
761
762
  geometry_->initDefaultU