44#include <ACG/GL/acg_glew.hh>
45#include "ShaderGenerator.hh"
54#include <QRegularExpression>
61std::vector<ShaderModifier*> ShaderProgGenerator::registeredModifiers_;
71ShaderGenerator::Keywords::Keywords()
73: macro_requestPosVS(
"#define SG_REQUEST_POSVS"),
74macro_requestPosOS(
"#define SG_REQUEST_POSOS"),
75macro_requestTexcoord(
"#define SG_REQUEST_TEXCOORD"),
76macro_requestVertexColor(
"#define SG_REQUEST_VERTEXCOLOR"),
77macro_requestNormalVS(
"#define SG_REQUEST_NORMALVS"),
78macro_requestNormalOS(
"#define SG_REQUEST_NORMALOS"),
82macro_inputPosVS(
"SG_INPUT_POSVS"),
83macro_inputPosOS(
"SG_INPUT_POSOS"),
84macro_inputPosCS(
"SG_INPUT_POSCS"),
85macro_inputNormalVS(
"SG_INPUT_NORMALVS"),
86macro_inputNormalOS(
"SG_INPUT_NORMALOS"),
87macro_inputTexcoord(
"SG_INPUT_TEXCOORD"),
88macro_inputVertexColor(
"SG_INPUT_VERTEXCOLOR"),
90macro_outputPosVS(
"SG_OUTPUT_POSVS"),
91macro_outputPosOS(
"SG_OUTPUT_POSOS"),
92macro_outputPosCS(
"SG_OUTPUT_POSCS"),
93macro_outputNormalVS(
"SG_OUTPUT_NORMALVS"),
94macro_outputNormalOS(
"SG_OUTPUT_NORMALOS"),
95macro_outputTexcoord(
"SG_OUTPUT_TEXCOORD"),
96macro_outputVertexColor(
"SG_OUTPUT_VERTEXCOLOR"),
101ioNormalVS(
"NormalVS"),
102ioNormalOS(
"NormalOS"),
103ioTexcoord(
"TexCoord"),
107vs_outputPrefix(
"outVertex"),
108tcs_outputPrefix(
"outTc"),
109tes_outputPrefix(
"outTe"),
110gs_outputPrefix(
"outGeometry"),
111fs_outputPrefix(
"outFragment"),
113vs_inputPosition(vs_inputPrefix +
"Position"),
114vs_inputNormal(vs_inputPrefix +
"Normal"),
115vs_inputTexCoord(vs_inputPrefix + ioTexcoord),
116vs_inputColor(vs_inputPrefix + ioColor),
118vs_outputPosCS(vs_outputPrefix + ioPosCS),
119vs_outputPosVS(vs_outputPrefix + ioPosVS),
120vs_outputPosOS(vs_outputPrefix + ioPosOS),
121vs_outputTexCoord(vs_outputPrefix + ioTexcoord),
122vs_outputNormalVS(vs_outputPrefix + ioNormalVS),
123vs_outputNormalOS(vs_outputPrefix + ioNormalOS),
124vs_outputVertexColor(vs_outputPrefix + ioColor),
125fs_outputFragmentColor(fs_outputPrefix)
129const ShaderGenerator::Keywords ShaderGenerator::keywords;
132ShaderGenerator::ShaderGenerator()
133 : version_(150), inputArrays_(false), outputArrays_(false)
137ShaderGenerator::~ShaderGenerator()
146 inputArrays_ =
false;
147 outputArrays_ =
false;
148 inputPrefix_ = keywords.vs_inputPrefix;
149 outputPrefix_ = keywords.vs_outputPrefix;
151 addInput(
"vec4", keywords.vs_inputPosition);
152 addOutput(
"vec4", keywords.vs_outputPosCS);
154 if (_iodesc->inputNormal_)
155 addInput(
"vec3", keywords.vs_inputNormal);
157 if (_desc->textured())
159 std::map<size_t,ShaderGenDesc::TextureType>::const_iterator iter = _desc->textureTypes().begin();
162 if (iter->second.type == GL_TEXTURE_3D) {
163 addInput(
"vec3", keywords.vs_inputTexCoord);
164 addOutput(
"vec3", keywords.vs_outputTexCoord);
166 addInput(
"vec2", keywords.vs_inputTexCoord);
167 addOutput(
"vec2", keywords.vs_outputTexCoord);
171 if (_iodesc->inputColor_)
172 addInput(
"vec4", keywords.vs_inputColor);
174 if (_iodesc->passNormalVS_)
177 if (_iodesc->passNormalOS_)
185 if (_desc->shadeMode == SG_SHADE_FLAT)
187 if (!_desc->geometryTemplateFile.isEmpty())
188 strColorOut = keywords.vs_outputVertexColor;
192 addStringToList(
"vec4 " + keywords.vs_outputVertexColor, &outputs_,
"flat out ",
"; ");
195 else if (_desc->shadeMode == SG_SHADE_GOURAUD || _desc->vertexColors || _iodesc->inputColor_)
196 strColorOut = keywords.vs_outputVertexColor;
198 if (strColorOut.size())
199 addOutput(
"vec4", strColorOut);
202 addStringToList(
"vec4 " + keywords.vs_outputVertexColor, &outputs_, _desc->
vertexColorsInterpolator +
" out ",
";");
209 addOutput(
"vec4", keywords.vs_outputPosVS);
211 if (_iodesc->passPosOS_)
212 addOutput(
"vec4", keywords.vs_outputPosOS);
214 if (_iodesc->passTexCoord_ && !_desc->textured())
219 if (_desc->texGenMode && _desc->texGenDim > 0 && _desc->texGenDim <= 4 && !_desc->texGenPerFragment)
220 texdim = _desc->texGenDim;
222 QString texcoordType;
224 texcoordType =QString(
"vec%1").arg(texdim);
226 texcoordType =
"float";
228 addInput(texcoordType, keywords.vs_inputTexCoord);
229 addOutput(texcoordType, keywords.vs_outputTexCoord);
233 defineIOAbstraction(_iodesc,
true,
false);
240 outputArrays_ =
true;
242 outputPrefix_ = keywords.tcs_outputPrefix;
244 matchInputs(_prevStage,
true, inputPrefix_, outputPrefix_);
246 defineIOAbstraction(_iodesc,
false,
false);
253 outputArrays_ =
false;
255 outputPrefix_ = keywords.tes_outputPrefix;
257 matchInputs(_prevStage,
true, inputPrefix_, outputPrefix_);
259 defineIOAbstraction(_iodesc,
false,
false);
266 outputArrays_ =
false;
268 outputPrefix_ = keywords.gs_outputPrefix;
270 matchInputs(_prevStage,
true, inputPrefix_, outputPrefix_);
272 defineIOAbstraction(_iodesc,
false,
false);
280 inputArrays_ =
false;
281 outputArrays_ =
false;
283 outputPrefix_ = keywords.fs_outputPrefix;
285 matchInputs(_prevStage,
false);
286 addOutput(
"vec4", keywords.fs_outputFragmentColor);
288 defineIOAbstraction(_iodesc,
false,
true);
292void ShaderGenerator::defineIOAbstraction(
const DefaultIODesc* _iodesc,
bool _vs,
bool _fs )
298 addIODefine(keywords.macro_inputPosOS, keywords.vs_inputPosition);
301 addIODefine(keywords.macro_inputTexcoord, keywords.vs_inputTexCoord);
303 if (_iodesc->inputNormal_)
304 addIODefine(keywords.macro_inputNormalOS, keywords.vs_inputNormal);
306 if (_iodesc->inputColor_)
307 addIODefine(keywords.macro_inputVertexColor, keywords.vs_inputColor);
313 addIODefine(keywords.macro_outputPosCS, keywords.vs_outputPosCS);
316 addIODefine(keywords.macro_outputPosVS, keywords.vs_outputPosVS);
318 if (_iodesc->passPosOS_)
319 addIODefine(keywords.macro_outputPosOS, keywords.vs_outputPosOS);
321 if (_iodesc->passTexCoord_)
322 addIODefine(keywords.macro_outputTexcoord, keywords.vs_outputTexCoord);
324 if (_iodesc->passNormalVS_)
325 addIODefine(keywords.macro_outputNormalVS, keywords.vs_outputNormalVS);
327 if (_iodesc->passNormalOS_)
328 addIODefine(keywords.macro_outputNormalOS, keywords.vs_outputNormalOS);
330 if (_iodesc->passColor_)
331 addIODefine(keywords.macro_outputVertexColor, keywords.vs_outputVertexColor);
337 addIODefine(keywords.macro_inputPosVS, inputPrefix_ + keywords.ioPosVS);
339 addIODefine(keywords.macro_outputPosVS, outputPrefix_ + keywords.ioPosVS);
342 if (_iodesc->passPosOS_)
344 addIODefine(keywords.macro_inputPosOS, inputPrefix_ + keywords.ioPosOS);
346 addIODefine(keywords.macro_outputPosOS, outputPrefix_ + keywords.ioPosOS);
349 addIODefine(keywords.macro_inputPosCS, inputPrefix_ + keywords.ioPosCS);
351 addIODefine(keywords.macro_outputPosCS, outputPrefix_ + keywords.ioPosCS);
353 if (_iodesc->passNormalVS_)
355 addIODefine(keywords.macro_inputNormalVS, inputPrefix_ + keywords.ioNormalVS);
357 addIODefine(keywords.macro_outputNormalVS, outputPrefix_ + keywords.ioNormalVS);
360 if (_iodesc->passNormalOS_)
362 addIODefine(keywords.macro_inputNormalOS, inputPrefix_ + keywords.ioNormalOS);
364 addIODefine(keywords.macro_outputNormalOS, outputPrefix_ + keywords.ioNormalOS);
367 if (_iodesc->passTexCoord_)
369 addIODefine(keywords.macro_inputTexcoord, inputPrefix_ + keywords.ioTexcoord);
371 addIODefine(keywords.macro_outputTexcoord, outputPrefix_ + keywords.ioTexcoord);
374 if (_iodesc->passColor_)
376 addIODefine(keywords.macro_inputVertexColor, inputPrefix_ + keywords.ioColor);
378 addIODefine(keywords.macro_outputVertexColor, outputPrefix_ + keywords.ioColor);
387void ShaderGenerator::initDefaultUniforms()
389 addUniform(
"mat4 g_mWVP" ,
" // Projection * Modelview");
390 addUniform(
"mat4 g_mWV" ,
" // Modelview matrix");
391 addUniform(
"mat3 g_mWVIT" ,
" // Modelview inverse transposed");
392 addUniform(
"mat4 g_mP",
" // Projection matrix");
394 addUniform(
"vec3 g_vCamPos");
395 addUniform(
"vec3 g_vCamDir");
397 addUniform(
"vec3 g_cDiffuse");
398 addUniform(
"vec3 g_cAmbient");
399 addUniform(
"vec3 g_cEmissive");
400 addUniform(
"vec3 g_cSpecular");
401 addUniform(
"vec4 g_vMaterial");
402 addUniform(
"vec3 g_cLightModelAmbient");
406#define ADDLIGHT(x) addUniform( QString( QString(x) + "_%1").arg(lightIndex_) )
408void ShaderGenerator::addLight(
int lightIndex_, ShaderGenLightType _light)
412 QTextStream stream(&sz);
414 ADDLIGHT(
"vec3 g_cLightDiffuse");
415 ADDLIGHT(
"vec3 g_cLightAmbient");
416 ADDLIGHT(
"vec3 g_cLightSpecular");
418 if (_light == SG_LIGHT_POINT ||
419 _light == SG_LIGHT_SPOT)
421 ADDLIGHT(
"vec3 g_vLightPos");
422 ADDLIGHT(
"vec3 g_vLightAtten");
425 if (_light == SG_LIGHT_DIRECTIONAL ||
426 _light == SG_LIGHT_SPOT)
427 ADDLIGHT(
"vec3 g_vLightDir");
430 if (_light == SG_LIGHT_SPOT)
431 ADDLIGHT(
"vec2 g_vLightAngleExp");
436void ShaderGenerator::addStringToList(QString _str,
444 if (!_str.startsWith(_prefix))
447 if (!_str.endsWith(_postfix))
452 tmp = tmp.simplified();
455 if (!_arr->contains(tmp))
456 _arr->push_back(tmp);
461void ShaderGenerator::addInput(
const QString& _input)
463 addStringToList(_input, &inputs_,
"in ",
";");
467void ShaderGenerator::addOutput(
const QString& _output)
469 addStringToList(_output, &outputs_,
"out ",
";");
473void ShaderGenerator::addDefine(
const QString& _def)
475 addStringToList(_def, &genDefines_,
"#define ");
479void ShaderGenerator::addIODefine(
const QString& _macroName,
const QString& _resolvedName)
481 addDefine(_macroName + QString(
" ") + _resolvedName);
484void ShaderGenerator::addMacros(
const QStringList& _macros)
489 typedef std::reverse_iterator<QStringList::const_iterator> QStringListReverseIterator;
490 QStringListReverseIterator rbegin( _macros.end() ), rend( _macros.begin() );
492 for (QStringListReverseIterator it = rbegin; it != rend; ++it)
493 genDefines_.push_front(*it);
496bool ShaderGenerator::hasDefine(QString _define)
const
498 if (genDefines_.contains(_define))
503 QString trimmedDef = _define.trimmed();
505 for (QStringList::const_iterator it = genDefines_.constBegin(); it != genDefines_.constEnd(); ++it)
507 QString trimmedRef = it->trimmed();
509 if (trimmedRef.startsWith(trimmedDef))
514 for (QStringList::const_iterator it = rawIO_.constBegin(); it != rawIO_.constEnd(); ++it)
516 QString trimmedRef = it->trimmed();
518 if (trimmedRef.startsWith(trimmedDef))
525void ShaderGenerator::addLayout(QString _def)
527 addStringToList(_def, &layouts_);
531void ShaderGenerator::addUniform(QString _uniform, QString _comment)
534 if (!_uniform.startsWith(
"uniform ") && !_uniform.contains(
" uniform "))
537 addStringToList(_uniform, &uniforms_, prefix,
"; " + _comment );
542void ShaderGenerator::addIOToCode(
const QStringList& _cmds)
550 if (!it.contains(
";"))
551 code_.back().append(
";");
557void ShaderGenerator::buildShaderCode(QStringList* _pMainCode,
const QStringList& _defaultLightingFunctions)
559 QString glslversion = QString(
"#version %1").arg(version_);
561 code_.push_back(glslversion);
566 foreach(it, genDefines_)
570 foreach(it, layouts_)
574 addIOToCode(inputs_);
575 addIOToCode(outputs_);
576 addIOToCode(uniforms_);
579 bool requiresLightingCode =
false;
582 foreach(it, imports_)
584 if (it.contains(
"LitDirLight") || it.contains(
"LitPointLight") || it.contains(
"LitSpotLight"))
585 requiresLightingCode =
true;
588 if (requiresLightingCode)
590 foreach(it, _defaultLightingFunctions)
595 foreach(it, imports_)
601 if (!requiresLightingCode)
603 foreach(it, (*_pMainCode))
605 if (it.contains(
"LitDirLight") || it.contains(
"LitPointLight") || it.contains(
"LitSpotLight"))
606 requiresLightingCode =
true;
609 if (requiresLightingCode)
611 foreach(it, _defaultLightingFunctions)
618 code_.append(rawIO_);
622 foreach(it, (*_pMainCode))
628void ShaderGenerator::addIncludeFile(QString _fileName)
630 QFile file(_fileName);
632 if (file.open(QIODevice::ReadOnly | QIODevice::Text))
634 QTextStream fileStream(&file);
638 imports_.push_back(
"// ==============================================================================");
639 imports_.push_back(QString(
"// ShaderGenerator - begin of imported file: ") + _fileName);
642 while (!fileStream.atEnd())
644 QString tmpLine = fileStream.readLine();
646 imports_.push_back(tmpLine.simplified());
652 imports_.push_back(QString(
"// ShaderGenerator - end of imported file #include \"") + _fileName);
653 imports_.push_back(
"// ==============================================================================");
661void ShaderGenerator::saveToFile(
const char* _fileName)
663 QFile file(_fileName);
664 if (file.open(QIODevice::WriteOnly | QIODevice::Text))
666 QTextStream fileStream(&file);
670 fileStream << it <<
'\n';
676const QStringList& ShaderGenerator::getShaderCode()
681void ShaderGenerator::setGLSLVersion(
int _version )
687 bool _passToNextStage,
688 QString _inputPrefix,
689 QString _outputPrefix)
691 if (!_previousShaderStage)
693 std::cout <<
"error: ShaderGenerator::matchInputs called without providing input stage" << std::endl;
698 foreach(it, _previousShaderStage->outputs_)
702 QString outKeyword =
"out ";
703 QString inKeyword =
"in ";
706 input.replace(input.indexOf(outKeyword), outKeyword.size(), inKeyword);
712 int lastNameChar = input.lastIndexOf(QRegularExpression(
"[a-zA-Z0-9]"));
713 input.insert(lastNameChar+1,
"[]");
719 addStringToList(input, &inputs_);
721 if (_passToNextStage)
725 QString output = input;
726 output.replace(output.indexOf(_inputPrefix), _inputPrefix.size(), _outputPrefix);
727 output.replace(output.indexOf(inKeyword), inKeyword.size(), outKeyword);
730 if (inputArrays_ && !outputArrays_)
732 int bracketStart = output.indexOf(
"[");
733 int bracketEnd = output.indexOf(
"]");
734 output.remove(bracketStart, bracketEnd-bracketStart+1);
736 else if (!inputArrays_ && outputArrays_)
738 int lastNameChar = output.lastIndexOf(QRegularExpression(
"[a-zA-Z0-9]"));
739 output.insert(lastNameChar+1,
"[]");
745 addStringToList(output, &outputs_);
750int ShaderGenerator::getNumOutputs()
const
752 return outputs_.size();
755QString ShaderGenerator::getOutputName(
int _id)
const
757 QString output = outputs_.at(_id);
760 output.remove(
"out ");
762 int bracketStart = output.indexOf(
"[");
763 int bracketEnd = output.lastIndexOf(
"]");
765 if (bracketStart >= 0)
766 output.remove(bracketStart, bracketEnd-bracketStart+1);
769 QStringList decompOutput = output.split(
" ");
770 return decompOutput.last();
773int ShaderGenerator::getNumInputs()
const
775 return inputs_.size();
778QString ShaderGenerator::getInputName(
int _id)
const
780 QString input = inputs_.at(_id);
783 input.remove(
"out ");
785 int bracketStart = input.indexOf(
"[");
786 int bracketEnd = input.lastIndexOf(
"]");
788 if (bracketStart >= 0)
789 input.remove(bracketStart, bracketEnd-bracketStart+1);
792 QStringList decompInput = input.split(
" ");
793 return decompInput.last();
796QString ShaderGenerator::getIOMapName(
int _inId)
const
798 QString inputName = getInputName(_inId);
801 QString outputName = inputName;
802 outputName.replace(outputName.indexOf(inputPrefix_), inputPrefix_.size(), outputPrefix_);
808ShaderGenerator::DefaultIODesc::DefaultIODesc()
809 : inputTexCoord_(false),
812 passPosVS_(false), passPosOS_(false),
813 passTexCoord_(false),
815 passNormalVS_(false), passNormalOS_(false)
822QString ShaderProgGenerator::shaderDir_;
823QStringList ShaderProgGenerator::lightingCode_;
827 : vertex_(0), tessControl_(0), tessEval_(0), geometry_(0), fragment_(0)
833 : vertex_(0), tessControl_(0), tessEval_(0), geometry_(0), fragment_(0)
835 init(_desc, _modifierIDs, _numActiveMods);
839 : vertex_(0), tessControl_(0), tessEval_(0), geometry_(0), fragment_(0)
841 init(_desc, _modifierIDs.empty() ? 0 : &_modifierIDs[0], (
unsigned int)_modifierIDs.size());
845 : vertex_(0), tessControl_(0), tessEval_(0), geometry_(0), fragment_(0)
847 unsigned int numMods = !_modifierIDs || _modifierIDs->empty() ? 0 : (
unsigned int)_modifierIDs->size();
848 init(_desc, numMods ? &((*_modifierIDs)[0]) : 0, numMods);
852 : vertex_(0), tessControl_(0), tessEval_(0), geometry_(0), fragment_(0)
854 init(_desc, _modifiers, _numActiveMods);
858 : vertex_(0), tessControl_(0), tessEval_(0), geometry_(0), fragment_(0)
860 init(_desc, _modifierIDs.empty() ? 0 : &(_modifierIDs[0]), (
unsigned int)_modifierIDs.size());
864 : vertex_(0), tessControl_(0), tessEval_(0), geometry_(0), fragment_(0)
866 unsigned int numMods = !_modifierIDs || _modifierIDs->empty() ? 0 : (
unsigned int)_modifierIDs->size();
867 init(_desc, numMods ? &((*_modifierIDs)[0]) : 0, numMods);
873 if (_modifierIDs && _numActiveMods)
875 activeMods_.resize(_numActiveMods);
877 for (
unsigned int i = 0; i < _numActiveMods; ++i)
878 activeMods_[i] = registeredModifiers_[ _modifierIDs[i] ];
881 init(_desc, (ShaderModifier**)0, 0);
889 size_t numDescMods = _desc->shaderMods.size();
890 size_t numTotalMods = _numActiveMods + numDescMods;
893 activeMods_.resize(numTotalMods);
895 for (
size_t i = 0; i < numDescMods; ++i)
897 unsigned int modID = _desc->shaderMods[i];
898 activeMods_[i] = registeredModifiers_[modID];
901 if (_modifiers && _numActiveMods)
903 for (
unsigned int i = 0; i < _numActiveMods; ++i)
904 activeMods_[i + numDescMods] = _modifiers[i];
911 if (shaderDir_.isEmpty())
912 std::cout <<
"error: call ShaderProgGenerator::setShaderDir() first!" << std::endl;
920 if (!desc_.geometryTemplateFile.isEmpty())
921 std::cerr <<
"Warning: removing geometry shader from ShaderDesc" << std::endl;
923 desc_.geometryTemplateFile.clear();
929 if (!desc_.tessControlTemplateFile.isEmpty() || !desc_.tessEvaluationTemplateFile.isEmpty())
930 std::cerr <<
"Warning: removing tessellation shader from ShaderDesc" << std::endl;
932 desc_.tessControlTemplateFile.clear();
933 desc_.tessEvaluationTemplateFile.clear();
938 if (!desc_.geometryTemplateFile.isEmpty())
939 desc_.version = std::max(desc_.version, 150);
941 if (!desc_.tessControlTemplateFile.isEmpty() || !desc_.tessEvaluationTemplateFile.isEmpty())
942 desc_.version = std::max(desc_.version, 400);
945 loadLightingFunctions();
952ShaderProgGenerator::~ShaderProgGenerator(
void)
965 bool success =
false;
970 QFile file(absFilename);
972 if (file.open(QIODevice::ReadOnly | QIODevice::Text))
974 if (!file.isReadable())
975 std::cout <<
"error: unreadable file -> \"" << absFilename.toStdString() <<
"\"" << std::endl;
978 QTextStream filestream(&file);
980 while (!filestream.atEnd())
982 QString szLine = filestream.readLine();
983 _out->push_back(szLine.trimmed());
992 std::cout <<
"error: " << file.errorString().toStdString() <<
" -> \"" << absFilename.toStdString() <<
"\"" << std::endl;
998void ShaderProgGenerator::loadLightingFunctions()
1000 if (lightingCode_.size())
return;
1002 static const QString lightingCodeFile =
"ShaderGen/SG_LIGHTING.GLSL";
1004 QString fileName = shaderDir_ + QDir::separator() + QString(lightingCodeFile);
1006 lightingCode_.push_back(
"// ==============================================================================");
1007 lightingCode_.push_back(QString(
"// ShaderGenerator - default lighting functions imported from file: ") + fileName);
1013 lightingCode_.push_back(QString(
"// ShaderGenerator - end of default lighting functions"));
1014 lightingCode_.push_back(
"// ==============================================================================");
1021 switch (desc_.shadeMode)
1023 case SG_SHADE_GOURAUD:
1027 case SG_SHADE_UNLIT:
1029 case SG_SHADE_PHONG:
1033 std::cout << __FUNCTION__ <<
" -> unknown shade mode: " << desc_.shadeMode << std::endl;
1036 if (desc_.twoSidedLighting)
1037 _gen->
addDefine(
"TWO_SIDED_LIGHTING 1");
1039 if (desc_.textured())
1042 if (desc_.vertexColors)
1056 QString strNumLights = QString(
"SG_NUM_LIGHTS %1").arg(desc_.numLights);
1060 const char* lightTypeNames[] = {
"SG_LIGHT_DIRECTIONAL",
1061 "SG_LIGHT_POINT",
"SG_LIGHT_SPOT"};
1063 for (
int i = 0; i < 3; ++i)
1067 for (
int i = 0; i < desc_.numLights; ++i) {
1068 _gen->
addDefine( QString (
"SG_LIGHT_TYPE_%1 %2").arg(i).arg(lightTypeNames[desc_.lightTypes[i]]) );
1071 _gen->
addDefine(
"SG_ALPHA g_vMaterial.y");
1072 _gen->
addDefine(
"SG_MINALPHA g_vMaterial.z");
1081void ShaderProgGenerator::buildVertexShader()
1093 if (desc_.texGenDim && (desc_.texGenMode == GL_OBJECT_LINEAR || desc_.texGenMode == GL_EYE_LINEAR) && !desc_.texGenPerFragment)
1096 QString uniformDecl =
"vec4 g_vTexGenPlane";
1097 if (desc_.texGenDim > 1)
1098 uniformDecl +=
"[" + QString::number(desc_.texGenDim) +
"]";
1099 vertex_->
addUniform(uniformDecl,
" // texture projection planes");
1104 for (
size_t i = 0; i < activeMods_.size(); ++i)
1105 activeMods_[i]->modifyVertexIO(vertex_);
1115 if (desc_.shadeMode == SG_SHADE_GOURAUD ||
1116 desc_.shadeMode == SG_SHADE_FLAT)
1118 for (
int i = 0; i < desc_.numLights; ++i)
1119 vertex_->
addLight(i, desc_.lightTypes[i]);
1124 QStringList mainCode;
1126 if (!vertexTemplate_.size())
1128 mainCode.push_back(
"void main()");
1129 mainCode.push_back(
"{");
1131 addVertexBeginCode(&mainCode);
1132 addVertexEndCode(&mainCode);
1134 mainCode.push_back(
"}");
1142 foreach(it,vertexTemplate_)
1149 if (it.contains(
"SG_VERTEX_BEGIN"))
1150 addVertexBeginCode(&mainCode);
1153 if (it.contains(
"SG_VERTEX_END"))
1154 addVertexEndCode(&mainCode);
1158 mainCode.push_back(it);
1172void ShaderProgGenerator::addVertexBeginCode(QStringList* _code)
1176 _code->push_back(QString(
"vec4 sg_vPosPS = g_mWVP * ") + ShaderGenerator::keywords.macro_inputPosOS + QString(
";"));
1177 _code->push_back(
"vec4 sg_vPosVS = g_mWV * inPosition;");
1178 _code->push_back(
"vec3 sg_vNormalVS = vec3(0.0, 1.0, 0.0);");
1179 _code->push_back(
"vec3 sg_vNormalOS = vec3(0.0, 1.0, 0.0);");
1181 if (desc_.vertexColors && (desc_.colorMaterialMode == GL_AMBIENT || desc_.colorMaterialMode == GL_AMBIENT_AND_DIFFUSE))
1182 _code->push_back(QString(
"vec4 sg_cColor = vec4(g_cEmissive + g_cLightModelAmbient * ")
1183 + ShaderGenerator::keywords.macro_inputVertexColor
1184 + QString(
".rgb, SG_ALPHA * ")
1185 + ShaderGenerator::keywords.macro_inputVertexColor
1188 _code->push_back(
"vec4 sg_cColor = vec4(g_cEmissive + g_cLightModelAmbient * g_cAmbient, SG_ALPHA);");
1192 _code->push_back(
"sg_vNormalVS = normalize(g_mWVIT * inNormal);");
1193 _code->push_back(
"sg_vNormalOS = normalize(inNormal);");
1196 if (
ioDesc_.inputColor_ && (desc_.shadeMode == SG_SHADE_UNLIT || desc_.colorMaterialMode == GL_EMISSION))
1197 _code->push_back(QString(
"sg_cColor = ") + ShaderGenerator::keywords.macro_inputVertexColor + QString(
";"));
1204 for (
size_t i = 0; i < activeMods_.size(); ++i)
1205 activeMods_[i]->modifyVertexBeginCode(_code);
1209void ShaderProgGenerator::addVertexEndCode(QStringList* _code)
1211 if (desc_.shadeMode == SG_SHADE_GOURAUD ||
1212 desc_.shadeMode == SG_SHADE_FLAT)
1219 _code->push_back(
"gl_Position = sg_vPosPS;");
1220 _code->push_back(
"outVertexPosCS = sg_vPosPS;");
1223 _code->push_back(
"outVertexTexCoord = sg_vTexCoord;");
1226 _code->push_back(
"outVertexColor = sg_cColor;");
1229 _code->push_back(ShaderGenerator::keywords.macro_outputNormalVS + QString(
" = sg_vNormalVS;"));
1232 _code->push_back(ShaderGenerator::keywords.macro_outputNormalOS + QString(
" = sg_vNormalOS;"));
1235 _code->push_back(ShaderGenerator::keywords.macro_outputPosVS + QString(
" = sg_vPosVS;"));
1238 _code->push_back(ShaderGenerator::keywords.macro_outputPosOS + QString(
" = ") + ShaderGenerator::keywords.macro_inputPosOS + QString(
";"));
1243 for (
size_t i = 0; i < activeMods_.size(); ++i)
1244 activeMods_[i]->modifyVertexEndCode(_code);
1250 if (_str.contains(
"#include "))
1252 QString strIncludeFile = _str.remove(
"#include ").remove(
'\"').remove(
'<').remove(
'>').trimmed();
1254 if (strIncludeFile.isEmpty())
1255 std::cout <<
"wrong include syntax: " << _str.toStdString() << std::endl;
1258 QString fullPathToIncludeFile = _includePath + QDir::separator() + strIncludeFile;
1271 if (_str.contains(
"#include "))
1273 QString strIncludeFile = _str.remove(
"#include ").remove(
'\"').remove(
'<').remove(
'>').trimmed();
1275 if (strIncludeFile.isEmpty())
1276 std::cout <<
"wrong include syntax: " << _str.toStdString() << std::endl;
1279 QString fullPathToIncludeFile = _includePath + QDir::separator() + strIncludeFile;
1282 fullPathToIncludeFile.replace(
'\\',
'/');
1285 QString cleanFilepath = QDir::cleanPath(fullPathToIncludeFile);
1296void ShaderProgGenerator::buildTessControlShader()
1299 if ( desc_.tessControlTemplateFile.isEmpty() )
1309 delete tessControl_;
1327 for (
size_t i = 0; i < activeMods_.size(); ++i)
1328 activeMods_[i]->modifyTessControlIO(tessControl_);
1335 QStringList mainCode;
1341 mainCode.push_back(
"#define sg_MapIO(inIdx) do {\\");
1344 mainCode.push_back(
"gl_out[gl_InvocationID].gl_Position = gl_in[inIdx].gl_Position;\\");
1352 QString outputAssignCode = outputName + QString(
"[gl_InvocationID] = ") + inputName + QString(
"[inIdx];\\");
1354 mainCode.push_back(outputAssignCode);
1358 mainCode.push_back(
"} while(false)");
1364 foreach(it,tessControlTemplate_)
1369 mainCode.push_back(it);
1376void ShaderProgGenerator::buildTessEvalShader()
1379 if ( desc_.tessEvaluationTemplateFile.isEmpty() )
1392 tessEval_ =
new ShaderGenerator();
1397 ShaderGenerator* prevStage = tessControl_;
1400 prevStage = vertex_;
1407 foreach(itLayout, tessEvalLayout_)
1411 for (
size_t i = 0; i < activeMods_.size(); ++i)
1412 activeMods_[i]->modifyTessControlIO(tessEval_);
1418 QStringList mainCode;
1425 mainCode.push_back(
"void sg_MapIOBarycentric()");
1426 mainCode.push_back(
"{");
1429 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;");
1437 QString outputAssignCode = outputName + QString(
" = ") +
1438 QString(
"gl_TessCoord.x*") + inputName + QString(
"[0] + ") +
1439 QString(
"gl_TessCoord.y*") + inputName + QString(
"[1] + ") +
1440 QString(
"gl_TessCoord.z*") + inputName + QString(
"[2];");
1442 mainCode.push_back(outputAssignCode);
1445 mainCode.push_back(
"}");
1450 mainCode.push_back(
"void sg_MapIOBilinear()");
1451 mainCode.push_back(
"{");
1454 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);");
1462 QString outputAssignCode = outputName + QString(
" = mix( ") +
1463 QString(
"mix(") + inputName + QString(
"[0], ") + inputName + QString(
"[1], gl_TessCoord.x), ") +
1464 QString(
"mix(") + inputName + QString(
"[2], ") + inputName + QString(
"[3], gl_TessCoord.x), gl_TessCoord.y); ");
1466 mainCode.push_back(outputAssignCode);
1469 mainCode.push_back(
"}");
1475 QStringList::iterator it;
1476 for (it = tessEvalTemplate_.begin(); it != tessEvalTemplate_.end(); ++it)
1485 if (line.contains(
"SG_INPUT") || line.contains(
"SG_OUTPUT"))
1488 QStringList resolvedCode;
1490 resolvedCode.push_back(
"// ----------------------------------------");
1491 resolvedCode.push_back(
"// ShaderGen: resolve SG_OUTPUT = expression(SG_INPUT);");
1493 int numOccurrences = 0;
1501 QString resolvedLine = line;
1511 for (
int k = 0; k < 2; ++k)
1513 const QString stringToReplace = k ?
"SG_OUTPUT" :
"SG_INPUT";
1514 const int lenStringToReplace = stringToReplace.length();
1515 const QString replacementString = k ? outputName : inputName;
1517 int linePos = resolvedLine.indexOf(stringToReplace);
1519 while (linePos >= 0)
1521 bool replaceOcc =
true;
1523 int nextCharPos = linePos + lenStringToReplace;
1525 if (nextCharPos >= resolvedLine.size())
1528 if (nextCharPos > 0)
1530 QChar nextChar = resolvedLine.at(nextCharPos);
1532 if (nextChar ==
'_' || nextChar.isDigit() || nextChar.isLetter())
1536 linePos += lenStringToReplace;
1545 resolvedLine.replace(linePos, lenStringToReplace, replacementString);
1549 linePos = resolvedLine.indexOf(stringToReplace, linePos + 1);
1557 resolvedCode.push_back(resolvedLine);
1560 resolvedCode.push_back(
"// ----------------------------------------");
1563 mainCode.append(resolvedCode);
1565 mainCode.push_back(line);
1568 mainCode.push_back(line);
1574void ShaderProgGenerator::buildGeometryShader()
1577 if ( desc_.geometryTemplateFile.isEmpty() )
1583 geometry_ =
new ShaderGenerator();
1588 ShaderGenerator* prevStage = tessEval_;
1591 prevStage = vertex_;
1599 for (
size_t i = 0; i < activeMods_.size(); ++i)
1600 activeMods_[i]->modifyGeometryIO(geometry_);
1606 QStringList mainCode;
1612 mainCode.push_back(
"#define sg_MapIO(inIdx) do {\\");
1615 mainCode.push_back(
"gl_Position = gl_in[inIdx].gl_Position;\\");
1616 mainCode.push_back(
"gl_PrimitiveID = gl_PrimitiveIDIn;\\");
1620 static int maxClipDistances = -1;
1621 if (maxClipDistances < 0)
1623#ifdef GL_MAX_CLIP_DISTANCES
1624 glGetIntegerv(GL_MAX_CLIP_DISTANCES, &maxClipDistances);
1625 maxClipDistances = std::min(maxClipDistances, 32);
1627 maxClipDistances = 32;
1630 for (
int i = 0; i < maxClipDistances; ++i)
1632 if (desc_.clipDistanceMask & (1 << i))
1633 mainCode.push_back(QString(
"gl_ClipDistance[%1] = gl_in[inIdx].gl_ClipDistance[%1];\\").arg(i));
1642 QString outputAssignCode = outputName + QString(
" = ") + inputName + QString(
"[inIdx];\\");
1644 mainCode.push_back(outputAssignCode);
1648 mainCode.push_back(
"} while(false)");
1655 foreach(it,geometryTemplate_)
1660 mainCode.push_back(it);
1668void ShaderProgGenerator::buildFragmentShader()
1672 fragment_ =
new ShaderGenerator();
1676 ShaderGenerator* prevStage = geometry_;
1679 prevStage = tessEval_;
1681 prevStage = tessControl_;
1683 prevStage = vertex_;
1688 if (desc_.texGenDim && (desc_.texGenMode == GL_OBJECT_LINEAR || desc_.texGenMode == GL_EYE_LINEAR) && desc_.texGenPerFragment)
1691 QString uniformDecl =
"vec4 g_vTexGenPlane";
1692 if (desc_.texGenDim > 1)
1693 uniformDecl +=
"[" + QString::number(desc_.texGenDim) +
"]";
1694 fragment_->
addUniform(uniformDecl,
" // texture projection planes");
1702 if (desc_.textured())
1704 for (std::map<size_t,ShaderGenDesc::TextureType>::const_iterator iter = desc_.textureTypes().begin();
1705 iter != desc_.textureTypes().end(); ++iter)
1707 QString name = QString(
"g_Texture%1").arg(iter->first);
1709 switch (iter->second.type)
1711 case GL_TEXTURE_1D: type =
"sampler1D";
break;
1712 case GL_TEXTURE_2D: type =
"sampler2D";
break;
1713 case GL_TEXTURE_3D: type =
"sampler3D";
break;
1714 case GL_TEXTURE_CUBE_MAP: type =
"samplerCube";
break;
1715#ifdef GL_ARB_texture_rectangle
1716 case GL_TEXTURE_RECTANGLE_ARB: type =
"sampler2DRect";
break;
1718 case GL_TEXTURE_BUFFER: type =
"samplerBuffer";
break;
1719#ifdef GL_EXT_texture_array
1720 case GL_TEXTURE_1D_ARRAY_EXT: type =
"sampler1DArray";
break;
1721 case GL_TEXTURE_2D_ARRAY_EXT: type =
"sampler2DArray";
break;
1723#ifdef GL_ARB_texture_cube_map_array
1724 case GL_TEXTURE_CUBE_MAP_ARRAY_ARB: type =
"samplerCubeArray";
break;
1726#ifdef GL_ARB_texture_multisample
1727 case GL_TEXTURE_2D_MULTISAMPLE: type =
"sampler2DMS";
break;
1728 case GL_TEXTURE_2D_MULTISAMPLE_ARRAY: type =
"sampler2DMSArray";
break;
1730 default: std::cerr <<
"Texture Type not supported "<< iter->second.type << std::endl;
break;
1733 if (iter->second.shadow)
1740 for (
size_t i = 0; i < activeMods_.size(); ++i)
1741 activeMods_[i]->modifyFragmentIO(fragment_);
1751 if (desc_.shadeMode == SG_SHADE_PHONG)
1753 for (
int i = 0; i < desc_.numLights; ++i)
1754 fragment_->
addLight(i, desc_.lightTypes[i]);
1758 QStringList mainCode;
1760 if (!fragmentTemplate_.size())
1762 mainCode.push_back(
"void main()");
1763 mainCode.push_back(
"{");
1765 addFragmentBeginCode(&mainCode);
1766 addFragmentEndCode(&mainCode);
1768 mainCode.push_back(
"}");
1775 foreach(it,fragmentTemplate_)
1782 if (it.contains(
"SG_FRAGMENT_BEGIN"))
1783 addFragmentBeginCode(&mainCode);
1784 else if (it.contains(
"SG_FRAGMENT_END"))
1785 addFragmentEndCode(&mainCode);
1786 else if (it.contains(
"SG_FRAGMENT_LIGHTING"))
1789 mainCode.push_back(it);
1804void ShaderProgGenerator::addFragmentBeginCode(QStringList* _code)
1807 _code->push_back(QString(
"vec4 sg_vPosCS = ") + ShaderGenerator::keywords.macro_inputPosCS + QString(
";"));
1808 _code->push_back(
"vec2 sg_vScreenPos = sg_vPosCS.xy / sg_vPosCS.w * 0.5 + vec2(0.5, 0.5);");
1810 _code->push_back(QString(
"#ifdef ") + ShaderGenerator::keywords.macro_inputPosVS);
1811 _code->push_back(QString(
"vec4 sg_vPosVS = ") + ShaderGenerator::keywords.macro_inputPosVS + QString(
";"));
1812 _code->push_back(
"#endif");
1814 _code->push_back(QString(
"#ifdef ") + ShaderGenerator::keywords.macro_inputNormalVS);
1815 _code->push_back(QString(
"vec3 sg_vNormalVS = ") + ShaderGenerator::keywords.macro_inputNormalVS + QString(
";"));
1816 _code->push_back(
"sg_vNormalVS = normalize(sg_vNormalVS);");
1817 _code->push_back(
"#endif");
1820 if (desc_.vertexColors && (desc_.colorMaterialMode == GL_AMBIENT || desc_.colorMaterialMode == GL_AMBIENT_AND_DIFFUSE))
1821 _code->push_back(QString(
"vec4 sg_cColor = vec4(g_cEmissive + g_cLightModelAmbient * ")
1822 + ShaderGenerator::keywords.macro_inputVertexColor
1823 + QString(
".rgb, SG_ALPHA * ")
1824 + ShaderGenerator::keywords.macro_inputVertexColor
1827 _code->push_back(
"vec4 sg_cColor = vec4(g_cEmissive + g_cLightModelAmbient * g_cAmbient, SG_ALPHA);");
1829 if (desc_.shadeMode == SG_SHADE_GOURAUD ||
1830 desc_.shadeMode == SG_SHADE_FLAT ||
1831 (
ioDesc_.passColor_ && (desc_.shadeMode == SG_SHADE_UNLIT || desc_.colorMaterialMode == GL_EMISSION)))
1832 _code->push_back(QString(
"sg_cColor = ") + ShaderGenerator::keywords.macro_inputVertexColor + QString(
";"));
1834 _code->push_back(QString(
"if (sg_cColor.a < SG_MINALPHA) discard;"));
1835 if (desc_.shadeMode == SG_SHADE_PHONG)
1841 if (desc_.textured())
1843 std::map<size_t,ShaderGenDesc::TextureType>::const_iterator iter = desc_.textureTypes().begin();
1844 _code->push_back(
"vec4 sg_cTex = texture(g_Texture"+QString::number(iter->first)+
", sg_vTexCoord);");
1846 for (++iter; iter != desc_.textureTypes().end(); ++iter)
1847 _code->push_back(
"sg_cTex += texture(g_Texture"+QString::number(iter->first)+
", sg_vTexCoord);");
1850 _code->push_back(
"sg_cTex = sg_cTex * 1.0/" + QString::number(desc_.textureTypes().size()) +
".0 ;");
1852 if (desc_.shadeMode == SG_SHADE_UNLIT)
1853 _code->push_back(
"sg_cColor += sg_cTex;");
1855 _code->push_back(
"sg_cColor *= sg_cTex;");
1860 for (
size_t i = 0; i < activeMods_.size(); ++i)
1861 activeMods_[i]->modifyFragmentBeginCode(_code);
1864void ShaderProgGenerator::addFragmentEndCode(QStringList* _code)
1866 _code->push_back(ShaderGenerator::keywords.fs_outputFragmentColor + QString(
" = sg_cColor;"));
1869 for (
size_t i = 0; i < activeMods_.size(); ++i)
1870 activeMods_[i]->modifyFragmentEndCode(_code);
1881 for (
size_t i = 0; i < activeMods_.size() && !lightingModifier; ++i)
1883 if (activeMods_[i]->replaceDefaultLightingCode())
1884 lightingModifier = activeMods_[i];
1887 if (!lightingModifier)
1893 QString vertexColorString = (
ioDesc_.inputColor_ &&
ioDesc_.passColor_) ? (ShaderGenerator::keywords.macro_inputVertexColor + QString(
".xyz * ")) :
"";
1894 QString diffuseVertexColor = (desc_.colorMaterialMode == GL_DIFFUSE || desc_.colorMaterialMode == GL_AMBIENT_AND_DIFFUSE) ? vertexColorString :
"";
1895 QString ambientVertexColor = (desc_.colorMaterialMode == GL_AMBIENT || desc_.colorMaterialMode == GL_AMBIENT_AND_DIFFUSE) ? vertexColorString :
"";
1896 QString specularVertexColor = (desc_.colorMaterialMode == GL_SPECULAR) ? vertexColorString :
"";
1898 for (
int i = 0; i < desc_.numLights; ++i)
1900 ShaderGenLightType lgt = desc_.lightTypes[i];
1904 case SG_LIGHT_DIRECTIONAL:
1906 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);
1909 case SG_LIGHT_POINT:
1911 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);
1916 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);
1922 _code->push_back(buf);
1927 for (
size_t i = 0; i < activeMods_.size(); ++i)
1938 for (
size_t i = 0; i < activeMods_.size(); ++i)
1940 if (lightingModifier != activeMods_[i])
1949 if (!_modifier)
return;
1951 for (
int i = 0; i < desc_.numLights; ++i)
1953 ShaderGenLightType lgt = desc_.lightTypes[i];
1963 foreach(it,lightingCode_)
1964 _code->push_back(it);
1971 int texcoordVarDim = 2;
1973 !desc_.textureTypes().empty() &&
1974 desc_.textureTypes().begin()->second.type == GL_TEXTURE_3D)
1977 bool generateTexCoord = desc_.texGenDim && desc_.texGenMode && (_fragmentShader == desc_.texGenPerFragment);
1978 if (generateTexCoord)
1979 texcoordVarDim = desc_.texGenDim;
1981 QString texcoordVarInit;
1982 if (texcoordVarDim == 1)
1983 texcoordVarInit =
"float sg_vTexCoord";
1985 texcoordVarInit = QString(
"vec%1 sg_vTexCoord").arg(texcoordVarDim);
1989 texcoordVarInit += QString(
"= ") + ShaderGenerator::keywords.macro_inputTexcoord + QString(
";");
1990 else if (0 <= texcoordVarDim && texcoordVarDim <= 4)
1992 QString zeroVecDefs[] =
2000 texcoordVarInit += zeroVecDefs[texcoordVarDim];
2003 _code->push_back(texcoordVarInit);
2008 if (generateTexCoord)
2011 const char* texGenCoordString[] = {
"x",
"y",
"z",
"w" };
2013 switch (desc_.texGenMode)
2015 case GL_OBJECT_LINEAR:
2017 for (
int i = 0; i < desc_.texGenDim; ++i)
2019 QString assignmentInstrString;
2020 assignmentInstrString =
"sg_vTexCoord";
2021 if (desc_.texGenDim > 1)
2023 assignmentInstrString +=
".";
2024 assignmentInstrString += texGenCoordString[i];
2026 assignmentInstrString +=
" = dot(";
2027 assignmentInstrString += ShaderGenerator::keywords.macro_inputPosOS;
2028 assignmentInstrString +=
", g_vTexGenPlane";
2029 if (desc_.texGenDim > 1)
2031 assignmentInstrString +=
"[";
2032 assignmentInstrString += QString::number(i);
2033 assignmentInstrString +=
"]";
2035 assignmentInstrString +=
");";
2036 _code->push_back(assignmentInstrString);
2042 for (
int i = 0; i < desc_.texGenDim; ++i)
2044 QString assignmentInstrString;
2045 assignmentInstrString =
"sg_vTexCoord";
2046 if (desc_.texGenDim > 1)
2048 assignmentInstrString +=
".";
2049 assignmentInstrString += texGenCoordString[i];
2051 assignmentInstrString +=
" = dot(sg_vPosVS, g_vTexGenPlane";
2052 if (desc_.texGenDim > 1)
2054 assignmentInstrString +=
"[";
2055 assignmentInstrString += QString::number(i);
2056 assignmentInstrString +=
"]";
2058 assignmentInstrString +=
");";
2059 _code->push_back(assignmentInstrString);
2066 _code->push_back(
"vec3 sg_vPosVS_unit = normalize(sg_vPosVS.xyz);");
2067 _code->push_back(
"vec3 sg_TexGenRefl = reflect(sg_vPosVS_unit, sg_vNormalVS);");
2068 _code->push_back(
"vec3 sg_TexGenRefl2 = sg_TexGenRefl; sg_TexGenRefl2.z += 1.0;");
2069 _code->push_back(
"float sg_TexGenMRcp = 0.5 * inversesqrt(dot(sg_TexGenRefl2, sg_TexGenRefl2));");
2070 for (
int i = 0; i < desc_.texGenDim; ++i)
2072 _code->push_back(QString (
"sg_vTexCoord.%1 = sg_TexGenRefl.%2 * sg_TexGenMRcp + 0.5;").arg(texGenCoordString[i]).arg(texGenCoordString[i]));
2078 for (
int i = 0; i < desc_.texGenDim; ++i)
2080 _code->push_back( QString (
"sg_vTexCoord.%1 = sg_vNormalVS.%2;").arg(texGenCoordString[i]).arg(texGenCoordString[i]) );
2084 case GL_REFLECTION_MAP:
2086 _code->push_back(
"vec3 sg_vPosVS_unit = normalize(sg_vPosVS.xyz);");
2087 _code->push_back(
"vec3 sg_TexGenRefl = reflect(sg_vPosVS_unit, sg_vNormalVS);");
2088 for (
int i = 0; i < desc_.texGenDim; ++i)
2091 _code->push_back( QString (
"sg_vTexCoord.%1 = sg_TexGenRefl.%2;").arg(texGenCoordString[i]).arg(texGenCoordString[i]) );
2108 if (desc_.shadeMode != SG_SHADE_UNLIT)
2111 if (desc_.textured())
2118 int maxTexGenDim = 4;
2120 switch (desc_.texGenMode)
2123 case GL_OBJECT_LINEAR: maxTexGenDim = 4;
break;
2125 case GL_SPHERE_MAP: maxTexGenDim = 2;
break;
2128 case GL_REFLECTION_MAP: maxTexGenDim = 3;
break;
2130 default: maxTexGenDim = 0;
break;
2133 desc_.texGenDim = std::max(std::min(desc_.texGenDim, maxTexGenDim), 0);
2136 if (desc_.texGenDim && desc_.texGenMode)
2139 if (!desc_.texGenPerFragment)
2143 if (desc_.texGenMode == GL_REFLECTION_MAP || desc_.texGenMode == GL_SPHERE_MAP || desc_.texGenMode == GL_NORMAL_MAP)
2147 if (desc_.texGenPerFragment)
2149 switch (desc_.texGenMode)
2151 case GL_OBJECT_LINEAR:
ioDesc_.passPosOS_ =
true;
break;
2154 case GL_NORMAL_MAP:
ioDesc_.passNormalVS_ =
true;
break;
2162 if (desc_.vertexColors)
2165 if (desc_.shadeMode == SG_SHADE_PHONG)
2171 if (desc_.shadeMode == SG_SHADE_FLAT || desc_.shadeMode == SG_SHADE_GOURAUD || desc_.vertexColors)
2179 for (
size_t i = 0; i < activeMods_.size(); ++i)
2191 if (dummy.
hasDefine(ShaderGenerator::keywords.macro_requestPosVS))
2193 if (dummy.
hasDefine(ShaderGenerator::keywords.macro_requestTexcoord))
2198 if (dummy.
hasDefine(ShaderGenerator::keywords.macro_requestVertexColor))
2203 if (dummy.
hasDefine(ShaderGenerator::keywords.macro_requestNormalVS))
2208 if (dummy.
hasDefine(ShaderGenerator::keywords.macro_requestNormalOS))
2213 if (dummy.
hasDefine(ShaderGenerator::keywords.macro_requestPosOS))
2222 buildVertexShader();
2223 buildTessControlShader();
2224 buildTessEvalShader();
2225 buildGeometryShader();
2226 buildFragmentShader();
2256void ShaderProgGenerator::saveVertexShToFile(
const char* _fileName)
2261void ShaderProgGenerator::saveGeometryShToFile(
const char* _fileName)
2266void ShaderProgGenerator::saveFragmentShToFile(
const char* _fileName)
2274 if (!desc_.vertexTemplateFile.isEmpty())
2279 if (!desc_.fragmentTemplateFile.isEmpty())
2284 if (!desc_.geometryTemplateFile.isEmpty())
2289 if (!desc_.tessControlTemplateFile.isEmpty())
2294 if (!desc_.tessEvaluationTemplateFile.isEmpty())
2297 scanShaderTemplate(tessEvalTemplate_, desc_.tessEvaluationTemplateFile, &tessEvalLayout_);
2302 tessControlShaderFile_ = desc_.tessControlTemplateFile;
2303 tessEvalShaderFile_ = desc_.tessEvaluationTemplateFile;
2304 geometryShaderFile_ = desc_.geometryTemplateFile;
2305 fragmentShaderFile_ = desc_.fragmentTemplateFile;
2313 QString filePath =
getPathName(_templateFilename);
2315 QStringList::iterator it;
2316 for (it = _templateSrc.begin(); it != _templateSrc.end(); ++it)
2325 it = _templateSrc.erase(it);
2327 int offset = it - _templateSrc.begin();
2332 foreach(importLine,
import)
2334 it = _templateSrc.insert(it, importLine);
2340 it = _templateSrc.begin() + offset;
2344 QString trimmedLine = it->trimmed();
2347 QByteArray lineBytes = trimmedLine.toUtf8();
2349 if (trimmedLine.startsWith(
"#version "))
2351 QStringList tokens = trimmedLine.split(
' ');
2353 if (tokens.size() > 1)
2356 bool convOk =
false;
2357 int templateVersion = tokens.at(1).toInt(&convOk);
2361 desc_.version = std::max(templateVersion, desc_.version);
2364 it = _templateSrc.erase(it);
2369 else if (trimmedLine.startsWith(
"layout(") || trimmedLine.startsWith(
"layout ("))
2371 if (_outLayoutDirectives)
2373 _outLayoutDirectives->push_back(trimmedLine);
2376 it = _templateSrc.erase(it);
2383 if (trimmedLine.startsWith(ShaderGenerator::keywords.macro_requestPosVS))
2385 else if (trimmedLine.startsWith(ShaderGenerator::keywords.macro_requestTexcoord))
2390 else if (trimmedLine.startsWith(ShaderGenerator::keywords.macro_requestVertexColor))
2395 else if (trimmedLine.startsWith(ShaderGenerator::keywords.macro_requestNormalVS))
2400 else if (trimmedLine.startsWith(ShaderGenerator::keywords.macro_requestNormalOS))
2405 else if (trimmedLine.startsWith(ShaderGenerator::keywords.macro_requestPosOS))
2407 else if (trimmedLine.startsWith(
"SG_FRAGMENT_LIGHTING"))
2411 desc_.shadeMode = SG_SHADE_PHONG;
2423 return fileInfo.absolutePath();
2428 QString absFilename;
2429 if ( QDir(_strFileName).isRelative() )
2430 absFilename =
getShaderDir() + QDir::separator() + _strFileName;
2432 absFilename = _strFileName;
2434 return QDir::cleanPath(absFilename);
2444 return shaderDir_ + QString(
"/");
2450 if (!_modifier)
return 0;
2455 if (registeredModifiers_[i] == _modifier)
2458 return registeredModifiers_[i]->getID();
2464 registeredModifiers_.push_back(_modifier);
2465 return _modifier->modifierID_;
2470 if (_i >= 0 && _i <=
int(activeMods_.size()))
2471 return activeMods_[_i];
2479 return int(activeMods_.size());
2485 return !desc_.geometryTemplateFile.isEmpty();
2490 return !desc_.tessControlTemplateFile.isEmpty();
2495 return !desc_.tessEvaluationTemplateFile.isEmpty();
2501ShaderModifier::ShaderModifier(
void )
2505ShaderModifier::~ShaderModifier(
void )
2532 const QString& filename()
const {
return filename_;}
2533 const QDateTime& filetime()
const {
return filetime_;}
2534 void filetime(
const QDateTime& _newtime) {filetime_ = _newtime;}
2540 for (
int i = 0; i < 5; ++i)
2543 vertexBeginCode_.clear();
2544 vertexEndCode_.clear();
2545 fragmentBeginCode_.clear();
2546 fragmentEndCode_.clear();
2549 static ShaderModifierFile* loadFromFile(QString _filename)
2551 ShaderModifierFile* res = 0;
2555 QDateTime lastmod = QFileInfo(absFilename).lastModified();
2558 QHash<QString, ShaderModifierFile>::iterator cacheEntry = fileCache_.find(_filename);
2560 bool reload =
false;
2561 bool firstLoad =
false;
2563 if (cacheEntry != fileCache_.end())
2566 res = &cacheEntry.value();
2568 if (lastmod != res->filetime())
2588 res = &fileCache_[_filename];
2590 res->loadBlocks(lines);
2591 res->filetime(lastmod);
2605 void loadBlocks(
const QStringList& _lines)
2607 static const char* markers [] =
2616 "FragmentBeginCode:",
2619 const int numMarkers =
sizeof(markers) /
sizeof(markers[0]);
2621 QStringList* blockTargets [] =
2630 &fragmentBeginCode_,
2634 assert(
sizeof(blockTargets) /
sizeof(blockTargets[0]) == numMarkers);
2638 QStringList* curBlock_ = 0;
2643 for (QStringList::const_iterator it = _lines.begin(); it != _lines.end(); ++it, ++curLine)
2649 if (version_ <= 0 && it->startsWith(
"#version "))
2651 const int offset = strlen(
"#version ");
2652 version_ = atoi(it->toLatin1().data() + offset);
2658 bool blockMarker =
false;
2660 for (
int i = 0; i < numMarkers && !blockMarker; ++i)
2662 if ( it->startsWith(markers[i]) )
2665 curBlock_ = blockTargets[i];
2673 curBlock_->push_back(*it);
2675 std::cerr <<
"ShaderModifierFile::loadBlocks - line belongs to unknown block in file " << filename_.toLatin1().data() <<
" at line " << curLine << std::endl;
2681 void modifyIO(
int _stage, ShaderGenerator* _shader)
2684 _shader->setGLSLVersion(version_);
2686 _shader->addRawIOBlock(io_[_stage]);
2693 QDateTime filetime_;
2702 QStringList vertexBeginCode_,
2709 static QHash<QString, ShaderModifierFile> fileCache_;
2712QHash<QString, ShaderModifierFile> ShaderModifierFile::fileCache_;
2717 return ShaderModifierFile::loadFromFile(_filename);
2727 const char* shadeModeString[] =
2736 QTextStream resStrm(&res);
2738 resStrm <<
"version: " << version;
2740 resStrm <<
"\nshaderDesc.numLights: " << numLights;
2744 resStrm <<
"\nshaderDesc.lightTypes[]: {";
2746 for (
int i = 0; i < numLights; ++i)
2748 switch (lightTypes[i])
2750 case SG_LIGHT_DIRECTIONAL: resStrm <<
"DIRECTIONAL";
break;
2751 case SG_LIGHT_POINT: resStrm <<
"POINT";
break;
2752 case SG_LIGHT_SPOT: resStrm <<
"SPOT";
break;
2753 default: resStrm <<
"UNDEFINED";
break;
2756 if (i + 1 < numLights)
2762 resStrm <<
"\nshaderDesc.shadeMode: " << shadeModeString[shadeMode];
2763 resStrm <<
"\nshaderDesc.twoSidedLighting: " << (twoSidedLighting ?
"Yes" :
"No");
2764 resStrm <<
"\nshaderDesc.vertexColors: " << vertexColors;
2765 resStrm <<
"\nshaderDesc.textured(): " << textured();
2768 resStrm <<
"\nTexture stage: " << iter->first;
2769 resStrm <<
"\nTexture Type: ";
2770 switch (iter->second.type)
2772 case GL_TEXTURE_1D: resStrm <<
"GL_TEXTURE_1D";
break;
2773 case GL_TEXTURE_2D: resStrm <<
"GL_TEXTURE_2D";
break;
2774 case GL_TEXTURE_3D: resStrm <<
"GL_TEXTURE_3D";
break;
2775 case GL_TEXTURE_CUBE_MAP: resStrm <<
"GL_TEXTURE_CUBE_MAP";
break;
2776#ifdef GL_ARB_texture_rectangle
2777 case GL_TEXTURE_RECTANGLE_ARB: resStrm <<
"GL_TEXTURE_RECTANGLE";
break;
2779 case GL_TEXTURE_BUFFER: resStrm <<
"GL_TEXTURE_BUFFER";
break;
2780#ifdef GL_EXT_texture_array
2781 case GL_TEXTURE_1D_ARRAY_EXT: resStrm <<
"GL_TEXTURE_1D_ARRAY";
break;
2782 case GL_TEXTURE_2D_ARRAY_EXT: resStrm <<
"GL_TEXTURE_2D_ARRAY";
break;
2784#ifdef GL_ARB_texture_cube_map_array
2785 case GL_TEXTURE_CUBE_MAP_ARRAY_ARB: resStrm <<
"GL_TEXTURE_CUBE_MAP_ARRAY";
break;
2787#ifdef GL_ARB_texture_multisample
2788 case GL_TEXTURE_2D_MULTISAMPLE: resStrm <<
"GL_TEXTURE_2D_MULTISAMPLE";
break;
2789 case GL_TEXTURE_2D_MULTISAMPLE_ARRAY: resStrm <<
"GL_TEXTURE_2D_MULTISAMPLE_ARRAY";
break;
2791 default: std::cerr <<
"Texture Type with number "<< iter->second.type <<
" on stage "<< iter->first <<
" is not supported " << std::endl;
break;
2794 resStrm <<
"\nShadowTexture: " << iter->second.shadow;
2797 resStrm <<
"\nshaderDesc.texGenDim: " << texGenDim;
2801 case GL_OBJECT_LINEAR: resStrm <<
"\nshaderDesc.texGenMode: GL_OBJECT_LINEAR";
break;
2802 case GL_EYE_LINEAR: resStrm <<
"\nshaderDesc.texGenMode: GL_EYE_LINEAR";
break;
2803 case GL_SPHERE_MAP: resStrm <<
"\nshaderDesc.texGenMode: GL_SPHERE_MAP";
break;
2804 case GL_NORMAL_MAP: resStrm <<
"\nshaderDesc.texGenMode: GL_NORMAL_MAP";
break;
2805 case GL_REFLECTION_MAP: resStrm <<
"\nshaderDesc.texGenMode: GL_REFLECTION_MAP";
break;
2806 default: resStrm <<
"\nshaderDesc.texGenMode: unknown";
break;
2809 resStrm <<
"\nshaderDesc.texGenPerFragment: " << texGenPerFragment;
2811 if (!vertexTemplateFile.isEmpty())
2812 resStrm <<
"\nshaderDesc.vertexTemplateFile: " << vertexTemplateFile;
2814 if (!tessControlTemplateFile.isEmpty())
2815 resStrm <<
"\nshaderDesc.tessControlTemplateFile: " << tessControlTemplateFile;
2817 if (!tessEvaluationTemplateFile.isEmpty())
2818 resStrm <<
"\nshaderDesc.tessEvaluationTemplateFile: " << tessEvaluationTemplateFile;
2820 if (!geometryTemplateFile.isEmpty())
2821 resStrm <<
"\nshaderDesc.geometryTemplateFile: " << geometryTemplateFile;
2823 if (!fragmentTemplateFile.isEmpty())
2824 resStrm <<
"\nshaderDesc.fragmentTemplateFile: " << fragmentTemplateFile;
QString vertexColorsInterpolator
interpolation qualifier for input vertex colors: "flat", "smooth", "noperspective"
QString vertexNormalInterpolator
interpolation qualifier for vertex shader normal outputs: "flat", "smooth", "noperspective"
QString toString() const
convert ShaderGenDesc to string format for debugging
bool normalizeTexColors
Defines if the textureVariable is normalized or not, if multiple textures are used.
std::map< size_t, TextureType > textureTypes_
holds the texture types (second) and the stage id (first). if empty, shader does not support textures
void initTessEvalShaderIO(const ShaderGenDesc *_desc, ShaderGenerator *_prevStage, const DefaultIODesc *_iodesc)
Adds fitting tess-evaluation shader io for a given description.
QString getInputName(int _id) const
get variable name of input
void addLayout(QString _layout)
Add a layout directive.
void initGeometryShaderIO(const ShaderGenDesc *_desc, ShaderGenerator *_prevStage, const DefaultIODesc *_iodesc)
Adds fitting geometry shader io for a given description.
void buildShaderCode(QStringList *_pMainCode, const QStringList &_defaultLightingFunctions)
Shader assembly function.
QString getIOMapName(int _inId) const
get corresponding output name of an input id
void saveToFile(const char *_fileName)
Save generated shader code to text file.
bool hasDefine(QString _define) const
Check for define.
const QStringList & getShaderCode()
Get result of buildShaderCode.
void initFragmentShaderIO(const ShaderGenDesc *_desc, ShaderGenerator *_prevStage, const DefaultIODesc *_iodesc)
Adds fitting fragment shader io for a given description.
void initTessControlShaderIO(const ShaderGenDesc *_desc, ShaderGenerator *_prevStage, const DefaultIODesc *_iodesc)
Adds fitting tess-control shader io for a given description.
void addUniform(QString _uniform, QString _comment="")
Add one GLSL uniform specifier.
void addIncludeFile(QString _fileName)
Imports another shader, same as #include.
int getNumInputs() const
get number of inputs
void addLight(int lightIndex_, ShaderGenLightType _light)
Add a light description to shader:
void addMacros(const QStringList &_macros)
Add a list of preprocessor macros.
bool outputArrays_
outputs of shader are arrays (tess-control)
void initVertexShaderIO(const ShaderGenDesc *_desc, const DefaultIODesc *_iodesc)
Adds fitting vertex shader io for a given description.
void addDefine(const QString &_define)
Add one define.
QString outputPrefix_
prefix of outputs of this shader
void initDefaultUniforms()
Adds frequently used uniform parameters.
void setGLSLVersion(int _version)
Set glsl version.
void modifyTessEvalIO(ShaderGenerator *_shader) override
Add your own inputs/outputs to the tessellation evaluation shader.
void modifyFragmentBeginCode(QStringList *_code) override
Append code the the fragment shader.
void modifyGeometryIO(ShaderGenerator *_shader) override
Add your own inputs/outputs to the geometry shader.
void modifyVertexEndCode(QStringList *_code) override
Append code the the vertex shader.
void modifyVertexIO(ShaderGenerator *_shader) override
Add your own inputs/outputs to the vertex shader.
void modifyFragmentEndCode(QStringList *_code) override
Append code the the fragment shader.
void modifyFragmentIO(ShaderGenerator *_shader) override
Add your own inputs/outputs to the fragment shader.
void modifyVertexBeginCode(QStringList *_code) override
Append code the the vertex shader.
void modifyTessControlIO(ShaderGenerator *_shader) override
Add your own inputs/outputs to the tessellation control shader.
virtual void modifyVertexIO(ShaderGenerator *_shader)
Add your own inputs/outputs to the vertex shader.
virtual void modifyLightingCode(QStringList *_code, int _lightId, ShaderGenLightType _lightType)
Modify the default lighting code of the shader generator.
virtual void modifyGeometryIO(ShaderGenerator *_shader)
Add your own inputs/outputs to the geometry shader.
virtual void modifyTessEvalIO(ShaderGenerator *_shader)
Add your own inputs/outputs to the tessellation evaluation shader.
virtual void modifyTessControlIO(ShaderGenerator *_shader)
Add your own inputs/outputs to the tessellation control shader.
static ShaderModifier * loadFromFile(QString _filename)
Load a modifier from file.
virtual void modifyFragmentIO(ShaderGenerator *_shader)
Add your own inputs/outputs to the fragment shader.
ShaderGenerator::DefaultIODesc ioDesc_
default IO descriptor for the vertex shader
const QStringList & getTessEvaluationShaderCode()
Returns generated tessellation control shader code.
const QStringList & getTessControlShaderCode()
Returns generated vertex shader code.
QStringList tessControlLayout_
layout() directives scanned from loaded templates
bool hasTessEvaluationShader() const
check whether there is a tess-evaluation shader present
ShaderModifier * getActiveModifier(int _i)
Get active modfiers for this program.
QString vertexShaderFile_
path + filename to shader templates
const QStringList & getGeometryShaderCode()
Returns generated tessellation evaluation shader code.
static int numRegisteredModifiers_
registered shader modifier
void initGenDefines(ShaderGenerator *_gen)
provide generated defines to shader
ShaderProgGenerator(const ShaderGenDesc *_desc)
static QString getShaderDir()
void scanShaderTemplate(QStringList &_templateSrc, QString _templateFilename, QStringList *_outLayoutDirectives=0)
Scans loaded shader template for requested inputs, glsl version or includes.
void loadShaderTemplateFromFile()
Loads external shader templates.
void addTexGenCode(QStringList *_code, bool _fragmentShader)
Add texture coordinate generation code.
static bool loadStringListFromFile(QString _fileName, QStringList *_out)
Load a text file as string list.
static void setShaderDir(QString _dir)
bool hasGeometryShader() const
check whether there is a geometry shader present
bool hasTessControlShader() const
check whether there is a tess-control shader present
static QString getPathName(QString _strFileName)
returns path to _strFileName without last slash
static unsigned int registerModifier(ShaderModifier *_modifier)
Shader modifiers have to be registered before they can be used. They also must remain allocated for t...
void modifyLightingCode(QStringList *_code, ShaderModifier *_modifier)
Calls lighting modifier for each light.
const QStringList & getFragmentShaderCode()
Returns generated fragment shader code.
int getNumActiveModifiers() const
Get the number of active modifiers.
void init(const ShaderGenDesc *_desc, ShaderModifier *const *_modifiers, unsigned int _numActiveMods)
Called in constructor.
void addLightingCode(QStringList *_code)
Adds lighting function calls to code.
void generateShaders()
Generates the shader code.
void addLightingFunctions(QStringList *_code)
Adds lighting definition functions.
int checkForIncludes(QString _str, ShaderGenerator *_gen, QString _includePath)
static QString getAbsFilePath(QString _fileName)
Convert a filename to an absolute filename.
const QStringList & getVertexShaderCode()
Returns generated vertex shader code.
Namespace providing different geometric functions concerning angles.
bool ACGDLLEXPORT openGLVersionTest(const int _major, const int _minor)
bool inputTexCoord_
default attributes that should be imported in vertex shader
bool passPosVS_
default attributes that should be passed down from vertex shader