#include "ShaderManager.h" #include #include #ifdef __ANDROID__ #include #endif namespace ZL { ShaderResource::ShaderResource(const std::string &vertexCode, const std::string &fragmentCode) { const int CONST_INFOLOG_LENGTH = 256; char infoLog[CONST_INFOLOG_LENGTH]; int infoLogLength; 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, &infoLogLength, infoLog); if (!vertexShaderCompiled) { #ifdef __ANDROID__ __android_log_print(ANDROID_LOG_ERROR, "ShaderManager", "Failed to compile vertex shader: %s", infoLog); #endif throw std::runtime_error("Failed to compile vertex shader code!"); } if (!fragmentShaderCompiled) { #ifdef __ANDROID__ __android_log_print(ANDROID_LOG_ERROR, "ShaderManager", "Failed to compile fragment shader: %s", infoLog); #endif throw std::runtime_error("Failed to compile fragment shader code!"); } 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); if (!programLinked) { shaderProgram = 0; #ifdef __ANDROID__ __android_log_print(ANDROID_LOG_ERROR, "ShaderManager", "Failed to link shader program: %s", infoLog); #endif throw std::runtime_error("Failed to link shader program!"); } //================= 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); } //================= 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); } #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 std::string vertexShader; std::string fragmentShader; if (!ZIPFileName.empty()) { std::vector 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); } ///std::cout << "Shader: "<< vertexShader << std::endl; 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()) { throw std::runtime_error("Shader does not exist!"); } shaderStack.push(shaderName); glUseProgram(shaderResourceMap[shaderName]->getShaderProgram()); } void ShaderManager::PopShader() { if (shaderStack.size() == 0) { throw std::runtime_error("Shader stack underflow!"); } shaderStack.pop(); if (shaderStack.size() == 0) { glUseProgram(0); } else { glUseProgram(shaderResourceMap[shaderStack.top()]->getShaderProgram()); } } 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(); } }