Developer Documentation

- Main Page
- Related Pages
- Modules
- Namespaces
- Classes
- Files

- File List
- File Members

All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Modules Pages
ShaderGenerator.cc
1 /*===========================================================================*\
2 * *
3 * OpenFlipper *
4 * Copyright (c) 2001-2015, RWTH-Aachen University *
5 * Department of Computer Graphics and Multimedia *
6 * All rights reserved. *
7 * www.openflipper.org *
8 * *
9 *---------------------------------------------------------------------------*
10 * This file is part of OpenFlipper. *
11 *---------------------------------------------------------------------------*
12 * *
13 * Redistribution and use in source and binary forms, with or without *
14 * modification, are permitted provided that the following conditions *
15 * are met: *
16 * *
17 * 1. Redistributions of source code must retain the above copyright notice, *
18 * this list of conditions and the following disclaimer. *
19 * *
20 * 2. Redistributions in binary form must reproduce the above copyright *
21 * notice, this list of conditions and the following disclaimer in the *
22 * documentation and/or other materials provided with the distribution. *
23 * *
24 * 3. Neither the name of the copyright holder nor the names of its *
25 * contributors may be used to endorse or promote products derived from *
26 * this software without specific prior written permission. *
27 * *
28 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS *
29 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED *
30 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A *
31 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER *
32 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, *
33 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, *
34 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR *
35 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF *
36 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING *
37 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS *
38 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *
39 * *
40 \*===========================================================================*/
41
42 /*===========================================================================*\
43 * *
44 * $Revision$ *
45 * $Author$ *
46 * $Date$ *
47 * *
48 \*===========================================================================*/
49
50 #include "ShaderGenerator.hh"
51 #include <cstdio>
52 #include <iostream>
53
54 #include <QFile>
55 #include <QFileInfo>
56 #include <QDir>
57 #include <QTextStream>
58 #include <QDateTime>
59
60 namespace ACG
61 {
62
63
64 int ShaderProgGenerator::numRegisteredModifiers_ = 0;
65 std::vector<ShaderModifier*> ShaderProgGenerator::registeredModifiers_;
66
67
68
69 // space naming
70 // OS : object space
71 // VS : view space
72 // CS : clip space
73
74
75 ShaderGenerator::Keywords::Keywords()
76 // attribute request keywords
77 : macro_requestPosVS("#define SG_REQUEST_POSVS"),
78 macro_requestPosOS("#define SG_REQUEST_POSOS"),
79 macro_requestTexcoord("#define SG_REQUEST_TEXCOORD"),
80 macro_requestVertexColor("#define SG_REQUEST_VERTEXCOLOR"),
81 macro_requestNormalVS("#define SG_REQUEST_NORMALVS"),
82 macro_requestNormalOS("#define SG_REQUEST_NORMALOS"),
83 // // renormalize normal-vec before lighting in fragment shader
84 macro_requestRenormalize("#define SG_REQUEST_RENORMARLIZE"),
85
86 // generic default attribute input keywords
87 // these are extended by the correct input name by the generator for each stage
88 macro_inputPosVS("SG_INPUT_POSVS"),
89 macro_inputPosOS("SG_INPUT_POSOS"),
90 macro_inputPosCS("SG_INPUT_POSCS"),
91 macro_inputNormalVS("SG_INPUT_NORMALVS"),
92 macro_inputNormalOS("SG_INPUT_NORMALOS"),
93 macro_inputTexcoord("SG_INPUT_TEXCOORD"),
94 macro_inputVertexColor("SG_INPUT_VERTEXCOLOR"),
95
96 macro_outputPosVS("SG_OUTPUT_POSVS"),
97 macro_outputPosOS("SG_OUTPUT_POSOS"),
98 macro_outputPosCS("SG_OUTPUT_POSCS"),
99 macro_outputNormalVS("SG_OUTPUT_NORMALVS"),
100 macro_outputNormalOS("SG_OUTPUT_NORMALOS"),
101 macro_outputTexcoord("SG_OUTPUT_TEXCOORD"),
102 macro_outputVertexColor("SG_OUTPUT_VERTEXCOLOR"),
103
104 ioPosCS("PosCS"),
105 ioPosOS("PosOS"),
106 ioPosVS("PosVS"),
107 ioNormalVS("NormalVS"),
108 ioNormalOS("NormalOS"),
109 ioTexcoord("TexCoord"),
110 ioColor("Color"),
111
112 vs_inputPrefix("in"),
113 vs_outputPrefix("outVertex"),
114 tcs_outputPrefix("outTc"),
115 tes_outputPrefix("outTe"),
116 gs_outputPrefix("outGeometry"),
117 fs_outputPrefix("outFragment"),
118
119 vs_inputPosition(vs_inputPrefix + "Position"),
120 vs_inputNormal(vs_inputPrefix + "Normal"),
121 vs_inputTexCoord(vs_inputPrefix + ioTexcoord),
122 vs_inputColor(vs_inputPrefix + ioColor),
123
124 vs_outputPosCS(vs_outputPrefix + ioPosCS),
125 vs_outputPosVS(vs_outputPrefix + ioPosVS),
126 vs_outputPosOS(vs_outputPrefix + ioPosOS),
127 vs_outputTexCoord(vs_outputPrefix + ioTexcoord),
128 vs_outputNormalVS(vs_outputPrefix + ioNormalVS),
129 vs_outputNormalOS(vs_outputPrefix + ioNormalOS),
130 vs_outputVertexColor(vs_outputPrefix + ioColor),
131 fs_outputFragmentColor(fs_outputPrefix)
132 {
133 }
134
135 const ShaderGenerator::Keywords ShaderGenerator::keywords;
136
137
138 ShaderGenerator::ShaderGenerator()
139 : version_(150), inputArrays_(false), outputArrays_(false)
140 {
141 }
142
143 ShaderGenerator::~ShaderGenerator()
144 {
145
146 }
147
148
149 void ShaderGenerator::initVertexShaderIO(const ShaderGenDesc* _desc, const DefaultIODesc* _iodesc)
150 {
151 // set type of IO
152 inputArrays_ = false;
153 outputArrays_ = false;
154 inputPrefix_ = keywords.vs_inputPrefix; // inputs: inPosition, inTexCoord...
155 outputPrefix_ = keywords.vs_outputPrefix; // outputs: outVertexPosition, outVertexTexCoord..
156
157 addInput("vec4", keywords.vs_inputPosition);
158 addOutput("vec4", keywords.vs_outputPosCS);
159
160 if (_iodesc->inputNormal_)
161 addInput("vec3", keywords.vs_inputNormal);
162
163 if (_desc->textured())
164 {
165 std::map<size_t,ShaderGenDesc::TextureType>::const_iterator iter = _desc->textureTypes().begin();
166
168 if (iter->second.type == GL_TEXTURE_3D) {
169 addInput("vec3", keywords.vs_inputTexCoord);
170 addOutput("vec3", keywords.vs_outputTexCoord);
171 } else {
172 addInput("vec2", keywords.vs_inputTexCoord);
173 addOutput("vec2", keywords.vs_outputTexCoord);
174 }
175 }
176
177 if (_iodesc->inputColor_)
178 addInput("vec4", keywords.vs_inputColor);
179
180 if (_iodesc->passNormalVS_)
181 addOutput("vec3", keywords.vs_outputNormalVS);
182
183 if (_iodesc->passNormalOS_)
184 addOutput("vec3", keywords.vs_outputNormalOS);
185
186
187 // vertex color output
188
189 if (_desc->vertexColorsInterpolator.isEmpty())
190 {
191 QString strColorOut;
192 if (_desc->shadeMode == SG_SHADE_FLAT)
193 {
194 if (!_desc->geometryTemplateFile.isEmpty())
195 strColorOut = keywords.vs_outputVertexColor;
196 else
197 {
198 // Bypass the output setter, as we have to set that directly with the flat.
199 addStringToList("vec4 " + keywords.vs_outputVertexColor, &outputs_, "flat out ", "; ");
200 }
201 }
202 else if (_desc->shadeMode == SG_SHADE_GOURAUD || _desc->vertexColors || _iodesc->inputColor_)
203 strColorOut = keywords.vs_outputVertexColor;
204
205 if (strColorOut.size())
206 addOutput("vec4", strColorOut);
207 }
208 else
209 addStringToList("vec4 " + keywords.vs_outputVertexColor, &outputs_, _desc->vertexColorsInterpolator + " out ", ";");
210
211
212
213 // handle other requests: normals, positions, texcoords
214
215 if (_iodesc->passPosVS_)
216 addOutput("vec4", keywords.vs_outputPosVS);
217
218 if (_iodesc->passPosOS_)
219 addOutput("vec4", keywords.vs_outputPosOS);
220
221 if (_iodesc->passTexCoord_ && !_desc->textured())
222 {
223 // assume 2d texcoords as default
224 int texdim = 2;
225
226 if (_desc->texGenMode && _desc->texGenDim > 0 && _desc->texGenDim <= 4 && !_desc->texGenPerFragment)
227 texdim = _desc->texGenDim;
228
229 QString texcoordType;
230 if (texdim > 1)
231 texcoordType.sprintf("vec%i", texdim);
232 else
233 texcoordType = "float";
234
235 addInput(texcoordType, keywords.vs_inputTexCoord);
236 addOutput(texcoordType, keywords.vs_outputTexCoord);
237 }
238
239
240 defineIOAbstraction(_iodesc, true, false);
241 }
242
243 void ShaderGenerator::initTessControlShaderIO(const ShaderGenDesc* _desc, ShaderGenerator* _prevStage, const DefaultIODesc* _iodesc)
244 {
245 // set type of IO
246 inputArrays_ = true;
247 outputArrays_ = true;
248 inputPrefix_ = _prevStage->outputPrefix_;
249 outputPrefix_ = keywords.tcs_outputPrefix; // outputs: outTcPosition, outTcTexCoord..
250
251 matchInputs(_prevStage, true, inputPrefix_, outputPrefix_);
252
253 defineIOAbstraction(_iodesc, false, false);
254 }
255
256 void ShaderGenerator::initTessEvalShaderIO(const ShaderGenDesc* _desc, ShaderGenerator* _prevStage, const DefaultIODesc* _iodesc)
257 {
258 // set type of IO
259 inputArrays_ = true;
260 outputArrays_ = false;
261 inputPrefix_ = _prevStage->outputPrefix_;
262 outputPrefix_ = keywords.tes_outputPrefix; // outputs: outTePosition, outTeTexCoord..
263
264 matchInputs(_prevStage, true, inputPrefix_, outputPrefix_);
265
266 defineIOAbstraction(_iodesc, false, false);
267 }
268
269 void ShaderGenerator::initGeometryShaderIO(const ShaderGenDesc* _desc, ShaderGenerator* _prevStage, const DefaultIODesc* _iodesc)
270 {
271 // set type of IO
272 inputArrays_ = true;
273 outputArrays_ = false;
274 inputPrefix_ = _prevStage->outputPrefix_;
275 outputPrefix_ = keywords.gs_outputPrefix; // outputs: outGeometryPosition, outGeometryTexCoord..
276
277 matchInputs(_prevStage, true, inputPrefix_, outputPrefix_);
278
279 defineIOAbstraction(_iodesc, false, false);
280 }
281
282
283
284 void ShaderGenerator::initFragmentShaderIO(const ShaderGenDesc* _desc, ShaderGenerator* _prevStage, const DefaultIODesc* _iodesc)
285 {
286 // set type of IO
287 inputArrays_ = false;
288 outputArrays_ = false;
289 inputPrefix_ = _prevStage->outputPrefix_;
290 outputPrefix_ = keywords.fs_outputPrefix;
291
292 matchInputs(_prevStage, false);
293 addOutput("vec4", keywords.fs_outputFragmentColor);
294
295 defineIOAbstraction(_iodesc, false, true);
296 }
297
298
299 void ShaderGenerator::defineIOAbstraction( const DefaultIODesc* _iodesc, bool _vs, bool _fs )
300 {
301 if (_vs)
302 {
303 // input name abstraction
304
305 addIODefine(keywords.macro_inputPosOS, keywords.vs_inputPosition);
306
307 if (_iodesc->inputTexCoord_)
308 addIODefine(keywords.macro_inputTexcoord, keywords.vs_inputTexCoord);
309
310 if (_iodesc->inputNormal_)
311 addIODefine(keywords.macro_inputNormalOS, keywords.vs_inputNormal);
312
313 if (_iodesc->inputColor_)
314 addIODefine(keywords.macro_inputVertexColor, keywords.vs_inputColor);
315
316
317
318 // output name abstraction
319
320 addIODefine(keywords.macro_outputPosCS, keywords.vs_outputPosCS);
321
322 if (_iodesc->passPosVS_)
323 addIODefine(keywords.macro_outputPosVS, keywords.vs_outputPosVS);
324
325 if (_iodesc->passPosOS_)
326 addIODefine(keywords.macro_outputPosOS, keywords.vs_outputPosOS);
327
328 if (_iodesc->passTexCoord_)
329 addIODefine(keywords.macro_outputTexcoord, keywords.vs_outputTexCoord);
330
331 if (_iodesc->passNormalVS_)
332 addIODefine(keywords.macro_outputNormalVS, keywords.vs_outputNormalVS);
333
334 if (_iodesc->passNormalOS_)
335 addIODefine(keywords.macro_outputNormalOS, keywords.vs_outputNormalOS);
336
337 if (_iodesc->passColor_)
338 addIODefine(keywords.macro_outputVertexColor, keywords.vs_outputVertexColor);
339 }
340 else
341 {
342 if (_iodesc->passPosVS_)
343 {
344 addIODefine(keywords.macro_inputPosVS, inputPrefix_ + keywords.ioPosVS);
345 if (!_fs)
346 addIODefine(keywords.macro_outputPosVS, outputPrefix_ + keywords.ioPosVS);
347 }
348
349 if (_iodesc->passPosOS_)
350 {
351 addIODefine(keywords.macro_inputPosOS, inputPrefix_ + keywords.ioPosOS);
352 if (!_fs)
353 addIODefine(keywords.macro_outputPosOS, outputPrefix_ + keywords.ioPosOS);
354 }
355
356 addIODefine(keywords.macro_inputPosCS, inputPrefix_ + keywords.ioPosCS);
357 if (!_fs)
358 addIODefine(keywords.macro_outputPosCS, outputPrefix_ + keywords.ioPosCS);
359
360 if (_iodesc->passNormalVS_)
361 {
362 addIODefine(keywords.macro_inputNormalVS, inputPrefix_ + keywords.ioNormalVS);
363 if (!_fs)
364 addIODefine(keywords.macro_outputNormalVS, outputPrefix_ + keywords.ioNormalVS);
365 }
366
367 if (_iodesc->passNormalOS_)
368 {
369 addIODefine(keywords.macro_inputNormalOS, inputPrefix_ + keywords.ioNormalOS);
370 if (!_fs)
371 addIODefine(keywords.macro_outputNormalOS, outputPrefix_ + keywords.ioNormalOS);
372 }
373
374 if (_iodesc->passTexCoord_)
375 {
376 addIODefine(keywords.macro_inputTexcoord, inputPrefix_ + keywords.ioTexcoord);
377 if (!_fs)
378 addIODefine(keywords.macro_outputTexcoord, outputPrefix_ + keywords.ioTexcoord);
379 }
380
381 if (_iodesc->passColor_)
382 {
383 addIODefine(keywords.macro_inputVertexColor, inputPrefix_ + keywords.ioColor);
384 if (!_fs)
385 addIODefine(keywords.macro_outputVertexColor, outputPrefix_ + keywords.ioColor);
386 }
387 }
388
389
390 }
391
392
393
394 void ShaderGenerator::initDefaultUniforms()
395 {
396 addUniform("mat4 g_mWVP" , " // Projection * Modelview"); // Transforms directly from Object space to NDC
397 addUniform("mat4 g_mWV" , " // Modelview matrix"); // Modelview transforms from Object to World to View coordinates
398 addUniform("mat3 g_mWVIT" , " // Modelview inverse transposed"); // Modelview inverse transposed, transforms from view across World into Object coordinates
399 addUniform("mat4 g_mP", " // Projection matrix"); // Projection Matrix
400
401 addUniform("vec3 g_vCamPos");
402 addUniform("vec3 g_vCamDir");
403
404 addUniform("vec3 g_cDiffuse");
405 addUniform("vec3 g_cAmbient");
406 addUniform("vec3 g_cEmissive");
407 addUniform("vec3 g_cSpecular");
408 addUniform("vec4 g_vMaterial");
409 addUniform("vec3 g_cLightModelAmbient");
410 }
411
412
413 #define ADDLIGHT(x) (sz.sprintf(x"_%d", lightIndex_), addUniform(sz))
414
415 void ShaderGenerator::addLight(int lightIndex_, ShaderGenLightType _light)
416 {
417 QString sz;
418
419 ADDLIGHT("vec3 g_cLightDiffuse");
420 ADDLIGHT("vec3 g_cLightAmbient");
421 ADDLIGHT("vec3 g_cLightSpecular");
422
423 if (_light == SG_LIGHT_POINT ||
424 _light == SG_LIGHT_SPOT)
425 {
426 ADDLIGHT("vec3 g_vLightPos");
427 ADDLIGHT("vec3 g_vLightAtten");
428 }
429
430 if (_light == SG_LIGHT_DIRECTIONAL ||
431 _light == SG_LIGHT_SPOT)
432 ADDLIGHT("vec3 g_vLightDir");
433
434
435 if (_light == SG_LIGHT_SPOT)
436 ADDLIGHT("vec2 g_vLightAngleExp");
437 }
438
439
440
441 void ShaderGenerator::addStringToList(QString _str,
442 QStringList* _arr,
443 QString _prefix,
444 QString _postfix)
445 {
446 // Construct the whole string
447 QString tmp = _str;
448
449 if (!_str.startsWith(_prefix))
450 tmp = _prefix + tmp;
451
452 if (!_str.endsWith(_postfix))
453 tmp += _postfix;
454
455 // normalize string
456 // remove tabs, double whitespace
457 tmp = tmp.simplified();
458
459 // avoid duplicates
460 if (!_arr->contains(tmp))
461 _arr->push_back(tmp);
462
463 }
464
465
466 void ShaderGenerator::addInput(const QString& _input)
467 {
468 addStringToList(_input, &inputs_, "in ", ";");
469 }
470
471
472 void ShaderGenerator::addOutput(const QString& _output)
473 {
474 addStringToList(_output, &outputs_, "out ", ";");
475 }
476
477
478 void ShaderGenerator::addDefine(const QString& _def)
479 {
480 addStringToList(_def, &genDefines_, "#define ");
481 }
482
483
484 void ShaderGenerator::addIODefine(const QString& _macroName, const QString& _resolvedName)
485 {
486 addDefine(_macroName + QString(" ") + _resolvedName);
487 }
488
489 void ShaderGenerator::addMacros(const QStringList& _macros)
490 {
491 // prepend macros to the "defines" list
492
493 // QStringList reverse_iterator:
494 typedef std::reverse_iterator<QStringList::const_iterator> QStringListReverseIterator;
495 QStringListReverseIterator rbegin( _macros.end() ), rend( _macros.begin() );
496
497 for (QStringListReverseIterator it = rbegin; it != rend; ++it)
498 genDefines_.push_front(*it);
499 }
500
501 bool ShaderGenerator::hasDefine(QString _define) const
502 {
503 if (genDefines_.contains(_define))
504 return true;
505
506 // check trimmed strings and with startsWith()
507
508 QString trimmedDef = _define.trimmed();
509
510 for (QStringList::const_iterator it = genDefines_.constBegin(); it != genDefines_.constEnd(); ++it)
511 {
512 QString trimmedRef = it->trimmed();
513
514 if (trimmedRef.startsWith(trimmedDef))
515 return true;
516 }
517
518 // also check raw io blocks
519 for (QStringList::const_iterator it = rawIO_.constBegin(); it != rawIO_.constEnd(); ++it)
520 {
521 QString trimmedRef = it->trimmed();
522
523 if (trimmedRef.startsWith(trimmedDef))
524 return true;
525 }
526
527 return false;
528 }
529
530 void ShaderGenerator::addLayout(QString _def)
531 {
532 addStringToList(_def, &layouts_);
533 }
534
535
536 void ShaderGenerator::addUniform(QString _uniform, QString _comment)
537 {
538 QString prefix = "";
539 if (!_uniform.startsWith("uniform ") && !_uniform.contains(" uniform "))
540 prefix = "uniform ";
541
542 addStringToList(_uniform, &uniforms_, prefix, "; " + _comment );
543 }
544
545
546
547 void ShaderGenerator::addIOToCode(const QStringList& _cmds)
548 {
549 QString it;
550 foreach(it, _cmds)
551 {
552 code_.push_back(it);
553 // append ; eventually
554
555 if (!it.contains(";"))
556 code_.back().append(";");
557 }
558 }
559
560
561
562 void ShaderGenerator::buildShaderCode(QStringList* _pMainCode, const QStringList& _defaultLightingFunctions)
563 {
564 QString glslversion;
565 glslversion.sprintf("#version %d", version_);
566
567 code_.push_back(glslversion);
568
569 // provide defines
570 QString it;
571
572 foreach(it, genDefines_)
573 code_.push_back(it);
574
575 // layouts
576 foreach(it, layouts_)
577 code_.push_back(it);
578
579 // IO
580 addIOToCode(inputs_);
581 addIOToCode(outputs_);
582 addIOToCode(uniforms_);
583
584 // eventually attach lighting functions if required
585 bool requiresLightingCode = false;
586
587 // search for references in imports
588 foreach(it, imports_)
589 {
590 if (it.contains("LitDirLight") || it.contains("LitPointLight") || it.contains("LitSpotLight"))
591 requiresLightingCode = true;
592 }
593
594 if (requiresLightingCode)
595 {
596 foreach(it, _defaultLightingFunctions)
597 code_.push_back(it);
598 }
599
600 // provide imports
601 foreach(it, imports_)
602 code_.push_back(it);
603
604
605 // search for lighting references in main code
606
607 if (!requiresLightingCode)
608 {
609 foreach(it, (*_pMainCode))
610 {
611 if (it.contains("LitDirLight") || it.contains("LitPointLight") || it.contains("LitSpotLight"))
612 requiresLightingCode = true;
613 }
614
615 if (requiresLightingCode)
616 {
617 foreach(it, _defaultLightingFunctions)
618 code_.push_back(it);
619 }
620 }
621
622
623 // add raw IO code block
624 code_.append(rawIO_);
625
626
627 // main function
628 foreach(it, (*_pMainCode))
629 code_.push_back(it);
630 }
631
632
633
634 void ShaderGenerator::addIncludeFile(QString _fileName)
635 {
636 QFile file(_fileName);
637
638 if (file.open(QIODevice::ReadOnly | QIODevice::Text))
639 {
640 QTextStream fileStream(&file);
641
642 // track source of include files in shader comment
643
644 imports_.push_back("// ==============================================================================");
645 imports_.push_back(QString("// ShaderGenerator - begin of imported file: ") + _fileName);
646
647
648 while (!fileStream.atEnd())
649 {
650 QString tmpLine = fileStream.readLine();
651
652 imports_.push_back(tmpLine.simplified());
653 }
654
655
656 // mark end of include file in comment
657
658 imports_.push_back(QString("// ShaderGenerator - end of imported file #include \"") + _fileName);
659 imports_.push_back("// ==============================================================================");
660
661 }
662
663 }
664
665
666
667 void ShaderGenerator::saveToFile(const char* _fileName)
668 {
669 QFile file(_fileName);
670 if (file.open(QIODevice::WriteOnly | QIODevice::Text))
671 {
672 QTextStream fileStream(&file);
673
674 QString it;
675 foreach(it, code_)
676 fileStream << it << '\n';
677 }
678 }
679
680
681
682 const QStringList& ShaderGenerator::getShaderCode()
683 {
684 return code_;
685 }
686
687 void ShaderGenerator::setGLSLVersion( int _version )
688 {
689 version_ = _version;
690 }
691
692 void ShaderGenerator::matchInputs(const ShaderGenerator* _previousShaderStage,
693 bool _passToNextStage,
694 QString _inputPrefix,
695 QString _outputPrefix)
696 {
697 if (!_previousShaderStage)
698 {
699 std::cout << "error: ShaderGenerator::matchInputs called without providing input stage" << std::endl;
700 return;
701 }
702
703 QString it;
704 foreach(it, _previousShaderStage->outputs_)
705 {
706 QString input = it;
707
708 QString outKeyword = "out ";
709 QString inKeyword = "in ";
710
711 // replace first occurrence of "out" with "in"
712 input.replace(input.indexOf(outKeyword), outKeyword.size(), inKeyword);
713
714 // special case for array IO
715
716 if (inputArrays_ && !_previousShaderStage->outputArrays_)
717 {
718 QRegExp alphaNum("[a-zA-Z0-9]");
719 int lastNameChar = input.lastIndexOf(alphaNum);
720 input.insert(lastNameChar+1, "[]");
721 // input.insert(lastNameChar+1, "[gl_in.length()]");
722 }
723
724
725 // add to input list with duplicate check
726 addStringToList(input, &inputs_);
727
728 if (_passToNextStage)
729 {
730 // replace prefixes of in/outputs to avoid name collision
731
732 QString output = input;
733 output.replace(output.indexOf(_inputPrefix), _inputPrefix.size(), _outputPrefix);
734 output.replace(output.indexOf(inKeyword), inKeyword.size(), outKeyword);
735
736 // take care of arrays
737 if (inputArrays_ && !outputArrays_)
738 {
739 int bracketStart = output.indexOf("[");
740 int bracketEnd = output.indexOf("]");
741 output.remove(bracketStart, bracketEnd-bracketStart+1);
742 }
743 else if (!inputArrays_ && outputArrays_)
744 {
745 QRegExp alphaNum("[a-zA-Z0-9]");
746 int lastNameChar = output.lastIndexOf(alphaNum);
747 output.insert(lastNameChar+1, "[]");
748 // output.insert(lastNameChar+1, "[gl_in.length()]");
749 }
750
751
752 // add to output list with duplicate check
753 addStringToList(output, &outputs_);
754 }
755 }
756 }
757
758 int ShaderGenerator::getNumOutputs() const
759 {
760 return outputs_.size();
761 }
762
763 QString ShaderGenerator::getOutputName(int _id) const
764 {
765 QString output = outputs_.at(_id);
766
767 output.remove(";");
768 output.remove("out ");
769
770 int bracketStart = output.indexOf("[");
771 int bracketEnd = output.lastIndexOf("]");
772
773 if (bracketStart >= 0)
774 output.remove(bracketStart, bracketEnd-bracketStart+1);
775
776 // decompose output declaration
777 QStringList decompOutput = output.split(" ");
778 return decompOutput.last();
779 }
780
781 int ShaderGenerator::getNumInputs() const
782 {
783 return inputs_.size();
784 }
785
786 QString ShaderGenerator::getInputName(int _id) const
787 {
788 QString input = inputs_.at(_id);
789
790 input.remove(";");
791 input.remove("out ");
792
793 int bracketStart = input.indexOf("[");
794 int bracketEnd = input.lastIndexOf("]");
795
796 if (bracketStart >= 0)
797 input.remove(bracketStart, bracketEnd-bracketStart+1);
798
799 // decompose output declaration
800 QStringList decompInput = input.split(" ");
801 return decompInput.last();
802 }
803
804 QString ShaderGenerator::getIOMapName(int _inId) const
805 {
806 QString inputName = getInputName(_inId);
807
808 // output name = input name with swapped prefix
809 QString outputName = inputName;
810 outputName.replace(outputName.indexOf(inputPrefix_), inputPrefix_.size(), outputPrefix_);
811
812 return outputName;
813 }
814
815
816 ShaderGenerator::DefaultIODesc::DefaultIODesc()
817 : inputTexCoord_(false),
818 inputColor_(false),
819 inputNormal_(false),
820 passPosVS_(false), passPosOS_(false),
821 passTexCoord_(false),
822 passColor_(false),
823 passNormalVS_(false), passNormalOS_(false)
824 {
825 }
826
827
828
829
830 QString ShaderProgGenerator::shaderDir_;
831 QStringList ShaderProgGenerator::lightingCode_;
832
833
834 ShaderProgGenerator::ShaderProgGenerator( const ShaderGenDesc* _desc )
835 : vertex_(0), tessControl_(0), tessEval_(0), geometry_(0), fragment_(0), renormalizeLighting_(false)
836 {
837 init(_desc, (ShaderModifier**)0, 0);
838 }
839
840 ShaderProgGenerator::ShaderProgGenerator( const ShaderGenDesc* _desc, const unsigned int* _modifierIDs, unsigned int _numActiveMods )
841 : vertex_(0), tessControl_(0), tessEval_(0), geometry_(0), fragment_(0), renormalizeLighting_(false)
842 {
843 init(_desc, _modifierIDs, _numActiveMods);
844 }
845
846 ShaderProgGenerator::ShaderProgGenerator(const ShaderGenDesc* _desc, const std::vector<unsigned int>& _modifierIDs)
847 : vertex_(0), tessControl_(0), tessEval_(0), geometry_(0), fragment_(0), renormalizeLighting_(false)
848 {
849 init(_desc, _modifierIDs.empty() ? 0 : &_modifierIDs[0], (unsigned int)_modifierIDs.size());
850 }
851
852 ShaderProgGenerator::ShaderProgGenerator(const ShaderGenDesc* _desc, const std::vector<unsigned int>* _modifierIDs)
853 : vertex_(0), tessControl_(0), tessEval_(0), geometry_(0), fragment_(0), renormalizeLighting_(false)
854 {
855 unsigned int numMods = !_modifierIDs || _modifierIDs->empty() ? 0 : (unsigned int)_modifierIDs->size();
856 init(_desc, numMods ? &((*_modifierIDs)[0]) : 0, numMods);
857 }
858
859 ShaderProgGenerator::ShaderProgGenerator(const ShaderGenDesc* _desc, ShaderModifier* const* _modifiers, unsigned int _numActiveMods)
860 : vertex_(0), tessControl_(0), tessEval_(0), geometry_(0), fragment_(0), renormalizeLighting_(false)
861 {
862 init(_desc, _modifiers, _numActiveMods);
863 }
864
865 ShaderProgGenerator::ShaderProgGenerator(const ShaderGenDesc* _desc, const std::vector<ShaderModifier*>& _modifierIDs)
866 : vertex_(0), tessControl_(0), tessEval_(0), geometry_(0), fragment_(0), renormalizeLighting_(false)
867 {
868 init(_desc, _modifierIDs.empty() ? 0 : &(_modifierIDs[0]), (unsigned int)_modifierIDs.size());
869 }
870
871 ShaderProgGenerator::ShaderProgGenerator(const ShaderGenDesc* _desc, const std::vector<ShaderModifier*>* _modifierIDs)
872 : vertex_(0), tessControl_(0), tessEval_(0), geometry_(0), fragment_(0), renormalizeLighting_(false)
873 {
874 unsigned int numMods = !_modifierIDs || _modifierIDs->empty() ? 0 : (unsigned int)_modifierIDs->size();
875 init(_desc, numMods ? &((*_modifierIDs)[0]) : 0, numMods);
876 }
877
878
879 void ShaderProgGenerator::init( const ShaderGenDesc* _desc, const unsigned int* _modifierIDs, unsigned int _numActiveMods )
880 {
881 if (_modifierIDs && _numActiveMods)
882 {
883 activeMods_.resize(_numActiveMods);
884
885 for (unsigned int i = 0; i < _numActiveMods; ++i)
886 activeMods_[i] = registeredModifiers_[ _modifierIDs[i] ];
887 }
888
889 init(_desc, (ShaderModifier**)0, 0);
890 }
891
892 void ShaderProgGenerator::init( const ShaderGenDesc* _desc, ShaderModifier* const* _modifiers, unsigned int _numActiveMods )
893 {
894 if (_modifiers && _numActiveMods)
895 {
896 activeMods_.resize(_numActiveMods);
897
898 for (unsigned int i = 0; i < _numActiveMods; ++i)
899 activeMods_[i] = _modifiers[i];
900 }
901
902
903 if (shaderDir_.isEmpty())
904 std::cout << "error: call ShaderProgGenerator::setShaderDir() first!" << std::endl;
905 else
906 {
907 desc_ = *_desc;
908
909 // We need at least version 3.2 or higher to support geometry shaders
910 if ( !ACG::openGLVersion(3,2) )
911 {
912 if (!desc_.geometryTemplateFile.isEmpty())
913 std::cerr << "Warning: removing geometry shader from ShaderDesc" << std::endl;
914
915 desc_.geometryTemplateFile.clear();
916 }
917
918 // We need at least version 4.0 or higher to support tessellation
919 if ( !ACG::openGLVersion(4, 0) )
920 {
921 if (!desc_.tessControlTemplateFile.isEmpty() || !desc_.tessEvaluationTemplateFile.isEmpty())
922 std::cerr << "Warning: removing tessellation shader from ShaderDesc" << std::endl;
923
924 desc_.tessControlTemplateFile.clear();
925 desc_.tessEvaluationTemplateFile.clear();
926 }
927
928 // adjust glsl version to requirement
929
930 if (!desc_.geometryTemplateFile.isEmpty())
931 desc_.version = std::max(desc_.version, 150);
932
933 if (!desc_.tessControlTemplateFile.isEmpty() || !desc_.tessEvaluationTemplateFile.isEmpty())
934 desc_.version = std::max(desc_.version, 400);
935
936
937 loadLightingFunctions();
938
939 generateShaders();
940 }
941 }
942
943
944 ShaderProgGenerator::~ShaderProgGenerator(void)
945 {
946 delete vertex_;
947 delete fragment_;
948 delete geometry_;
949 delete tessControl_;
950 delete tessEval_;
951 }
952
953
954
955 bool ShaderProgGenerator::loadStringListFromFile(QString _fileName, QStringList* _out)
956 {
957 bool success = false;
958
959 QString absFilename = getAbsFilePath(_fileName);
960
961
962 QFile file(absFilename);
963
964 if (file.open(QIODevice::ReadOnly | QIODevice::Text))
965 {
966 if (!file.isReadable())
967 std::cout << "error: unreadable file -> \"" << absFilename.toStdString() << "\"" << std::endl;
968 else
969 {
970 QTextStream filestream(&file);
971
972 while (!filestream.atEnd())
973 {
974 QString szLine = filestream.readLine();
975 _out->push_back(szLine.trimmed());
976 }
977
978 success = true;
979 }
980
981 file.close();
982 }
983 else
984 std::cout << "error: " << file.errorString().toStdString() << " -> \"" << absFilename.toStdString() << "\"" << std::endl;
985
986 return success;
987 }
988
989
990 void ShaderProgGenerator::loadLightingFunctions()
991 {
992 if (lightingCode_.size()) return;
993
994 static const QString lightingCodeFile = "ShaderGen/SG_LIGHTING.GLSL";
995
996 QString fileName = shaderDir_ + QDir::separator() + QString(lightingCodeFile);
997
998 lightingCode_.push_back("// ==============================================================================");
999 lightingCode_.push_back(QString("// ShaderGenerator - default lighting functions imported from file: ") + fileName);
1000
1001
1002 // load shader code from file
1003 loadStringListFromFile(fileName, &lightingCode_);
1004
1005 lightingCode_.push_back(QString("// ShaderGenerator - end of default lighting functions"));
1006 lightingCode_.push_back("// ==============================================================================");
1007 }
1008
1009
1010
1011 void ShaderProgGenerator::initGenDefines(ShaderGenerator* _gen)
1012 {
1013 switch (desc_.shadeMode)
1014 {
1015 case SG_SHADE_GOURAUD:
1016 _gen->addDefine("SG_GOURAUD 1"); break;
1017 case SG_SHADE_FLAT:
1018 _gen->addDefine("SG_FLAT 1"); break;
1019 case SG_SHADE_UNLIT:
1020 _gen->addDefine("SG_UNLIT 1"); break;
1021 case SG_SHADE_PHONG:
1022 _gen->addDefine("SG_PHONG 1"); break;
1023
1024 default:
1025 std::cout << __FUNCTION__ << " -> unknown shade mode: " << desc_.shadeMode << std::endl;
1026 }
1027
1028 if (desc_.textured())
1029 _gen->addDefine("SG_TEXTURED 1");
1030
1031 if (desc_.vertexColors)
1032 _gen->addDefine("SG_VERTEX_COLOR 1");
1033
1034 // if (desc_.shadeMode != SG_SHADE_UNLIT)
1035 if (ioDesc_.passNormalVS_)
1036 _gen->addDefine("SG_NORMALS 1");
1037
1038 if (ioDesc_.passPosVS_)
1039 _gen->addDefine("SG_POSVS 1");
1040
1041 if (ioDesc_.passPosOS_)
1042 _gen->addDefine("SG_POSOS 1");
1043
1044 // # lights define
1045 QString strNumLights;
1046 strNumLights.sprintf("SG_NUM_LIGHTS %d", desc_.numLights);
1047 _gen->addDefine(strNumLights);
1048
1049 // light types define
1050 const char* lightTypeNames[] = {"SG_LIGHT_DIRECTIONAL",
1051 "SG_LIGHT_POINT", "SG_LIGHT_SPOT"};
1052
1053 for (int i = 0; i < 3; ++i)
1054 _gen->addDefine(lightTypeNames[i]);
1055
1056
1057 for (int i = 0; i < desc_.numLights; ++i)
1058 {
1059 QString strLightType;
1060 strLightType.sprintf("SG_LIGHT_TYPE_%d %s", i, lightTypeNames[desc_.lightTypes[i]]);
1061 _gen->addDefine(strLightType);
1062 }
1063
1064 _gen->addDefine("SG_ALPHA g_vMaterial.y");
1065
1066
1067 _gen->addMacros(desc_.macros);
1068 }
1069
1070
1071
1072
1073 void ShaderProgGenerator::buildVertexShader()
1074 {
1075 delete vertex_;
1076
1077 vertex_ = new ShaderGenerator();
1078 vertex_->setGLSLVersion(desc_.version);
1079
1080 vertex_->initVertexShaderIO(&desc_, &ioDesc_);
1081
1082 vertex_->initDefaultUniforms();
1083
1084
1085 if (desc_.texGenDim && (desc_.texGenMode == GL_OBJECT_LINEAR || desc_.texGenMode == GL_EYE_LINEAR) && !desc_.texGenPerFragment)
1086 {
1087 // application has to provide texture projection planes
1088 QString uniformDecl = "vec4 g_vTexGenPlane";
1089 if (desc_.texGenDim > 1)
1090 uniformDecl += "[" + QString::number(desc_.texGenDim) + "]";
1091 vertex_->addUniform(uniformDecl, " // texture projection planes");
1092 }
1093
1094
1095 // apply i/o modifiers
1096 for (size_t i = 0; i < activeMods_.size(); ++i)
1097 activeMods_[i]->modifyVertexIO(vertex_);
1098
1099
1100 initGenDefines(vertex_);
1101
1102
1103
1104 // IO
1105
1106 // when to use vertex lights
1107 if (desc_.shadeMode == SG_SHADE_GOURAUD ||
1108 desc_.shadeMode == SG_SHADE_FLAT)
1109 {
1110 for (int i = 0; i < desc_.numLights; ++i)
1111 vertex_->addLight(i, desc_.lightTypes[i]);
1112 }
1113
1114
1115 // assemble main function
1116 QStringList mainCode;
1117
1118 if (!vertexTemplate_.size())
1119 {
1120 mainCode.push_back("void main()");
1121 mainCode.push_back("{");
1122
1123 addVertexBeginCode(&mainCode);
1124 addVertexEndCode(&mainCode);
1125
1126 mainCode.push_back("}");
1127 }
1128 else
1129 {
1130 // interpret loaded shader template:
1131 // import #includes and replace SG_VERTEX_BEGIN/END markers
1132
1133 QString it;
1134 foreach(it,vertexTemplate_)
1135 {
1136 if (!checkForIncludes(it, vertex_, getPathName(vertexShaderFile_)))
1137 {
1138 // str line is no include directive
1139 // check for SG_ markers
1140
1141 if (it.contains("SG_VERTEX_BEGIN"))
1142 addVertexBeginCode(&mainCode);
1143 else
1144 {
1145 if (it.contains("SG_VERTEX_END"))
1146 addVertexEndCode(&mainCode);
1147 else
1148 {
1149 // no SG marker
1150 mainCode.push_back(it);
1151 }
1152 }
1153
1154 }
1155 }
1156
1157 }
1158
1159 vertex_->buildShaderCode(&mainCode, lightingCode_);
1160
1161 }
1162
1163
1164 void ShaderProgGenerator::addVertexBeginCode(QStringList* _code)
1165 {
1166 // size in pixel of rendered point-lists, set by user via uniform
1167
1168 _code->push_back(QString("vec4 sg_vPosPS = g_mWVP * ") + ShaderGenerator::keywords.macro_inputPosOS + QString(";"));
1169 _code->push_back("vec4 sg_vPosVS = g_mWV * inPosition;");
1170 _code->push_back("vec3 sg_vNormalVS = vec3(0.0, 1.0, 0.0);");
1171 _code->push_back("vec3 sg_vNormalOS = vec3(0.0, 1.0, 0.0);");
1172
1173 if (desc_.vertexColors && (desc_.colorMaterialMode == GL_AMBIENT || desc_.colorMaterialMode == GL_AMBIENT_AND_DIFFUSE))
1174 _code->push_back(QString("vec4 sg_cColor = vec4(g_cEmissive + g_cLightModelAmbient * ") + ShaderGenerator::keywords.macro_inputVertexColor + QString(".xyz, SG_ALPHA);"));
1175 else
1176 _code->push_back("vec4 sg_cColor = vec4(g_cEmissive + g_cLightModelAmbient * g_cAmbient, SG_ALPHA);");
1177
1178 if (ioDesc_.inputNormal_)
1179 {
1180 _code->push_back("sg_vNormalVS = normalize(g_mWVIT * inNormal);");
1181 _code->push_back("sg_vNormalOS = normalize(inNormal);");
1182 }
1183
1184 if (ioDesc_.inputColor_ && (desc_.shadeMode == SG_SHADE_UNLIT || desc_.colorMaterialMode == GL_EMISSION))
1185 _code->push_back(QString("sg_cColor = ") + ShaderGenerator::keywords.macro_inputVertexColor + QString(";"));
1186
1187 // texcoord generation
1188 addTexGenCode(_code, false);
1189
1190
1191 // apply modifiers
1192 for (size_t i = 0; i < activeMods_.size(); ++i)
1193 activeMods_[i]->modifyVertexBeginCode(_code);
1194 }
1195
1196
1197 void ShaderProgGenerator::addVertexEndCode(QStringList* _code)
1198 {
1199 if (desc_.shadeMode == SG_SHADE_GOURAUD ||
1200 desc_.shadeMode == SG_SHADE_FLAT)
1201 {
1202 // add lighting code here
1203
1204 addLightingCode(_code);
1205 }
1206
1207 _code->push_back("gl_Position = sg_vPosPS;");
1208 _code->push_back("outVertexPosCS = sg_vPosPS;");
1209
1210 if (ioDesc_.passTexCoord_)
1211 _code->push_back("outVertexTexCoord = sg_vTexCoord;");
1212
1213 if (ioDesc_.passColor_)
1214 _code->push_back("outVertexColor = sg_cColor;");
1215
1216 if (ioDesc_.passNormalVS_)
1217 _code->push_back(ShaderGenerator::keywords.macro_outputNormalVS + QString(" = sg_vNormalVS;"));
1218
1219 if (ioDesc_.passNormalOS_)
1220 _code->push_back(ShaderGenerator::keywords.macro_outputNormalOS + QString(" = sg_vNormalOS;"));
1221
1222 if (ioDesc_.passPosVS_)
1223 _code->push_back(ShaderGenerator::keywords.macro_outputPosVS + QString(" = sg_vPosVS;"));
1224
1225 if (ioDesc_.passPosOS_)
1226 _code->push_back(ShaderGenerator::keywords.macro_outputPosOS + QString(" = ") + ShaderGenerator::keywords.macro_inputPosOS + QString(";"));
1227
1228
1229
1230 // apply modifiers
1231 for (size_t i = 0; i < activeMods_.size(); ++i)
1232 activeMods_[i]->modifyVertexEndCode(_code);
1233 }
1234
1235
1236 int ShaderProgGenerator::checkForIncludes(QString _str, ShaderGenerator* _gen, QString _includePath)
1237 {
1238 if (_str.contains("#include "))
1239 {
1240 QString strIncludeFile = _str.remove("#include ").remove('\"').remove('<').remove('>').trimmed();
1241
1242 if (strIncludeFile.isEmpty())
1243 std::cout << "wrong include syntax: " << _str.toStdString() << std::endl;
1244 else
1245 {
1246 QString fullPathToIncludeFile = _includePath + QDir::separator() + strIncludeFile;
1247
1248 _gen->addIncludeFile(fullPathToIncludeFile);
1249 }
1250
1251 return 1;
1252 }
1253
1254 return 0;
1255 }
1256
1257 int ShaderProgGenerator::checkForIncludes(QString _str, QStringList* _outImport, QString _includePath)
1258 {
1259 if (_str.contains("#include "))
1260 {
1261 QString strIncludeFile = _str.remove("#include ").remove('\"').remove('<').remove('>').trimmed();
1262
1263 if (strIncludeFile.isEmpty())
1264 std::cout << "wrong include syntax: " << _str.toStdString() << std::endl;
1265 else
1266 {
1267 QString fullPathToIncludeFile = _includePath + QDir::separator() + strIncludeFile;
1268
1269 // unify separator chars
1270 fullPathToIncludeFile.replace('\\', '/');
1271
1272 // get rid of ".." usage inside shader includes
1273 QString cleanFilepath = QDir::cleanPath(fullPathToIncludeFile);
1274
1275 loadStringListFromFile(cleanFilepath, _outImport);
1276 }
1277
1278 return 1;
1279 }
1280
1281 return 0;
1282 }
1283
1284 void ShaderProgGenerator::buildTessControlShader()
1285 {
1286 // Only build a tess-control shader if enabled
1287 if ( desc_.tessControlTemplateFile.isEmpty() )
1288 return;
1289
1290 // the generator provides an IO mapping function and adds default uniforms to this stage
1291 // - template is necessary
1292 // - combination/modification of tess-control shader is not supported
1293 // - template may call sg_MapIO(inId) somewhere in code to take care of default IO pass-through
1294 // this function reads elements from gl_in[inID] and writes them to elements of gl_out[gl_InvocationID]
1295 // inId can be gl_InvocationID if the patch size is not modified
1296
1297 delete tessControl_;
1298
1299 tessControl_ = new ShaderGenerator();
1300 tessControl_->setGLSLVersion(desc_.version);
1301
1302 QString it;
1303 foreach(it, tessControlLayout_)
1304 tessControl_->addLayout(it);
1305
1306 // find previous shader stage
1307 ShaderGenerator* prevStage = vertex_;
1308
1309 tessControl_->initTessControlShaderIO(&desc_, prevStage, &ioDesc_);
1310
1311 tessControl_->initDefaultUniforms();
1312
1313
1314 // apply i/o modifiers
1315 for (size_t i = 0; i < activeMods_.size(); ++i)
1316 activeMods_[i]->modifyTessControlIO(tessControl_);
1317
1318 initGenDefines(tessControl_);
1319
1320
1321
1322 // assemble main function
1323 QStringList mainCode;
1324
1325 // add simple io passthrough mapper
1326
1327 {
1328 mainCode.push_back("void sg_MapIO(const int inIdx)");
1329 mainCode.push_back("{");
1330
1331 // built-in IO
1332 mainCode.push_back("gl_out[gl_InvocationID].gl_Position = gl_in[inIdx].gl_Position;");
1333
1334 // custom IO
1335 for (int i = 0; i < tessControl_->getNumInputs(); ++i)
1336 {
1337 QString inputName = tessControl_->getInputName(i);
1338 QString outputName = tessControl_->getIOMapName(i);
1339
1340 QString outputAssignCode = outputName + QString("[gl_InvocationID] = ") + inputName + QString("[inIdx];");
1341
1342 mainCode.push_back(outputAssignCode);
1343 }
1344
1345 mainCode.push_back("}");
1346 }
1347
1348
1349 // interpret loaded shader template:
1350 // import #includes
1351 foreach(it,tessControlTemplate_)
1352 {
1353 if (!checkForIncludes(it, tessControl_, getPathName(tessControlShaderFile_)))
1354 {
1355 // str line is no include directive
1356 mainCode.push_back(it);
1357 }
1358 }
1359
1360 tessControl_->buildShaderCode(&mainCode, lightingCode_);
1361 }
1362
1363 void ShaderProgGenerator::buildTessEvalShader()
1364 {
1365 // Only build a tess-eval shader if enabled
1366 if ( desc_.tessEvaluationTemplateFile.isEmpty() )
1367 return;
1368
1369 // the generator provides default interpolation functions and adds default uniforms to this stage
1370 // - template is necessary
1371 // - combination/modification of tess-eval shader is not supported
1372 // - template may call sg_MapIOBarycentric() or sg_MapIOBilinear() somewhere in code to take care of default IO pass-through
1373 // - barycentric interpolation can be used for triangle patches
1374 // - bilinear interpolation can be used for quad patches
1375 // - other interpolation schemes have to be user defined
1376
1377 delete tessEval_;
1378
1379 tessEval_ = new ShaderGenerator();
1380 tessEval_->setGLSLVersion(desc_.version);
1381
1382
1383 // find previous shader stage
1384 ShaderGenerator* prevStage = tessControl_;
1385
1386 if (!prevStage)
1387 prevStage = vertex_;
1388
1389 tessEval_->initTessEvalShaderIO(&desc_, prevStage, &ioDesc_);
1390
1391 tessEval_->initDefaultUniforms();
1392
1393 QString itLayout;
1394 foreach(itLayout, tessEvalLayout_)
1395 tessEval_->addLayout(itLayout);
1396
1397 // apply i/o modifiers
1398 for (size_t i = 0; i < activeMods_.size(); ++i)
1399 activeMods_[i]->modifyTessControlIO(tessEval_);
1400
1401 initGenDefines(tessEval_);
1402
1403
1404 // assemble main function
1405 QStringList mainCode;
1406
1407 // add simple io passthrough mapper
1408
1409 {
1410 // barycentric interpolation
1411
1412 mainCode.push_back("void sg_MapIOBarycentric()");
1413 mainCode.push_back("{");
1414
1415 // built-in IO
1416 mainCode.push_back("gl_Position = gl_TessCoord.x * gl_in[0].gl_Position + gl_TessCoord.y * gl_in[1].gl_Position + gl_TessCoord.z * gl_in[2].gl_Position;");
1417
1418 // custom IO
1419 for (int i = 0; i < tessEval_->getNumInputs(); ++i)
1420 {
1421 QString inputName = tessEval_->getInputName(i);
1422 QString outputName = tessEval_->getIOMapName(i);
1423
1424 QString outputAssignCode = outputName + QString(" = ") +
1425 QString("gl_TessCoord.x*") + inputName + QString("[0] + ") +
1426 QString("gl_TessCoord.y*") + inputName + QString("[1] + ") +
1427 QString("gl_TessCoord.z*") + inputName + QString("[2];");
1428
1429 mainCode.push_back(outputAssignCode);
1430 }
1431
1432 mainCode.push_back("}");
1433
1434
1435 // bilinear interpolation
1436
1437 mainCode.push_back("void sg_MapIOBilinear()");
1438 mainCode.push_back("{");
1439
1440 // built-in IO
1441 mainCode.push_back("gl_Position = mix( mix(gl_in[0].gl_Position, gl_in[1].gl_Position, gl_TessCoord.x), mix(gl_in[2].gl_Position, gl_in[3].gl_Position, gl_TessCoord.x), gl_TessCoord.y);");
1442
1443 // custom IO
1444 for (int i = 0; i < tessEval_->getNumInputs(); ++i)
1445 {
1446 QString inputName = tessEval_->getInputName(i);
1447 QString outputName = tessEval_->getIOMapName(i);
1448
1449 QString outputAssignCode = outputName + QString(" = mix( ") +
1450 QString("mix(") + inputName + QString("[0], ") + inputName + QString("[1], gl_TessCoord.x), ") +
1451 QString("mix(") + inputName + QString("[2], ") + inputName + QString("[3], gl_TessCoord.x), gl_TessCoord.y); ");
1452
1453 mainCode.push_back(outputAssignCode);
1454 }
1455
1456 mainCode.push_back("}");
1457 }
1458
1459
1460 // interpret loaded shader template:
1461 // replace (SG_INPUT, SG_OUTPUT) with matching io pairs
1462 QStringList::iterator it;
1463 for (it = tessEvalTemplate_.begin(); it != tessEvalTemplate_.end(); ++it)
1464 {
1465 QString line = *it;
1466
1467 // replace IO line matching the pattern:
1468 // SG_OUTPUT = r_expression(SG_INPUT);
1469 // the complete expression must be contained in a single line for this to work
1470 // more complex interpolation code should use #if SG_NORMALS etc.
1471
1472 if (line.contains("SG_INPUT") || line.contains("SG_OUTPUT"))
1473 {
1474
1475 QStringList resolvedCode;
1476
1477 resolvedCode.push_back("// ----------------------------------------");
1478 resolvedCode.push_back("// ShaderGen: resolve SG_OUTPUT = expression(SG_INPUT);");
1479
1480 int numOccurrences = 0;
1481
1482 for (int i = 0; i < tessEval_->getNumInputs(); ++i)
1483 {
1484 QString inputName = tessEval_->getInputName(i);
1485 QString outputName = tessEval_->getIOMapName(i);
1486
1487 // replace SG_INPUT, SG_OUTPUT with actual names
1488 QString resolvedLine = line;
1489
1490 // avoid confusion with SG_INPUT_NORMALVS etc. naming convention
1491 // resolvedLine.replace("SG_INPUT", inputName);
1492 // resolvedLine.replace("SG_OUTPUT", outputName);
1493 // fails to do this
1494
1495 // maybe this can be simplified with regexp
1496 // ie. replace SG_INPUT with inputName, but not SG_INPUTN, SG_INPUT_ ..
1497
1498 for (int k = 0; k < 2; ++k)
1499 {
1500 const QString stringToReplace = k ? "SG_OUTPUT" : "SG_INPUT";
1501 const int lenStringToReplace = stringToReplace.length();
1502 const QString replacementString = k ? outputName : inputName;
1503
1504 int linePos = resolvedLine.indexOf(stringToReplace);
1505
1506 while (linePos >= 0)
1507 {
1508 bool replaceOcc = true;
1509
1510 int nextCharPos = linePos + lenStringToReplace;
1511
1512 if (nextCharPos >= resolvedLine.size())
1513 nextCharPos = -1;
1514
1515 if (nextCharPos > 0)
1516 {
1517 QChar nextChar = resolvedLine.at(nextCharPos);
1518
1519 if (nextChar == '_' || nextChar.isDigit() || nextChar.isLetter())
1520 {
1521 // name token continues, this should not be replaced!
1522
1523 linePos += lenStringToReplace;
1524 replaceOcc = false;
1525 }
1526 }
1527
1528 // replace
1529
1530 if (replaceOcc)
1531 {
1532 resolvedLine.replace(linePos, lenStringToReplace, replacementString);
1533 ++numOccurrences;
1534 }
1535
1536 linePos = resolvedLine.indexOf(stringToReplace, linePos + 1);
1537 }
1538 }
1539
1540
1541
1542
1543
1544 resolvedCode.push_back(resolvedLine);
1545 }
1546
1547 resolvedCode.push_back("// ----------------------------------------");
1548
1549 if (numOccurrences)
1550 mainCode.append(resolvedCode);
1551 else
1552 mainCode.push_back(line); // nothing to replace in this line
1553 }
1554 else
1555 mainCode.push_back(line);
1556 }
1557
1558 tessEval_->buildShaderCode(&mainCode, lightingCode_);
1559 }
1560
1561 void ShaderProgGenerator::buildGeometryShader()
1562 {
1563 // Only build a geometry shader if enabled
1564 if ( desc_.geometryTemplateFile.isEmpty() )
1565 return;
1566
1567
1568 delete geometry_;
1569
1570 geometry_ = new ShaderGenerator();
1571 geometry_->setGLSLVersion(desc_.version);
1572
1573
1574 // find previous shader stage
1575 ShaderGenerator* prevStage = tessEval_;
1576
1577 if (!prevStage)
1578 prevStage = vertex_;
1579
1580 geometry_->initGeometryShaderIO(&desc_, prevStage, &ioDesc_);
1581
1582 geometry_->initDefaultUniforms();
1583
1584
1585 // apply i/o modifiers
1586 for (size_t i = 0; i < activeMods_.size(); ++i)
1587 activeMods_[i]->modifyGeometryIO(geometry_);
1588
1589 initGenDefines(geometry_);
1590
1591
1592 // assemble main function
1593 QStringList mainCode;
1594
1595 // add simple io passthrough mapper
1596
1597 {
1598 mainCode.push_back("void sg_MapIO(const int inIdx)");
1599 mainCode.push_back("{");
1600
1601 // built-in IO
1602 mainCode.push_back("gl_Position = gl_in[inIdx].gl_Position;");
1603 mainCode.push_back("gl_PrimitiveID = gl_PrimitiveIDIn;");
1604
1605 // custom IO
1606 for (int i = 0; i < geometry_->getNumInputs(); ++i)
1607 {
1608 QString inputName = geometry_->getInputName(i);
1609 QString outputName = geometry_->getIOMapName(i);
1610
1611 QString outputAssignCode = outputName + QString(" = ") + inputName + QString("[inIdx];");
1612
1613 mainCode.push_back(outputAssignCode);
1614 }
1615
1616 mainCode.push_back("}");
1617 }
1618
1619
1620 // interpret loaded shader template:
1621 // import #includes
1622 QString it;
1623 foreach(it,geometryTemplate_)
1624 {
1625 if (!checkForIncludes(it, geometry_, getPathName(geometryShaderFile_)))
1626 {
1627 // str line is no include directive
1628 mainCode.push_back(it);
1629 }
1630 }
1631
1632 geometry_->buildShaderCode(&mainCode, lightingCode_);
1633 }
1634
1635
1636 void ShaderProgGenerator::buildFragmentShader()
1637 {
1638 delete fragment_;
1639
1640 fragment_ = new ShaderGenerator();
1641 fragment_->setGLSLVersion(desc_.version);
1642
1643 // find previous shader stage
1644 ShaderGenerator* prevStage = geometry_;
1645
1646 if (!prevStage)
1647 prevStage = tessEval_;
1648 if (!prevStage)
1649 prevStage = tessControl_;
1650 if (!prevStage)
1651 prevStage = vertex_;
1652
1653
1654 fragment_->initFragmentShaderIO(&desc_, prevStage, &ioDesc_);
1655
1656 if (desc_.texGenDim && (desc_.texGenMode == GL_OBJECT_LINEAR || desc_.texGenMode == GL_EYE_LINEAR) && desc_.texGenPerFragment)
1657 {
1658 // application has to provide texture projection planes
1659 QString uniformDecl = "vec4 g_vTexGenPlane";
1660 if (desc_.texGenDim > 1)
1661 uniformDecl += "[" + QString::number(desc_.texGenDim) + "]";
1662 fragment_->addUniform(uniformDecl, " // texture projection planes");
1663 }
1664
1665
1666 fragment_->initDefaultUniforms();
1667
1668
1669 // texture sampler id
1670 if (desc_.textured())
1671 {
1672 for (std::map<size_t,ShaderGenDesc::TextureType>::const_iterator iter = desc_.textureTypes().begin();
1673 iter != desc_.textureTypes().end(); ++iter)
1674 {
1675 QString name = QString("g_Texture%1").arg(iter->first);
1676 QString type = "";
1677 switch (iter->second.type)
1678 {
1679 case GL_TEXTURE_1D: type = "sampler1D"; break;
1680 case GL_TEXTURE_2D: type = "sampler2D"; break;
1681 case GL_TEXTURE_3D: type = "sampler3D"; break;
1682 case GL_TEXTURE_CUBE_MAP: type = "samplerCube"; break;
1683 #ifdef GL_ARB_texture_rectangle //ARCH_DARWIN doesn't support all texture defines with all xcode version (xcode 5.0 seems to support all)
1684 case GL_TEXTURE_RECTANGLE_ARB: type = "sampler2DRect"; break;
1685 #endif
1686 #ifdef GL_ARB_texture_buffer_object
1687 case GL_TEXTURE_BUFFER_ARB: type = "samplerBuffer"; break;
1688 #endif
1689 #ifdef GL_EXT_texture_array
1690 case GL_TEXTURE_1D_ARRAY_EXT: type = "sampler1DArray"; break;
1691 case GL_TEXTURE_2D_ARRAY_EXT: type = "sampler2DArray"; break;
1692 #endif
1693 #ifdef GL_ARB_texture_cube_map_array
1694 case GL_TEXTURE_CUBE_MAP_ARRAY_ARB: type = "samplerCubeArray"; break;
1695 #endif
1696 #ifdef GL_ARB_texture_multisample
1697 case GL_TEXTURE_2D_MULTISAMPLE: type = "sampler2DMS"; break;
1698 case GL_TEXTURE_2D_MULTISAMPLE_ARRAY: type = "sampler2DMSArray"; break;
1699 #endif
1700 default: std::cerr << "Texture Type not supported "<< iter->second.type << std::endl; break;
1701 }
1702 // todo: check if texture type supports shadowtype
1703 if (iter->second.shadow)
1704 type += "Shadow";
1705 fragment_->addUniform(type + " " + name);
1706 }
1707 }
1708
1709 // apply i/o modifiers
1710 for (size_t i = 0; i < activeMods_.size(); ++i)
1711 activeMods_[i]->modifyFragmentIO(fragment_);
1712
1713
1714 initGenDefines(fragment_);
1715
1716
1717
1718 // io
1719
1720 // when to use fragment lights
1721 if (desc_.shadeMode == SG_SHADE_PHONG)
1722 {
1723 for (int i = 0; i < desc_.numLights; ++i)
1724 fragment_->addLight(i, desc_.lightTypes[i]);
1725 }
1726
1727 // assemble main function
1728 QStringList mainCode;
1729
1730 if (!fragmentTemplate_.size())
1731 {
1732 mainCode.push_back("void main()");
1733 mainCode.push_back("{");
1734
1735 addFragmentBeginCode(&mainCode);
1736 addFragmentEndCode(&mainCode);
1737
1738 mainCode.push_back("}");
1739 }
1740 else
1741 {
1742 // interpret loaded shader template:
1743 // import #includes and replace SG_VERTEX_BEGIN/END markers
1744 QString it;
1745 foreach(it,fragmentTemplate_)
1746 {
1747 if (!checkForIncludes(it, fragment_, getPathName(fragmentShaderFile_)))
1748 {
1749 // str line is no include directive
1750 // check for SG_ markers
1751
1752 if (it.contains("SG_FRAGMENT_BEGIN"))
1753 addFragmentBeginCode(&mainCode);
1754 else if (it.contains("SG_FRAGMENT_END"))
1755 addFragmentEndCode(&mainCode);
1756 else if (it.contains("SG_FRAGMENT_LIGHTING"))
1757 addLightingCode(&mainCode);
1758 else // no SG marker
1759 mainCode.push_back(it);
1760
1761 }
1762
1763
1764 }
1765
1766 }
1767
1768
1769
1770 fragment_->buildShaderCode(&mainCode, lightingCode_);
1771 }
1772
1773
1774 void ShaderProgGenerator::addFragmentBeginCode(QStringList* _code)
1775 {
1776 // support for projective texture mapping
1777 _code->push_back(QString("vec4 sg_vPosCS = ") + ShaderGenerator::keywords.macro_inputPosCS + QString(";"));
1778 _code->push_back("vec2 sg_vScreenPos = sg_vPosCS.xy / sg_vPosCS.w * 0.5 + vec2(0.5, 0.5);");
1779
1780 _code->push_back(QString("#ifdef ") + ShaderGenerator::keywords.macro_inputPosVS);
1781 _code->push_back(QString("vec4 sg_vPosVS = ") + ShaderGenerator::keywords.macro_inputPosVS + QString(";"));
1782 _code->push_back("#endif");
1783
1784 _code->push_back(QString("#ifdef ") + ShaderGenerator::keywords.macro_inputNormalVS);
1785 _code->push_back(QString("vec3 sg_vNormalVS = ") + ShaderGenerator::keywords.macro_inputNormalVS + QString(";"));
1786 if (renormalizeLighting_)
1787 _code->push_back("sg_vNormalVS = normalize(sg_vNormalVS);");
1788 _code->push_back("#endif");
1789
1790
1791 if (desc_.vertexColors && (desc_.colorMaterialMode == GL_AMBIENT || desc_.colorMaterialMode == GL_AMBIENT_AND_DIFFUSE))
1792 _code->push_back(QString("vec4 sg_cColor = vec4(g_cEmissive + g_cLightModelAmbient * ") + ShaderGenerator::keywords.macro_inputVertexColor + QString(".xyz, SG_ALPHA);"));
1793 else
1794 _code->push_back("vec4 sg_cColor = vec4(g_cEmissive + g_cLightModelAmbient * g_cAmbient, SG_ALPHA);");
1795
1796 if (desc_.shadeMode == SG_SHADE_GOURAUD ||
1797 desc_.shadeMode == SG_SHADE_FLAT ||
1798 (ioDesc_.passColor_ && (desc_.shadeMode == SG_SHADE_UNLIT || desc_.colorMaterialMode == GL_EMISSION)))
1799 _code->push_back(QString("sg_cColor = ") + ShaderGenerator::keywords.macro_inputVertexColor + QString(";"));
1800
1801 if (desc_.shadeMode == SG_SHADE_PHONG)
1802 addLightingCode(_code);
1803
1804
1805 addTexGenCode(_code, true);
1806
1807 if (desc_.textured())
1808 {
1809 std::map<size_t,ShaderGenDesc::TextureType>::const_iterator iter = desc_.textureTypes().begin();
1810 _code->push_back("vec4 sg_cTex = texture(g_Texture"+QString::number(iter->first)+", sg_vTexCoord);");
1811
1812 for (++iter; iter != desc_.textureTypes().end(); ++iter)
1813 _code->push_back("sg_cTex += texture(g_Texture"+QString::number(iter->first)+", sg_vTexCoord);");
1814
1815 if (desc_.textureTypes().size() > 1 && desc_.normalizeTexColors)
1816 _code->push_back("sg_cTex = sg_cTex * 1.0/" + QString::number(desc_.textureTypes().size()) +".0 ;");
1817
1818 if (desc_.shadeMode == SG_SHADE_UNLIT)
1819 _code->push_back("sg_cColor += sg_cTex;");
1820 else
1821 _code->push_back("sg_cColor *= sg_cTex;");
1822 }
1823
1824
1825 // apply modifiers
1826 for (size_t i = 0; i < activeMods_.size(); ++i)
1827 activeMods_[i]->modifyFragmentBeginCode(_code);
1828 }
1829
1830 void ShaderProgGenerator::addFragmentEndCode(QStringList* _code)
1831 {
1832 _code->push_back(ShaderGenerator::keywords.fs_outputFragmentColor + QString(" = sg_cColor;"));
1833
1834 // apply modifiers
1835 for (size_t i = 0; i < activeMods_.size(); ++i)
1836 activeMods_[i]->modifyFragmentEndCode(_code);
1837 }
1838
1839
1840
1841 void ShaderProgGenerator::addLightingCode(QStringList* _code)
1842 {
1843
1844 ShaderModifier* lightingModifier = 0;
1845
1846 // check if any modifier replaces the default lighting function
1847 for (size_t i = 0; i < activeMods_.size() && !lightingModifier; ++i)
1848 {
1849 if (activeMods_[i]->replaceDefaultLightingCode())
1850 lightingModifier = activeMods_[i];
1851 }
1852
1853 if (!lightingModifier)
1854 {
1855 // default lighting code:
1856
1857 QString buf;
1858
1859 QString vertexColorString = (ioDesc_.inputColor_ && ioDesc_.passColor_) ? (ShaderGenerator::keywords.macro_inputVertexColor + QString(".xyz * ")) : "";
1860 QString diffuseVertexColor = (desc_.colorMaterialMode == GL_DIFFUSE || desc_.colorMaterialMode == GL_AMBIENT_AND_DIFFUSE) ? vertexColorString : "";
1861 QString ambientVertexColor = (desc_.colorMaterialMode == GL_AMBIENT || desc_.colorMaterialMode == GL_AMBIENT_AND_DIFFUSE) ? vertexColorString : "";
1862 QString specularVertexColor = (desc_.colorMaterialMode == GL_SPECULAR) ? vertexColorString : "";
1863
1864 for (int i = 0; i < desc_.numLights; ++i)
1865 {
1866 ShaderGenLightType lgt = desc_.lightTypes[i];
1867
1868 switch (lgt)
1869 {
1870 case SG_LIGHT_DIRECTIONAL:
1871 // buf.sprintf("sg_cColor.xyz += LitDirLight(sg_vPosVS.xyz, sg_vNormalVS, g_vLightDir_%d, %s g_cLightAmbient_%d, %s g_cLightDiffuse_%d, %s g_cLightSpecular_%d);", i, ambientVertexColor, i, diffuseVertexColor, i, specularVertexColor, i);
1872 buf = QString("sg_cColor.xyz += LitDirLight(sg_vPosVS.xyz, sg_vNormalVS, g_vLightDir_%1, %2 g_cLightAmbient_%1, %3 g_cLightDiffuse_%1, %4 g_cLightSpecular_%1);").arg(QString::number(i), ambientVertexColor, diffuseVertexColor, specularVertexColor);
1873 break;
1874
1875 case SG_LIGHT_POINT:
1876 // buf.sprintf("sg_cColor.xyz += LitPointLight(sg_vPosVS.xyz, sg_vNormalVS, g_vLightPos_%d, %s g_cLightAmbient_%d, %s g_cLightDiffuse_%d, %s g_cLightSpecular_%d, g_vLightAtten_%d);", i, ambientVertexColor, i, diffuseVertexColor, i, specularVertexColor, i, i);
1877 buf = QString("sg_cColor.xyz += LitPointLight(sg_vPosVS.xyz, sg_vNormalVS, g_vLightPos_%1, %2 g_cLightAmbient_%1, %3 g_cLightDiffuse_%1, %4 g_cLightSpecular_%1, g_vLightAtten_%1);").arg(QString::number(i), ambientVertexColor, diffuseVertexColor, specularVertexColor);
1878 break;
1879
1880 case SG_LIGHT_SPOT:
1881 // buf.sprintf("sg_cColor.xyz += LitSpotLight(sg_vPosVS.xyz, sg_vNormalVS, g_vLightPos_%d, g_vLightDir_%d, %s g_cLightAmbient_%d, %s g_cLightDiffuse_%d, %s g_cLightSpecular_%d, g_vLightAtten_%d, g_vLightAngleExp_%d);", i, i, ambientVertexColor, i, diffuseVertexColor, i, specularVertexColor, i, i, i);
1882 buf = QString("sg_cColor.xyz += LitSpotLight(sg_vPosVS.xyz, sg_vNormalVS, g_vLightPos_%1, g_vLightDir_%1, %2 g_cLightAmbient_%1, %3 g_cLightDiffuse_%1, %4 g_cLightSpecular_%1, g_vLightAtten_%1, g_vLightAngleExp_%1);").arg(QString::number(i), ambientVertexColor, diffuseVertexColor, specularVertexColor);
1883 break;
1884
1885 default: break;
1886 }
1887
1888 _code->push_back(buf);
1889 }
1890
1891 // modify lighting color afterwards
1892
1893 for (size_t i = 0; i < activeMods_.size(); ++i)
1894 modifyLightingCode(_code, activeMods_[i]);
1895 }
1896 else
1897 {
1898 // there exists a lighting modifier that completely replaces the default lighting shader
1899 modifyLightingCode(_code, lightingModifier);
1900
1901
1902 // apply remaining modifiers that do not replace the complete lighting code
1903
1904 for (size_t i = 0; i < activeMods_.size(); ++i)
1905 {
1906 if (lightingModifier != activeMods_[i])
1907 modifyLightingCode(_code, activeMods_[i]);
1908 }
1909 }
1910
1911 }
1912
1913 void ShaderProgGenerator::modifyLightingCode( QStringList* _code, ShaderModifier* _modifier )
1914 {
1915 if (!_modifier) return;
1916
1917 for (int i = 0; i < desc_.numLights; ++i)
1918 {
1919 ShaderGenLightType lgt = desc_.lightTypes[i];
1920
1921 _modifier->modifyLightingCode(_code, i, lgt);
1922 }
1923 }
1924
1925
1926 void ShaderProgGenerator::addLightingFunctions(QStringList* _code)
1927 {
1928 QString it;
1929 foreach(it,lightingCode_)
1930 _code->push_back(it);
1931 }
1932
1933
1934 void ShaderProgGenerator::addTexGenCode( QStringList* _code, bool _fragmentShader )
1935 {
1936 // declare local texcoord variable name as "sg_vTexCoord"
1937 int texcoordVarDim = 2;
1938 if (ioDesc_.inputTexCoord_ &&
1939 !desc_.textureTypes().empty() &&
1940 desc_.textureTypes().begin()->second.type == GL_TEXTURE_3D)
1941 texcoordVarDim = 3;
1942
1943 bool generateTexCoord = desc_.texGenDim && desc_.texGenMode && (_fragmentShader == desc_.texGenPerFragment);
1944 if (generateTexCoord)
1945 texcoordVarDim = desc_.texGenDim;
1946
1947 QString texcoordVarInit;
1948 if (texcoordVarDim == 1)
1949 texcoordVarInit = "float sg_vTexCoord";
1950 else
1951 texcoordVarInit.sprintf("vec%i sg_vTexCoord", texcoordVarDim);
1952
1953 // init with default value: input or zero
1954 if (ioDesc_.inputTexCoord_ && !generateTexCoord)
1955 texcoordVarInit += QString("= ") + ShaderGenerator::keywords.macro_inputTexcoord + QString(";");
1956 else if (0 <= texcoordVarDim && texcoordVarDim <= 4)
1957 {
1958 QString zeroVecDefs[] =
1959 {
1960 ";",
1961 "= 0;",
1962 "= vec2(0,0);",
1963 "= vec3(0,0,0);",
1964 "= vec4(0,0,0,0);"
1965 };
1966 texcoordVarInit += zeroVecDefs[texcoordVarDim];
1967 }
1968
1969 _code->push_back(texcoordVarInit);
1970
1971
1972 // texcoord generation
1973 // https://www.opengl.org/wiki/Mathematics_of_glTexGen
1974 if (generateTexCoord)
1975 {
1976
1977 const char* texGenCoordString[] = { "x", "y", "z", "w" };
1978
1979 switch (desc_.texGenMode)
1980 {
1981 case GL_OBJECT_LINEAR:
1982 {
1983 for (int i = 0; i < desc_.texGenDim; ++i)
1984 {
1985 QString assignmentInstrString;
1986 assignmentInstrString = "sg_vTexCoord";
1987 if (desc_.texGenDim > 1)
1988 {
1989 assignmentInstrString +=".";
1990 assignmentInstrString += texGenCoordString[i];
1991 }
1992 assignmentInstrString += " = dot(";
1993 assignmentInstrString += ShaderGenerator::keywords.macro_inputPosOS;
1994 assignmentInstrString += ", g_vTexGenPlane";
1995 if (desc_.texGenDim > 1)
1996 {
1997 assignmentInstrString += "[";
1998 assignmentInstrString += QString::number(i);
1999 assignmentInstrString += "]";
2000 }
2001 assignmentInstrString += ");";
2002 _code->push_back(assignmentInstrString);
2003 }
2004 } break;
2005
2006 case GL_EYE_LINEAR:
2007 {
2008 for (int i = 0; i < desc_.texGenDim; ++i)
2009 {
2010 QString assignmentInstrString;
2011 assignmentInstrString = "sg_vTexCoord";
2012 if (desc_.texGenDim > 1)
2013 {
2014 assignmentInstrString += ".";
2015 assignmentInstrString += texGenCoordString[i];
2016 }
2017 assignmentInstrString += " = dot(sg_vPosVS, g_vTexGenPlane";
2018 if (desc_.texGenDim > 1)
2019 {
2020 assignmentInstrString += "[";
2021 assignmentInstrString += QString::number(i);
2022 assignmentInstrString += "]";
2023 }
2024 assignmentInstrString += ");";
2025 _code->push_back(assignmentInstrString);
2026 }
2027
2028 } break;
2029
2030 case GL_SPHERE_MAP:
2031 {
2032 _code->push_back("vec3 sg_vPosVS_unit = normalize(sg_vPosVS.xyz);");
2033 _code->push_back("vec3 sg_TexGenRefl = reflect(sg_vPosVS_unit, sg_vNormalVS);");
2034 _code->push_back("vec3 sg_TexGenRefl2 = sg_TexGenRefl; sg_TexGenRefl2.z += 1.0;");
2035 _code->push_back("float sg_TexGenMRcp = 0.5 * inversesqrt(dot(sg_TexGenRefl2, sg_TexGenRefl2));");
2036 for (int i = 0; i < desc_.texGenDim; ++i)
2037 {
2038 QString assignmentInstrString;
2039 assignmentInstrString.sprintf("sg_vTexCoord.%s = sg_TexGenRefl.%s * sg_TexGenMRcp + 0.5;", texGenCoordString[i], texGenCoordString[i]);
2040 _code->push_back(assignmentInstrString);
2041 }
2042 } break;
2043
2044 case GL_NORMAL_MAP:
2045 {
2046 for (int i = 0; i < desc_.texGenDim; ++i)
2047 {
2048 QString assignmentInstrString;
2049 assignmentInstrString.sprintf("sg_vTexCoord.%s = sg_vNormalVS.%s;", texGenCoordString[i], texGenCoordString[i]);
2050 _code->push_back(assignmentInstrString);
2051 }
2052 } break;
2053
2054 case GL_REFLECTION_MAP:
2055 {
2056 _code->push_back("vec3 sg_vPosVS_unit = normalize(sg_vPosVS.xyz);");
2057 _code->push_back("vec3 sg_TexGenRefl = reflect(sg_vPosVS_unit, sg_vNormalVS);");
2058 for (int i = 0; i < desc_.texGenDim; ++i)
2059 {
2060 QString assignmentInstrString;
2061 assignmentInstrString.sprintf("sg_vTexCoord.%s = sg_TexGenRefl.%s;", texGenCoordString[i], texGenCoordString[i]);
2062 _code->push_back(assignmentInstrString);
2063 }
2064 } break;
2065
2066 default: break;
2067 }
2068 }
2069 }
2070
2071
2072 void ShaderProgGenerator::generateShaders()
2073 {
2074 // import template source from files
2075 loadShaderTemplateFromFile();
2076
2077 // check what needs to be passed down from vertex shader
2078
2079 if (desc_.shadeMode != SG_SHADE_UNLIT)
2080 ioDesc_.inputNormal_ = true;
2081
2082 if (desc_.textured())
2083 {
2084 ioDesc_.inputTexCoord_ = true;
2085 ioDesc_.passTexCoord_ = true;
2086 }
2087
2088 // clamp generated texcoord dimension
2089 int maxTexGenDim = 4;
2090
2091 switch (desc_.texGenMode)
2092 {
2093 case GL_EYE_LINEAR:
2094 case GL_OBJECT_LINEAR: maxTexGenDim = 4; break;
2095
2096 case GL_SPHERE_MAP: maxTexGenDim = 2; break;
2097
2098 case GL_NORMAL_MAP:
2099 case GL_REFLECTION_MAP: maxTexGenDim = 3; break;
2100
2101 default: maxTexGenDim = 0; break;
2102 }
2103
2104 desc_.texGenDim = std::max(std::min(desc_.texGenDim, maxTexGenDim), 0);
2105
2106
2107 if (desc_.texGenDim && desc_.texGenMode)
2108 {
2109 // pass generated texcoord from vertex to fragment shader
2110 if (!desc_.texGenPerFragment)
2111 ioDesc_.passTexCoord_ = true;
2112
2113 // some modes require normal vectors
2114 if (desc_.texGenMode == GL_REFLECTION_MAP || desc_.texGenMode == GL_SPHERE_MAP || desc_.texGenMode == GL_NORMAL_MAP)
2115 ioDesc_.inputNormal_ = true;
2116
2117 // pass data to the fragment shader as required for the generation
2118 if (desc_.texGenPerFragment)
2119 {
2120 switch (desc_.texGenMode)
2121 {
2122 case GL_OBJECT_LINEAR: ioDesc_.passPosOS_ = true; break;
2123 case GL_EYE_LINEAR: ioDesc_.passPosVS_ = true; break;
2124 case GL_SPHERE_MAP: ioDesc_.passPosVS_ = ioDesc_.passNormalVS_ = true; break;
2125 case GL_NORMAL_MAP: ioDesc_.passNormalVS_ = true; break;
2126 case GL_REFLECTION_MAP: ioDesc_.passPosVS_ = ioDesc_.passNormalVS_ = true; break;
2127 default: break;
2128 }
2129 }
2130 }
2131
2132
2133 if (desc_.vertexColors)
2134 ioDesc_.inputColor_ = true;
2135
2136 if (desc_.shadeMode == SG_SHADE_PHONG)
2137 {
2138 ioDesc_.passNormalVS_ = true;
2139 ioDesc_.passPosVS_ = true;
2140 }
2141
2142 if (desc_.shadeMode == SG_SHADE_FLAT || desc_.shadeMode == SG_SHADE_GOURAUD || desc_.vertexColors)
2143 ioDesc_.passColor_ = true;
2144
2145
2146 // scan macros of modifiers for attribute requests,
2147 // done by adding modifier io to an empty dummy
2148 ShaderGenerator dummy;
2149
2150 for (size_t i = 0; i < activeMods_.size(); ++i)
2151 {
2152 ShaderModifier* mod = activeMods_[i];
2153
2154 mod->modifyVertexIO(&dummy);
2155 mod->modifyTessControlIO(&dummy);
2156 mod->modifyTessEvalIO(&dummy);
2157 mod->modifyGeometryIO(&dummy);
2158 mod->modifyFragmentIO(&dummy);
2159 }
2160 // scan requested inputs from modifiers
2161
2162 if (dummy.hasDefine(ShaderGenerator::keywords.macro_requestPosVS))
2163 ioDesc_.passPosVS_ = true;
2164 if (dummy.hasDefine(ShaderGenerator::keywords.macro_requestTexcoord))
2165 {
2166 ioDesc_.inputTexCoord_ = true;
2167 ioDesc_.passTexCoord_ = true;
2168 }
2169 if (dummy.hasDefine(ShaderGenerator::keywords.macro_requestVertexColor))
2170 {
2171 ioDesc_.inputColor_ = true;
2172 ioDesc_.passColor_ = true;
2173 }
2174 if (dummy.hasDefine(ShaderGenerator::keywords.macro_requestNormalVS))
2175 {
2176 ioDesc_.inputNormal_ = true;
2177 ioDesc_.passNormalVS_ = true;
2178 }
2179 if (dummy.hasDefine(ShaderGenerator::keywords.macro_requestNormalOS))
2180 {
2181 ioDesc_.inputNormal_ = true;
2182 ioDesc_.passNormalOS_ = true;
2183 }
2184 if (dummy.hasDefine(ShaderGenerator::keywords.macro_requestPosOS))
2185 ioDesc_.passPosOS_ = true;
2186
2187 if (dummy.hasDefine(ShaderGenerator::keywords.macro_requestRenormalize))
2188 renormalizeLighting_ = true;
2189
2190
2191
2192
2193 // assemble shader codes
2194
2195 buildVertexShader();
2196 buildTessControlShader();
2197 buildTessEvalShader();
2198 buildGeometryShader();
2199 buildFragmentShader();
2200 }
2201
2202
2203 const QStringList& ShaderProgGenerator::getVertexShaderCode()
2204 {
2205 return vertex_->getShaderCode();
2206 }
2207
2208 const QStringList& ShaderProgGenerator::getTessControlShaderCode()
2209 {
2210 return tessControl_->getShaderCode();
2211 }
2212
2213 const QStringList& ShaderProgGenerator::getTessEvaluationShaderCode()
2214 {
2215 return tessEval_->getShaderCode();
2216 }
2217
2218 const QStringList& ShaderProgGenerator::getGeometryShaderCode()
2219 {
2220 return geometry_->getShaderCode();
2221 }
2222
2223 const QStringList& ShaderProgGenerator::getFragmentShaderCode()
2224 {
2225 return fragment_->getShaderCode();
2226 }
2227
2228
2229 void ShaderProgGenerator::saveVertexShToFile(const char* _fileName)
2230 {
2231 vertex_->saveToFile(_fileName);
2232 }
2233
2234 void ShaderProgGenerator::saveGeometryShToFile(const char* _fileName)
2235 {
2236 geometry_->saveToFile(_fileName);
2237 }
2238
2239 void ShaderProgGenerator::saveFragmentShToFile(const char* _fileName)
2240 {
2241 fragment_->saveToFile(_fileName);
2242 }
2243
2244
2245 void ShaderProgGenerator::loadShaderTemplateFromFile()
2246 {
2247 if (!desc_.vertexTemplateFile.isEmpty())
2248 {
2249 loadStringListFromFile(desc_.vertexTemplateFile, &vertexTemplate_);
2250 scanShaderTemplate(vertexTemplate_, desc_.vertexTemplateFile);
2251 }
2252 if (!desc_.fragmentTemplateFile.isEmpty())
2253 {
2254 loadStringListFromFile(desc_.fragmentTemplateFile, &fragmentTemplate_);
2255 scanShaderTemplate(fragmentTemplate_, desc_.fragmentTemplateFile);
2256 }
2257 if (!desc_.geometryTemplateFile.isEmpty())
2258 {
2259 loadStringListFromFile(desc_.geometryTemplateFile, &geometryTemplate_);
2260 scanShaderTemplate(geometryTemplate_, desc_.geometryTemplateFile);
2261 }
2262 if (!desc_.tessControlTemplateFile.isEmpty())
2263 {
2264 loadStringListFromFile(desc_.tessControlTemplateFile, &tessControlTemplate_);
2265 scanShaderTemplate(tessControlTemplate_, desc_.tessControlTemplateFile, &tessControlLayout_);
2266 }
2267 if (!desc_.tessEvaluationTemplateFile.isEmpty())
2268 {
2269 loadStringListFromFile(desc_.tessEvaluationTemplateFile, &tessEvalTemplate_);
2270 scanShaderTemplate(tessEvalTemplate_, desc_.tessEvaluationTemplateFile, &tessEvalLayout_);
2271 }
2272
2273
2274 vertexShaderFile_ = desc_.vertexTemplateFile;
2275 tessControlShaderFile_ = desc_.tessControlTemplateFile;
2276 tessEvalShaderFile_ = desc_.tessEvaluationTemplateFile;
2277 geometryShaderFile_ = desc_.geometryTemplateFile;
2278 fragmentShaderFile_ = desc_.fragmentTemplateFile;
2279 }
2280
2281 void ShaderProgGenerator::scanShaderTemplate(QStringList& _templateSrc, QString _templateFilename, QStringList* _outLayoutDirectives)
2282 {
2283 // interpret loaded shader template:
2284 // import #includes
2285
2286 QString filePath = getPathName(_templateFilename);
2287
2288 QStringList::iterator it;
2289 for (it = _templateSrc.begin(); it != _templateSrc.end(); ++it)
2290 {
2291 QStringList import;
2292
2293 if (checkForIncludes(*it, &import, filePath))
2294 {
2295 // line is include directive
2296
2297 // remove line from source
2298 it = _templateSrc.erase(it);
2299
2300 int offset = it - _templateSrc.begin();
2301
2302 // insert imported file
2303
2304 QString importLine;
2305 foreach(importLine, import)
2306 {
2307 it = _templateSrc.insert(it, importLine);
2308 ++it;
2309 }
2310
2311 // included file might recursively include something again
2312 // -> scan included file
2313 it = _templateSrc.begin() + offset;
2314 }
2315 else
2316 {
2317 QString trimmedLine = it->trimmed();
2318
2319 // scan and adjust glsl version
2320 QByteArray lineBytes = trimmedLine.toUtf8();
2321
2322 int templateVersion = 0;
2323 if (sscanf(lineBytes.constData(), "#version %d", &templateVersion) == 1)
2324 {
2325 desc_.version = std::max(templateVersion, desc_.version);
2326
2327 // remove version line from template since this is added later in the build functions
2328 it = _templateSrc.erase(it);
2329 }
2330 // scan layout() directive
2331 else if (trimmedLine.startsWith("layout(") || trimmedLine.startsWith("layout ("))
2332 {
2333 if (_outLayoutDirectives)
2334 {
2335 _outLayoutDirectives->push_back(trimmedLine);
2336 // layout() will be inserted later at the correct position in the build functions
2337 // - must be placed before shader IO declaration to make tess-control shaders compilable on ati
2338 it = _templateSrc.erase(it);
2339 }
2340 }
2341 else
2342 {
2343 // scan requested inputs
2344
2345 if (trimmedLine.startsWith(ShaderGenerator::keywords.macro_requestPosVS))
2346 ioDesc_.passPosVS_ = true;
2347 else if (trimmedLine.startsWith(ShaderGenerator::keywords.macro_requestTexcoord))
2348 {
2349 ioDesc_.inputTexCoord_ = true;
2350 ioDesc_.passTexCoord_ = true;
2351 }
2352 else if (trimmedLine.startsWith(ShaderGenerator::keywords.macro_requestVertexColor))
2353 {
2354 ioDesc_.inputColor_ = true;
2355 ioDesc_.passColor_ = true;
2356 }
2357 else if (trimmedLine.startsWith(ShaderGenerator::keywords.macro_requestNormalVS))
2358 {
2359 ioDesc_.inputNormal_ = true;
2360 ioDesc_.passNormalVS_ = true;
2361 }
2362 else if (trimmedLine.startsWith(ShaderGenerator::keywords.macro_requestNormalOS))
2363 {
2364 ioDesc_.inputNormal_ = true;
2365 ioDesc_.passNormalOS_ = true;
2366 }
2367 else if (trimmedLine.startsWith(ShaderGenerator::keywords.macro_requestPosOS))
2368 ioDesc_.passPosOS_ = true;
2369 else if (trimmedLine.startsWith(ShaderGenerator::keywords.macro_requestRenormalize))
2370 renormalizeLighting_ = true;
2371 else if (trimmedLine.startsWith("SG_FRAGMENT_LIGHTING"))
2372 {
2373 // shader template performs lighting in fragment shader
2374 // -> forced phong shading
2375 desc_.shadeMode = SG_SHADE_PHONG;
2376 }
2377 }
2378
2379 }
2380 }
2381
2382 }
2383
2384 QString ShaderProgGenerator::getPathName(QString _strFileName)
2385 {
2386 QFileInfo fileInfo(getAbsFilePath(_strFileName));
2387 return fileInfo.absolutePath();
2388 }
2389
2390 QString ShaderProgGenerator::getAbsFilePath(QString _strFileName)
2391 {
2392 QString absFilename;
2393 if ( QDir(_strFileName).isRelative() )
2394 absFilename = getShaderDir() + QDir::separator() + _strFileName;
2395 else
2396 absFilename = _strFileName;
2397
2398 return QDir::cleanPath(absFilename);
2399 }
2400
2401 void ShaderProgGenerator::setShaderDir( QString _dir )
2402 {
2403 shaderDir_ = _dir;
2404 }
2405
2406 QString ShaderProgGenerator::getShaderDir()
2407 {
2408 return shaderDir_ + QString("/");
2409 }
2410
2411
2412 unsigned int ShaderProgGenerator::registerModifier( ShaderModifier* _modifier )
2413 {
2414 if (!_modifier) return 0;
2415
2416 // redundancy check
2417 for (int i = 0; i < numRegisteredModifiers_; ++i)
2418 {
2419 if (registeredModifiers_[i] == _modifier)
2420 {
2421 // std::cout << "warning: trying to re-register shader modifier " << _modifier->getID() << std::endl;
2422 return registeredModifiers_[i]->getID();
2423 }
2424 }
2425
2426 _modifier->modifierID_ = (unsigned int)(numRegisteredModifiers_++);
2427
2428 registeredModifiers_.push_back(_modifier);
2429 return _modifier->modifierID_;
2430 }
2431
2432 ShaderModifier* ShaderProgGenerator::getActiveModifier( int _i )
2433 {
2434 if (_i >= 0 && _i <= int(activeMods_.size()))
2435 return activeMods_[_i];
2436
2437 // invalid _i
2438 return 0;
2439 }
2440
2441 int ShaderProgGenerator::getNumActiveModifiers() const
2442 {
2443 return int(activeMods_.size());
2444 }
2445
2446
2447 bool ShaderProgGenerator::hasGeometryShader() const
2448 {
2449 return !desc_.geometryTemplateFile.isEmpty();
2450 }
2451
2452 bool ShaderProgGenerator::hasTessControlShader() const
2453 {
2454 return !desc_.tessControlTemplateFile.isEmpty();
2455 }
2456
2457 bool ShaderProgGenerator::hasTessEvaluationShader() const
2458 {
2459 return !desc_.tessEvaluationTemplateFile.isEmpty();
2460 }
2461
2462
2463 //=============================================================================
2464
2465 ShaderModifier::ShaderModifier( void )
2466 : modifierID_(0)
2467 {}
2468
2469 ShaderModifier::~ShaderModifier( void )
2470 {}
2471
2472
2473 class ShaderModifierFile : public ShaderModifier
2474 {
2475 public:
2476
2477 ShaderModifierFile()
2478 : version_(0)
2479 {}
2480
2481 virtual ~ShaderModifierFile()
2482 {}
2483
2484 void modifyVertexIO(ShaderGenerator* _shader) { modifyIO(0, _shader); }
2485 void modifyTessControlIO(ShaderGenerator* _shader) { modifyIO(1, _shader); }
2486 void modifyTessEvalIO(ShaderGenerator* _shader) { modifyIO(2, _shader); }
2487 void modifyGeometryIO(ShaderGenerator* _shader) { modifyIO(3, _shader); }
2488 void modifyFragmentIO(ShaderGenerator* _shader) { modifyIO(4, _shader); }
2489
2490
2491 void modifyVertexBeginCode(QStringList* _code) { _code->append(vertexBeginCode_); }
2492 void modifyVertexEndCode(QStringList* _code) { _code->append(vertexEndCode_); }
2493 void modifyFragmentBeginCode(QStringList* _code) { _code->append(fragmentBeginCode_); }
2494 void modifyFragmentEndCode(QStringList* _code) { _code->append(fragmentEndCode_); }
2495
2496 const QString& filename() const {return filename_;}
2497 const QDateTime& filetime() const {return filetime_;}
2498 void filetime(const QDateTime& _newtime) {filetime_ = _newtime;}
2499
2500 void clear()
2501 {
2502 version_ = 0;
2503
2504 for (int i = 0; i < 5; ++i)
2505 io_[i].clear();
2506
2507 vertexBeginCode_.clear();
2508 vertexEndCode_.clear();
2509 fragmentBeginCode_.clear();
2510 fragmentEndCode_.clear();
2511 }
2512
2513 static ShaderModifierFile* loadFromFile(QString _filename)
2514 {
2515 ShaderModifierFile* res = 0;
2516
2517 // get timestamp
2518 QString absFilename = ShaderProgGenerator::getAbsFilePath(_filename);
2519 QDateTime lastmod = QFileInfo(absFilename).lastModified();
2520
2521 // check cache
2522 QHash<QString, ShaderModifierFile>::iterator cacheEntry = fileCache_.find(_filename);
2523
2524 bool reload = false;
2525 bool firstLoad = false;
2526
2527 if (cacheEntry != fileCache_.end())
2528 {
2529 // fetch from cache
2530 res = &cacheEntry.value();
2531
2532 if (lastmod != res->filetime())
2533 {
2534 res->clear();
2535 reload = true;
2536 }
2537 }
2538 else
2539 {
2540 // load new modifier
2541 reload = true;
2542 firstLoad = true;
2543 }
2544
2545 if (reload)
2546 {
2547 QStringList lines;
2548 if (ShaderProgGenerator::loadStringListFromFile(_filename, &lines))
2549 {
2550 // new cache entry
2551 if (firstLoad)
2552 res = &fileCache_[_filename];
2553
2554 res->loadBlocks(lines);
2555 res->filetime(lastmod);
2556
2557 // also register to generator
2558 if (firstLoad)
2559 ShaderProgGenerator::registerModifier(res);
2560 }
2561 }
2562
2563 return res;
2564 }
2565
2566 private:
2567
2568
2569 void loadBlocks(const QStringList& _lines)
2570 {
2571 static const char* markers [] =
2572 {
2573 "VertexIO:",
2574 "TessControlIO:",
2575 "TessEvalIO:",
2576 "GeometryIO:",
2577 "FragmentIO:",
2578 "VertexBeginCode:",
2579 "VertexEndCode:",
2580 "FragmentBeginCode:",
2581 "FragmentEndCode:"
2582 };
2583 const int numMarkers = sizeof(markers) / sizeof(markers[0]);
2584
2585 QStringList* blockTargets [] =
2586 {
2587 io_ + 0,
2588 io_ + 1,
2589 io_ + 2,
2590 io_ + 3,
2591 io_ + 4,
2592 &vertexBeginCode_,
2593 &vertexEndCode_,
2594 &fragmentBeginCode_,
2595 &fragmentEndCode_
2596 };
2597
2598 assert(sizeof(blockTargets) / sizeof(blockTargets[0]) == numMarkers);
2599
2600
2601 // current block in file, points to one of io_[idx], vertexBeginCode_, ...
2602 QStringList* curBlock_ = 0;
2603
2604
2605 int curLine = 0;
2606
2607 for (QStringList::const_iterator it = _lines.begin(); it != _lines.end(); ++it, ++curLine)
2608 {
2609 if (it->isEmpty())
2610 continue;
2611
2612 // read glsl version
2613 if (version_ <= 0 && it->startsWith("#version "))
2614 {
2615 const int offset = strlen("#version ");
2616 version_ = atoi(it->toLatin1().data() + offset);
2617 }
2618 else
2619 {
2620 // read code blocks
2621
2622 bool blockMarker = false;
2623
2624 for (int i = 0; i < numMarkers && !blockMarker; ++i)
2625 {
2626 if ( it->startsWith(markers[i]) )
2627 {
2628 // new block start
2629 curBlock_ = blockTargets[i];
2630 blockMarker = true;
2631 }
2632 }
2633
2634 if (!blockMarker)
2635 {
2636 if (curBlock_) // code belongs to some block
2637 curBlock_->push_back(*it);
2638 else // wrong file structure
2639 std::cerr << "ShaderModifierFile::loadBlocks - line belongs to unknown block in file " << filename_.toLatin1().data() << " at line " << curLine << std::endl;
2640 }
2641 }
2642 }
2643 }
2644
2645 void modifyIO(int _stage, ShaderGenerator* _shader)
2646 {
2647 if (version_ > 0)
2648 _shader->setGLSLVersion(version_);
2649
2650 _shader->addRawIOBlock(io_[_stage]);
2651 }
2652
2653 private:
2654
2655 QString filename_;
2656
2657 QDateTime filetime_;
2658
2659 // glsl version
2660 int version_;
2661
2662 // io mods
2663 QStringList io_[5];
2664
2665 // code mods
2666 QStringList vertexBeginCode_,
2667 vertexEndCode_,
2668 fragmentBeginCode_,
2669 fragmentEndCode_;
2670
2671
2672 // loaded modifiers
2673 static QHash<QString, ShaderModifierFile> fileCache_;
2674 };
2675
2676 QHash<QString, ShaderModifierFile> ShaderModifierFile::fileCache_;
2677
2678
2679 ShaderModifier* ShaderModifier::loadFromFile(QString _filename)
2680 {
2681 return ShaderModifierFile::loadFromFile(_filename);
2682 }
2683
2684
2685 //=============================================================================
2686
2687
2688 QString ShaderGenDesc::toString() const
2689 {
2690 // mapping (int)ShaderGenMode -> string
2691 const char* shadeModeString[] =
2692 {
2693 "SG_SHADE_UNLIT",
2694 "SG_SHADE_FLAT",
2695 "SG_SHADE_GOURAUD",
2696 "SG_SHADE_PHONG"
2697 };
2698
2699 QString res;
2700 QTextStream resStrm(&res);
2701
2702 resStrm << "version: " << version;
2703
2704 resStrm << "shaderDesc.numLights: " << numLights;
2705
2706 if (numLights)
2707 {
2708 resStrm << "\nshaderDesc.lightTypes[]: {";
2709
2710 for (int i = 0; i < numLights; ++i)
2711 {
2712 switch (lightTypes[i])
2713 {
2714 case SG_LIGHT_DIRECTIONAL: resStrm << "DIRECTIONAL"; break;
2715 case SG_LIGHT_POINT: resStrm << "POINT"; break;
2716 case SG_LIGHT_SPOT: resStrm << "SPOT"; break;
2717 default: resStrm << "UNDEFINED"; break;
2718 }
2719
2720 if (i + 1 < numLights)
2721 resStrm << ", ";
2722 else
2723 resStrm << "}";
2724 }
2725 }
2726
2727
2728 resStrm << "\nshaderDesc.shadeMode: " << shadeModeString[shadeMode];
2729 resStrm << "\nshaderDesc.vertexColors: " << vertexColors;
2730 resStrm << "\nshaderDesc.textured(): " << textured();
2731 for (std::map<size_t,TextureType>::const_iterator iter = textureTypes_.begin(); iter != textureTypes_.end();++iter)
2732 {
2733 resStrm << "\nTexture stage: " << iter->first;
2734 resStrm << "\nTexture Type: ";
2735 switch (iter->second.type)
2736 {
2737 case GL_TEXTURE_1D: resStrm << "GL_TEXTURE_1D"; break;
2738 case GL_TEXTURE_2D: resStrm << "GL_TEXTURE_2D"; break;
2739 case GL_TEXTURE_3D: resStrm << "GL_TEXTURE_3D"; break;
2740 case GL_TEXTURE_CUBE_MAP: resStrm << "GL_TEXTURE_CUBE_MAP"; break;
2741 #ifdef GL_ARB_texture_rectangle //ARCH_DARWIN doesn't support all texture defines with all xcode version (xcode 5.0 seems to support all)
2742 case GL_TEXTURE_RECTANGLE_ARB: resStrm << "GL_TEXTURE_RECTANGLE"; break;
2743 #endif
2744 #ifdef GL_ARB_texture_buffer_object
2745 case GL_TEXTURE_BUFFER_ARB: resStrm << "GL_TEXTURE_BUFFER"; break;
2746 #endif
2747 #ifdef GL_EXT_texture_array
2748 case GL_TEXTURE_1D_ARRAY_EXT: resStrm << "GL_TEXTURE_1D_ARRAY"; break;
2749 case GL_TEXTURE_2D_ARRAY_EXT: resStrm << "GL_TEXTURE_2D_ARRAY"; break;
2750 #endif
2751 #ifdef GL_ARB_texture_cube_map_array
2752 case GL_TEXTURE_CUBE_MAP_ARRAY_ARB: resStrm << "GL_TEXTURE_CUBE_MAP_ARRAY"; break;
2753 #endif
2754 #ifdef GL_ARB_texture_multisample
2755 case GL_TEXTURE_2D_MULTISAMPLE: resStrm << "GL_TEXTURE_2D_MULTISAMPLE"; break;
2756 case GL_TEXTURE_2D_MULTISAMPLE_ARRAY: resStrm << "GL_TEXTURE_2D_MULTISAMPLE_ARRAY"; break;
2757 #endif
2758 default: std::cerr << "Texture Type with number "<< iter->second.type << " on stage "<< iter->first << " is not supported " << std::endl; break;
2759 }
2760
2761 resStrm << "\nShadowTexture: " << iter->second.shadow;
2762 }
2763
2764 resStrm << "\nshaderDesc.texGenDim: " << texGenDim;
2765
2766 switch (texGenMode)
2767 {
2768 case GL_OBJECT_LINEAR: resStrm << "\nshaderDesc.texGenMode: GL_OBJECT_LINEAR"; break;
2769 case GL_EYE_LINEAR: resStrm << "\nshaderDesc.texGenMode: GL_EYE_LINEAR"; break;
2770 case GL_SPHERE_MAP: resStrm << "\nshaderDesc.texGenMode: GL_SPHERE_MAP"; break;
2771 case GL_NORMAL_MAP: resStrm << "\nshaderDesc.texGenMode: GL_NORMAL_MAP"; break;
2772 case GL_REFLECTION_MAP: resStrm << "\nshaderDesc.texGenMode: GL_REFLECTION_MAP"; break;
2773 default: resStrm << "\nshaderDesc.texGenMode: unknown"; break;
2774 }
2775
2776 resStrm << "\nshaderDesc.texGenPerFragment: " << texGenPerFragment;
2777
2778 if (!vertexTemplateFile.isEmpty())
2779 resStrm << "\nshaderDesc.vertexTemplateFile: " << vertexTemplateFile;
2780
2781 if (!tessControlTemplateFile.isEmpty())
2782 resStrm << "\nshaderDesc.tessControlTemplateFile: " << tessControlTemplateFile;
2783
2784 if (!tessEvaluationTemplateFile.isEmpty())
2785 resStrm << "\nshaderDesc.tessEvaluationTemplateFile: " << tessEvaluationTemplateFile;
2786
2787 if (!geometryTemplateFile.isEmpty())
2788 resStrm << "\nshaderDesc.geometryTemplateFile: " << geometryTemplateFile;
2789
2790 if (!fragmentTemplateFile.isEmpty())
2791 resStrm << "\nshaderDesc.fragmentTemplateFile: " << fragmentTemplateFile;
2792
2793 return res;
2794 }
2795
2796
2797
2798 } // namespace ACG
2799 //=============================================================================
ACG::ShaderGenDesc::normalizeTexColors
bool normalizeTexColors
Defines if the textureVariable is normalized or not, if multiple textures are used.
Definition: ShaderGenerator.hh:165
ACG::ShaderProgGenerator::init
void init(const ShaderGenDesc *_desc, ShaderModifier *const *_modifiers, unsigned int _numActiveMods)
Called in constructor.
Definition: ShaderGenerator.cc:892
ACG::ShaderGenerator::initVertexShaderIO
void initVertexShaderIO(const ShaderGenDesc *_desc, const DefaultIODesc *_iodesc)
Adds fitting vertex shader io for a given description.
Definition: ShaderGenerator.cc:149
ACG::ShaderProgGenerator::getVertexShaderCode
const QStringList & getVertexShaderCode()
Returns generated vertex shader code.
Definition: ShaderGenerator.cc:2203
ACG::ShaderProgGenerator::tessControlLayout_
QStringList tessControlLayout_
layout() directives scanned from loaded templates
Definition: ShaderGenerator.hh:1373
ACG::ShaderGenerator::addUniform
void addUniform(QString _uniform, QString _comment="")
Add one GLSL uniform specifier.
Definition: ShaderGenerator.cc:536
ACG::ShaderModifier::modifyTessControlIO
virtual void modifyTessControlIO(ShaderGenerator *_shader)
Add your own inputs/outputs to the tessellation control shader.
Definition: ShaderGenerator.hh:1006
ACG
Namespace providing different geometric functions concerning angles.
Definition: DBSCANT.cc:51
ACG::ShaderProgGenerator::getActiveModifier
ShaderModifier * getActiveModifier(int _i)
Get active modfiers for this program.
Definition: ShaderGenerator.cc:2432
ACG::ShaderProgGenerator::numRegisteredModifiers_
static int numRegisteredModifiers_
registered shader modifier
Definition: ShaderGenerator.hh:1362
ACG::ShaderGenerator::outputPrefix_
QString outputPrefix_
prefix of outputs of this shader
Definition: ShaderGenerator.hh:872
ACG::ShaderModifierFile::modifyTessControlIO
void modifyTessControlIO(ShaderGenerator *_shader)
Add your own inputs/outputs to the tessellation control shader.
Definition: ShaderGenerator.cc:2485
ACG::ShaderGenerator::addDefine
void addDefine(const QString &_define)
Add one define.
Definition: ShaderGenerator.cc:478
ACG::ShaderGenerator::addLight
void addLight(int lightIndex_, ShaderGenLightType _light)
Add a light description to shader:
Definition: ShaderGenerator.cc:415
ACG::ShaderGenerator::DefaultIODesc
Definition: ShaderGenerator.hh:526
ACG::ShaderProgGenerator::ShaderProgGenerator
ShaderProgGenerator(const ShaderGenDesc *_desc)
Definition: ShaderGenerator.cc:834
ACG::ShaderProgGenerator::getFragmentShaderCode
const QStringList & getFragmentShaderCode()
Returns generated fragment shader code.
Definition: ShaderGenerator.cc:2223
ACG::ShaderProgGenerator::getTessEvaluationShaderCode
const QStringList & getTessEvaluationShaderCode()
Returns generated tessellation control shader code.
Definition: ShaderGenerator.cc:2213
ACG::ShaderProgGenerator::getAbsFilePath
static QString getAbsFilePath(QString _fileName)
Convert a filename to an absolute filename.
Definition: ShaderGenerator.cc:2390
ACG::ShaderGenerator::getIOMapName
QString getIOMapName(int _inId) const
get corresponding output name of an input id
Definition: ShaderGenerator.cc:804
ACG::ShaderProgGenerator::getPathName
static QString getPathName(QString _strFileName)
returns path to _strFileName without last slash
Definition: ShaderGenerator.cc:2384
ACG::ShaderModifier::loadFromFile
static ShaderModifier * loadFromFile(QString _filename)
Load a modifier from file.
Definition: ShaderGenerator.cc:2679
ACG::ShaderGenerator::addInput
void addInput(const QString &_input)
Add one GLSL input specifier.
Definition: ShaderGenerator.cc:466
ACG::ShaderProgGenerator::registerModifier
static unsigned int registerModifier(ShaderModifier *_modifier)
Shader modifiers have to be registered before they can be used. They also must remain allocated for t...
Definition: ShaderGenerator.cc:2412
ACG::ShaderModifier::modifyVertexIO
virtual void modifyVertexIO(ShaderGenerator *_shader)
Add your own inputs/outputs to the vertex shader.
Definition: ShaderGenerator.hh:951
ACG::ShaderModifier::modifyGeometryIO
virtual void modifyGeometryIO(ShaderGenerator *_shader)
Add your own inputs/outputs to the geometry shader.
Definition: ShaderGenerator.hh:993
ACG::openGLVersion
bool openGLVersion(const int _major, const int _minor)
Definition: gl.cc:95
ACG::ShaderModifierFile::modifyTessEvalIO
void modifyTessEvalIO(ShaderGenerator *_shader)
Add your own inputs/outputs to the tessellation evaluation shader.
Definition: ShaderGenerator.cc:2486
ACG::ShaderProgGenerator::generateShaders
void generateShaders()
Generates the shader code.
Definition: ShaderGenerator.cc:2072
ACG::ShaderGenerator::setGLSLVersion
void setGLSLVersion(int _version)
Set glsl version.
Definition: ShaderGenerator.cc:687
ACG::ShaderGenerator::getNumInputs
int getNumInputs() const
get number of inputs
Definition: ShaderGenerator.cc:781
ACG::ShaderGenerator::addOutput
void addOutput(const QString &_output)
Add one GLSL output specifier.
Definition: ShaderGenerator.cc:472
ACG::ShaderGenerator::saveToFile
void saveToFile(const char *_fileName)
Save generated shader code to text file.
Definition: ShaderGenerator.cc:667
ACG::ShaderProgGenerator::ioDesc_
ShaderGenerator::DefaultIODesc ioDesc_
default IO descriptor for the vertex shader
Definition: ShaderGenerator.hh:1378
ACG::ShaderGenerator::addMacros
void addMacros(const QStringList &_macros)
Add a list of preprocessor macros.
Definition: ShaderGenerator.cc:489
ACG::ShaderGenDesc::toString
QString toString() const
convert ShaderGenDesc to string format for debugging
Definition: ShaderGenerator.cc:2688
ACG::ShaderProgGenerator::loadShaderTemplateFromFile
void loadShaderTemplateFromFile()
Loads external shader templates.
Definition: ShaderGenerator.cc:2245
ACG::ShaderGenerator::initTessEvalShaderIO
void initTessEvalShaderIO(const ShaderGenDesc *_desc, ShaderGenerator *_prevStage, const DefaultIODesc *_iodesc)
Adds fitting tess-evaluation shader io for a given description.
Definition: ShaderGenerator.cc:256
ACG::ShaderProgGenerator::hasTessControlShader
bool hasTessControlShader() const
check whether there is a tess-control shader present
Definition: ShaderGenerator.cc:2452
ACG::ShaderModifier::modifyTessEvalIO
virtual void modifyTessEvalIO(ShaderGenerator *_shader)
Add your own inputs/outputs to the tessellation evaluation shader.
Definition: ShaderGenerator.hh:1019
ACG::ShaderGenerator::hasDefine
bool hasDefine(QString _define) const
Check for define.
Definition: ShaderGenerator.cc:501
ACG::ShaderGenerator::DefaultIODesc::passPosVS_
bool passPosVS_
default attributes that should be passed down from vertex shader
Definition: ShaderGenerator.hh:536
ACG::ShaderProgGenerator::modifyLightingCode
void modifyLightingCode(QStringList *_code, ShaderModifier *_modifier)
Calls lighting modifier for each light.
Definition: ShaderGenerator.cc:1913
ACG::ShaderGenerator::addIncludeFile
void addIncludeFile(QString _fileName)
Imports another shader, same as #include.
Definition: ShaderGenerator.cc:634
ACG::ShaderGenDesc::vertexColorsInterpolator
QString vertexColorsInterpolator
interpolation qualifier for input vertex colors: "flat", "smooth", "noperspective" ...
Definition: ShaderGenerator.hh:168
ACG::ShaderModifier
Definition: ShaderGenerator.hh:932
ACG::ShaderProgGenerator::checkForIncludes
int checkForIncludes(QString _str, ShaderGenerator *_gen, QString _includePath)
Definition: ShaderGenerator.cc:1236
ACG::ShaderGenerator::DefaultIODesc::inputTexCoord_
bool inputTexCoord_
default attributes that should be imported in vertex shader
Definition: ShaderGenerator.hh:531
ACG::ShaderGenerator::getShaderCode
const QStringList & getShaderCode()
Get result of buildShaderCode.
Definition: ShaderGenerator.cc:682
ACG::ShaderGenerator::addStringToList
void addStringToList(QString _str, QStringList *_list, QString _prefix="", QString _postfix="")
Definition: ShaderGenerator.cc:441
ACG::ShaderGenerator::initFragmentShaderIO
void initFragmentShaderIO(const ShaderGenDesc *_desc, ShaderGenerator *_prevStage, const DefaultIODesc *_iodesc)
Adds fitting fragment shader io for a given description.
Definition: ShaderGenerator.cc:284
ACG::ShaderGenDesc
Definition: ShaderGenerator.hh:89
ACG::ShaderGenerator::outputArrays_
bool outputArrays_
outputs of shader are arrays (tess-control)
Definition: ShaderGenerator.hh:866
ACG::ShaderModifier::modifyLightingCode
virtual void modifyLightingCode(QStringList *_code, int _lightId, ShaderGenLightType _lightType)
Modify the default lighting code of the shader generator.
Definition: ShaderGenerator.hh:1083
ACG::ShaderGenerator::inputArrays_
bool inputArrays_
inputs of shader are arrays (tess-control, tess-eval, geometry)
Definition: ShaderGenerator.hh:863
ACG::ShaderGenerator::initDefaultUniforms
void initDefaultUniforms()
Adds frequently used uniform parameters.
Definition: ShaderGenerator.cc:394
ACG::ShaderProgGenerator::loadStringListFromFile
static bool loadStringListFromFile(QString _fileName, QStringList *_out)
Load a text file as string list.
Definition: ShaderGenerator.cc:955
ACG::ShaderGenerator::initTessControlShaderIO
void initTessControlShaderIO(const ShaderGenDesc *_desc, ShaderGenerator *_prevStage, const DefaultIODesc *_iodesc)
Adds fitting tess-control shader io for a given description.
Definition: ShaderGenerator.cc:243
ACG::ShaderProgGenerator::hasTessEvaluationShader
bool hasTessEvaluationShader() const
check whether there is a tess-evaluation shader present
Definition: ShaderGenerator.cc:2457
ACG::ShaderGenDesc::textureTypes_
std::map< size_t, TextureType > textureTypes_
holds the texture types (second) and the stage id (first). if empty, shader does not support textures...
Definition: ShaderGenerator.hh:183
ACG::ShaderProgGenerator::setShaderDir
static void setShaderDir(QString _dir)
Definition: ShaderGenerator.cc:2401
ACG::ShaderModifierFile::modifyVertexIO
void modifyVertexIO(ShaderGenerator *_shader)
Add your own inputs/outputs to the vertex shader.
Definition: ShaderGenerator.cc:2484
ACG::ShaderModifierFile::modifyFragmentBeginCode
void modifyFragmentBeginCode(QStringList *_code)
Append code the the fragment shader.
Definition: ShaderGenerator.cc:2493
ACG::ShaderProgGenerator::getGeometryShaderCode
const QStringList & getGeometryShaderCode()
Returns generated tessellation evaluation shader code.
Definition: ShaderGenerator.cc:2218
ACG::ShaderProgGenerator::addLightingFunctions
void addLightingFunctions(QStringList *_code)
Adds lighting definition functions.
Definition: ShaderGenerator.cc:1926
ACG::ShaderProgGenerator::renormalizeLighting_
bool renormalizeLighting_
renormalize before lighting, default false, can be activated via "#define SG_REQUEST_RENORMALIZE" ...
Definition: ShaderGenerator.hh:1381
ACG::ShaderProgGenerator::scanShaderTemplate
void scanShaderTemplate(QStringList &_templateSrc, QString _templateFilename, QStringList *_outLayoutDirectives=0)
Scans loaded shader template for requested inputs, glsl version or includes.
Definition: ShaderGenerator.cc:2281
ACG::ShaderProgGenerator::addTexGenCode
void addTexGenCode(QStringList *_code, bool _fragmentShader)
Add texture coordinate generation code.
Definition: ShaderGenerator.cc:1934
ACG::ShaderGenerator::getInputName
QString getInputName(int _id) const
get variable name of input
Definition: ShaderGenerator.cc:786
ACG::ShaderProgGenerator::getNumActiveModifiers
int getNumActiveModifiers() const
Get the number of active modifiers.
Definition: ShaderGenerator.cc:2441
ACG::ShaderProgGenerator::addLightingCode
void addLightingCode(QStringList *_code)
Adds lighting function calls to code.
Definition: ShaderGenerator.cc:1841
ACG::ShaderGenerator::initGeometryShaderIO
void initGeometryShaderIO(const ShaderGenDesc *_desc, ShaderGenerator *_prevStage, const DefaultIODesc *_iodesc)
Adds fitting geometry shader io for a given description.
Definition: ShaderGenerator.cc:269
ACG::ShaderModifierFile::modifyFragmentEndCode
void modifyFragmentEndCode(QStringList *_code)
Append code the the fragment shader.
Definition: ShaderGenerator.cc:2494
ACG::ShaderModifierFile::modifyGeometryIO
void modifyGeometryIO(ShaderGenerator *_shader)
Add your own inputs/outputs to the geometry shader.
Definition: ShaderGenerator.cc:2487
ACG::ShaderGenerator::inputPrefix_
QString inputPrefix_
prefix of inputs to this shader, same as prefix of ouputs of previous stage
Definition: ShaderGenerator.hh:869
ACG::ShaderModifierFile::modifyVertexBeginCode
void modifyVertexBeginCode(QStringList *_code)
Append code the the vertex shader.
Definition: ShaderGenerator.cc:2491
ACG::ShaderProgGenerator::getTessControlShaderCode
const QStringList & getTessControlShaderCode()
Returns generated vertex shader code.
Definition: ShaderGenerator.cc:2208
ACG::ShaderModifierFile::modifyVertexEndCode
void modifyVertexEndCode(QStringList *_code)
Append code the the vertex shader.
Definition: ShaderGenerator.cc:2492
ACG::ShaderProgGenerator::initGenDefines
void initGenDefines(ShaderGenerator *_gen)
provide generated defines to shader
Definition: ShaderGenerator.cc:1011
ACG::ShaderProgGenerator::getShaderDir
static QString getShaderDir()
Definition: ShaderGenerator.cc:2406
ACG::ShaderGenerator
Definition: ShaderGenerator.hh:518
ACG::ShaderGenerator::addLayout
void addLayout(QString _layout)
Add a layout directive.
Definition: ShaderGenerator.cc:530
ACG::ShaderProgGenerator::hasGeometryShader
bool hasGeometryShader() const
check whether there is a geometry shader present
Definition: ShaderGenerator.cc:2447
ACG::ShaderModifierFile::modifyFragmentIO
void modifyFragmentIO(ShaderGenerator *_shader)
Add your own inputs/outputs to the fragment shader.
Definition: ShaderGenerator.cc:2488
ACG::ShaderModifier::modifyFragmentIO
virtual void modifyFragmentIO(ShaderGenerator *_shader)
Add your own inputs/outputs to the fragment shader.
Definition: ShaderGenerator.hh:1032
ACG::ShaderGenerator::buildShaderCode
void buildShaderCode(QStringList *_pMainCode, const QStringList &_defaultLightingFunctions)
Shader assembly function.
Definition: ShaderGenerator.cc:562
ACG::ShaderModifierFile
Definition: ShaderGenerator.cc:2473
ACG::ShaderProgGenerator::vertexShaderFile_
QString vertexShaderFile_
path + filename to shader templates
Definition: ShaderGenerator.hh:1366