space-game001/src/render/ShaderManager.cpp
2026-01-11 12:08:48 +03:00

222 lines
7.4 KiB
C++

#include "ShaderManager.h"
#include <iostream>
#include <SDL.h>
#ifdef __ANDROID__
#include <android/log.h>
#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<int>(strlen(vertexCode.c_str()));
int fragmentCodeLength = static_cast<int>(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<char> vertexShaderData;
std::vector<char> 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<ShaderResource>(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 <ShaderResource> 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();
}
}