engine/src/ShaderManager/ShaderManager.cpp

405 lines
12 KiB
C++

#include "include/ShaderManager/ShaderManager.h"
#include "include/Utils/Utils.h"
#include "include/Engine.h"
namespace SE
{
//===================================================
//============== SHADER RESOURCE ====================
//===================================================
TShaderResource::TShaderResource()
: ShaderProgram(0)
{
}
TShaderResource::~TShaderResource()
{
*Console<<"ResourceManager::ShaderManager::Shader deleting";
FreeShader();
}
bool TShaderResource::CompileShader(boost::shared_array<char> vertexCode, boost::shared_array<char> fragmentCode)
{
FreeShader();
const int CONST_INFOLOG_LENGTH = 256;
char infoLog[CONST_INFOLOG_LENGTH];
int infoLogLength;
int vertexShaderCompiled;
int fragmentShaderCompiled;
int programLinked;
cardinal vertexShader;
cardinal fragmentShader;
int vertexCodeLength = strlen(vertexCode.get());
int fragmentCodeLength = strlen(fragmentCode.get());
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);
*Console<<"ResourceManager::ShaderManager::Shader "+std::string(infoLog);
glCompileShader(fragmentShader);
glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &fragmentShaderCompiled);
glGetShaderInfoLog(fragmentShader, CONST_INFOLOG_LENGTH, &infoLogLength, infoLog);
*Console<<"ResourceManager::ShaderManager::Shader " + std::string(infoLog);
if (!vertexShaderCompiled || !fragmentShaderCompiled)
return false;
ShaderProgram = glCreateProgram();
*Console<<"Shader program is - " + tostr(ShaderProgram);
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);
*Console<<"ResourceManager::ShaderManager::Shader "+std::string(infoLog);
if (!programLinked)
{
ShaderProgram = 0;
return false;
}
int dummySize; //Dummy
int dummyLen; //Dummy
cardinal dummyType; //Dummy
//================= Parsing all uniforms ================
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, &dummyType, 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, &dummyType, attribName);
AttribList[attribName] = glGetAttribLocation(ShaderProgram, attribName);
}
return true;
}
void TShaderResource::FreeShader()
{
if (ShaderProgram != 0)
{
#ifdef TARGET_ANDROID
if (glIsProgram(ShaderProgram))
{
glDeleteProgram(ShaderProgram);
}
#else
glDeleteProgram(ShaderProgram);
#endif
ShaderProgram = 0;
}
UniformList.clear();
AttribList.clear();
}
int TShaderResource::GetAttribIndex(const std::string& attribName)
{
if (AttribList.count(attribName) > 0)
return AttribList[attribName];
else
return -1;
}
int TShaderResource::GetUniformIndex(const std::string& uniformName)
{
if (UniformList.count(uniformName) > 0)
return UniformList[uniformName];
else
return -1;
}
//===================================================
//=============== SHADER MANAGER ====================
//===================================================
TShaderManager::~TShaderManager()
{
Clear();
*Console<<"ResourceManager::ShaderManager deleting";
}
std::shared_ptr<TShaderResource> TShaderManager::GetCurrentShader()
{
if (ShaderNameStack.size() == 0)
{
throw ErrorToLog("GetCurrentShader: Shader is not selected!");
}
return ShaderList[ShaderNameStack.top()];
}
void TShaderManager::Serialize(boost::property_tree::ptree& propertyTree)
{
BOOST_FOREACH(boost::property_tree::ptree::value_type &v, propertyTree.get_child("Shaders"))
{
std::string shaderName = v.second.get<std::string>("Name");
std::string vertexFileName = v.second.get<std::string>("VertexFileName");
std::string fragmentFileName = v.second.get<std::string>("FragmentFileName");
AddShader(shaderName, vertexFileName, fragmentFileName);
}
}
bool TShaderManager::AddShader(const std::string& shaderName, const std::string& vertexFileName, const std::string& fragmentFileName)
{
std::string pathToResources = ST::PathToResources;
if (ShaderList.count(shaderName) > 0)
{
*Console<<"ResourceManager::ShaderManager ERROR shader already exists: "+shaderName;
return false;
}
*Console<<"Prepare to add shader "+shaderName;
cardinal fSize;
boost::shared_array<char> fPointer;
boost::shared_array<char> vertexCode;
boost::shared_array<char> fragmentCode;
fPointer = CreateMemFromFile<char>(pathToResources + vertexFileName, fSize);
vertexCode = boost::shared_array<char>(new char [fSize + 1]);
memcpy(vertexCode.get(), fPointer.get(), fSize);
vertexCode[fSize] = 0;
fPointer = CreateMemFromFile<char>(pathToResources + fragmentFileName, fSize);
fragmentCode = boost::shared_array<char>(new char [fSize + 1]);
memcpy(fragmentCode.get(), fPointer.get(), fSize);
fragmentCode[fSize] = 0;
std::shared_ptr<TShaderResource> shaderResource(new TShaderResource);
ShaderList[shaderName] = shaderResource;
if (!ShaderList[shaderName]->CompileShader(vertexCode, fragmentCode))
{
*Console<<"ResourceManager::ShaderManager ERROR shader could not be compiled or linked: "+shaderName;
return false;
}
*Console<<"ResourceManager::ShaderManager shader loaded: "+shaderName;
return true;
}
void TShaderManager::Clear()
{
glUseProgram(0);
ShaderList.clear();
*Console<<"ResourceManager::ShaderManager cleared";
}
void TShaderManager::PushShader(const std::string& shaderName)
{
if (ShaderList.count(shaderName) == 0)
throw ErrorShaderNotExists(shaderName);
if (ShaderNameStack.size() >= CONST_MAX_STACK_SIZE)
throw ErrorShaderStackOverflow();
if (ShaderNameStack.size() == 0 || ShaderNameStack.top() != shaderName)
{
glUseProgram(ShaderList[shaderName]->ShaderProgram);
}
ShaderNameStack.push(shaderName);
}
void TShaderManager::PopShader()
{
if (ShaderNameStack.size() <= 1)
{
throw ErrorToLog("Shader stack underflow!!");
}
std::string oldShaderName = ShaderNameStack.top();
ShaderNameStack.pop();
std::string shaderName = ShaderNameStack.top();
if (oldShaderName != shaderName)
{
glUseProgram(ShaderList[shaderName]->ShaderProgram);
}
}
//========================================================
//======================== Utilities =====================
//========================================================
void RenderUniform1f(const std::string& uniformName, const float value)
{
if (ResourceManager != NULL)
if (ResourceManager->ShaderManager.GetCurrentShader()->UniformList.count(uniformName) > 0)
glUniform1fv(ResourceManager->ShaderManager.GetCurrentShader()->UniformList[uniformName],1,&value);
}
void RenderUniform3fv(const std::string& uniformName, const float* value)
{
if (ResourceManager != NULL)
if (ResourceManager->ShaderManager.GetCurrentShader()->UniformList.count(uniformName) > 0)
glUniform3fv(ResourceManager->ShaderManager.GetCurrentShader()->UniformList[uniformName],1,value);
}
void RenderUniform4fv(const std::string& uniformName, const float* value)
{
if (ResourceManager != NULL)
if (ResourceManager->ShaderManager.GetCurrentShader()->UniformList.count(uniformName) > 0)
glUniform4fv(ResourceManager->ShaderManager.GetCurrentShader()->UniformList[uniformName],1,value);
}
void RenderUniformMatrix3fv(const std::string& uniformName,bool transpose, const float* value)
{
if (ResourceManager != NULL)
if (ResourceManager->ShaderManager.GetCurrentShader()->UniformList.count(uniformName) > 0)
glUniformMatrix3fv(ResourceManager->ShaderManager.GetCurrentShader()->UniformList[uniformName],1,transpose,value);
}
void RenderUniformMatrix4fv(const std::string& uniformName,bool transpose, const float* value)
{
if (ResourceManager != NULL)
if (ResourceManager->ShaderManager.GetCurrentShader()->UniformList.count(uniformName) > 0)
glUniformMatrix4fv(ResourceManager->ShaderManager.GetCurrentShader()->UniformList[uniformName],1,transpose,value);
}
void RenderUniform1i(const std::string& uniformName, const int value)
{
if (ResourceManager != NULL)
if (ResourceManager->ShaderManager.GetCurrentShader()->UniformList.count(uniformName) > 0)
glUniform1i(ResourceManager->ShaderManager.GetCurrentShader()->UniformList[uniformName],value);
}
void VertexAttrib2fv(const std::string& attribName, const float* value)
{
if (ResourceManager != NULL)
if (ResourceManager->ShaderManager.GetCurrentShader()->AttribList.count(attribName) > 0)
glVertexAttrib2fv(ResourceManager->ShaderManager.GetCurrentShader()->AttribList[attribName], value);
}
void VertexAttrib3fv(const std::string& attribName, const float* value)
{
if (ResourceManager != NULL)
if (ResourceManager->ShaderManager.GetCurrentShader()->AttribList.count(attribName) > 0)
glVertexAttrib3fv(ResourceManager->ShaderManager.GetCurrentShader()->AttribList[attribName], value);
}
void VertexAttribPointer2fv(const std::string& attribName,int stride, const char* pointer)
{
if (ResourceManager != NULL)
if (ResourceManager->ShaderManager.GetCurrentShader()->AttribList.count(attribName) > 0)
glVertexAttribPointer(ResourceManager->ShaderManager.GetCurrentShader()->AttribList[attribName], 2, GL_FLOAT, GL_FALSE, stride, pointer);
}
void VertexAttribPointer3fv(const std::string& attribName,int stride, const char* pointer)
{
if (ResourceManager != NULL)
if (ResourceManager->ShaderManager.GetCurrentShader()->AttribList.count(attribName) > 0)
glVertexAttribPointer(ResourceManager->ShaderManager.GetCurrentShader()->AttribList[attribName], 3, GL_FLOAT, GL_FALSE, stride, pointer);
}
void EnableVertexAttribArray(const std::string& attribName)
{
if (ResourceManager != NULL)
if (ResourceManager->ShaderManager.GetCurrentShader()->AttribList.count(attribName) > 0)
glEnableVertexAttribArray(ResourceManager->ShaderManager.GetCurrentShader()->AttribList[attribName]);
}
void DisableVertexAttribArray(const std::string& attribName)
{
if (ResourceManager != NULL)
if (ResourceManager->ShaderManager.GetCurrentShader()->AttribList.count(attribName) > 0)
glDisableVertexAttribArray(ResourceManager->ShaderManager.GetCurrentShader()->AttribList[attribName]);
}
#ifdef TARGET_WIN32
void RefreshAttribBuffer2fv(const std::string& attribName, std::map<std::string, std::vector<vec2> >& vec2CoordArr)
{
if (ResourceManager != NULL)
if (ResourceManager->ShaderManager.GetCurrentShader()->AttribList.count(attribName) > 0)
if (vec2CoordArr[attribName].size() > 0)
glBufferData(GL_ARRAY_BUFFER, vec2CoordArr[attribName].size()*8, &(*vec2CoordArr[attribName].begin()), GL_STATIC_DRAW);
}
void RefreshAttribBuffer3fv(const std::string& attribName, std::map<std::string, std::vector<vec3> >& vec3CoordArr)
{
if (ResourceManager != NULL)
if (ResourceManager->ShaderManager.GetCurrentShader()->AttribList.count(attribName) > 0)
if (vec3CoordArr[attribName].size() > 0)
glBufferData(GL_ARRAY_BUFFER, vec3CoordArr[attribName].size()*12, &(*vec3CoordArr[attribName].begin()), GL_STATIC_DRAW);
}
#endif
} //namespace SE