2020-09-16 20:14:35 +00:00
|
|
|
// SPDX-License-Identifier: MIT
|
2020-08-30 20:19:37 +00:00
|
|
|
//
|
2020-09-16 20:14:35 +00:00
|
|
|
// EmulationStation Desktop Edition
|
2020-08-30 20:19:37 +00:00
|
|
|
// Shader_GL21.cpp
|
|
|
|
//
|
|
|
|
// OpenGL 2.1 GLSL shader functions.
|
|
|
|
//
|
|
|
|
|
|
|
|
#if defined(USE_OPENGL_21)
|
|
|
|
|
|
|
|
#include "Shader_GL21.h"
|
|
|
|
|
|
|
|
#include "renderers/Renderer.h"
|
|
|
|
#include "resources/ResourceManager.h"
|
|
|
|
#include "Log.h"
|
|
|
|
|
|
|
|
namespace Renderer
|
|
|
|
{
|
|
|
|
Renderer::Shader::Shader()
|
|
|
|
: mProgramID(-1),
|
2020-09-12 10:14:48 +00:00
|
|
|
shaderMVPMatrix(-1),
|
2020-09-04 16:59:19 +00:00
|
|
|
shaderTextureSize(-1),
|
|
|
|
shaderTextureCoord(-1),
|
|
|
|
shaderColor(-1),
|
2020-09-12 10:14:48 +00:00
|
|
|
shaderSaturation(-1),
|
2020-09-12 17:17:26 +00:00
|
|
|
shaderOpacity(-1),
|
2020-09-12 10:14:48 +00:00
|
|
|
shaderDimValue(-1)
|
2020-08-30 20:19:37 +00:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
Renderer::Shader::~Shader()
|
|
|
|
{
|
|
|
|
deleteProgram(mProgramID);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Renderer::Shader::loadShaderFile(const std::string& path, GLenum shaderType)
|
|
|
|
{
|
|
|
|
std::string preprocessorDefines;
|
|
|
|
std::string shaderCode;
|
|
|
|
|
|
|
|
// This will load the entire GLSL source code into the string variable.
|
|
|
|
const ResourceData& shaderData = ResourceManager::getInstance()->getFileData(path);
|
2020-09-16 20:14:35 +00:00
|
|
|
shaderCode.assign(reinterpret_cast<const char*>(shaderData.ptr.get()), shaderData.length);
|
2020-08-30 20:19:37 +00:00
|
|
|
|
|
|
|
// Define the GLSL version (version 120 = OpenGL 2.1).
|
|
|
|
preprocessorDefines = "#version 120\n";
|
|
|
|
|
2020-09-04 16:59:19 +00:00
|
|
|
// Define the preprocessor constants that will let the shader compiler know whether
|
2020-08-30 20:19:37 +00:00
|
|
|
// the VERTEX or FRAGMENT portion of the code should be used.
|
|
|
|
if (shaderType == GL_VERTEX_SHADER)
|
|
|
|
preprocessorDefines += "#define VERTEX\n";
|
|
|
|
else if (shaderType == GL_FRAGMENT_SHADER)
|
|
|
|
preprocessorDefines += "#define FRAGMENT\n";
|
|
|
|
|
|
|
|
shaderVector.push_back(std::make_tuple(
|
|
|
|
path, preprocessorDefines + shaderCode, shaderType));
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Renderer::Shader::createProgram()
|
|
|
|
{
|
|
|
|
GLint programSuccess;
|
|
|
|
|
|
|
|
mProgramID = glCreateProgram();
|
|
|
|
|
|
|
|
// Compile and attach all shaders that have been loaded.
|
|
|
|
for (auto it = shaderVector.cbegin(); it != shaderVector.cend(); it++) {
|
|
|
|
GLuint currentShader = glCreateShader(std::get<2>(*it));
|
|
|
|
GLchar const* shaderCodePtr = std::get<1>(*it).c_str();
|
|
|
|
|
2020-09-16 20:14:35 +00:00
|
|
|
glShaderSource(currentShader, 1,
|
|
|
|
reinterpret_cast<const GLchar**>(&shaderCodePtr), nullptr);
|
2020-08-30 20:19:37 +00:00
|
|
|
glCompileShader(currentShader);
|
|
|
|
|
|
|
|
GLint shaderCompiled;
|
|
|
|
glGetShaderiv(currentShader, GL_COMPILE_STATUS, &shaderCompiled);
|
|
|
|
|
|
|
|
if (shaderCompiled != GL_TRUE) {
|
|
|
|
LOG(LogError) << "OpenGL error: Unable to compile shader " <<
|
|
|
|
currentShader << " (" << std::get<0>(*it) << ").";
|
2020-09-04 16:59:19 +00:00
|
|
|
printShaderInfoLog(currentShader, std::get<2>(*it));
|
2020-08-30 20:19:37 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
GL_CHECK_ERROR(glAttachShader(mProgramID, currentShader));
|
|
|
|
}
|
|
|
|
|
|
|
|
glLinkProgram(mProgramID);
|
|
|
|
|
|
|
|
glGetProgramiv(mProgramID, GL_LINK_STATUS, &programSuccess);
|
|
|
|
if (programSuccess != GL_TRUE) {
|
|
|
|
LOG(LogError) << "OpenGL error: Unable to link program " << mProgramID << ".";
|
|
|
|
printProgramInfoLog(mProgramID);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2020-09-12 10:14:48 +00:00
|
|
|
getVariableLocations(mProgramID);
|
2020-08-30 20:19:37 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Renderer::Shader::deleteProgram(GLuint programID)
|
|
|
|
{
|
|
|
|
GL_CHECK_ERROR(glDeleteProgram(programID));
|
|
|
|
}
|
|
|
|
|
|
|
|
void Renderer::Shader::getVariableLocations(GLuint programID)
|
|
|
|
{
|
2020-09-04 16:59:19 +00:00
|
|
|
// Some of the variable names are chosen to be compatible with the RetroArch GLSL shaders.
|
2020-09-12 10:14:48 +00:00
|
|
|
shaderMVPMatrix = glGetUniformLocation(mProgramID, "MVPMatrix");
|
2020-09-04 16:59:19 +00:00
|
|
|
shaderTextureSize = glGetUniformLocation(mProgramID, "TextureSize");
|
|
|
|
shaderTextureCoord = glGetAttribLocation(mProgramID, "TexCoord");
|
|
|
|
shaderColor = glGetAttribLocation(mProgramID, "COLOR");
|
|
|
|
shaderSaturation = glGetUniformLocation(mProgramID, "saturation");
|
2020-09-12 17:17:26 +00:00
|
|
|
shaderOpacity = glGetUniformLocation(mProgramID, "opacity");
|
2020-09-12 10:14:48 +00:00
|
|
|
shaderDimValue = glGetUniformLocation(mProgramID, "dimValue");
|
|
|
|
}
|
|
|
|
|
|
|
|
void Renderer::Shader::setModelViewProjectionMatrix(Transform4x4f mvpMatrix)
|
|
|
|
{
|
|
|
|
if (shaderMVPMatrix != -1)
|
2020-09-16 20:14:35 +00:00
|
|
|
GL_CHECK_ERROR(glUniformMatrix4fv(shaderMVPMatrix, 1, GL_FALSE,
|
|
|
|
reinterpret_cast<GLfloat*>(&mvpMatrix)));
|
2020-08-30 20:19:37 +00:00
|
|
|
}
|
|
|
|
|
2020-09-04 16:59:19 +00:00
|
|
|
void Renderer::Shader::setTextureSize(std::array<GLfloat, 2> shaderVec2)
|
2020-08-30 20:19:37 +00:00
|
|
|
{
|
2020-09-12 10:14:48 +00:00
|
|
|
if (shaderTextureSize != -1)
|
|
|
|
GL_CHECK_ERROR(glUniform2f(shaderTextureSize, shaderVec2[0], shaderVec2[1]));
|
2020-08-30 20:19:37 +00:00
|
|
|
}
|
|
|
|
|
2020-09-04 16:59:19 +00:00
|
|
|
void Renderer::Shader::setTextureCoordinates(std::array<GLfloat, 4> shaderVec4)
|
2020-08-30 20:19:37 +00:00
|
|
|
{
|
2020-09-12 10:14:48 +00:00
|
|
|
if (shaderTextureCoord != -1) {
|
|
|
|
glVertexAttrib4f(shaderTextureCoord, shaderVec4[0], shaderVec4[1],
|
|
|
|
shaderVec4[2], shaderVec4[3]);
|
|
|
|
}
|
2020-09-04 16:59:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void Renderer::Shader::setColor(std::array<GLfloat, 4> shaderVec4)
|
|
|
|
{
|
2020-09-12 10:14:48 +00:00
|
|
|
if (shaderColor != -1)
|
|
|
|
GL_CHECK_ERROR(glUniform4f(shaderColor, shaderVec4[0],
|
|
|
|
shaderVec4[1], shaderVec4[2], shaderVec4[3]));
|
2020-09-04 16:59:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void Renderer::Shader::setSaturation(GLfloat saturation)
|
|
|
|
{
|
2020-09-12 10:14:48 +00:00
|
|
|
if (shaderSaturation != -1)
|
|
|
|
GL_CHECK_ERROR(glUniform1f(shaderSaturation, saturation));
|
|
|
|
}
|
|
|
|
|
2020-09-12 17:17:26 +00:00
|
|
|
void Renderer::Shader::setOpacity(GLfloat opacity)
|
|
|
|
{
|
|
|
|
if (shaderOpacity != -1)
|
|
|
|
GL_CHECK_ERROR(glUniform1f(shaderOpacity, opacity));
|
|
|
|
}
|
|
|
|
|
2020-09-12 10:14:48 +00:00
|
|
|
void Renderer::Shader::setDimValue(GLfloat dimValue)
|
|
|
|
{
|
|
|
|
if (shaderDimValue != -1)
|
|
|
|
GL_CHECK_ERROR(glUniform1f(shaderDimValue, dimValue));
|
2020-08-30 20:19:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void Renderer::Shader::activateShaders()
|
|
|
|
{
|
|
|
|
GL_CHECK_ERROR(glUseProgram(mProgramID));
|
|
|
|
}
|
|
|
|
|
|
|
|
void Renderer::Shader::deactivateShaders()
|
|
|
|
{
|
|
|
|
GL_CHECK_ERROR(glUseProgram(0));
|
|
|
|
}
|
|
|
|
|
|
|
|
GLuint Renderer::Shader::getProgramID()
|
|
|
|
{
|
|
|
|
return mProgramID;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Renderer::Shader::printProgramInfoLog(GLuint programID)
|
|
|
|
{
|
|
|
|
if (glIsProgram(programID)) {
|
|
|
|
int logLength;
|
|
|
|
int maxLength;
|
|
|
|
|
|
|
|
glGetProgramiv(programID, GL_INFO_LOG_LENGTH, &maxLength);
|
|
|
|
std::vector<char> infoLog(maxLength);
|
|
|
|
|
|
|
|
glGetProgramInfoLog(programID, maxLength, &logLength, &infoLog.front());
|
|
|
|
|
|
|
|
if (logLength > 0) {
|
|
|
|
LOG(LogDebug) << "Renderer_GL21::printProgramLog():\n" <<
|
|
|
|
std::string(infoLog.begin(), infoLog.end());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
LOG(LogError) << "OpenGL error: " << programID << " is not a program.";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-09-04 16:59:19 +00:00
|
|
|
void Renderer::Shader::printShaderInfoLog(GLuint shaderID, GLenum shaderType)
|
2020-08-30 20:19:37 +00:00
|
|
|
{
|
|
|
|
if (glIsShader(shaderID)) {
|
|
|
|
int logLength;
|
|
|
|
int maxLength;
|
|
|
|
|
|
|
|
glGetShaderiv(shaderID, GL_INFO_LOG_LENGTH, &maxLength);
|
|
|
|
std::vector<char> infoLog(maxLength);
|
|
|
|
|
|
|
|
glGetShaderInfoLog(shaderID, maxLength, &logLength, &infoLog.front());
|
|
|
|
|
|
|
|
if (logLength > 0) {
|
2020-09-04 16:59:19 +00:00
|
|
|
LOG(LogDebug) << "Renderer_GL21::printShaderLog(): Error in " <<
|
|
|
|
(shaderType == GL_VERTEX_SHADER ? "VERTEX section:\n" :
|
|
|
|
"FRAGMENT section:\n") << std::string(infoLog.begin(), infoLog.end());
|
2020-08-30 20:19:37 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
LOG(LogError) << "OpenGL error: " << shaderID << " is not a shader.";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
} // Renderer
|
|
|
|
|
|
|
|
#endif // USE_OPENGL_21
|