#include "ShaderManager.h" #include #include #ifdef __ANDROID__ #include #endif namespace FRG { ShaderResource::ShaderResource(const std::string &vertexCode, const std::string &fragmentCode) { logger() << "Started creating shader resource" << std::endl; const int CONST_INFOLOG_LENGTH = 256; char infoLog[CONST_INFOLOG_LENGTH]; int infoLogLength; char infoLog2[CONST_INFOLOG_LENGTH]; int infoLogLength2; int vertexShaderCompiled; int fragmentShaderCompiled; int programLinked; GLuint vertexShader; GLuint fragmentShader; int vertexCodeLength = static_cast(strlen(vertexCode.c_str())); int fragmentCodeLength = static_cast(strlen(fragmentCode.c_str())); const char *vc = &vertexCode[0]; const char *fc = &fragmentCode[0]; vertexShader = glCreateShader(GL_VERTEX_SHADER); glShaderSource(vertexShader, 1, &(vc), &vertexCodeLength); fragmentShader = glCreateShader(GL_FRAGMENT_SHADER); glShaderSource(fragmentShader, 1, &(fc), &fragmentCodeLength); glCompileShader(vertexShader); glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &vertexShaderCompiled); glGetShaderInfoLog(vertexShader, CONST_INFOLOG_LENGTH, &infoLogLength, infoLog); glCompileShader(fragmentShader); glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &fragmentShaderCompiled); glGetShaderInfoLog(fragmentShader, CONST_INFOLOG_LENGTH, &infoLogLength2, infoLog2); //logger() << "Creating shader resource step 1" << std::endl; if (!vertexShaderCompiled) { #ifdef __ANDROID__ __android_log_print(ANDROID_LOG_ERROR, "ShaderManager", "Failed to compile vertex shader: %s", infoLog); #endif logger() << "Vertex shader compilation failed: " << infoLog << std::endl; throw std::runtime_error("Failed to compile vertex shader code!"); } //logger() << "Creating shader resource step 2" << std::endl; if (!fragmentShaderCompiled) { #ifdef __ANDROID__ __android_log_print(ANDROID_LOG_ERROR, "ShaderManager", "Failed to compile fragment shader: %s", infoLog); #endif logger() << "Fragment shader compilation failed: " << infoLog << std::endl; throw std::runtime_error("Failed to compile fragment shader code!"); } //logger() << "Creating shader resource step 4" << std::endl; shaderProgram = glCreateProgram(); glAttachShader(shaderProgram, vertexShader); glAttachShader(shaderProgram, fragmentShader); glLinkProgram(shaderProgram); glDeleteShader(vertexShader); glDeleteShader(fragmentShader); glGetProgramiv(shaderProgram, GL_LINK_STATUS, &programLinked); glGetProgramInfoLog(shaderProgram, CONST_INFOLOG_LENGTH, &infoLogLength, infoLog); //logger() << "Creating shader resource step 4" << std::endl; if (!programLinked) { shaderProgram = 0; #ifdef __ANDROID__ __android_log_print(ANDROID_LOG_ERROR, "ShaderManager", "Failed to link shader program: %s", infoLog); #endif logger() << "Failed to link shader program: " << infoLog << std::endl; throw std::runtime_error("Failed to link shader program!"); } //logger() << "Creating shader resource step 5" << std::endl; //================= Parsing all uniforms ================ int dummySize; //Dummy int dummyLen; //Dummy GLenum dummyEnum; int activeUniforms; const int CONST_UNIFORM_NAME_LENGTH = 256; char uniformName[CONST_UNIFORM_NAME_LENGTH]; glGetProgramiv(shaderProgram, GL_ACTIVE_UNIFORMS, &activeUniforms); for (int i = 0; i < activeUniforms; i++) { glGetActiveUniform(shaderProgram, i, CONST_UNIFORM_NAME_LENGTH, &dummyLen, &dummySize, &dummyEnum, uniformName); uniformList[uniformName] = glGetUniformLocation(shaderProgram, uniformName); } //logger() << "Creating shader resource step 6" << std::endl; //================= Parsing all attributes ================ int activeAttribs; const int CONST_ATTRIB_NAME_LENGTH = 256; char attribName[CONST_ATTRIB_NAME_LENGTH]; glGetProgramiv(shaderProgram, GL_ACTIVE_ATTRIBUTES, &activeAttribs); for (int i = 0; i < activeAttribs; i++) { glGetActiveAttrib(shaderProgram, i, CONST_ATTRIB_NAME_LENGTH, &dummyLen, &dummySize, &dummyEnum, attribName); attribList[attribName] = glGetAttribLocation(shaderProgram, attribName); } //logger() << "Creating shader resource step 7" << std::endl; #ifdef __ANDROID__ __android_log_print(ANDROID_LOG_INFO, "ShaderManager", "Shader created successfully, program ID: %u", shaderProgram); #endif } ShaderResource::~ShaderResource() { if (shaderProgram != 0) { glDeleteProgram(shaderProgram); shaderProgram = 0; } } GLuint ShaderResource::getShaderProgram() { return shaderProgram; } void ShaderManager::AddShaderFromFiles(const std::string &shaderName, const std::string &vertexShaderFileName, const std::string &fragmentShaderFileName, const std::string &ZIPFileName) { #ifdef __ANDROID__ __android_log_print(ANDROID_LOG_INFO, "ShaderManager", "Loading shader: %s", shaderName.c_str()); __android_log_print(ANDROID_LOG_INFO, "ShaderManager", "Vertex shader: %s", vertexShaderFileName.c_str()); __android_log_print(ANDROID_LOG_INFO, "ShaderManager", "Fragment shader: %s", fragmentShaderFileName.c_str()); #endif logger() <<"Loading shader: " << shaderName << " " << vertexShaderFileName << " " << fragmentShaderFileName < vertexShaderData; std::vector fragmentShaderData; vertexShaderData = readFileFromZIP(vertexShaderFileName, ZIPFileName); fragmentShaderData = readFileFromZIP(fragmentShaderFileName, ZIPFileName); vertexShader = std::string(vertexShaderData.begin(), vertexShaderData.end()); fragmentShader = std::string(fragmentShaderData.begin(), fragmentShaderData.end()); } else { vertexShader = readTextFile(vertexShaderFileName); fragmentShader = readTextFile(fragmentShaderFileName); } shaderResourceMap[shaderName] = std::make_shared(vertexShader, fragmentShader); } void ShaderManager::PushShader(const std::string &shaderName) { if (shaderStack.size() >= CONST_MAX_SHADER_STACK_SIZE) { throw std::runtime_error("Shader stack overflow!"); } if (shaderResourceMap.find(shaderName) == shaderResourceMap.end()) { logger() << "Shader does not exist: " << shaderName << std::endl; throw std::runtime_error("Shader does not exist!"); } if (shaderStack.size() > 0) { auto& prevShaderAttribList = shaderResourceMap[shaderStack.top()]->attribList; for (auto& attrib : prevShaderAttribList) { glDisableVertexAttribArray(attrib.second); } } shaderStack.push(shaderName); auto& shaderResource = shaderResourceMap[shaderName]; glUseProgram(shaderResource->getShaderProgram()); auto& shaderAttribList = shaderResource->attribList; for (auto& attrib : shaderAttribList) { glEnableVertexAttribArray(attrib.second); } } void ShaderManager::PopShader() { if (shaderStack.size() == 0) { throw std::runtime_error("Shader stack underflow!"); } auto& prevShaderAttribList = shaderResourceMap[shaderStack.top()]->attribList; for (auto& attrib : prevShaderAttribList) { glDisableVertexAttribArray(attrib.second); } shaderStack.pop(); if (shaderStack.size() == 0) { glUseProgram(0); } else { auto& shaderResource = shaderResourceMap[shaderStack.top()]; glUseProgram(shaderResource->getShaderProgram()); auto& shaderAttribList = shaderResource->attribList; for (auto& attrib : shaderAttribList) { glEnableVertexAttribArray(attrib.second); } } } void ShaderManager::EnableVertexAttribArrays() { if (shaderStack.size() != 0) { auto& shaderResource = shaderResourceMap[shaderStack.top()]; auto& shaderAttribList = shaderResource->attribList; for (auto& attrib : shaderAttribList) { glEnableVertexAttribArray(attrib.second); } } } std::shared_ptr ShaderManager::GetCurrentShader() { if (shaderStack.size() == 0) { throw std::runtime_error("Shader stack underflow!"); } return shaderResourceMap[shaderStack.top()]; } ShaderSetter::ShaderSetter(ShaderManager &inShaderManager, const std::string &shaderName) : shaderManager(inShaderManager) { shaderManager.PushShader(shaderName); } ShaderSetter::~ShaderSetter() { shaderManager.PopShader(); } }