mirror of
https://github.com/projectM-visualizer/projectm.git
synced 2026-02-06 12:05:28 +00:00
971 lines
39 KiB
C++
971 lines
39 KiB
C++
/*
|
|
* ShaderEngine.cpp
|
|
*
|
|
* Created on: Jul 18, 2008
|
|
* Author: pete
|
|
*/
|
|
#include <fstream>
|
|
#include <algorithm>
|
|
#include "ShaderEngine.hpp"
|
|
#include "BeatDetect.hpp"
|
|
#include "Texture.hpp"
|
|
#include "HLSLParser.h"
|
|
#include "GLSLGenerator.h"
|
|
#include "StaticGlShaders.h"
|
|
#include <glm/mat4x4.hpp> // glm::mat4
|
|
#include <glm/gtc/matrix_transform.hpp> // glm::translate, glm::rotate, glm::scale, glm::perspective
|
|
#include <glm/gtc/type_ptr.hpp>
|
|
#include <set>
|
|
#include <regex>
|
|
|
|
#define FRAND ((rand() % 7381)/7380.0f)
|
|
|
|
ShaderEngine::ShaderEngine() : presetCompShaderLoaded(false), presetWarpShaderLoaded(false)
|
|
{
|
|
std::shared_ptr<StaticGlShaders> static_gl_shaders = StaticGlShaders::Get();
|
|
|
|
programID_v2f_c4f = CompileShaderProgram(
|
|
static_gl_shaders->GetV2fC4fVertexShader(),
|
|
static_gl_shaders->GetV2fC4fFragmentShader(), "v2f_c4f");
|
|
programID_v2f_c4f_t2f = CompileShaderProgram(
|
|
static_gl_shaders->GetV2fC4fT2fVertexShader(),
|
|
static_gl_shaders->GetV2fC4fT2fFragmentShader(), "v2f_c4f_t2f");
|
|
|
|
programID_blur1 = CompileShaderProgram(
|
|
static_gl_shaders->GetBlurVertexShader(),
|
|
static_gl_shaders->GetBlur1FragmentShader(), "blur1");
|
|
programID_blur2 = CompileShaderProgram(
|
|
static_gl_shaders->GetBlurVertexShader(),
|
|
static_gl_shaders->GetBlur2FragmentShader(), "blur2");
|
|
|
|
uniform_v2f_c4f_vertex_tranformation = glGetUniformLocation(programID_v2f_c4f, "vertex_transformation");
|
|
uniform_v2f_c4f_vertex_point_size = glGetUniformLocation(programID_v2f_c4f, "vertex_point_size");
|
|
uniform_v2f_c4f_t2f_vertex_tranformation = glGetUniformLocation(programID_v2f_c4f_t2f, "vertex_transformation");
|
|
uniform_v2f_c4f_t2f_frag_texture_sampler = glGetUniformLocation(programID_v2f_c4f_t2f, "texture_sampler");
|
|
|
|
uniform_blur1_sampler = glGetUniformLocation(programID_blur1, "texture_sampler");
|
|
uniform_blur1_c0 = glGetUniformLocation(programID_blur1, "_c0");
|
|
uniform_blur1_c1 = glGetUniformLocation(programID_blur1, "_c1");
|
|
uniform_blur1_c2 = glGetUniformLocation(programID_blur1, "_c2");
|
|
uniform_blur1_c3 = glGetUniformLocation(programID_blur1, "_c3");
|
|
|
|
uniform_blur2_sampler = glGetUniformLocation(programID_blur2, "texture_sampler");
|
|
uniform_blur2_c0 = glGetUniformLocation(programID_blur2, "_c0");
|
|
uniform_blur2_c5 = glGetUniformLocation(programID_blur2, "_c5");
|
|
uniform_blur2_c6 = glGetUniformLocation(programID_blur2, "_c6");
|
|
|
|
// Initialize Blur vao/vbo
|
|
float pointsBlur[16] = {
|
|
-1.0, -1.0, 0.0, 1.0,
|
|
1.0, -1.0, 1.0, 1.0,
|
|
-1.0, 1.0, 0.0, 0.0,
|
|
1.0, 1.0, 1.0, 0.0};
|
|
|
|
glGenBuffers(1, &vboBlur);
|
|
glGenVertexArrays(1, &vaoBlur);
|
|
|
|
glBindVertexArray(vaoBlur);
|
|
glBindBuffer(GL_ARRAY_BUFFER, vboBlur);
|
|
|
|
glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 8 * 2, pointsBlur, GL_STATIC_DRAW);
|
|
|
|
glEnableVertexAttribArray(0);
|
|
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(float)*4, (void*)0); // Positions
|
|
|
|
glEnableVertexAttribArray(1);
|
|
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(float)*4, (void*)(sizeof(float)*2)); // Textures
|
|
|
|
glBindVertexArray(0);
|
|
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
|
}
|
|
|
|
ShaderEngine::~ShaderEngine()
|
|
{
|
|
glDeleteProgram(programID_v2f_c4f);
|
|
glDeleteProgram(programID_v2f_c4f_t2f);
|
|
|
|
glDeleteProgram(programID_blur1);
|
|
glDeleteProgram(programID_blur2);
|
|
|
|
glDeleteBuffers(1, &vboBlur);
|
|
glDeleteVertexArrays(1, &vaoBlur);
|
|
|
|
disablePresetShaders();
|
|
}
|
|
|
|
bool ShaderEngine::checkCompileStatus(GLuint shader, const std::string & shaderTitle) {
|
|
GLint status;
|
|
glGetShaderiv(shader, GL_COMPILE_STATUS, &status);
|
|
if (status == GL_TRUE)
|
|
return true; // success
|
|
|
|
int InfoLogLength;
|
|
glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &InfoLogLength);
|
|
if ( InfoLogLength > 0 ){
|
|
std::vector<char> FragmentShaderErrorMessage(InfoLogLength+1);
|
|
glGetShaderInfoLog(shader, InfoLogLength, NULL, &FragmentShaderErrorMessage[0]);
|
|
std::cerr << "Failed to compile shader '" << shaderTitle << "'. Error: " << &FragmentShaderErrorMessage[0] << std::endl;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
void ShaderEngine::setParams(const int _texsizeX, const int _texsizeY, BeatDetect *_beatDetect,
|
|
TextureManager *_textureManager)
|
|
{
|
|
this->beatDetect = _beatDetect;
|
|
this->textureManager = _textureManager;
|
|
|
|
aspectX = 1;
|
|
aspectY = 1;
|
|
if (_texsizeX > _texsizeY)
|
|
aspectY = (float)_texsizeY/(float)_texsizeX;
|
|
else
|
|
aspectX = (float)_texsizeX/(float)_texsizeY;
|
|
|
|
this->texsizeX = _texsizeX;
|
|
this->texsizeY = _texsizeY;
|
|
}
|
|
|
|
|
|
// compile a user-defined shader from a preset. returns program ID if successful.
|
|
GLuint ShaderEngine::compilePresetShader(const PresentShaderType shaderType, Shader &pmShader, const std::string &shaderFilename) {
|
|
std::string program = pmShader.programSource;
|
|
|
|
if (program.length() <= 0)
|
|
return GL_FALSE;
|
|
|
|
// replace "}" with return statement (this can probably be optimized for the GLSL conversion...)
|
|
size_t found = program.rfind('}');
|
|
if (found != std::string::npos)
|
|
{
|
|
//std::cout << "last '}' found at: " << int(found) << std::endl;
|
|
program.replace(int(found), 1, "_return_value = float4(ret.xyz, 1.0);\n"
|
|
"}\n");
|
|
}
|
|
else
|
|
return GL_FALSE;
|
|
|
|
// replace shader_body with entry point function
|
|
found = program.find("shader_body");
|
|
if (found != std::string::npos)
|
|
{
|
|
//std::cout << "first 'shader_body' found at: " << int(found) << std::endl;
|
|
if (shaderType == PresentWarpShader) {
|
|
program.replace(int(found), 11, "void PS(float4 _vDiffuse : COLOR, float4 _uv : TEXCOORD0, float2 _rad_ang : TEXCOORD1, out float4 _return_value : COLOR)\n");
|
|
|
|
} else {
|
|
program.replace(int(found), 11, "void PS(float4 _vDiffuse : COLOR, float2 _uv : TEXCOORD0, float2 _rad_ang : TEXCOORD1, out float4 _return_value : COLOR)\n");
|
|
|
|
}
|
|
}
|
|
else
|
|
return GL_FALSE;
|
|
|
|
// replace "{" with some variable declarations
|
|
found = program.find('{',found);
|
|
if (found != std::string::npos)
|
|
{
|
|
//std::cout << "first '{' found at: " << int(found) << std::endl;
|
|
const char *progMain = \
|
|
"{\n"
|
|
"float3 ret = 0;\n";
|
|
program.replace(int(found), 1, progMain);
|
|
}
|
|
else
|
|
return GL_FALSE;
|
|
|
|
pmShader.textures.clear();
|
|
|
|
|
|
// Add builtin textures
|
|
pmShader.textures["main"] = textureManager->getTexture("main", GL_REPEAT, GL_LINEAR);
|
|
pmShader.textures["fc_main"] = textureManager->getTexture("main", GL_CLAMP_TO_EDGE, GL_LINEAR);
|
|
pmShader.textures["pc_main"] = textureManager->getTexture("main", GL_CLAMP_TO_EDGE, GL_NEAREST);
|
|
pmShader.textures["fw_main"] = textureManager->getTexture("main", GL_REPEAT, GL_LINEAR);
|
|
pmShader.textures["pw_main"] = textureManager->getTexture("main", GL_REPEAT, GL_NEAREST);
|
|
|
|
pmShader.textures["noise_lq"] = textureManager->getTexture("noise_lq", GL_CLAMP_TO_EDGE, GL_LINEAR);
|
|
pmShader.textures["noise_lq_lite"] = textureManager->getTexture("noise_lq_lite", GL_CLAMP_TO_EDGE, GL_LINEAR);
|
|
pmShader.textures["noise_mq"] = textureManager->getTexture("noise_mq", GL_CLAMP_TO_EDGE, GL_LINEAR);
|
|
pmShader.textures["noise_hq"] = textureManager->getTexture("noise_hq", GL_CLAMP_TO_EDGE, GL_LINEAR);
|
|
pmShader.textures["noisevol_lq"] = textureManager->getTexture("noisevol_lq", GL_CLAMP_TO_EDGE, GL_LINEAR);
|
|
pmShader.textures["noisevol_hq"] = textureManager->getTexture("noisevol_hq", GL_CLAMP_TO_EDGE, GL_LINEAR);
|
|
|
|
|
|
|
|
// set up texture samplers for all samplers references in the shader program
|
|
found = 0;
|
|
found = program.find("sampler_", found);
|
|
while (found != std::string::npos)
|
|
{
|
|
found += 8;
|
|
size_t end = program.find_first_of(" ;,\n\r)", found);
|
|
|
|
if (end != std::string::npos)
|
|
{
|
|
std::string sampler = program.substr((int) found, (int) end - found);
|
|
std::string lowerCaseName(sampler);
|
|
std::transform(lowerCaseName.begin(), lowerCaseName.end(), lowerCaseName.begin(), tolower);
|
|
|
|
TextureSamplerDesc texDesc = textureManager->getTexture(sampler, GL_REPEAT, GL_LINEAR);
|
|
|
|
if (texDesc.first == NULL)
|
|
{
|
|
if (lowerCaseName.substr(0, 4) == "rand" || lowerCaseName.substr(2, 5) == "_rand")
|
|
{
|
|
texDesc = textureManager->getRandomTextureName(sampler);
|
|
}
|
|
else
|
|
{
|
|
texDesc = textureManager->tryLoadingTexture(sampler);
|
|
}
|
|
}
|
|
|
|
if (texDesc.first == NULL)
|
|
{
|
|
std::cerr << "Texture loading error for: " << sampler << std::endl;
|
|
}
|
|
else
|
|
{
|
|
std::map<std::string, TextureSamplerDesc>::const_iterator iter = pmShader.textures.cbegin();
|
|
for ( ; iter != pmShader.textures.cend(); ++iter)
|
|
{
|
|
if (iter->first == sampler)
|
|
break;
|
|
}
|
|
|
|
if (iter == pmShader.textures.cend())
|
|
pmShader.textures[sampler] = texDesc;
|
|
}
|
|
}
|
|
|
|
found = program.find("sampler_", found);
|
|
}
|
|
|
|
textureManager->clearRandomTextures();
|
|
|
|
found = program.find("GetBlur3");
|
|
if (found != std::string::npos)
|
|
{
|
|
blur1_enabled = blur2_enabled = blur3_enabled = true;
|
|
pmShader.textures["blur3"] = textureManager->getTexture("blur3", GL_CLAMP_TO_EDGE, GL_LINEAR);
|
|
pmShader.textures["blur2"] = textureManager->getTexture("blur2", GL_CLAMP_TO_EDGE, GL_LINEAR);
|
|
pmShader.textures["blur1"] = textureManager->getTexture("blur1", GL_CLAMP_TO_EDGE, GL_LINEAR);
|
|
}
|
|
else
|
|
{
|
|
found = program.find("GetBlur2");
|
|
if (found != std::string::npos)
|
|
{
|
|
blur1_enabled = blur2_enabled = true;
|
|
pmShader.textures["blur2"] = textureManager->getTexture("blur2", GL_CLAMP_TO_EDGE, GL_LINEAR);
|
|
pmShader.textures["blur1"] = textureManager->getTexture("blur1", GL_CLAMP_TO_EDGE, GL_LINEAR);
|
|
}
|
|
else
|
|
{
|
|
found = program.find("GetBlur1");
|
|
if (found != std::string::npos)
|
|
{
|
|
blur1_enabled = true;
|
|
pmShader.textures["blur1"] = textureManager->getTexture("blur1", GL_CLAMP_TO_EDGE, GL_LINEAR);
|
|
}
|
|
}
|
|
}
|
|
|
|
std::string fullSource;
|
|
|
|
// prepend our HLSL template to the actual program source
|
|
fullSource.append(StaticGlShaders::Get()->GetPresetShaderHeader());
|
|
|
|
if (shaderType == PresentWarpShader) {
|
|
fullSource.append( "#define rad _rad_ang.x\n"
|
|
"#define ang _rad_ang.y\n"
|
|
"#define uv _uv.xy\n"
|
|
"#define uv_orig _uv.zw\n");
|
|
} else {
|
|
fullSource.append( "#define rad _rad_ang.x\n"
|
|
"#define ang _rad_ang.y\n"
|
|
"#define uv _uv.xy\n"
|
|
"#define uv_orig _uv.xy\n"
|
|
"#define hue_shader _vDiffuse.xyz\n");
|
|
}
|
|
|
|
|
|
fullSource.append(program);
|
|
|
|
std::string shaderTypeString;
|
|
switch(shaderType) {
|
|
case PresentWarpShader: shaderTypeString = "Warp"; break;
|
|
case PresentCompositeShader: shaderTypeString = "Comp"; break;
|
|
case PresentBlur1Shader: shaderTypeString = "Blur1"; break;
|
|
case PresentBlur2Shader: shaderTypeString = "Blur2"; break;
|
|
default: shaderTypeString = "Other";
|
|
}
|
|
|
|
M4::GLSLGenerator generator;
|
|
M4::Allocator allocator;
|
|
|
|
M4::HLSLTree tree( &allocator );
|
|
M4::HLSLParser parser(&allocator, &tree);
|
|
|
|
// preprocess define macros
|
|
std::string sourcePreprocessed;
|
|
if (!parser.ApplyPreprocessor(shaderFilename.c_str(), fullSource.c_str(), fullSource.size(), sourcePreprocessed)) {
|
|
std::cerr << "Failed to preprocess HLSL(step1) " << shaderTypeString << " shader" << std::endl;
|
|
|
|
#if !DUMP_SHADERS_ON_ERROR
|
|
std::cerr << "Source: " << std::endl << fullSource << std::endl;
|
|
#else
|
|
std::ofstream out("/tmp/shader_" + shaderTypeString + "_step1.txt");
|
|
out << fullSource;
|
|
out.close();
|
|
#endif
|
|
return GL_FALSE;
|
|
}
|
|
|
|
// Remove previous shader declarations
|
|
std::smatch matches;
|
|
while(std::regex_search(sourcePreprocessed, matches, std::regex("sampler(2D|3D|)(\\s+|\\().*"))) {
|
|
sourcePreprocessed.replace(matches.position(), matches.length(), "");
|
|
}
|
|
|
|
// Remove previous texsize declarations
|
|
while(std::regex_search(sourcePreprocessed, matches, std::regex("float4\\s+texsize_.*"))) {
|
|
sourcePreprocessed.replace(matches.position(), matches.length(), "");
|
|
}
|
|
|
|
// Declare samplers
|
|
std::set<std::string> texsizes;
|
|
std::map<std::string, TextureSamplerDesc>::const_iterator iter_samplers = pmShader.textures.cbegin();
|
|
for ( ; iter_samplers != pmShader.textures.cend(); ++iter_samplers)
|
|
{
|
|
Texture * texture = iter_samplers->second.first;
|
|
|
|
if (texture->type == GL_TEXTURE_3D) {
|
|
sourcePreprocessed.insert(0, "uniform sampler3D sampler_" + iter_samplers->first + ";\n");
|
|
} else {
|
|
sourcePreprocessed.insert(0, "uniform sampler2D sampler_" + iter_samplers->first + ";\n");
|
|
}
|
|
|
|
texsizes.insert(iter_samplers->first);
|
|
texsizes.insert(texture->name);
|
|
}
|
|
|
|
// Declare texsizes
|
|
std::set<std::string>::const_iterator iter_texsizes = texsizes.cbegin();
|
|
for ( ; iter_texsizes != texsizes.cend(); ++iter_texsizes)
|
|
{
|
|
sourcePreprocessed.insert(0, "uniform float4 texsize_" + *iter_texsizes + ";\n");
|
|
}
|
|
|
|
|
|
// transpile from HLSL (aka preset shader aka directX shader) to GLSL (aka OpenGL shader lang)
|
|
|
|
// parse
|
|
if( !parser.Parse(shaderFilename.c_str(), sourcePreprocessed.c_str(), sourcePreprocessed.size()) ) {
|
|
std::cerr << "Failed to parse HLSL(step2) " << shaderTypeString << " shader" << std::endl;
|
|
|
|
#if !DUMP_SHADERS_ON_ERROR
|
|
std::cerr << "Source: " << std::endl << sourcePreprocessed << std::endl;
|
|
#else
|
|
std::ofstream out2("/tmp/shader_" + shaderTypeString + "_step2.txt");
|
|
out2 << sourcePreprocessed;
|
|
out2.close();
|
|
#endif
|
|
return GL_FALSE;
|
|
}
|
|
|
|
// generate GLSL
|
|
if (!generator.Generate(&tree, M4::GLSLGenerator::Target_FragmentShader,
|
|
StaticGlShaders::Get()->GetGlslGeneratorVersion(),
|
|
"PS")) {
|
|
std::cerr << "Failed to transpile HLSL(step3) " << shaderTypeString << " shader to GLSL" << std::endl;
|
|
#if !DUMP_SHADERS_ON_ERROR
|
|
std::cerr << "Source: " << std::endl << sourcePreprocessed << std::endl;
|
|
#else
|
|
std::ofstream out2("/tmp/shader_" + shaderTypeString + "_step2.txt");
|
|
out2 << sourcePreprocessed;
|
|
out2.close();
|
|
#endif
|
|
return GL_FALSE;
|
|
}
|
|
|
|
// now we have GLSL source for the preset shader program (hopefully it's
|
|
// valid!) copmile the preset shader fragment shader with the standard
|
|
// vertex shader and cross our fingers
|
|
GLuint ret = 0;
|
|
if (shaderType == PresentWarpShader) {
|
|
ret = CompileShaderProgram(
|
|
StaticGlShaders::Get()->GetPresetWarpVertexShader(),
|
|
generator.GetResult(), shaderTypeString);
|
|
} else {
|
|
ret = CompileShaderProgram(
|
|
StaticGlShaders::Get()->GetPresetCompVertexShader(),
|
|
generator.GetResult(), shaderTypeString);
|
|
}
|
|
|
|
if (ret != GL_FALSE) {
|
|
#ifdef DEBUG
|
|
std::cerr << "Successful compilation of " << shaderTypeString << std::endl;
|
|
#endif
|
|
} else {
|
|
std::cerr << "Compilation error (step3) of " << shaderTypeString << std::endl;
|
|
|
|
#if !DUMP_SHADERS_ON_ERROR
|
|
std::cerr << "Source:" << std::endl << generator.GetResult() << std::endl;
|
|
#else
|
|
std::ofstream out3("/tmp/shader_" + shaderTypeString + "_step3.txt");
|
|
out3 << generator.GetResult();
|
|
out3.close();
|
|
#endif
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
|
|
void ShaderEngine::SetupShaderVariables(GLuint program, const Pipeline &pipeline, const PipelineContext &context)
|
|
{
|
|
// pass info from projectM to the shader uniforms
|
|
// these are the inputs: http://www.geisswerks.com/milkdrop/milkdrop_preset_authoring.html#3f6
|
|
|
|
float time_since_preset_start = context.time - context.presetStartTime;
|
|
float time_since_preset_start_wrapped = time_since_preset_start - (int)(time_since_preset_start/10000)*10000;
|
|
float mip_x = logf((float)texsizeX)/logf(2.0f);
|
|
float mip_y = logf((float)texsizeX)/logf(2.0f);
|
|
float mip_avg = 0.5f*(mip_x + mip_y);
|
|
|
|
glUniform4f(glGetUniformLocation(program, "rand_frame"), (rand() % 100) * .01, (rand() % 100) * .01, (rand()% 100) * .01, (rand() % 100) * .01);
|
|
glUniform4f(glGetUniformLocation(program, "rand_preset"), rand_preset[0], rand_preset[1], rand_preset[2], rand_preset[3]);
|
|
|
|
glUniform4f(glGetUniformLocation(program, "_c0"), aspectX, aspectY, 1 / aspectX, 1 / aspectY);
|
|
glUniform4f(glGetUniformLocation(program, "_c1"), 0.0, 0.0, 0.0, 0.0);
|
|
glUniform4f(glGetUniformLocation(program, "_c2"), time_since_preset_start_wrapped, context.fps, context.frame, context.progress);
|
|
glUniform4f(glGetUniformLocation(program, "_c3"), beatDetect->bass/100, beatDetect->mid/100, beatDetect->treb/100, beatDetect->vol/100);
|
|
glUniform4f(glGetUniformLocation(program, "_c4"), beatDetect->bass_att/100, beatDetect->mid_att/100, beatDetect->treb_att/100, beatDetect->vol_att/100);
|
|
glUniform4f(glGetUniformLocation(program, "_c5"), pipeline.blur1x-pipeline.blur1n, pipeline.blur1n, pipeline.blur2x-pipeline.blur2n, pipeline.blur2n);
|
|
glUniform4f(glGetUniformLocation(program, "_c6"), pipeline.blur3x-pipeline.blur3n, pipeline.blur3n, pipeline.blur1n, pipeline.blur1x);
|
|
glUniform4f(glGetUniformLocation(program, "_c7"), texsizeX, texsizeY, 1 / (float) texsizeX, 1 / (float) texsizeY);
|
|
|
|
glUniform4f(glGetUniformLocation(program, "_c8"), 0.5f+0.5f*cosf(context.time* 0.329f+1.2f),
|
|
0.5f+0.5f*cosf(context.time* 1.293f+3.9f),
|
|
0.5f+0.5f*cosf(context.time* 5.070f+2.5f),
|
|
0.5f+0.5f*cosf(context.time*20.051f+5.4f));
|
|
|
|
glUniform4f(glGetUniformLocation(program, "_c9"), 0.5f+0.5f*sinf(context.time* 0.329f+1.2f),
|
|
0.5f+0.5f*sinf(context.time* 1.293f+3.9f),
|
|
0.5f+0.5f*sinf(context.time* 5.070f+2.5f),
|
|
0.5f+0.5f*sinf(context.time*20.051f+5.4f));
|
|
|
|
glUniform4f(glGetUniformLocation(program, "_c10"), 0.5f+0.5f*cosf(context.time*0.0050f+2.7f),
|
|
0.5f+0.5f*cosf(context.time*0.0085f+5.3f),
|
|
0.5f+0.5f*cosf(context.time*0.0133f+4.5f),
|
|
0.5f+0.5f*cosf(context.time*0.0217f+3.8f));
|
|
|
|
glUniform4f(glGetUniformLocation(program, "_c11"), 0.5f+0.5f*sinf(context.time*0.0050f+2.7f),
|
|
0.5f+0.5f*sinf(context.time*0.0085f+5.3f),
|
|
0.5f+0.5f*sinf(context.time*0.0133f+4.5f),
|
|
0.5f+0.5f*sinf(context.time*0.0217f+3.8f));
|
|
|
|
glUniform4f(glGetUniformLocation(program, "_c12"), mip_x, mip_y, mip_avg, 0 );
|
|
glUniform4f(glGetUniformLocation(program, "_c13"), pipeline.blur2n, pipeline.blur2x, pipeline.blur3n, pipeline.blur3x);
|
|
|
|
|
|
glm::mat4 temp_mat[24];
|
|
|
|
// write matrices
|
|
for (int i=0; i<20; i++)
|
|
{
|
|
glm::mat4 mx, my, mz, mxlate;
|
|
|
|
mx = glm::rotate(glm::mat4(1.0f), rot_base[i].x + rot_speed[i].x*context.time, glm::vec3(1.0f, 0.0f, 0.0f));
|
|
my = glm::rotate(glm::mat4(1.0f), rot_base[i].y + rot_speed[i].y*context.time, glm::vec3(0.0f, 1.0f, 0.0f));
|
|
mz = glm::rotate(glm::mat4(1.0f), rot_base[i].z + rot_speed[i].z*context.time, glm::vec3(0.0f, 0.0f, 1.0f));
|
|
|
|
mxlate = glm::translate(glm::mat4(1.0f), glm::vec3(xlate[i].x, xlate[i].y, xlate[i].z));
|
|
|
|
temp_mat[i] = mxlate * mx;
|
|
temp_mat[i] = mz * temp_mat[i];
|
|
temp_mat[i] = my * temp_mat[i];
|
|
}
|
|
|
|
// the last 4 are totally random, each frame
|
|
for (int i=20; i<24; i++)
|
|
{
|
|
glm::mat4 mx, my, mz, mxlate;
|
|
|
|
mx = glm::rotate(glm::mat4(1.0f), FRAND * 6.28f, glm::vec3(1.0f, 0.0f, 0.0f));
|
|
my = glm::rotate(glm::mat4(1.0f), FRAND * 6.28f, glm::vec3(0.0f, 1.0f, 0.0f));
|
|
mz = glm::rotate(glm::mat4(1.0f), FRAND * 6.28f, glm::vec3(0.0f, 0.0f, 1.0f));
|
|
|
|
mxlate = glm::translate(glm::mat4(1.0f), glm::vec3(FRAND, FRAND, FRAND));
|
|
|
|
temp_mat[i] = mxlate * mx;
|
|
temp_mat[i] = mz * temp_mat[i];
|
|
temp_mat[i] = my * temp_mat[i];
|
|
}
|
|
|
|
glUniformMatrix3x4fv(glGetUniformLocation(program, "rot_s1"), 1, GL_FALSE, glm::value_ptr(glm::mat3x4(temp_mat[0])));
|
|
glUniformMatrix3x4fv(glGetUniformLocation(program, "rot_s2"), 1, GL_FALSE, glm::value_ptr(glm::mat3x4(temp_mat[1])));
|
|
glUniformMatrix3x4fv(glGetUniformLocation(program, "rot_s3"), 1, GL_FALSE, glm::value_ptr(glm::mat3x4(temp_mat[2])));
|
|
glUniformMatrix3x4fv(glGetUniformLocation(program, "rot_s4"), 1, GL_FALSE, glm::value_ptr(glm::mat3x4(temp_mat[3])));
|
|
glUniformMatrix3x4fv(glGetUniformLocation(program, "rot_d1"), 1, GL_FALSE, glm::value_ptr(glm::mat3x4(temp_mat[4])));
|
|
glUniformMatrix3x4fv(glGetUniformLocation(program, "rot_d2"), 1, GL_FALSE, glm::value_ptr(glm::mat3x4(temp_mat[5])));
|
|
glUniformMatrix3x4fv(glGetUniformLocation(program, "rot_d3"), 1, GL_FALSE, glm::value_ptr(glm::mat3x4(temp_mat[6])));
|
|
glUniformMatrix3x4fv(glGetUniformLocation(program, "rot_d4"), 1, GL_FALSE, glm::value_ptr(glm::mat3x4(temp_mat[7])));
|
|
glUniformMatrix3x4fv(glGetUniformLocation(program, "rot_f1"), 1, GL_FALSE, glm::value_ptr(glm::mat3x4(temp_mat[8])));
|
|
glUniformMatrix3x4fv(glGetUniformLocation(program, "rot_f2"), 1, GL_FALSE, glm::value_ptr(glm::mat3x4(temp_mat[9])));
|
|
glUniformMatrix3x4fv(glGetUniformLocation(program, "rot_f3"), 1, GL_FALSE, glm::value_ptr(glm::mat3x4(temp_mat[10])));
|
|
glUniformMatrix3x4fv(glGetUniformLocation(program, "rot_f4"), 1, GL_FALSE, glm::value_ptr(glm::mat3x4(temp_mat[11])));
|
|
glUniformMatrix3x4fv(glGetUniformLocation(program, "rot_vf1"), 1, GL_FALSE, glm::value_ptr(glm::mat3x4(temp_mat[12])));
|
|
glUniformMatrix3x4fv(glGetUniformLocation(program, "rot_vf2"), 1, GL_FALSE, glm::value_ptr(glm::mat3x4(temp_mat[13])));
|
|
glUniformMatrix3x4fv(glGetUniformLocation(program, "rot_vf3"), 1, GL_FALSE, glm::value_ptr(glm::mat3x4(temp_mat[14])));
|
|
glUniformMatrix3x4fv(glGetUniformLocation(program, "rot_vf4"), 1, GL_FALSE, glm::value_ptr(glm::mat3x4(temp_mat[15])));
|
|
glUniformMatrix3x4fv(glGetUniformLocation(program, "rot_uf1"), 1, GL_FALSE, glm::value_ptr(glm::mat3x4(temp_mat[16])));
|
|
glUniformMatrix3x4fv(glGetUniformLocation(program, "rot_uf2"), 1, GL_FALSE, glm::value_ptr(glm::mat3x4(temp_mat[17])));
|
|
glUniformMatrix3x4fv(glGetUniformLocation(program, "rot_uf3"), 1, GL_FALSE, glm::value_ptr(glm::mat3x4(temp_mat[18])));
|
|
glUniformMatrix3x4fv(glGetUniformLocation(program, "rot_uf4"), 1, GL_FALSE, glm::value_ptr(glm::mat3x4(temp_mat[19])));
|
|
glUniformMatrix3x4fv(glGetUniformLocation(program, "rot_rand1"), 1, GL_FALSE, glm::value_ptr(glm::mat3x4(temp_mat[20])));
|
|
glUniformMatrix3x4fv(glGetUniformLocation(program, "rot_rand2"), 1, GL_FALSE, glm::value_ptr(glm::mat3x4(temp_mat[21])));
|
|
glUniformMatrix3x4fv(glGetUniformLocation(program, "rot_rand3"), 1, GL_FALSE, glm::value_ptr(glm::mat3x4(temp_mat[22])));
|
|
glUniformMatrix3x4fv(glGetUniformLocation(program, "rot_rand4"), 1, GL_FALSE, glm::value_ptr(glm::mat3x4(temp_mat[23])));
|
|
|
|
// set program uniform "_q[a-h]" values (_qa.x, _qa.y, _qa.z, _qa.w, _qb.x, _qb.y ... ) alias q[1-32]
|
|
for (int i=0; i < 32; i+=4) {
|
|
std::string varName = "_q";
|
|
varName.push_back('a' + i/4);
|
|
glUniform4f(glGetUniformLocation(program, varName.c_str()), pipeline.q[i], pipeline.q[i+1], pipeline.q[i+2], pipeline.q[i+3]);
|
|
}
|
|
}
|
|
|
|
void ShaderEngine::SetupTextures(GLuint program, const Shader &shader)
|
|
{
|
|
|
|
unsigned int texNum = 0;
|
|
std::map<std::string, Texture*> texsizes;
|
|
|
|
// Set samplers
|
|
for (std::map<std::string, TextureSamplerDesc>::const_iterator iter_samplers = shader.textures.begin(); iter_samplers
|
|
!= shader.textures.end(); ++iter_samplers)
|
|
{
|
|
std::string texName = iter_samplers->first;
|
|
Texture * texture = iter_samplers->second.first;
|
|
Sampler * sampler = iter_samplers->second.second;
|
|
std::string samplerName = "sampler_" + texName;
|
|
|
|
// https://www.khronos.org/opengl/wiki/Sampler_(GLSL)#Binding_textures_to_samplers
|
|
GLint param = glGetUniformLocation(program, samplerName.c_str());
|
|
if (param < 0) {
|
|
// unused uniform have been optimized out by glsl compiler
|
|
continue;
|
|
}
|
|
|
|
texsizes[texName] = texture;
|
|
texsizes[texture->name] = texture;
|
|
|
|
glActiveTexture(GL_TEXTURE0 + texNum);
|
|
glBindTexture(texture->type, texture->texID);
|
|
glBindSampler(texNum, sampler->samplerID);
|
|
|
|
glUniform1i(param, texNum);
|
|
texNum++;
|
|
}
|
|
|
|
|
|
// Set texsizes
|
|
std::map<std::string, Texture*>::const_iterator iter_textures = texsizes.cbegin();
|
|
for ( ; iter_textures != texsizes.cend(); ++iter_textures)
|
|
{
|
|
Texture * texture = iter_textures->second;
|
|
|
|
std::string texsizeName = "texsize_" + iter_textures->first;
|
|
GLint textSizeParam = glGetUniformLocation(program, texsizeName.c_str());
|
|
if (textSizeParam >= 0) {
|
|
glUniform4f(textSizeParam, texture->width, texture->height,
|
|
1 / (float) texture->width, 1 / (float) texture->height);
|
|
} else {
|
|
// unused uniform have been optimized out by glsl compiler
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void ShaderEngine::RenderBlurTextures(const Pipeline &pipeline, const PipelineContext &pipelineContext)
|
|
{
|
|
unsigned int passes = 0;
|
|
if (blur3_enabled) {
|
|
passes = 6;
|
|
} else if (blur2_enabled) {
|
|
passes = 4;
|
|
} else if (blur1_enabled) {
|
|
passes = 2;
|
|
} else {
|
|
return;
|
|
}
|
|
|
|
const float w[8] = { 4.0f, 3.8f, 3.5f, 2.9f, 1.9f, 1.2f, 0.7f, 0.3f }; //<- user can specify these
|
|
float edge_darken = pipeline.blur1ed;
|
|
float blur_min[3], blur_max[3];
|
|
|
|
blur_min[0] = pipeline.blur1n;
|
|
blur_min[1] = pipeline.blur2n;
|
|
blur_min[2] = pipeline.blur3n;
|
|
blur_max[0] = pipeline.blur1x;
|
|
blur_max[1] = pipeline.blur2x;
|
|
blur_max[2] = pipeline.blur3x;
|
|
|
|
// check that precision isn't wasted in later blur passes [...min-max gap can't grow!]
|
|
// also, if min-max are close to each other, push them apart:
|
|
const float fMinDist = 0.1f;
|
|
if (blur_max[0] - blur_min[0] < fMinDist) {
|
|
float avg = (blur_min[0] + blur_max[0])*0.5f;
|
|
blur_min[0] = avg - fMinDist*0.5f;
|
|
blur_max[0] = avg - fMinDist*0.5f;
|
|
}
|
|
blur_max[1] = std::min(blur_max[0], blur_max[1]);
|
|
blur_min[1] = std::max(blur_min[0], blur_min[1]);
|
|
if (blur_max[1] - blur_min[1] < fMinDist) {
|
|
float avg = (blur_min[1] + blur_max[1])*0.5f;
|
|
blur_min[1] = avg - fMinDist*0.5f;
|
|
blur_max[1] = avg - fMinDist*0.5f;
|
|
}
|
|
blur_max[2] = std::min(blur_max[1], blur_max[2]);
|
|
blur_min[2] = std::max(blur_min[1], blur_min[2]);
|
|
if (blur_max[2] - blur_min[2] < fMinDist) {
|
|
float avg = (blur_min[2] + blur_max[2])*0.5f;
|
|
blur_min[2] = avg - fMinDist*0.5f;
|
|
blur_max[2] = avg - fMinDist*0.5f;
|
|
}
|
|
|
|
float fscale[3];
|
|
float fbias[3];
|
|
|
|
// figure out the progressive scale & bias needed, at each step,
|
|
// to go from one [min..max] range to the next.
|
|
float temp_min, temp_max;
|
|
fscale[0] = 1.0f / (blur_max[0] - blur_min[0]);
|
|
fbias [0] = -blur_min[0] * fscale[0];
|
|
temp_min = (blur_min[1] - blur_min[0]) / (blur_max[0] - blur_min[0]);
|
|
temp_max = (blur_max[1] - blur_min[0]) / (blur_max[0] - blur_min[0]);
|
|
fscale[1] = 1.0f / (temp_max - temp_min);
|
|
fbias [1] = -temp_min * fscale[1];
|
|
temp_min = (blur_min[2] - blur_min[1]) / (blur_max[1] - blur_min[1]);
|
|
temp_max = (blur_max[2] - blur_min[1]) / (blur_max[1] - blur_min[1]);
|
|
fscale[2] = 1.0f / (temp_max - temp_min);
|
|
fbias [2] = -temp_min * fscale[2];
|
|
|
|
const std::vector<Texture*> & blurTextures = textureManager->getBlurTextures();
|
|
const Texture * mainTexture = textureManager->getMainTexture();
|
|
|
|
glBlendFunc(GL_ONE, GL_ZERO);
|
|
glBindVertexArray(vaoBlur);
|
|
|
|
for (unsigned int i=0; i<passes; i++)
|
|
{
|
|
// set pixel shader
|
|
if ((i%2) == 0) {
|
|
glUseProgram(programID_blur1);
|
|
glUniform1i(uniform_blur1_sampler, 0);
|
|
|
|
} else {
|
|
glUseProgram(programID_blur2);
|
|
glUniform1i(uniform_blur2_sampler, 0);
|
|
|
|
}
|
|
|
|
glViewport(0, 0, blurTextures[i]->width, blurTextures[i]->height);
|
|
|
|
// hook up correct source texture - assume there is only one, at stage 0
|
|
glActiveTexture(GL_TEXTURE0);
|
|
if (i == 0) {
|
|
glBindTexture(GL_TEXTURE_2D, mainTexture->texID);
|
|
} else {
|
|
glBindTexture(GL_TEXTURE_2D, blurTextures[i-1]->texID);
|
|
}
|
|
|
|
float srcw = (i==0) ? mainTexture->width : blurTextures[i-1]->width;
|
|
float srch = (i==0) ? mainTexture->height : blurTextures[i-1]->height;
|
|
|
|
|
|
float fscale_now = fscale[i/2];
|
|
float fbias_now = fbias[i/2];
|
|
|
|
// set constants
|
|
if (i%2==0)
|
|
{
|
|
// pass 1 (long horizontal pass)
|
|
//-------------------------------------
|
|
const float w1 = w[0] + w[1];
|
|
const float w2 = w[2] + w[3];
|
|
const float w3 = w[4] + w[5];
|
|
const float w4 = w[6] + w[7];
|
|
const float d1 = 0 + 2*w[1]/w1;
|
|
const float d2 = 2 + 2*w[3]/w2;
|
|
const float d3 = 4 + 2*w[5]/w3;
|
|
const float d4 = 6 + 2*w[7]/w4;
|
|
const float w_div = 0.5f/(w1+w2+w3+w4);
|
|
//-------------------------------------
|
|
//float4 _c0; // source texsize (.xy), and inverse (.zw)
|
|
//float4 _c1; // w1..w4
|
|
//float4 _c2; // d1..d4
|
|
//float4 _c3; // scale, bias, w_div, 0
|
|
//-------------------------------------
|
|
glUniform4f(uniform_blur1_c0, srcw, srch, 1.0f/srcw, 1.0f/srch);
|
|
glUniform4f(uniform_blur1_c1, w1,w2,w3,w4);
|
|
glUniform4f(uniform_blur1_c2, d1,d2,d3,d4);
|
|
glUniform4f(uniform_blur1_c3, fscale_now, fbias_now, w_div, 0.0);
|
|
}
|
|
else
|
|
{
|
|
// pass 2 (short vertical pass)
|
|
//-------------------------------------
|
|
const float w1 = w[0]+w[1] + w[2]+w[3];
|
|
const float w2 = w[4]+w[5] + w[6]+w[7];
|
|
const float d1 = 0 + 2*((w[2]+w[3])/w1);
|
|
const float d2 = 2 + 2*((w[6]+w[7])/w2);
|
|
const float w_div = 1.0f/((w1+w2)*2);
|
|
//-------------------------------------
|
|
//float4 _c0; // source texsize (.xy), and inverse (.zw)
|
|
//float4 _c5; // w1,w2,d1,d2
|
|
//float4 _c6; // w_div, edge_darken_c1, edge_darken_c2, edge_darken_c3
|
|
//-------------------------------------
|
|
glUniform4f(uniform_blur2_c0, srcw, srch, 1.0f/srcw, 1.0f/srch);
|
|
glUniform4f(uniform_blur2_c5, w1,w2,d1,d2);
|
|
// note: only do this first time; if you do it many times,
|
|
// then the super-blurred levels will have big black lines along the top & left sides.
|
|
if (i==1)
|
|
glUniform4f(uniform_blur2_c6, w_div, (1-edge_darken), edge_darken, 5.0f); //darken edges
|
|
else
|
|
glUniform4f(uniform_blur2_c6, w_div, 1.0f, 0.0f, 5.0f); // don't darken
|
|
}
|
|
|
|
// draw fullscreen quad
|
|
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
|
|
|
|
// save to blur texture
|
|
glBindTexture(GL_TEXTURE_2D, blurTextures[i]->texID);
|
|
glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, blurTextures[i]->width, blurTextures[i]->height);
|
|
}
|
|
|
|
glBindVertexArray(0);
|
|
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
|
|
|
glBindTexture(GL_TEXTURE_2D, 0);
|
|
}
|
|
|
|
bool ShaderEngine::linkProgram(GLuint programID) {
|
|
glLinkProgram(programID);
|
|
|
|
GLint program_linked;
|
|
glGetProgramiv(programID, GL_LINK_STATUS, &program_linked);
|
|
if (program_linked == GL_TRUE) {
|
|
return true; // success
|
|
}
|
|
|
|
int InfoLogLength;
|
|
glGetProgramiv(programID, GL_INFO_LOG_LENGTH, &InfoLogLength);
|
|
if ( InfoLogLength > 0 ){
|
|
std::vector<char> ProgramErrorMessage(InfoLogLength+1);
|
|
glGetProgramInfoLog(programID, InfoLogLength, NULL, &ProgramErrorMessage[0]);
|
|
std::cerr << "Failed to link program: " << &ProgramErrorMessage[0] << std::endl;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
|
|
bool ShaderEngine::loadPresetShaders(Pipeline &pipeline, const std::string & presetName) {
|
|
|
|
bool ok = true;
|
|
|
|
// blur programs
|
|
blur1_enabled = false;
|
|
blur2_enabled = false;
|
|
blur3_enabled = false;
|
|
|
|
m_presetName = presetName;
|
|
|
|
// compile and link warp and composite shaders from pipeline
|
|
if (!pipeline.warpShader.programSource.empty()) {
|
|
programID_presetWarp = loadPresetShader(PresentWarpShader, pipeline.warpShader, pipeline.warpShaderFilename);
|
|
if (programID_presetWarp != GL_FALSE) {
|
|
uniform_vertex_transf_warp_shader = glGetUniformLocation(programID_presetWarp, "vertex_transformation");
|
|
presetWarpShaderLoaded = true;
|
|
} else {
|
|
ok = false;
|
|
}
|
|
}
|
|
|
|
if (!pipeline.compositeShader.programSource.empty()) {
|
|
programID_presetComp = loadPresetShader(PresentCompositeShader, pipeline.compositeShader, pipeline.compositeShaderFilename);
|
|
if (programID_presetComp != GL_FALSE) {
|
|
presetCompShaderLoaded = true;
|
|
} else {
|
|
ok = false;
|
|
}
|
|
}
|
|
|
|
// std::cout << "Preset composite shader active: " << presetCompShaderLoaded << ", preset warp shader active: " << presetWarpShaderLoaded << std::endl;
|
|
|
|
return ok;
|
|
}
|
|
|
|
GLuint ShaderEngine::loadPresetShader(const ShaderEngine::PresentShaderType shaderType, Shader &presetShader, std::string &shaderFilename) {
|
|
GLuint program = compilePresetShader(shaderType, presetShader, shaderFilename);
|
|
|
|
if (program == GL_FALSE) {
|
|
// failed to compile
|
|
return GL_FALSE;
|
|
}
|
|
|
|
return program;
|
|
}
|
|
|
|
// deactivate preset shaders
|
|
void ShaderEngine::disablePresetShaders() {
|
|
if (presetCompShaderLoaded)
|
|
glDeleteProgram(programID_presetComp);
|
|
|
|
if (presetWarpShaderLoaded)
|
|
glDeleteProgram(programID_presetWarp);
|
|
|
|
presetCompShaderLoaded = false;
|
|
presetWarpShaderLoaded = false;
|
|
}
|
|
|
|
void ShaderEngine::reset()
|
|
{
|
|
disablePresetShaders();
|
|
rand_preset[0] = FRAND;
|
|
rand_preset[1] = FRAND;
|
|
rand_preset[2] = FRAND;
|
|
rand_preset[3] = FRAND;
|
|
|
|
unsigned int k = 0;
|
|
do
|
|
{
|
|
for (int i=0; i<4; i++)
|
|
{
|
|
float xlate_mult = 1;
|
|
float rot_mult = 0.9f*powf(k/8.0f, 3.2f);
|
|
xlate[k].x = (FRAND*2-1)*xlate_mult;
|
|
xlate[k].y = (FRAND*2-1)*xlate_mult;
|
|
xlate[k].z = (FRAND*2-1)*xlate_mult;
|
|
rot_base[k].x = FRAND*6.28f;
|
|
rot_base[k].y = FRAND*6.28f;
|
|
rot_base[k].z = FRAND*6.28f;
|
|
rot_speed[k].x = (FRAND*2-1)*rot_mult;
|
|
rot_speed[k].y = (FRAND*2-1)*rot_mult;
|
|
rot_speed[k].z = (FRAND*2-1)*rot_mult;
|
|
k++;
|
|
}
|
|
}
|
|
while (k < sizeof(xlate)/sizeof(xlate[0]));
|
|
}
|
|
|
|
GLuint ShaderEngine::CompileShaderProgram(const std::string & VertexShaderCode, const std::string & FragmentShaderCode, const std::string & shaderTypeString){
|
|
|
|
#if defined(WIN32) && !defined(EYETUNE_WINRT)
|
|
GLenum err = glewInit();
|
|
#endif /** WIN32 */
|
|
|
|
// Create the shaders
|
|
GLuint VertexShaderID = glCreateShader(GL_VERTEX_SHADER);
|
|
GLuint FragmentShaderID = glCreateShader(GL_FRAGMENT_SHADER);
|
|
|
|
|
|
// Compile Vertex Shader
|
|
char const * VertexSourcePointer = VertexShaderCode.c_str();
|
|
glShaderSource(VertexShaderID, 1, &VertexSourcePointer , NULL);
|
|
glCompileShader(VertexShaderID);
|
|
checkCompileStatus(VertexShaderID, "Vertex: " + shaderTypeString);
|
|
|
|
|
|
// Compile Fragment Shader
|
|
char const * FragmentSourcePointer = FragmentShaderCode.c_str();
|
|
glShaderSource(FragmentShaderID, 1, &FragmentSourcePointer , NULL);
|
|
glCompileShader(FragmentShaderID);
|
|
checkCompileStatus(FragmentShaderID, "Fragment: " + shaderTypeString);
|
|
|
|
|
|
// Link the program
|
|
GLuint programID = glCreateProgram();
|
|
|
|
glAttachShader(programID, VertexShaderID);
|
|
glAttachShader(programID, FragmentShaderID);
|
|
bool linkOK = linkProgram(programID);
|
|
|
|
glDetachShader(programID, VertexShaderID);
|
|
glDetachShader(programID, FragmentShaderID);
|
|
|
|
glDeleteShader(VertexShaderID);
|
|
glDeleteShader(FragmentShaderID);
|
|
|
|
return linkOK ? programID : GL_FALSE;
|
|
}
|
|
|
|
void ShaderEngine::validateProgram(const GLuint programID) {
|
|
GLint Result = GL_FALSE;
|
|
int InfoLogLength;
|
|
|
|
glValidateProgram(programID);
|
|
|
|
// Check the program
|
|
glGetProgramiv(programID, GL_VALIDATE_STATUS, &Result);
|
|
glGetProgramiv(programID, GL_INFO_LOG_LENGTH, &InfoLogLength);
|
|
if ( InfoLogLength > 0 ){
|
|
std::vector<char> ProgramErrorMessage(InfoLogLength+1);
|
|
glGetProgramInfoLog(programID, InfoLogLength, NULL, &ProgramErrorMessage[0]);
|
|
fprintf(stderr, "%s\n", &ProgramErrorMessage[0]);
|
|
}
|
|
}
|
|
|
|
// use the appropriate shader program for rendering the interpolation.
|
|
// it will use the preset shader if available, otherwise the textured shader
|
|
bool ShaderEngine::enableWarpShader(Shader &shader, const Pipeline &pipeline, const PipelineContext &pipelineContext, const glm::mat4 & mat_ortho) {
|
|
if (presetWarpShaderLoaded) {
|
|
glUseProgram(programID_presetWarp);
|
|
|
|
SetupTextures(programID_presetWarp, shader);
|
|
|
|
SetupShaderVariables(programID_presetWarp, pipeline, pipelineContext);
|
|
|
|
glUniformMatrix4fv(uniform_vertex_transf_warp_shader, 1, GL_FALSE, glm::value_ptr(mat_ortho));
|
|
|
|
#if OGL_DEBUG
|
|
validateProgram(programID_presetWarp);
|
|
#endif
|
|
|
|
return true;
|
|
}
|
|
|
|
glUseProgram(programID_v2f_c4f_t2f);
|
|
|
|
glUniformMatrix4fv(uniform_v2f_c4f_t2f_vertex_tranformation, 1, GL_FALSE, glm::value_ptr(mat_ortho));
|
|
glUniform1i(uniform_v2f_c4f_t2f_frag_texture_sampler, 0);
|
|
|
|
return false;
|
|
}
|
|
|
|
bool ShaderEngine::enableCompositeShader(Shader &shader, const Pipeline &pipeline, const PipelineContext &pipelineContext) {
|
|
if (presetCompShaderLoaded) {
|
|
glUseProgram(programID_presetComp);
|
|
|
|
SetupTextures(programID_presetComp, shader);
|
|
|
|
SetupShaderVariables(programID_presetComp, pipeline, pipelineContext);
|
|
|
|
#if OGL_DEBUG
|
|
validateProgram(programID_presetComp);
|
|
#endif
|
|
|
|
return true;
|
|
}
|
|
|
|
glUseProgram(programID_v2f_c4f_t2f);
|
|
|
|
return false;
|
|
}
|