kick
/Users/morten/Programmering/cpp/kick/src/kick/material/shader.cpp
00001 //
00002 //  shader.cpp
00003 //  KickCPP
00004 //
00005 //  Created by morten on 8/25/13.
00006 //  Copyright (c) 2013 Morten Nobel-Joergensen. All rights reserved.
00007 //
00008 
00009 #include "kick/material/shader.h"
00010 #include "kick/material/material.h"
00011 #include "kick/core/Project.h"
00012 #include "kick/core/engine.h"
00013 #include "kick/core/time.h"
00014 #include "kick/math/misc.h"
00015 #include <sstream>
00016 #include <vector>
00017 #include <iostream>
00018 #include <array>
00019 #include <cassert>
00020 #include <regex>
00021 #include <cstring>
00022 #include <algorithm>
00023 #include <iterator>
00024 #include <sstream>
00025 #include "kick/core/cpp_ext.h"
00026 #include "kick/scene/transform.h"
00027 #include "kick/scene/light.h"
00028 #include "kick/core/debug.h"
00029 using namespace std;
00030 
00031 namespace kick {
00032     
00033 #define casetype(X) case static_cast<int>(X): \
00034 enumValue = X; \
00035 break;
00036     
00037     
00038     
00039     bool toEnum(int value, ShaderType& enumValue){
00040         switch (value) {
00041                 casetype(ShaderType::VertexShader);
00042                 casetype(ShaderType::FragmentShader);
00043 #ifndef GL_ES_VERSION_2_0
00044                 casetype(ShaderType::GeometryShader);
00045 #endif
00046             default:
00047                 return false;
00048         }
00049         return true;
00050     }
00051     
00052     bool toEnum(int value, ShaderErrorType& enumValue){
00053         switch (value) {
00054                 casetype(ShaderErrorType::VertexShader);
00055                 casetype(ShaderErrorType::FragmentShader);
00056 #ifndef GL_ES_VERSION_2_0
00057                 casetype(ShaderErrorType::GeometryShader);
00058 #endif
00059                 casetype(ShaderErrorType::Linker);
00060                 casetype(ShaderErrorType::IncompleteShader);
00061             default:
00062                 return false;
00063         }
00064         return true;
00065     }
00066     
00067     bool toEnum(int value, BlendType& enumValue){
00068         switch (value) {
00069                 casetype(BlendType::Zero);
00070                 casetype(BlendType::One);
00071                 casetype(BlendType::SrcColor);
00072                 casetype(BlendType::OneMinusSrcColor);
00073                 casetype(BlendType::DstColor);
00074                 casetype(BlendType::OneMinusDstColor);
00075                 casetype(BlendType::SrcAlpha);
00076                 casetype(BlendType::OneMinusSrcAlpha);
00077                 casetype(BlendType::DstAlpha);
00078                 casetype(BlendType::OneMinusDstAlpha);
00079                 casetype(BlendType::ConstantColor);
00080                 casetype(BlendType::OneMinusConstantColor);
00081                 casetype(BlendType::ConstantAlpha);
00082                 casetype(BlendType::OneMinusConstantAlpha);
00083             default:
00084                 return false;
00085         }
00086         return true;
00087     }
00088     
00089     bool toEnum(int value, FaceCullingType& enumValue){
00090         switch (value) {
00091                 casetype(FaceCullingType::Front);
00092                 casetype(FaceCullingType::Back);
00093                 casetype(FaceCullingType::FrontAndBack);
00094                 casetype(FaceCullingType::None);
00095             default:
00096                 return false;
00097         }
00098         return true;
00099     }
00100     
00101     bool toEnum(int value, ZTestType& enumValue){
00102         switch (value) {
00103                 casetype(ZTestType::Never);
00104                 casetype(ZTestType::Less);
00105                 casetype(ZTestType::Equal);
00106                 casetype(ZTestType::LEqual);
00107                 casetype(ZTestType::Greater);
00108                 casetype(ZTestType::NotEqual);
00109                 casetype(ZTestType::GEqual);
00110                 casetype(ZTestType::Always);
00111             default:
00112                 return false;
00113         }
00114         return true;
00115     }
00116     
00117     ShaderObj::ShaderObj(ShaderType type)
00118     :shader(glCreateShader((GLenum)type))
00119     {
00120         assert(shader != 0);
00121         assert(shader != GL_INVALID_ENUM);
00122     }
00123     
00124     ShaderObj::ShaderObj(ShaderObj&& other)
00125     :shader(other.shader){
00126         other.shader = 0;
00127     }
00128     
00129     ShaderObj& ShaderObj::operator=(ShaderObj&& other){
00130         if (this != &other){
00131             glDeleteShader(shader);
00132             shader = other.shader;
00133             other.shader = 0;
00134         }
00135         return *this;
00136     }
00137 
00138     ShaderObj::~ShaderObj(){
00139         if (shader>0){
00140             glDeleteShader(shader);
00141         }
00142     }
00143 
00144     void ShaderObj::detach(GLuint shaderProgram){
00145         // warn http://stackoverflow.com/a/9117411/420250
00146         glDetachShader(shaderProgram, shader);
00147     }
00148 
00149     Shader::Shader(Shader&& s)
00150 
00151     {
00152         *this = move(s);
00153     }
00154     
00155     Shader& Shader::operator=(Shader&& o){
00156         swap(mShaderProgram, o.mShaderProgram);
00157         swap(shaderSources, o.shaderSources);
00158         swap(outputAttributeName, o.outputAttributeName);
00159         swap(mShaderAttributes, o.mShaderAttributes);
00160         swap(shaderUniforms, o.shaderUniforms);
00161         swap(mBlendDFactorAlpha, o.mBlendDFactorAlpha);
00162         swap(mBlendDFactorRGB, o.mBlendDFactorRGB);
00163         swap(mBlendSFactorAlpha, o.mBlendSFactorAlpha);
00164         swap(mBlendSFactorRGB, o.mBlendSFactorRGB);
00165         swap(mDepthBufferWrite, o.mDepthBufferWrite);
00166         swap(mFaceCulling, o.mFaceCulling);
00167         swap(mPolygonOffsetEnabled, o.mPolygonOffsetEnabled);
00168         swap(mPolygonOffsetFactorAndUnit, o.mPolygonOffsetFactorAndUnit);
00169         swap(mZTest, o.mZTest);
00170         return *this;
00171     }
00172     
00173     Shader::Shader(string vertexShader, string fragmentShader, string geometryShader)
00174     : mShaderProgram(0)
00175     {
00176         setShaderSource(ShaderType::VertexShader, vertexShader);
00177         setShaderSource(ShaderType::FragmentShader, fragmentShader);
00178 #ifndef GL_ES_VERSION_2_0
00179         setShaderSource(ShaderType::GeometryShader, geometryShader);
00180 #endif
00181         if (vertexShader.length()>0 && fragmentShader.length()>0) {
00182             apply();
00183         }
00184     }
00185     
00186     Shader::~Shader(){
00187         if (mShaderProgram != 0){
00188             glDeleteProgram(mShaderProgram);
00189         }
00190     }
00191     
00192     const UniformDescriptor* Shader::getShaderUniform(std::string name) const{
00193         for (auto & desc : shaderUniforms) {
00194             if (desc.name == name){
00195                 return &desc;
00196             }
00197         }
00198         return nullptr;
00199     }
00200     
00201     vector<AttributeDescriptor > getActiveShaderAttributes(GLuint programid){
00202         vector<AttributeDescriptor > res;
00203         int numberOfActiveAttributes;
00204         glGetProgramiv(programid,GL_ACTIVE_ATTRIBUTES,&numberOfActiveAttributes);
00205         GLint bufSize;
00206         glGetProgramiv(programid, GL_ACTIVE_ATTRIBUTE_MAX_LENGTH, &bufSize);
00207         vector<GLchar> buffer(bufSize);
00208         for (GLuint i=0;i<numberOfActiveAttributes;i++){
00209             AttributeDescriptor  att{i};
00210             glGetActiveAttrib(programid,
00211                               i,
00212                               bufSize,
00213                               nullptr,
00214                               &att.size,
00215                               &att.type,
00216                               buffer.data());
00217             att.name = buffer.data();
00218             att.semantic = to_semantic(att.name);
00219             if (att.semantic == VertexAttributeSemantic::Unknown){
00220                 logWarning(string{"Invalid vertex attribute in shader source: "}+att.name);
00221             }
00222             res.push_back(att);
00223         }
00224         
00225         return move(res);
00226     }
00227 
00228     void Shader::translateToGLSLES(string& source, ShaderType type){
00229         // replace textures
00230         if (type == ShaderType::VertexShader){
00231             static regex regExpSearchShim3 { R"(\n\s*out\b)"};
00232             source = regex_replace(source, regExpSearchShim3, "\nvarying");
00233             static regex regExpSearchShim4 { R"(\n\s*in\b)"};
00234             source = regex_replace(source, regExpSearchShim4, "\nattribute");
00235         } else {
00236             static regex regExpSearchShim2 { R"(\bfragColor\b)"};
00237             source = regex_replace(source, regExpSearchShim2, "gl_FragColor");
00238             static regex regExpSearchShim3 { R"(\n\s*out\b)"};
00239             source = regex_replace(source, regExpSearchShim3, "\n// out");
00240             static regex regExpSearchShim4 { R"(\n\s*in\b)"};
00241             source = regex_replace(source, regExpSearchShim4, "\nvarying");
00242         }
00243 
00244         static regex regExpSearchShim1 { R"(\s*uniform\s+sampler([\w]*)\s+([\w_]*)\s*;.*)"};
00245         istringstream iss(source);
00246         map<string,string> textureType;
00247         smatch match;
00248         for (std::string line; std::getline(iss, line); )
00249         {
00250             regex_search(line, match, regExpSearchShim1);
00251             if (match.size() > 0){
00252                 string samplerType = match[1].str();
00253                 string samplerName = match[2].str();
00254                 textureType[samplerName] = samplerType;
00255 
00256             }
00257         }
00258 
00259         for (auto val : textureType){
00260             regex regExpSearchShim4 { string{"texture\\s*\\(\\s*"}+val.first+"\\s*," };
00261             source = regex_replace(source, regExpSearchShim4, string{"texture"}+val.second+"("+val.first+",");
00262         }
00263     }
00264 
00265     vector<UniformDescriptor > getActiveShaderUniforms(GLuint programid){
00266         vector<UniformDescriptor > res;
00267         
00268         int numberOfActiveUniforms;
00269         glGetProgramiv(programid,GL_ACTIVE_UNIFORMS,&numberOfActiveUniforms);
00270         GLint bufSize;
00271         glGetProgramiv(programid, GL_ACTIVE_UNIFORM_MAX_LENGTH, &bufSize);
00272         vector<GLchar> buffer(bufSize);
00273         for (GLuint i=0;i<numberOfActiveUniforms;i++){
00274             UniformDescriptor uni{i};
00275             glGetActiveUniform(programid,
00276                                i,
00277                                bufSize,
00278                                nullptr,
00279                                &uni.size,
00280                                &uni.type,
00281                                buffer.data());
00282             uni.name = buffer.data();
00283             int index = glGetUniformLocation(programid, buffer.data());
00284             if (index>=0){
00285                 uni.index = index;
00286                 res.push_back(uni);
00287             } else {
00288                 cout << "cannot find uniform index "<< buffer.data()<<endl;
00289             }
00290         }
00291 
00292         return move(res);
00293     }
00294     
00295     string Shader::getPrecompiledSource(string source, ShaderType type) {
00296         if (source.find("#version") != 0){
00297 #ifdef GL_ES_VERSION_2_0
00298             string prefix = "#version 100\n";// context.getGLSLPrefix() // todo - get prefix from context
00299 #else
00300             string prefix = "#version 150\n";// context.getGLSLPrefix() // todo - get prefix from context
00301 #endif
00302             source = prefix + source;
00303         }
00304         string precisionSpecifier = "";
00305 
00306 
00307         // remove commented out usages of #pragma include
00308         static regex regExpSearch { R"(//\s*#?\s*pragma\s+include[^\n]*)"};
00309         source = regex_replace(source, regExpSearch, "");
00310 
00311         // find pragma include files
00312         static regex regExpSearch2 { "[ ]*#\\s*pragma\\s+include\\s+\"([^\"]*)\"[^\\n]*"};
00313         vector<string> includeNames;
00314         auto iter = std::sregex_token_iterator(source.begin(), source.end(), regExpSearch2, 1);
00315         auto endIter = std::sregex_token_iterator();
00316         while (iter != endIter){
00317             includeNames.push_back(*iter);
00318             iter++;
00319         }
00320         
00321         // replace source
00322         for (auto includeName : includeNames){
00323             string includedSource;
00324             if (Project::loadTextResource(includeName, includedSource)) {
00325                 if (includedSource.size() == 0) {
00326                     cout << "Could not load source " << includeName << endl;
00327                 } else {
00328                     regex regExpSearch3{string{"[ ]*#\\s*pragma\\s+include\\s+\""} + includeName + "\"[^\\n]*"};
00329                     source = regex_replace(source, regExpSearch3, includedSource);
00330                 }
00331             }
00332         }
00333 
00334 #ifdef GL_ES_VERSION_2_0
00335         translateToGLSLES(source, type);
00336         if (type == ShaderType::FragmentShader){
00337             precisionSpecifier = "precision mediump float;\n";
00338         }
00339 #endif
00340         // Insert compile
00341         size_t indexOfNewline = source.find('\n');
00342         string version = source.substr(0, indexOfNewline); // save version info
00343         source = source.substr(indexOfNewline + 1); // strip version info
00344 
00345 
00346         source = version + "\n" +
00347                 precisionSpecifier+
00348         "#define SHADOWS " + (Engine::config().shadows?"true":"false") + "\n" +
00349         "#define LIGHTS " + std::to_string((int) Engine::config().maxNumerOfLights) + "\n" +
00350         "#line " + std::to_string(2) + "\n" +
00351                 source;
00352 
00353         return source;
00354     }
00355     
00356     bool Shader::apply(){
00357         if (mShaderProgram){
00358             glDeleteShader(mShaderProgram);
00359         }
00360         mShaderProgram = glCreateProgram();
00361         vector<ShaderObj> shaderObjects;
00362         vector<ShaderType> requiredTypes{ShaderType::VertexShader, ShaderType::FragmentShader};
00363         for (auto & element : shaderSources) {
00364             auto shaderType = element.first;
00365             string & source = element.second;
00366             if (source.length()>0){
00367                 string precompiledSource = getPrecompiledSource(source, shaderType);
00368                 
00369                 shaderObjects.push_back(compileShader(precompiledSource, shaderType));
00370                 // remove element from vector
00371                 requiredTypes.erase(std::remove(requiredTypes.begin(), requiredTypes.end(), shaderType), requiredTypes.end());
00372                 glAttachShader(mShaderProgram,  shaderObjects.back());
00373             }
00374         }
00375         if (requiredTypes.size()>0){
00376             logError("Both vertex and fragment shader required.");
00377             return false;
00378         }
00379         
00380         bool linked = linkProgram();
00381         if (!linked){
00382             return false;
00383         }
00384         // shaderObjects deleted when goes out of scope (which is ok as long as program is not deleted)
00385         glUseProgram(mShaderProgram);
00386 
00387         mShaderAttributes = getActiveShaderAttributes(mShaderProgram);
00388         shaderUniforms = getActiveShaderUniforms(mShaderProgram);
00389 
00390         updateDefaultShaderLocation();
00391 
00392         shaderChanged.notifyListeners({this, ShaderEventType::shader });
00393 
00394         // clean up
00395         for (auto & shaderObject : shaderObjects){
00396             shaderObject.detach(mShaderProgram);
00397         }
00398         shaderObjects.clear();
00399 
00400         return true;
00401     }
00402     
00403     bool Shader::linkProgram(){
00404 #ifndef GL_ES_VERSION_2_0
00405         glBindFragDataLocation(mShaderProgram, 0, outputAttributeName.c_str());
00406 #endif
00407                 glLinkProgram(mShaderProgram);
00408         
00409                 GLint  linked;
00410                 glGetProgramiv(mShaderProgram, GL_LINK_STATUS, &linked );
00411                 if (linked == GL_FALSE) {
00412                         GLint  logSize;
00413                         glGetProgramiv(mShaderProgram, GL_INFO_LOG_LENGTH, &logSize);
00414             vector<char> errorLog((size_t) logSize);
00415                         glGetProgramInfoLog(mShaderProgram, logSize, NULL, errorLog.data() );
00416 //            throw ShaderBuildException{, ShaderErrorType::Linker};
00417             logError(errorLog.data());
00418             return false;
00419                 }
00420         return true;
00421     }
00422     
00423     void updateFaceCulling(FaceCullingType faceCulling){
00424         if (faceCulling == FaceCullingType::None){
00425             glDisable(GL_CULL_FACE);
00426         } else {
00427             glEnable(GL_CULL_FACE);
00428             glCullFace(static_cast<GLuint>(faceCulling));
00429         }
00430     }
00431     
00432     void updateDepthProperties(ZTestType zTest, bool depthWrite){
00433         if (zTest == ZTestType::Never){
00434             glDisable(GL_DEPTH_TEST);
00435         } else {
00436             glEnable(GL_DEPTH_TEST);
00437         }
00438         glDepthFunc(static_cast<GLuint>(zTest));
00439         glDepthMask(depthWrite ? GL_TRUE : GL_FALSE);
00440     }
00441     
00442     void updateBlending(bool blend, BlendType blendDFactorAlpha,BlendType blendDFactorRGB, BlendType blendSFactorAlpha, BlendType blendSFactorRGB){
00443         if (blend){
00444             glEnable(GL_BLEND);
00445             GLenum sfactorRGB = static_cast<GLenum>(blendSFactorRGB);
00446             GLenum dfactorRGB = static_cast<GLenum>(blendDFactorRGB);
00447             GLenum sfactorAlpha = static_cast<GLenum>(blendSFactorAlpha);
00448             GLenum dfactorAlpha = static_cast<GLenum>(blendDFactorAlpha);;
00449             glBlendFuncSeparate(sfactorRGB, dfactorRGB, sfactorAlpha, dfactorAlpha);
00450         } else {
00451             glDisable(GL_BLEND);
00452         }
00453     }
00454     
00455     void Shader::bind(){
00456         glUseProgram(mShaderProgram);
00457         updateFaceCulling(mFaceCulling);
00458         updateDepthProperties(mZTest, mDepthBufferWrite);
00459         updateBlending(mBlend, mBlendDFactorAlpha, mBlendDFactorRGB, mBlendSFactorAlpha, mBlendSFactorRGB);
00460     }
00461     
00462     ShaderObj Shader::compileShader(std::string source, ShaderType type){
00463         ShaderObj shader(type);
00464         const GLchar* sourceArray[1];
00465         sourceArray[0] = source.c_str();
00466         GLint stringLengths[1];
00467         stringLengths[0] = (GLint)source.length();
00468         glShaderSource(shader, 1, sourceArray, stringLengths);
00469         glCompileShader(shader);
00470         GLint success = 0;
00471         glGetShaderiv(shader, GL_COMPILE_STATUS, &success);
00472         if (success == GL_FALSE){
00473             ShaderBuildException::logCurrentCompileException(shader, (ShaderErrorType) type, source);
00474         }
00475         return move(shader);
00476     }
00477     
00478     void Shader::setShaderSource(ShaderType type, string str){
00479         shaderSources[type] = str;
00480     }
00481     
00482     std::string Shader::getShaderSource(ShaderType type) const {
00483         return shaderSources.at(type);
00484     }
00485 
00486     std::string Shader::getPrecompiledShaderSource(ShaderType type) const{
00487         string value = getShaderSource(type);
00488         return getPrecompiledSource(value, type);
00489     }
00490 
00491     const std::vector<AttributeDescriptor >& Shader::getShaderAttributes() const  {
00492         return mShaderAttributes;
00493     }
00494     
00495     const std::vector<UniformDescriptor >& Shader::getShaderUniforms() const {
00496         return shaderUniforms;
00497     }
00498     
00499     const AttributeDescriptor* Shader::getShaderAttribute(VertexAttributeSemantic semantic) const{
00500         for (int i=0;i< mShaderAttributes.size();i++){
00501             if (mShaderAttributes[i].semantic == semantic){
00502                 return &mShaderAttributes[i];
00503             }
00504         }
00505         return nullptr;
00506     }
00507     
00508     string ShaderBuildException::extractLines(std::string errorMessage, std::string source, int extraLines){
00509         static regex regExpSearch { R"(\d+:(\d+))"};
00510         auto iter = std::sregex_token_iterator(errorMessage.begin(), errorMessage.end(), regExpSearch, 1);
00511         auto endIter = std::sregex_token_iterator();
00512         if (iter != endIter){
00513             string lineStr = *iter;
00514             int line = atoi(lineStr.c_str());
00515             const int buffer_size = 512;
00516             array<char, buffer_size> lineBuffer;
00517             istringstream inbuf(source);
00518             string res;
00519             for (int i=1;i<=line+extraLines && inbuf.getline(lineBuffer.data(),buffer_size);i++){
00520                 if (strncmp(lineBuffer.data(), "#line ", 6)==0){
00521                     string s{lineBuffer.data()};
00522                     static regex regExpSearchLine { R"((\d+))"};
00523                     auto iterLine = std::sregex_token_iterator(s.begin(), s.end(), regExpSearchLine, 1);
00524                     if (iterLine != endIter){
00525                         string newLineNumberStr = *iterLine;
00526                         i = atoi(newLineNumberStr.c_str());
00527                     }
00528                 }
00529                 if (i >= line-extraLines){
00530                     res += std::to_string(i)+"\t"+string{lineBuffer.data()}+"\n";
00531                 }
00532             }
00533             return res;
00534         } else
00535             return "";
00536     }
00537     
00538     
00539     void ShaderBuildException::logCurrentCompileException(GLuint shader, ShaderErrorType type, string source){
00540         GLint logSize = 0;
00541         glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &logSize);
00542         
00543         vector<char> errorLog((unsigned long) logSize);
00544         glGetShaderInfoLog(shader, logSize, &logSize, errorLog.data());
00545         string errorLines = extractLines(errorLog.data(), source);
00546         string typeStr;
00547         switch (type){
00548             case ShaderErrorType::FragmentShader:
00549                 typeStr = "Fragment shader";
00550                 break;
00551 #ifndef GL_ES_VERSION_2_0
00552             case ShaderErrorType::GeometryShader:
00553                 typeStr = "Geometry shader";
00554                 break;
00555 #endif
00556             case ShaderErrorType::IncompleteShader:
00557                 typeStr = "Incomplete shader";
00558                 break;
00559             case ShaderErrorType::Linker:
00560                 typeStr = "Linker";
00561                 break;
00562             case ShaderErrorType::VertexShader :
00563                 typeStr = "Vertex shader";
00564                 break;
00565 
00566         }
00567         logError(string{errorLog.data()}+"\n"+ typeStr +" error\n"+ errorLines);
00568     }
00569     
00570     void Shader::setBlend(bool b){ mBlend = b; }
00571     bool Shader::blend() { return mBlend; }
00572     BlendType Shader::blendDFactorAlpha() { return mBlendDFactorAlpha; }
00573     BlendType Shader::blendDFactorRGB() { return mBlendDFactorRGB; }
00574     BlendType Shader::blendSFactorAlpha() { return mBlendSFactorAlpha; }
00575     BlendType Shader::blendSFactorRGB() { return mBlendSFactorRGB; }
00576     void Shader::setBlendDFactorAlpha(BlendType blendDFactorAlpha) { this->mBlendDFactorAlpha =blendDFactorAlpha; }
00577     void Shader::setBlendDFactorRGB(BlendType blendDFactorRGB) { this->mBlendDFactorRGB =blendDFactorRGB; }
00578     void Shader::setBlendSFactorAlpha(BlendType blendSFactorAlpha) { this->mBlendSFactorAlpha = blendSFactorAlpha; }
00579     void Shader::setBlendSFactorRGB(BlendType blendSFactorRGB) { this->mBlendSFactorRGB = blendSFactorRGB; }
00580     void Shader::setDepthWrite(bool depthMask) { this->mDepthBufferWrite = depthMask;}
00581     bool Shader::depthWrite() { return mDepthBufferWrite; }
00582     void Shader::setFaceCulling(FaceCullingType faceCulling) { this->mFaceCulling = faceCulling; }
00583     FaceCullingType Shader::faceCulling() { return mFaceCulling; }
00584     void Shader::setPolygonOffsetEnabled(bool polygonOffsetEnabled) { this->mPolygonOffsetEnabled = polygonOffsetEnabled; }
00585     bool Shader::polygonOffsetEnabled() { return mPolygonOffsetEnabled; }
00586     void Shader::setPolygonOffsetFactorAndUnit(glm::vec2 polygonOffsetFactorAndUnit) { this->mPolygonOffsetFactorAndUnit = polygonOffsetFactorAndUnit; }
00587     glm::vec2 Shader::polygonOffsetFactorAndUnit() { return mPolygonOffsetFactorAndUnit; }
00588     void Shader::setZTest(ZTestType zTest) { this->mZTest = zTest; }
00589     ZTestType Shader::zTest() { return mZTest; }
00590 
00591     void Shader::bind_uniforms(Material *material, EngineUniforms *engineUniforms, Transform* transform){
00592         material->bind();
00593         SceneLights * sceneLights = engineUniforms->sceneLights;
00594         for (auto& uniform : shaderUniforms){
00595             if (uniform.name == UniformNames::modelMatrix){
00596                 auto globalMatrix = transform->globalMatrix();
00597                 glUniformMatrix4fv(uniform.index, 1, GL_FALSE, glm::value_ptr(globalMatrix));
00598             } else if (uniform.name == UniformNames::mv){
00599                 auto modelView = engineUniforms->viewMatrix * transform->globalMatrix();
00600                 glUniformMatrix4fv(uniform.index, 1, GL_FALSE, glm::value_ptr(modelView));
00601             } else if (uniform.name == UniformNames::norm) {
00602                 auto modelView = engineUniforms->viewMatrix * transform->globalMatrix();
00603                 auto normal = glm::inverseTranspose(glm::mat3(modelView));
00604                 glUniformMatrix3fv(uniform.index, 1, GL_FALSE, glm::value_ptr(normal));
00605             } else if (uniform.name == UniformNames::v) {
00606                 auto viewMatrix = engineUniforms->viewMatrix;
00607                 glUniformMatrix4fv(uniform.index, 1, GL_FALSE, glm::value_ptr(viewMatrix));
00608             } else if (uniform.name == UniformNames::proj){
00609                 glUniformMatrix4fv(uniform.index, 1, GL_FALSE, glm::value_ptr(engineUniforms->projectionMatrix));
00610             } else if (uniform.name == UniformNames::worldCamPos){
00611                 auto cameraPos = engineUniforms->currentCameraTransform->position();
00612                 glUniform3fv(uniform.index, 1, glm::value_ptr(cameraPos));
00613             } else if (uniform.name == UniformNames::world2object){
00614                 auto world2object = transform->globalTRSInverse();
00615                 glUniformMatrix4fv(uniform.index, 1, GL_FALSE, glm::value_ptr(world2object));
00616             } else if (uniform.name == UniformNames::mvProj){
00617                 auto mvProj = engineUniforms->viewProjectionMatrix * transform->globalMatrix();
00618                 glUniformMatrix4fv(uniform.index, 1, GL_FALSE, glm::value_ptr(mvProj));
00619             } else if (uniform.name == UniformNames::gameObjectUID){
00620                 int32_t uid = transform->gameObject()->uniqueId();
00621                 glm::vec4 packedInt = uint32ToVec4(uid);
00622                 glUniform4fv(uniform.index, 1, glm::value_ptr(packedInt ));
00623             } else if (uniform.name == UniformNames::shadowMapTexture) {
00624                 //throw invalid_argument("shadowMapTexture not yet implemented"); // todo
00625                 cout <<"shadowMapTexture not yet implemented\n"; // todo
00626                 logWarning("\"shadowMapTexture not yet implemented");
00627             } else if (uniform.name == UniformNames::lightMat){
00628                 auto lightMatrix = engineUniforms->lightMatrix * transform->globalMatrix();
00629                 glUniformMatrix4fv(uniform.index, 1, GL_FALSE, glm::value_ptr(lightMatrix));
00630             } else if (uniform.name == UniformNames::ambient){
00631                 glm::vec3 ambientLight = sceneLights->ambientLight ? sceneLights->ambientLight->colorIntensity() : glm::vec3{0};
00632                 glUniform3fv(uniform.index, 1, glm::value_ptr(ambientLight));
00633             } else if (uniform.name == UniformNames::pointLight){
00634                 glUniformMatrix3fv(uniform.index, KICK_MAX_POINT_LIGHTS, GL_FALSE, glm::value_ptr(sceneLights->pointLightData[0]));
00635             } else if (uniform.name == UniformNames::directionalLight){
00636                 glUniformMatrix3fv(uniform.index, 1, GL_FALSE, glm::value_ptr(sceneLights->directionalLightData));
00637             } else if (uniform.name == UniformNames::directionalLightWorld){
00638                 glUniform3fv(uniform.index, 1, glm::value_ptr(sceneLights->directionalLightWorld));
00639             } else if (uniform.name == UniformNames::time){
00640                 float time = Time::total();
00641                 glUniform1f(uniform.index, time);
00642             } else if (uniform.name == UniformNames::viewport){
00643                 glm::vec2 viewportSize = (glm::vec2)engineUniforms->viewportDimension.getValue();
00644                 glUniform2fv(uniform.index, 1, glm::value_ptr(viewportSize));
00645             }
00646 
00647             // debug output
00648             //else {
00649             //    continue;
00650             //}
00651             //cout << to_string(uniform)<<"\n";
00652         }
00653     }
00654 
00655     void Shader::updateDefaultShaderLocation(){
00656         for (auto & e : defaultUniformData){
00657             updateShaderLocation(e.first, e.second);
00658         }
00659     }
00660 
00661     void Shader::updateShaderLocation(std::string name, MaterialData& value){
00662         auto descriptor = getShaderUniform(name);
00663         value.defaultUniform = true;
00664         if (descriptor == nullptr){
00665             value.shaderLocation = -1;
00666         } else {
00667             value.shaderLocation = descriptor->index;
00668         }
00669     }
00670 
00671     void Shader::setDefaultUniformData(std::string name, MaterialData &&value) {
00672         auto pos = defaultUniformData.find(name);
00673         if (pos != defaultUniformData.end()){
00674             pos->second.setValue(value.value);
00675             if (pos->second.glType != value.glType){
00676                 pos->second.glType = value.glType;
00677                 updateShaderLocation(name, pos->second);
00678             }
00679         } else {
00680             // not found insert new
00681             auto insertedElement = defaultUniformData.emplace(make_pair(name, move(value)));
00682             bool didInsert = insertedElement.second;
00683             assert(didInsert);
00684             auto insertedIterator = insertedElement.first;
00685             updateShaderLocation(name, insertedIterator->second);
00686         }
00687         shaderChanged.notifyListeners({this, ShaderEventType::defaultUniform });
00688     }
00689 
00690     bool Shader::tryGetDefaultUniform(std::string name, MaterialData &value) {
00691         auto pos = defaultUniformData.find(name);
00692         if (pos != defaultUniformData.end()){
00693             value = pos->second;
00694             return true;
00695         }
00696         return false;
00697     }
00698 
00699     int Shader::getRenderOrder() const {
00700         return mDenderOrder;
00701     }
00702 
00703     void Shader::setRenderOrder(int renderOrder) {
00704         if (renderOrder != Shader::mDenderOrder){
00705             Shader::mDenderOrder = renderOrder;
00706             shaderChanged.notifyListeners({this, ShaderEventType::shader });
00707         }
00708     }
00709 
00710     void Shader::setDefaultUniform(std::string name, int value) { setDefaultUniformInternal(name, value); }
00711 
00712     void Shader::setDefaultUniform(std::string name, float value) { setDefaultUniformInternal(name, value); }
00713 
00714     void Shader::setDefaultUniform(std::string name, glm::vec4 value) { setDefaultUniformInternal(name, value); }
00715 
00716     void Shader::setDefaultUniform(std::string name, glm::mat3 value) { setDefaultUniformInternal(name, value); }
00717 
00718     void Shader::setDefaultUniform(std::string name, glm::mat4 value) { setDefaultUniformInternal(name, value); }
00719 
00720     void Shader::setDefaultUniform(std::string name, std::shared_ptr<Texture2D> value) {
00721         texture2DRef[name] = value;
00722         setDefaultUniformInternal(name, value.get());
00723     }
00724 
00725     void Shader::setDefaultUniform(std::string name, std::shared_ptr<TextureCube> value) {
00726         textureCubeRef[name] = value;
00727         setDefaultUniformInternal(name, value.get());
00728     }
00729 }
 All Classes Functions Variables