UltimateZoneBuilder/Source/Native/Shader.cpp

151 lines
3.7 KiB
C++
Raw Normal View History

#include "Precomp.h"
#include "Shader.h"
#include "RenderDevice.h"
#include <stdexcept>
2019-12-15 21:53:33 +00:00
void Shader::Setup(const std::string& identifier, const std::string& vertexShader, const std::string& fragmentShader, bool alphatest)
{
2019-12-15 21:53:33 +00:00
mIdentifier = identifier;
2019-08-22 13:46:24 +00:00
mVertexText = vertexShader;
mFragmentText = fragmentShader;
mAlphatest = alphatest;
}
2019-12-18 03:22:47 +00:00
bool Shader::CheckCompile(RenderDevice* device)
2019-08-22 13:46:24 +00:00
{
bool firstCall = !mProgramBuilt;
if (firstCall)
{
mProgramBuilt = true;
2019-12-18 03:22:47 +00:00
CreateProgram(device);
2019-12-15 21:53:33 +00:00
glUseProgram(mProgram);
glUniform1i(glGetUniformLocation(mProgram, "texture1"), 0);
glUseProgram(0);
2019-08-22 13:46:24 +00:00
}
2019-12-15 21:53:33 +00:00
return !mErrors.size();
}
2019-08-22 13:46:24 +00:00
2019-12-15 21:53:33 +00:00
std::string Shader::GetCompileError()
{
std::string lines = "Error compiling ";
if (!mVertexShader)
lines += "vertex ";
else if (!mFragmentShader)
lines += "fragment ";
lines += "shader \"" + mIdentifier + "\":\r\n";
for (auto c : mErrors)
2019-08-22 13:46:24 +00:00
{
2019-12-15 21:53:33 +00:00
if (c == '\r')
continue;
if (c == '\n')
lines += "\r\n";
else lines += c;
2019-08-22 13:46:24 +00:00
}
2019-12-15 21:53:33 +00:00
return lines;
}
void Shader::Bind()
{
if (!mProgram || !mProgramBuilt || mErrors.size())
return;
glUseProgram(mProgram);
2019-08-22 13:46:24 +00:00
}
2019-12-18 03:22:47 +00:00
void Shader::CreateProgram(RenderDevice* device)
{
2019-08-16 02:10:03 +00:00
const char* prefixNAT = R"(
#version 150
#line 1
)";
const char* prefixAT = R"(
#version 150
#define ALPHA_TEST
#line 1
)";
2019-08-22 13:46:24 +00:00
const char* prefix = mAlphatest ? prefixAT : prefixNAT;
2019-08-16 02:10:03 +00:00
2019-08-22 13:46:24 +00:00
mVertexShader = CompileShader(prefix + mVertexText, GL_VERTEX_SHADER);
if (!mVertexShader)
2019-08-22 13:46:24 +00:00
return;
2019-08-22 13:46:24 +00:00
mFragmentShader = CompileShader(prefix + mFragmentText, GL_FRAGMENT_SHADER);
if (!mFragmentShader)
2019-08-22 13:46:24 +00:00
return;
mProgram = glCreateProgram();
glAttachShader(mProgram, mVertexShader);
glAttachShader(mProgram, mFragmentShader);
glBindAttribLocation(mProgram, (GLuint)DeclarationUsage::Position, "AttrPosition");
glBindAttribLocation(mProgram, (GLuint)DeclarationUsage::Color, "AttrColor");
glBindAttribLocation(mProgram, (GLuint)DeclarationUsage::TextureCoordinate, "AttrUV");
glBindAttribLocation(mProgram, (GLuint)DeclarationUsage::Normal, "AttrNormal");
glLinkProgram(mProgram);
GLint status = 0;
glGetProgramiv(mProgram, GL_LINK_STATUS, &status);
if (status != GL_TRUE)
{
GLsizei length = 0;
glGetProgramiv(mProgram, GL_INFO_LOG_LENGTH, &length);
std::vector<GLchar> errors(length + (size_t)1);
glGetProgramInfoLog(mProgram, (GLsizei)errors.size(), &length, errors.data());
mErrors = { errors.begin(), errors.begin() + length };
glDeleteProgram(mProgram);
glDeleteShader(mVertexShader);
glDeleteShader(mFragmentShader);
mProgram = 0;
mVertexShader = 0;
mFragmentShader = 0;
2019-08-22 13:46:24 +00:00
return;
}
2019-08-14 10:36:33 +00:00
for (int i = 0; i < (int)UniformName::NumUniforms; i++)
{
2019-12-18 03:22:47 +00:00
if (!device->mUniformInfo[i].Name.empty())
UniformLocations[i] = glGetUniformLocation(mProgram, device->mUniformInfo[i].Name.c_str());
else
UniformLocations[i] = (GLuint)-1;
2019-08-14 10:36:33 +00:00
}
}
GLuint Shader::CompileShader(const std::string& code, GLenum type)
{
GLuint shader = glCreateShader(type);
const GLchar* sources[] = { (GLchar*)code.data() };
const GLint lengths[] = { (GLint)code.size() };
glShaderSource(shader, 1, sources, lengths);
glCompileShader(shader);
GLint status = 0;
glGetShaderiv(shader, GL_COMPILE_STATUS, &status);
if (status != GL_TRUE)
{
GLsizei length = 0;
glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &length);
std::vector<GLchar> errors(length + (size_t)1);
glGetShaderInfoLog(shader, (GLsizei)errors.size(), &length, errors.data());
mErrors = { errors.begin(), errors.begin() + length };
glDeleteShader(shader);
return 0;
}
return shader;
}
2019-08-22 13:46:24 +00:00
void Shader::ReleaseResources()
{
if (mProgram)
glDeleteProgram(mProgram);
if (mVertexShader)
glDeleteShader(mVertexShader);
if (mFragmentShader)
glDeleteShader(mFragmentShader);
mProgram = 0;
mVertexShader = 0;
mFragmentShader = 0;
}