ShaderGenerator.cc 30.1 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->geometryTemplateFile.isEmpty())
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
  addInput("vec4 outVertexPosCS[]");
  addOutput("vec4 outGeometryPosCS");

138
  if (_desc->textured()) {
139
140
141
142
143
144
145
146
147
148
149
150
151

    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");
    }

152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
  }


  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
171
      addStringToList("vec4 outGeometryColor", &outputs_, "flat out ", ";");
172
173
174
175
176
    else {
      if (_desc->shadeMode == SG_SHADE_GOURAUD || _desc->vertexColors)
        strColorOut = "vec4 outGeometryColor";
    }

Jan Möbius's avatar
Jan Möbius committed
177
178
    if ( !strColorOut.isEmpty() )
      addOutput(strColorOut);
179
180
  }

181
182
}

Christopher Tenter's avatar
Christopher Tenter committed
183
184
185
186


void ShaderGenerator::initFragmentShaderIO(const ShaderGenDesc* _desc)
{
187
188
189

  QString inputShader = "Vertex";

190
  if ( !_desc->geometryTemplateFile.isEmpty() )
191
192
193
    inputShader = "Geometry";


194
195
196
197
198
199
200
201
202
203
204
205
  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
206

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

209
  QString strColorIn = "";
Christopher Tenter's avatar
Christopher Tenter committed
210
211

  if (_desc->shadeMode == SG_SHADE_FLAT)
Jan Möbius's avatar
Jan Möbius committed
212
    addStringToList("vec4 out"+inputShader+"Color", &inputs_, "flat in ", ";");
Christopher Tenter's avatar
Christopher Tenter committed
213
214
215
216
  else
  {
    if (_desc->shadeMode == SG_SHADE_GOURAUD ||
      _desc->vertexColors)
217
      strColorIn = "vec4 out"+inputShader+"Color";
Christopher Tenter's avatar
Christopher Tenter committed
218
219
  }

220
221
  if (strColorIn.size())
    addInput(strColorIn);
Christopher Tenter's avatar
Christopher Tenter committed
222
223
224
225


  if (_desc->shadeMode == SG_SHADE_PHONG)
  {
226
227
    addInput("vec3 out"+inputShader+"Normal");
    addInput("vec4 out"+inputShader+"PosVS");
Christopher Tenter's avatar
Christopher Tenter committed
228
229
230
231
232
233
234
235
236
237
  }

  addOutput("vec4 outFragment");
}




void ShaderGenerator::initDefaultUniforms()
{
Jan Möbius's avatar
Jan Möbius committed
238
239
240
241
  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
242
243
244
245
246
247
248
249
250
251
252
253

  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");
}


254
#define ADDLIGHT(x) (sz.sprintf(x"_%d", lightIndex_), addUniform(sz))
Christopher Tenter's avatar
Christopher Tenter committed
255
256
257

void ShaderGenerator::addLight(int lightIndex_, ShaderGenLightType _light)
{
258
  QString sz;
Christopher Tenter's avatar
Christopher Tenter committed
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281

  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");
}



282
void ShaderGenerator::addStringToList(QString _str, 
283
                                      QStringList* _arr,
Jan Möbius's avatar
Jan Möbius committed
284
285
                                      QString _prefix,
                                      QString _postfix)
Christopher Tenter's avatar
Christopher Tenter committed
286
{
Jan Möbius's avatar
Jan Möbius committed
287
288
  // Construct the whole string
  QString tmp = _prefix + _str + _postfix;
Christopher Tenter's avatar
Christopher Tenter committed
289
290
291

  // normalize string
  //  remove tabs, double whitespace
292
  tmp = tmp.simplified();
Christopher Tenter's avatar
Christopher Tenter committed
293
294

  // avoid duplicates
295
296
  if (!_arr->contains(tmp))
    _arr->push_back(tmp);
Christopher Tenter's avatar
Christopher Tenter committed
297
298
299
300

}


301
void ShaderGenerator::addInput(QString _input)
Christopher Tenter's avatar
Christopher Tenter committed
302
303
304
305
306
307
{
  addStringToList(_input, &inputs_, "in ", ";");
}



308
void ShaderGenerator::addOutput(QString _output)
Christopher Tenter's avatar
Christopher Tenter committed
309
310
311
312
313
{
  addStringToList(_output, &outputs_, "out ", ";");
}


314
void ShaderGenerator::addDefine(QString _def)
Christopher Tenter's avatar
Christopher Tenter committed
315
316
317
318
319
320
321
{
  addStringToList(_def, &genDefines_, "#define ");
}




Jan Möbius's avatar
Jan Möbius committed
322
void ShaderGenerator::addUniform(QString _uniform, QString _comment)
Christopher Tenter's avatar
Christopher Tenter committed
323
{
Jan Möbius's avatar
Jan Möbius committed
324
  addStringToList(_uniform, &uniforms_, "uniform ", "; " + _comment );
Christopher Tenter's avatar
Christopher Tenter committed
325
326
327
328
}



329
void ShaderGenerator::addIOToCode(const QStringList& _cmds)
Christopher Tenter's avatar
Christopher Tenter committed
330
{
331
332
  QString it;
  foreach(it, _cmds)
Christopher Tenter's avatar
Christopher Tenter committed
333
  {
334
    code_.push_back(it);
Christopher Tenter's avatar
Christopher Tenter committed
335
336
    // append ; eventually

337
    if (!it.contains(";"))
Christopher Tenter's avatar
Christopher Tenter committed
338
339
340
341
342
343
      code_.back().append(";");
  }
}



344
void ShaderGenerator::buildShaderCode(QStringList* _pMainCode)
Christopher Tenter's avatar
Christopher Tenter committed
345
346
347
348
{
  code_.push_back(version_);

  // provide defines
349
  QString it;
Christopher Tenter's avatar
Christopher Tenter committed
350

351
352
  foreach(it, genDefines_)
    code_.push_back(it);
Christopher Tenter's avatar
Christopher Tenter committed
353

354
355
356
  // provide imports
  foreach(it, imports_)
    code_.push_back(it);
Christopher Tenter's avatar
Christopher Tenter committed
357

358
  // IO
Christopher Tenter's avatar
Christopher Tenter committed
359
360
361
362
363
  addIOToCode(inputs_);
  addIOToCode(outputs_);
  addIOToCode(uniforms_);

  // main function
364
365
  foreach(it, (*_pMainCode))
    code_.push_back(it);
Christopher Tenter's avatar
Christopher Tenter committed
366
367
368
369
370
371


}



372
void ShaderGenerator::addIncludeFile(QString _fileName)
Christopher Tenter's avatar
Christopher Tenter committed
373
{
374
  QFile file(_fileName);
Christopher Tenter's avatar
Christopher Tenter committed
375

Christopher Tenter's avatar
Christopher Tenter committed
376
  if (file.open(QIODevice::ReadOnly | QIODevice::Text))
Christopher Tenter's avatar
Christopher Tenter committed
377
  {
Christopher Tenter's avatar
Christopher Tenter committed
378
379
380
381
382
    QTextStream fileStream(&file);

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

Christopher Tenter's avatar
Christopher Tenter committed
384
385
      imports_.push_back(tmpLine.simplified());
    }
Christopher Tenter's avatar
Christopher Tenter committed
386
387
388
389
390
391
392
393
  }

}



void ShaderGenerator::saveToFile(const char* _fileName)
{
394
  QFile file(_fileName);
Christopher Tenter's avatar
Christopher Tenter committed
395
396
397
  if (file.open(QIODevice::WriteOnly | QIODevice::Text))
  {
    QTextStream fileStream(&file);
Christopher Tenter's avatar
Christopher Tenter committed
398

Christopher Tenter's avatar
Christopher Tenter committed
399
400
401
402
    QString it;
    foreach(it, code_)
      fileStream << it << '\n';
  }
Christopher Tenter's avatar
Christopher Tenter committed
403
404
405
406
}



407
const QStringList& ShaderGenerator::getShaderCode()
Christopher Tenter's avatar
Christopher Tenter committed
408
409
410
411
412
413
414
{
  return code_;
}




415
QString ShaderProgGenerator::shaderDir_;
416
QStringList ShaderProgGenerator::lightingCode_;
Christopher Tenter's avatar
Christopher Tenter committed
417

418
419
ShaderProgGenerator::ShaderProgGenerator(const ShaderGenDesc* _desc,
                                         unsigned int _usage)
420
: vertex_(0), geometry_(0), fragment_(0), usage_(_usage)
Christopher Tenter's avatar
Christopher Tenter committed
421
{
422
423
424
425
  if (shaderDir_.isEmpty())
    std::cout << "error: call ShaderProgGenerator::setShaderDir() first!" << std::endl;
  else
  {
426
    desc_ = *_desc;
Christopher Tenter's avatar
Christopher Tenter committed
427

428
    // We need at least version 3.2 or higher to support geometry shaders
429
430
    if ( !ACG::openGLVersion(3,2) )
      desc_.geometryTemplateFile.clear();
431

432
    loadLightingFunctions();
Christopher Tenter's avatar
Christopher Tenter committed
433

434
435
    generateShaders();
  }
Christopher Tenter's avatar
Christopher Tenter committed
436
437
438
439
440
441
442
443
444
445
}

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



Christopher Tenter's avatar
Christopher Tenter committed
446
void ShaderProgGenerator::loadStringListFromFile(QString _fileName, QStringList* _out)
Christopher Tenter's avatar
Christopher Tenter committed
447
{
448
  QFile file(_fileName);
Christopher Tenter's avatar
Christopher Tenter committed
449

450
451
452
  file.open(QIODevice::ReadOnly | QIODevice::Text);

  if (!file.isReadable())
453
    std::cout << "error: file missing -> \"" << _fileName.toStdString() << "\"" << std::endl;
Christopher Tenter's avatar
Christopher Tenter committed
454
455
456

  else
  {
457
    QTextStream filestream(&file);
Christopher Tenter's avatar
Christopher Tenter committed
458

459
    while (!filestream.atEnd())
Christopher Tenter's avatar
Christopher Tenter committed
460
    {
461
462
      QString szLine = filestream.readLine();
      _out->push_back(szLine.trimmed());
Christopher Tenter's avatar
Christopher Tenter committed
463
464
465
466
467
468
469
470
471
472
    }
  }
}


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

  // load shader code from file
473
  loadStringListFromFile(shaderDir_ + QDir::separator() + QString(LIGHTING_CODE_FILE), &lightingCode_);
Christopher Tenter's avatar
Christopher Tenter committed
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
}



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;
  }

495
  if (desc_.textured())
Christopher Tenter's avatar
Christopher Tenter committed
496
497
498
499
500
    _gen->addDefine("SG_TEXTURED 1");

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

501
502
503
  if (desc_.shadeMode != SG_SHADE_UNLIT)
    _gen->addDefine("SG_NORMALS 1");

Christopher Tenter's avatar
Christopher Tenter committed
504
  // # lights define
505
506
507
  QString strNumLights;
  strNumLights.sprintf("SG_NUM_LIGHTS %d", desc_.numLights);
  _gen->addDefine(strNumLights);
Christopher Tenter's avatar
Christopher Tenter committed
508
509
510
511
512
513
514
515
516
517
518

  // 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)
  {
519
520
521
    QString strLightType;
    strLightType.sprintf("SG_LIGHT_TYPE_%d %s", i, lightTypeNames[desc_.lightTypes[i]]);
    _gen->addDefine(strLightType);
Christopher Tenter's avatar
Christopher Tenter committed
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
  }
}




void ShaderProgGenerator::buildVertexShader()
{
  delete vertex_;

  vertex_  = new ShaderGenerator();


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

Christopher Tenter's avatar
Christopher Tenter committed
538
539
540
  vertex_->initDefaultUniforms();


541
542
543
544
545
546
547
548
  // 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
549
550
551
552
  initGenDefines(vertex_);



553
  // IO
Christopher Tenter's avatar
Christopher Tenter committed
554
555
556
557
558
559
560
561
562
563
564

  // 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
565
  QStringList mainCode;
Christopher Tenter's avatar
Christopher Tenter committed
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583

  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

584
585
    QString it;
    foreach(it,vertexTemplate_)
Christopher Tenter's avatar
Christopher Tenter committed
586
    {
587
      if (!checkForIncludes(it, vertex_, getPathName(vertexShaderFile_)))
Christopher Tenter's avatar
Christopher Tenter committed
588
589
590
591
      {
        // str line is no include directive
        // check for SG_ markers

592
        if (it.contains("SG_VERTEX_BEGIN"))
Christopher Tenter's avatar
Christopher Tenter committed
593
594
595
          addVertexBeginCode(&mainCode);
        else
        {
596
          if (it.contains("SG_VERTEX_END"))
Christopher Tenter's avatar
Christopher Tenter committed
597
598
599
600
            addVertexEndCode(&mainCode);
          else
          {
            // no SG marker
601
            mainCode.push_back(it);
Christopher Tenter's avatar
Christopher Tenter committed
602
603
604
605
606
607
608
609
610
611
612
613
614
          }
        }

      }
    }

  }

  vertex_->buildShaderCode(&mainCode);

}


615
void ShaderProgGenerator::addVertexBeginCode(QStringList* _code)
Christopher Tenter's avatar
Christopher Tenter committed
616
{
617
618
  // size in pixel of rendered point-lists, set by user via uniform

Christopher Tenter's avatar
Christopher Tenter committed
619
620
621
  _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);");
622
623

  /// TODO Setup for multiple texture coordinates as input
624
625
626
627
628
629
630
  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);");
    }
631
632
  }

633
  _code->push_back("vec4 sg_cColor = vec4(g_cEmissive, ALPHA);");
Christopher Tenter's avatar
Christopher Tenter committed
634
635

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

638
  if (desc_.textured())
Christopher Tenter's avatar
Christopher Tenter committed
639
640
641
642
643
644
645
646
647
648
649
650
651
652
    _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);
  }


653
654
655
656
657
658
659

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


663
void ShaderProgGenerator::addVertexEndCode(QStringList* _code)
Christopher Tenter's avatar
Christopher Tenter committed
664
665
{
  _code->push_back("gl_Position = sg_vPosPS;");
666
  _code->push_back("outVertexPosCS = sg_vPosPS;");
Christopher Tenter's avatar
Christopher Tenter committed
667

668
  if (desc_.textured())
669
    _code->push_back("outVertexTexCoord = sg_vTexCoord;");
Christopher Tenter's avatar
Christopher Tenter committed
670
671
672
673

  if (desc_.shadeMode == SG_SHADE_GOURAUD ||
    desc_.shadeMode == SG_SHADE_FLAT ||
    desc_.vertexColors)
674
    _code->push_back("outVertexColor = sg_cColor;");
Christopher Tenter's avatar
Christopher Tenter committed
675
676
677

  if (desc_.shadeMode == SG_SHADE_PHONG)
  {
678
679
    _code->push_back("outVertexNormal = sg_vNormalVS;");
    _code->push_back("outVertexPosVS  = sg_vPosVS;");
Christopher Tenter's avatar
Christopher Tenter committed
680
  }
681
682
683
684
685
686
687
688
689



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


693
int ShaderProgGenerator::checkForIncludes(QString _str, ShaderGenerator* _gen, QString _includePath)
Christopher Tenter's avatar
Christopher Tenter committed
694
{
695
  if (_str.contains("#include "))
Christopher Tenter's avatar
Christopher Tenter committed
696
  {
697
    QString strIncludeFile = _str.remove("#include ").remove('\"').remove('<').remove('>').trimmed();
Christopher Tenter's avatar
Christopher Tenter committed
698

699
    if (strIncludeFile.isEmpty())
700
      std::cout << "wrong include syntax: " << _str.toStdString() << std::endl;
Christopher Tenter's avatar
Christopher Tenter committed
701
702
    else
    {
703
      QString fullPathToIncludeFile = _includePath + QDir::separator() + strIncludeFile;
Christopher Tenter's avatar
Christopher Tenter committed
704

705
      _gen->addIncludeFile(fullPathToIncludeFile);
Christopher Tenter's avatar
Christopher Tenter committed
706
707
708
709
710
711
712
713
    }

    return 1;
  }

  return 0;
}

714
715
void ShaderProgGenerator::buildGeometryShader()
{
716
  // Only build a geometry shader if enabled
717
  if ( desc_.geometryTemplateFile.isEmpty() )
718
719
    return;

720

721
722
723
  delete geometry_;

  geometry_  = new ShaderGenerator();
724
725
726

  geometry_->initGeometryShaderIO(&desc_);

Jan Möbius's avatar
Jan Möbius committed
727
728
  geometry_->initDefaultUniforms();

729
730
731
732
733
734
735
736
737
738

  // apply i/o modifiers
  for (int i = 0; i < numModifiers_; ++i)
  {
    if (usage_ & (1 << i))
      modifiers_[i]->modifyGeometryIO(fragment_);
  }


  // assemble main function
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
  QStringList mainCode; 

  // add simple io passthrough mapper

  {
    mainCode.push_back("void sg_MapIO(const int inIdx)");
    mainCode.push_back("{");

    mainCode.push_back("gl_Position = gl_in[inIdx].gl_Position;");
    mainCode.push_back("outGeometryPosCS = outVertexPosCS[inIdx];");

    if (desc_.textured())
      mainCode.push_back("outGeometryTexCoord = outVertexTexCoord[inIdx];");

    if (desc_.shadeMode == SG_SHADE_GOURAUD ||
        desc_.shadeMode == SG_SHADE_FLAT    ||
        desc_.vertexColors)
      mainCode.push_back("outGeometryColor = outVertexColor[inIdx];");

    if (desc_.shadeMode == SG_SHADE_PHONG) {
      mainCode.push_back("outGeometryNormal = outVertexNormal[inIdx];");
      mainCode.push_back("outGeometryPosVS  = outVertexPosVS[inIdx];");
    }

    mainCode.push_back("}");
  }
765

766

767
768
769
770
  // interpret loaded shader template:
  //  import #includes
  QString it;
  foreach(it,geometryTemplate_)
771
  {
772
    if (!checkForIncludes(it, geometry_, getPathName(geometryShaderFile_)))
773
    {
774
775
      // str line is no include directive
      mainCode.push_back(it);
776
777
778
779
780
781
782
    }
  }

  geometry_->buildShaderCode(&mainCode);
}


Christopher Tenter's avatar
Christopher Tenter committed
783
784
785
786
787
788
789
790
791
void ShaderProgGenerator::buildFragmentShader()
{
  delete fragment_;

  fragment_  = new ShaderGenerator();


  fragment_->initFragmentShaderIO(&desc_);

792

Christopher Tenter's avatar
Christopher Tenter committed
793
794
795
796
  fragment_->initDefaultUniforms();


  // texture sampler id
797
798
  if (desc_.textured())
  {
Jan Möbius's avatar
Jan Möbius committed
799
    for (std::map<size_t,ShaderGenDesc::TextureType>::const_iterator iter = desc_.textureTypes().begin();
800
801
802
803
804
805
806
807
808
        iter != desc_.textureTypes().end(); ++iter)
    {
      QString name = QString("g_Texture%1").arg(iter->first);
      QString type = "";
      switch (iter->second.type)
      {
        case GL_TEXTURE_1D: type = "sampler1D"; break;
        case GL_TEXTURE_2D: type = "sampler2D"; break;
        case GL_TEXTURE_3D: type = "sampler3D"; break;
809
        case GL_TEXTURE_CUBE_MAP: type = "samplerCube​"; break;
Matthias Möller's avatar
Matthias Möller committed
810
#if !defined(ARCH_DARWIN)
811
812
813
814
815
816
817
        case GL_TEXTURE_RECTANGLE: type = "sampler2DRect"; break;
        case GL_TEXTURE_BUFFER: type = "samplerBuffer​"; break;
        case GL_TEXTURE_1D_ARRAY: type = "sampler1DArray"; break;
        case GL_TEXTURE_2D_ARRAY: type = "sampler2DArray"; break;
        case GL_TEXTURE_CUBE_MAP_ARRAY: type = "samplerCubeArray"; break;
        case GL_TEXTURE_2D_MULTISAMPLE: type = "sampler2DMS"; break;
        case GL_TEXTURE_2D_MULTISAMPLE_ARRAY: type = "sampler2DMSArray​"; break;
818
#endif //defined(ARCH_DARWIN)
819
820
821
822
823
824
825
826
827

        default: std::cerr << "Texture Type not supported "<< iter->second.type << std::endl; break;
      }
      // todo: check if texture type supports shadowtype
      if (iter->second.shadow)
        type += "Shadow";
      fragment_->addUniform(type + " " + name);
    }
  }
Christopher Tenter's avatar
Christopher Tenter committed
828

829
830
831
832
833
834
835
  // apply i/o modifiers
  for (int i = 0; i < numModifiers_; ++i)
  {
    if (usage_ & (1 << i))
      modifiers_[i]->modifyFragmentIO(fragment_);
  }

Christopher Tenter's avatar
Christopher Tenter committed
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850

  initGenDefines(fragment_);



  // io

  // when to use fragment lights
  if (desc_.shadeMode == SG_SHADE_PHONG)
  {
    for (int i = 0; i < desc_.numLights; ++i)
      fragment_->addLight(i, desc_.lightTypes[i]);
  }

  // assemble main function
851
  QStringList mainCode;
Christopher Tenter's avatar
Christopher Tenter committed
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869

  addLightingFunctions(&mainCode);


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

    addFragmentBeginCode(&mainCode);
    addFragmentEndCode(&mainCode);

    mainCode.push_back("}");
  }
  else
  {
    // interpret loaded shader template:
    //  import #includes and replace SG_VERTEX_BEGIN/END markers
870
871
    QString it;
    foreach(it,fragmentTemplate_)
Christopher Tenter's avatar
Christopher Tenter committed
872
    {
873
      if (!checkForIncludes(it, fragment_, getPathName(fragmentShaderFile_)))
Christopher Tenter's avatar
Christopher Tenter committed
874
875
876
877
      {
        // str line is no include directive
        // check for SG_ markers

878
        if (it.contains("SG_FRAGMENT_BEGIN"))
Christopher Tenter's avatar
Christopher Tenter committed
879
880
881
          addFragmentBeginCode(&mainCode);
        else
        {
882
          if (it.contains("SG_FRAGMENT_END"))
Christopher Tenter's avatar
Christopher Tenter committed
883
884
885
886
            addFragmentEndCode(&mainCode);
          else
          {
            // no SG marker
887
            mainCode.push_back(it);
Christopher Tenter's avatar
Christopher Tenter committed
888
889
890
891
          }
        }

      }
892
893

      
Christopher Tenter's avatar
Christopher Tenter committed
894
895
896
897
898
899
900
901
902
903
    }

  }



  fragment_->buildShaderCode(&mainCode);
}


904
void ShaderProgGenerator::addFragmentBeginCode(QStringList* _code)
Christopher Tenter's avatar
Christopher Tenter committed
905
{
906
907
908

  QString inputShader = "Vertex";

909
  if ( !desc_.geometryTemplateFile.isEmpty() )
910
911
    inputShader = "Geometry";

912
  // support for projective texture mapping
913
  _code->push_back("vec2 sg_vScreenPos = out" + inputShader + "PosCS.xy / out" + inputShader + "PosCS.w * 0.5 + vec2(0.5, 0.5);");
914

915
  _code->push_back("vec4 sg_cColor = vec4(g_cEmissive, ALPHA);");
Christopher Tenter's avatar
Christopher Tenter committed
916
917

  if (desc_.shadeMode == SG_SHADE_GOURAUD ||
918
919
920
      desc_.shadeMode == SG_SHADE_FLAT    ||
      desc_.vertexColors)
  {
921
    _code->push_back("sg_cColor = out" + inputShader + "Color;");
922
  }
Christopher Tenter's avatar
Christopher Tenter committed
923
924
925
926


  if (desc_.shadeMode == SG_SHADE_PHONG)
  {
927
928
    _code->push_back("vec4 sg_vPosVS = out" + inputShader + "PosVS;");
    _code->push_back("vec3 sg_vNormalVS = out" + inputShader + "Normal;");
Christopher Tenter's avatar
Christopher Tenter committed
929
930
931
932

    addLightingCode(_code);
  }

933
  if (desc_.textured())
Christopher Tenter's avatar
Christopher Tenter committed
934
  {
Jan Möbius's avatar
Jan Möbius committed
935
    std::map<size_t,ShaderGenDesc::TextureType>::const_iterator iter = desc_.textureTypes().begin();
936
937
938
939
940
941
942
943
    _code->push_back("vec4 sg_cTex = texture(g_Texture"+QString::number(iter->first)+", out" + inputShader + "TexCoord);");

    for (++iter; iter != desc_.textureTypes().end(); ++iter)
      _code->push_back("sg_cTex += texture(g_Texture"+QString::number(iter->first)+", out" + inputShader + "TexCoord);");

    if (desc_.textureTypes().size() > 1 && desc_.normalizeTexColors)
      _code->push_back("sg_cTex = sg_cTex * 1.0/" + QString::number(desc_.textureTypes().size()) +".0 ;");

944
945
946
947
    if (desc_.shadeMode == SG_SHADE_UNLIT)
      _code->push_back("sg_cColor += sg_cTex;");
    else
      _code->push_back("sg_cColor *= sg_cTex;");
Christopher Tenter's avatar
Christopher Tenter committed
948
  }
949
950
951
952
953
954
955
956

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

959
void ShaderProgGenerator::addFragmentEndCode(QStringList* _code)
Christopher Tenter's avatar
Christopher Tenter committed
960
961
{
  _code->push_back("outFragment = sg_cColor;");
962
963
964
965
966
967
968

  // apply modifiers
  for (int i = 0; i < numModifiers_; ++i)
  {
    if (usage_ & (1 << i))
      modifiers_[i]->modifyFragmentEndCode(_code);
  }
Christopher Tenter's avatar
Christopher Tenter committed
969
970
971
972
}



973
void ShaderProgGenerator::addLightingCode(QStringList* _code)
Christopher Tenter's avatar
Christopher Tenter committed
974
{
975
  QString buf;
976
  
Christopher Tenter's avatar
Christopher Tenter committed
977
978
979
980
981
982
983
984
  for (int i = 0; i < desc_.numLights; ++i)
  {
    ShaderGenLightType lgt = desc_.lightTypes[i];


    switch (lgt)
    {
    case SG_LIGHT_DIRECTIONAL:
985
      buf.sprintf("sg_cColor.xyz += LitDirLight(sg_vPosVS.xyz, sg_vNormalVS, g_vLightDir_%d,  g_cLightAmbient_%d,  g_cLightDiffuse_%d,  g_cLightSpecular_%d);", i, i, i, i);
Christopher Tenter's avatar
Christopher Tenter committed
986
987
988
      break;

    case SG_LIGHT_POINT:
989
      buf.sprintf("sg_cColor.xyz += LitPointLight(sg_vPosVS.xyz, sg_vNormalVS,  g_vLightPos_%d,  g_cLightAmbient_%d,  g_cLightDiffuse_%d,  g_cLightSpecular_%d,  g_vLightAtten_%d);", i, i, i, i, i);
Christopher Tenter's avatar
Christopher Tenter committed
990
991
992
      break;

    case SG_LIGHT_SPOT:
993
      buf.sprintf("sg_cColor.xyz += LitSpotLight(sg_vPosVS.xyz,  sg_vNormalVS,  g_vLightPos_%d,  g_vLightDir_%d,  g_cLightAmbient_%d,  g_cLightDiffuse_%d,  g_cLightSpecular_%d,  g_vLightAtten_%d,  g_vLightAngleExp_%d);", i, i, i, i, i, i, i);
Christopher Tenter's avatar
Christopher Tenter committed
994
995
996
997
998
999
1000
      break;

    default: break;
    }

    _code->push_back(buf);
  }