mirror of
https://github.com/projectM-visualizer/projectm.git
synced 2026-02-05 20:55:39 +00:00
812 lines
29 KiB
C++
812 lines
29 KiB
C++
/*
|
|
* ShaderEngine.cpp
|
|
*
|
|
* Created on: Jul 18, 2008
|
|
* Author: pete
|
|
*/
|
|
#include <fstream>
|
|
#include "PerlinNoise.hpp"
|
|
#include "ShaderEngine.hpp"
|
|
#include "BeatDetect.hpp"
|
|
#include "HLSLTranslator.hpp"
|
|
|
|
#define GLSL_VERSION "410"
|
|
|
|
std::string v2f_c4f_vert(
|
|
"#version "
|
|
GLSL_VERSION
|
|
"\n"
|
|
""
|
|
"layout(location = 0) in vec2 vertex_position;\n"
|
|
"layout(location = 1) in vec4 vertex_color;\n"
|
|
""
|
|
"uniform mat4 vertex_transformation;\n"
|
|
"uniform float vertex_point_size;\n"
|
|
""
|
|
"out vec4 fragment_color;\n"
|
|
""
|
|
"void main(){\n"
|
|
" gl_Position = vertex_transformation * vec4(vertex_position, 0.0, 1.0);\n"
|
|
" gl_PointSize = vertex_point_size;\n"
|
|
" fragment_color = vertex_color;\n"
|
|
"}\n");
|
|
|
|
std::string v2f_c4f_frag(
|
|
"#version "
|
|
GLSL_VERSION
|
|
"\n"
|
|
"precision mediump float;\n"
|
|
""
|
|
"in vec4 fragment_color;\n"
|
|
"out vec4 color;\n"
|
|
""
|
|
"void main(){\n"
|
|
" color = fragment_color;\n"
|
|
"}\n");
|
|
|
|
|
|
std::string v2f_c4f_t2f_vert(
|
|
"#version "
|
|
GLSL_VERSION
|
|
"\n"
|
|
"layout(location = 0) in vec2 vertex_position;\n"
|
|
"layout(location = 1) in vec4 vertex_color;\n"
|
|
"layout(location = 2) in vec2 vertex_texture;\n"
|
|
""
|
|
"uniform mat4 vertex_transformation;\n"
|
|
""
|
|
"out vec4 fragment_color;\n"
|
|
"out vec2 fragment_texture;\n"
|
|
""
|
|
"void main(){\n"
|
|
" gl_Position = vertex_transformation * vec4(vertex_position, 0.0, 1.0);\n"
|
|
" fragment_color = vertex_color;\n"
|
|
" fragment_texture = vertex_texture;\n"
|
|
"}\n");
|
|
|
|
std::string v2f_c4f_t2f_frag(
|
|
"#version "
|
|
GLSL_VERSION
|
|
"\n"
|
|
"precision mediump float;\n"
|
|
""
|
|
"in vec4 fragment_color;\n"
|
|
"in vec2 fragment_texture;\n"
|
|
""
|
|
"uniform sampler2D texture_sampler;\n"
|
|
""
|
|
"out vec4 color;\n"
|
|
""
|
|
"void main(){\n"
|
|
" color = fragment_color * texture(texture_sampler, fragment_texture.st);\n"
|
|
"}\n");
|
|
|
|
|
|
GLint ShaderEngine::UNIFORM_V2F_C4F_VERTEX_TRANFORMATION = 0;
|
|
GLint ShaderEngine::UNIFORM_V2F_C4F_VERTEX_POINT_SIZE = 0;
|
|
GLint ShaderEngine::UNIFORM_V2F_C4F_T2F_VERTEX_TRANFORMATION = 0;
|
|
GLint ShaderEngine::UNIFORM_V2F_C4F_T2F_FRAG_TEXTURE_SAMPLER = 0;
|
|
|
|
|
|
|
|
ShaderEngine::ShaderEngine()
|
|
{
|
|
GLuint m_temp_vao;
|
|
glGenVertexArrays(1, &m_temp_vao);
|
|
glBindVertexArray(m_temp_vao);
|
|
|
|
programID_v2f_c4f = CompileShaderProgram(v2f_c4f_vert, v2f_c4f_frag);
|
|
programID_v2f_c4f_t2f = CompileShaderProgram(v2f_c4f_t2f_vert, v2f_c4f_t2f_frag);
|
|
|
|
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");
|
|
}
|
|
|
|
ShaderEngine::~ShaderEngine()
|
|
{
|
|
glDeleteProgram(programID);
|
|
}
|
|
|
|
bool ShaderEngine::checkCompileStatus(GLuint shader, const char *shaderTitle) {
|
|
GLint status;
|
|
glGetShaderiv(shader, GL_COMPILE_STATUS, &status);
|
|
if (status == GL_TRUE)
|
|
return true; // success
|
|
|
|
char buffer[2048];
|
|
glGetShaderInfoLog(shader, 2048, NULL, buffer);
|
|
std::cerr << "Failed to compile shader '" << shaderTitle << "'. Error: " << buffer << std::endl;
|
|
return false;
|
|
}
|
|
|
|
void ShaderEngine::setParams(const int texsize, const unsigned int texId, const float aspect, BeatDetect *beatDetect,
|
|
TextureManager *textureManager)
|
|
{
|
|
mainTextureId = texId;
|
|
this->beatDetect = beatDetect;
|
|
this->textureManager = textureManager;
|
|
this->aspect = aspect;
|
|
this->texsize = texsize;
|
|
|
|
textureManager->setTexture("main", texId, texsize, texsize);
|
|
|
|
#ifndef GL_TRANSITION
|
|
glGenTextures(1, &blur1_tex);
|
|
glBindTexture(GL_TEXTURE_2D, blur1_tex);
|
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, texsize/2, texsize/2, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL );
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
|
|
|
|
glGenTextures(1, &blur2_tex);
|
|
glBindTexture(GL_TEXTURE_2D, blur2_tex);
|
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, texsize / 4, texsize / 4, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL );
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
|
|
|
|
glGenTextures(1, &blur3_tex);
|
|
glBindTexture(GL_TEXTURE_2D, blur3_tex);
|
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, texsize / 8, texsize / 8, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL );
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
|
|
#endif
|
|
|
|
blur1_enabled = false;
|
|
blur2_enabled = false;
|
|
blur3_enabled = false;
|
|
|
|
//std::cout << "Generating Noise Textures" << std::endl;
|
|
|
|
PerlinNoise *noise = new PerlinNoise;
|
|
#ifndef GL_TRANSITION
|
|
glGenTextures(1, &noise_texture_lq_lite);
|
|
glBindTexture(GL_TEXTURE_2D, noise_texture_lq_lite);
|
|
glTexImage2D(GL_TEXTURE_2D, 0, 4, 32, 32, 0, GL_LUMINANCE, GL_FLOAT, noise->noise_lq_lite);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
|
|
textureManager->setTexture("noise_lq_lite", noise_texture_lq_lite, 32, 32);
|
|
|
|
glGenTextures(1, &noise_texture_lq);
|
|
glBindTexture(GL_TEXTURE_2D, noise_texture_lq);
|
|
glTexImage2D(GL_TEXTURE_2D, 0, 4, 256, 256, 0, GL_LUMINANCE, GL_FLOAT, noise->noise_lq);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
|
|
textureManager->setTexture("noise_lq", noise_texture_lq, 256, 256);
|
|
|
|
glGenTextures(1, &noise_texture_mq);
|
|
glBindTexture(GL_TEXTURE_2D, noise_texture_mq);
|
|
glTexImage2D(GL_TEXTURE_2D, 0, 4, 256, 256, 0, GL_LUMINANCE, GL_FLOAT, noise->noise_mq);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
|
|
textureManager->setTexture("noise_mq", noise_texture_mq, 256, 256);
|
|
|
|
glGenTextures(1, &noise_texture_hq);
|
|
glBindTexture(GL_TEXTURE_2D, noise_texture_hq);
|
|
glTexImage2D(GL_TEXTURE_2D, 0, 4, 256, 256, 0, GL_LUMINANCE, GL_FLOAT, noise->noise_hq);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
|
|
textureManager->setTexture("noise_hq", noise_texture_hq, 256, 256);
|
|
|
|
glGenTextures(1, &noise_texture_perlin);
|
|
glBindTexture(GL_TEXTURE_2D, noise_texture_perlin);
|
|
glTexImage2D(GL_TEXTURE_2D, 0, 4, 512, 512, 0, GL_LUMINANCE, GL_FLOAT, noise->noise_perlin);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
|
|
textureManager->setTexture("noise_perlin", noise_texture_perlin, 512, 512);
|
|
|
|
glGenTextures( 1, &noise_texture_lq_vol );
|
|
glBindTexture( GL_TEXTURE_3D, noise_texture_lq_vol );
|
|
glTexImage3D(GL_TEXTURE_3D,0,4,32,32,32,0,GL_LUMINANCE,GL_FLOAT,noise->noise_lq_vol);
|
|
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
|
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
|
|
textureManager->setTexture("noisevol_lq", noise_texture_lq_vol, 256, 256);
|
|
|
|
glGenTextures( 1, &noise_texture_hq_vol );
|
|
glBindTexture( GL_TEXTURE_3D, noise_texture_hq_vol );
|
|
glTexImage3D(GL_TEXTURE_3D,0,4,32,32,32,0,GL_LUMINANCE,GL_FLOAT,noise->noise_hq_vol);
|
|
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
|
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
|
|
textureManager->setTexture("noisevol_hq", noise_texture_hq_vol, 8, 8);
|
|
#endif
|
|
}
|
|
|
|
GLuint ShaderEngine::compilePresetShader(GLenum shaderType, Shader &pmShader, std::string &shaderFilename) {
|
|
std::string program = pmShader.programSource;
|
|
|
|
if (program.length() <= 0)
|
|
return 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, "OUT.color.xyz=ret.xyz;\nOUT.color.w=1;\nreturn OUT;\n}");
|
|
}
|
|
else
|
|
return false;
|
|
|
|
// replace "{" with some variable declarations
|
|
found = program.rfind('{');
|
|
if (found != std::string::npos)
|
|
{
|
|
//std::cout << "first '{' found at: " << int(found) << std::endl;
|
|
const char *progMain = \
|
|
"{\n"
|
|
"float2 uv_orig = uv;\n"
|
|
"float rad=getrad(uv);\n"
|
|
"float ang=getang(uv);\n"
|
|
"float3 ret;\n"
|
|
"outtype OUT;\n";
|
|
program.replace(int(found), 1, progMain);
|
|
}
|
|
else
|
|
return 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;
|
|
program.replace(int(found), 11, "outtype projectm(float2 uv : TEXCOORD0)\n");
|
|
}
|
|
else
|
|
return false;
|
|
|
|
pmShader.textures.clear();
|
|
|
|
// 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);
|
|
UserTexture* texture = new UserTexture(sampler);
|
|
|
|
texture->texID = textureManager->getTexture(texture->name);
|
|
if (texture->texID != 0)
|
|
{
|
|
texture->width = textureManager->getTextureWidth(texture->name);
|
|
texture->height = textureManager->getTextureHeight(texture->name);
|
|
}
|
|
else
|
|
{
|
|
if (sampler.substr(0, 4) == "rand")
|
|
{
|
|
std::string random_name = textureManager->getRandomTextureName(texture->name);
|
|
if (random_name.size() > 0)
|
|
{
|
|
texture->texID = textureManager->getTexture(random_name);
|
|
texture->width = textureManager->getTextureWidth(random_name);
|
|
texture->height = textureManager->getTextureHeight(random_name);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
std::string extensions[6];
|
|
extensions[0] = ".jpg";
|
|
extensions[1] = ".dds";
|
|
extensions[2] = ".png";
|
|
extensions[3] = ".tga";
|
|
extensions[4] = ".bmp";
|
|
extensions[5] = ".dib";
|
|
|
|
for (int x = 0; x < 6; x++)
|
|
{
|
|
|
|
std::string filename = texture->name + extensions[x];
|
|
texture->texID = textureManager->getTexture(filename);
|
|
if (texture->texID != 0)
|
|
{
|
|
texture->width = textureManager->getTextureWidth(filename);
|
|
texture->height = textureManager->getTextureHeight(filename);
|
|
break;
|
|
}
|
|
}
|
|
|
|
}
|
|
}
|
|
if (texture->texID != 0 && pmShader.textures.find(texture->qname) == pmShader.textures.end())
|
|
pmShader.textures[texture->qname] = texture;
|
|
|
|
else
|
|
delete (texture);
|
|
}
|
|
|
|
found = program.find("sampler_", found);
|
|
}
|
|
textureManager->clearRandomTextures();
|
|
|
|
// add texture size vars
|
|
found = 0;
|
|
found = program.find("texsize_", 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 tex = program.substr((int) found, (int) end - found);
|
|
if (pmShader.textures.find(tex) != pmShader.textures.end())
|
|
{
|
|
UserTexture* texture = pmShader.textures[tex];
|
|
texture->texsizeDefined = true;
|
|
//std::cout << "texsize_" << tex << " found" << std::endl;
|
|
}
|
|
}
|
|
found = program.find("texsize_", found);
|
|
}
|
|
|
|
// blur programs
|
|
found = program.find("GetBlur3");
|
|
if (found != std::string::npos)
|
|
blur1_enabled = blur2_enabled = blur3_enabled = true;
|
|
else
|
|
{
|
|
found = program.find("GetBlur2");
|
|
if (found != std::string::npos)
|
|
blur1_enabled = blur2_enabled = true;
|
|
else
|
|
{
|
|
found = program.find("GetBlur1");
|
|
if (found != std::string::npos)
|
|
blur1_enabled = true;
|
|
}
|
|
}
|
|
|
|
// now we need to prepend the HLSL template to the program
|
|
|
|
// transpile from HLSL (aka preset shader aka directX shader) to GLSL (aka OpenGL shader lang)
|
|
HLSLTranslator translator = HLSLTranslator();
|
|
std::unique_ptr<std::string> glslSource = translator.parse(shaderType, shaderFilename.c_str(), program);
|
|
if (!glslSource) {
|
|
std::cerr << "Failed to parse shader from " << shaderFilename << std::endl;
|
|
std::cerr << "Original program: " << program << std::endl;
|
|
return false;
|
|
}
|
|
|
|
// https://www.khronos.org/opengl/wiki/Shader_Compilation#Shader_object_compilation
|
|
GLuint shader = glCreateShader(shaderType);
|
|
// Get strings for glShaderSource.
|
|
const char *shaderSourceCStr = glslSource.get()->c_str();
|
|
glShaderSource(shader, 1, &shaderSourceCStr, NULL);
|
|
|
|
// compile shader
|
|
glCompileShader(shader);
|
|
|
|
// check result
|
|
GLint isCompiled = 0;
|
|
glGetShaderiv(shader, GL_COMPILE_STATUS, &isCompiled);
|
|
if (!checkCompileStatus(shader, shaderFilename.c_str())) {
|
|
// failed to compile the preset shader
|
|
std::cout << "Translated program: " << glslSource.get()->c_str() << std::endl;
|
|
glDeleteShader(shader); // Don't leak the shader.
|
|
return false;
|
|
}
|
|
presetShaders[&pmShader] = shader;
|
|
|
|
return shader;
|
|
}
|
|
|
|
|
|
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
|
|
|
|
GLfloat slow_roam_cos[4] = { 0.5f + 0.5f * (float)cos(context.time * 0.005), 0.5f + 0.5f * (float)cos(context.time * 0.008), 0.5f + 0.5f * (float)cos(context.time * 0.013), 0.5f + 0.5f * (float)cos(context.time * 0.022) };
|
|
GLfloat roam_cos[4] = { 0.5f + 0.5f * cosf(context.time * 0.3), 0.5f + 0.5f * cosf(context.time * 1.3), 0.5f + 0.5f * cosf(context.time * 5), 0.5f + 0.5f * cosf(context.time * 20) };
|
|
GLfloat slow_roam_sin[4] = { 0.5f + 0.5f * sinf(context.time * 0.005), 0.5f + 0.5f * sinf(context.time * 0.008), 0.5f + 0.5f * sinf(context.time * 0.013), 0.5f + 0.5f * sinf(context.time * 0.022) };
|
|
GLfloat roam_sin[4] = { 0.5f + 0.5f * sinf(context.time * 0.3), 0.5f + 0.5f * sinf(context.time * 1.3), 0.5f + 0.5f * sinf(context.time * 5), 0.5f + 0.5f * sinf(context.time * 20) };
|
|
|
|
glProgramUniform4fv(program, glGetUniformLocation(program, "slow_roam_cos"), 4, slow_roam_cos);
|
|
glProgramUniform4fv(program, glGetUniformLocation(program, "roam_cos"), 4, roam_cos);
|
|
glProgramUniform4fv(program, glGetUniformLocation(program, "slow_roam_sin"), 4, slow_roam_sin);
|
|
glProgramUniform4fv(program, glGetUniformLocation(program, "roam_sin"), 4, roam_sin);
|
|
|
|
glProgramUniform1f(program, glGetUniformLocation(program, "time"), context.time);
|
|
glProgramUniform4f(program, glGetUniformLocation(program, "rand_preset"), rand_preset[0], rand_preset[1], rand_preset[2], rand_preset[3]);
|
|
glProgramUniform4f(program, glGetUniformLocation(program, "rand_frame"), (rand() % 100) * .01, (rand() % 100) * .01, (rand()% 100) * .01, (rand() % 100) * .01);
|
|
glProgramUniform1f(program, glGetUniformLocation(program, "fps"), context.fps);
|
|
glProgramUniform1f(program, glGetUniformLocation(program, "frame"), context.frame);
|
|
glProgramUniform1f(program, glGetUniformLocation(program, "progress"), context.progress);
|
|
|
|
glProgramUniform1f(program, glGetUniformLocation(program, "blur1_min"), pipeline.blur1n);
|
|
glProgramUniform1f(program, glGetUniformLocation(program, "blur1_max"), pipeline.blur1x);
|
|
glProgramUniform1f(program, glGetUniformLocation(program, "blur2_min"), pipeline.blur2n);
|
|
glProgramUniform1f(program, glGetUniformLocation(program, "blur2_max"), pipeline.blur2x);
|
|
glProgramUniform1f(program, glGetUniformLocation(program, "blur3_min"), pipeline.blur3n);
|
|
glProgramUniform1f(program, glGetUniformLocation(program, "blur3_max"), pipeline.blur3x);
|
|
|
|
glProgramUniform1f(program, glGetUniformLocation(program, "bass"), beatDetect->bass);
|
|
glProgramUniform1f(program, glGetUniformLocation(program, "mid"), beatDetect->mid);
|
|
glProgramUniform1f(program, glGetUniformLocation(program, "treb"), beatDetect->treb);
|
|
glProgramUniform1f(program, glGetUniformLocation(program, "bass_att"), beatDetect->bass_att);
|
|
glProgramUniform1f(program, glGetUniformLocation(program, "mid_att"), beatDetect->mid_att);
|
|
glProgramUniform1f(program, glGetUniformLocation(program, "treb_att"), beatDetect->treb_att);
|
|
glProgramUniform1f(program, glGetUniformLocation(program, "vol"), beatDetect->vol);
|
|
glProgramUniform1f(program, glGetUniformLocation(program, "vol_att"), beatDetect->vol);
|
|
|
|
glProgramUniform4f(program, glGetUniformLocation(program, "texsize"), texsize, texsize, 1 / (float) texsize, 1
|
|
/ (float) texsize);
|
|
glProgramUniform4f(program, glGetUniformLocation(program, "aspect"), 1 / aspect, 1, aspect, 1);
|
|
|
|
/*
|
|
if (blur1_enabled)
|
|
{
|
|
cgGLSetTextureParameter(program, glGetUniformLocation(program, "sampler_blur1"), blur1_tex);
|
|
cgGLEnableTextureParameter(program, glGetUniformLocation(program, "sampler_blur1"));
|
|
}
|
|
if (blur2_enabled)
|
|
{
|
|
cgGLSetTextureParameter(glGetUniformLocation(program, "sampler_blur2"), blur2_tex);
|
|
cgGLEnableTextureParameter(glGetUniformLocation(program, "sampler_blur2"));
|
|
}
|
|
if (blur3_enabled)
|
|
{
|
|
cgGLSetTextureParameter(glGetUniformLocation(program, "sampler_blur3"), blur3_tex);
|
|
cgGLEnableTextureParameter(glGetUniformLocation(program, "sampler_blur3"));
|
|
}
|
|
*/
|
|
}
|
|
|
|
void ShaderEngine::setupUserTexture(const UserTexture* texture)
|
|
{
|
|
std::string samplerName = "sampler_" + texture->qname;
|
|
|
|
// https://www.khronos.org/opengl/wiki/Sampler_(GLSL)#Binding_textures_to_samplers
|
|
GLint param = glGetUniformLocation(programID, samplerName.c_str());
|
|
if (param < 0) {
|
|
// FIXME: turn this on and fix it.
|
|
// i think sampler names are carrying over from previous shaders...
|
|
// std::cerr << "invalid uniform name " << samplerName << std::endl;
|
|
return;
|
|
}
|
|
|
|
glUniform1i(param, 0);
|
|
|
|
glActiveTexture(GL_TEXTURE0 + 0);
|
|
glBindTexture(GL_TEXTURE_2D, texture->texID);
|
|
|
|
if (texture->texsizeDefined)
|
|
{
|
|
std::string texsizeName = "texsize_" + texture->name;
|
|
GLint textSizeParam = glGetUniformLocation(programID, texsizeName.c_str());
|
|
if (param >= 0) {
|
|
glProgramUniform4f(textSizeParam, texture->width, texture->height, 0,
|
|
1 / (float) texture->width, 1 / (float) texture->height);
|
|
} else {
|
|
std::cerr << "invalid texsizeName " << texsizeName << std::endl;
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
void ShaderEngine::setupUserTextureState( const UserTexture* texture)
|
|
{
|
|
glBindTexture(GL_TEXTURE_2D, texture->texID);
|
|
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, texture->bilinear ? GL_LINEAR : GL_NEAREST);
|
|
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, texture->bilinear ? GL_LINEAR : GL_NEAREST);
|
|
#ifndef GL_TRANSITION
|
|
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, texture->wrap ? GL_REPEAT : GL_CLAMP);
|
|
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, texture->wrap ? GL_REPEAT : GL_CLAMP);
|
|
#endif
|
|
}
|
|
|
|
void ShaderEngine::SetupShaderQVariables(GLuint program, const Pipeline &q)
|
|
{
|
|
// set program uniform "q" values (q1, q2, ... q32)
|
|
for (int i=0; i < 32; i++) {
|
|
std::string varName = "q";
|
|
varName.append(std::to_string(i+1));
|
|
int loc = glGetUniformLocation(program, varName.c_str());
|
|
glProgramUniform1f(program, loc, q.q[i]);
|
|
}
|
|
}
|
|
|
|
void ShaderEngine::setAspect(float aspect)
|
|
{
|
|
this->aspect = aspect;
|
|
}
|
|
void ShaderEngine::RenderBlurTextures(const Pipeline &pipeline, const PipelineContext &pipelineContext,
|
|
const int texsize)
|
|
{
|
|
#ifndef GL_TRANSITION
|
|
if (blur1_enabled || blur2_enabled || blur3_enabled)
|
|
{
|
|
float tex[4][2] =
|
|
{
|
|
{ 0, 1 },
|
|
{ 0, 0 },
|
|
{ 1, 0 },
|
|
{ 1, 1 } };
|
|
|
|
glBlendFunc(GL_ONE, GL_ZERO);
|
|
glColor4f(1.0, 1.0, 1.0, 1.0f);
|
|
|
|
glBindTexture(GL_TEXTURE_2D, mainTextureId);
|
|
glEnable(GL_TEXTURE_2D);
|
|
|
|
glEnableClientState(GL_VERTEX_ARRAY);
|
|
glDisableClientState(GL_COLOR_ARRAY);
|
|
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
|
|
glTexCoordPointer(2, GL_FLOAT, 0, tex);
|
|
|
|
if (blur1_enabled)
|
|
{
|
|
glProgramUniform4f(glGetUniformLocation(blur1Program, "srctexsize"), 4, texsize/2, texsize/2, 2 / (float) texsize,
|
|
2 / (float) texsize);
|
|
glProgramUniform4f(glGetUniformLocation(blur2Program, "srctexsize"), 4, texsize/2 , texsize/2, 2 / (float) texsize,
|
|
2 / (float) texsize);
|
|
|
|
|
|
|
|
float pointsold[4][2] =
|
|
{
|
|
{ 0, 1 },
|
|
{ 0, 0 },
|
|
{ 1, 0 },
|
|
{ 1, 1 } };
|
|
float points[4][2] =
|
|
{
|
|
{ 0, 0.5 },
|
|
{ 0, 0 },
|
|
{ 0.5, 0 },
|
|
{ 0.5, 0.5 } };
|
|
|
|
// cgGLBindProgram(blur1Program);
|
|
|
|
glVertexPointer(2, GL_FLOAT, 0, points);
|
|
glBlendFunc(GL_ONE,GL_ZERO);
|
|
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
|
|
|
|
|
|
glBindTexture(GL_TEXTURE_2D, blur1_tex);
|
|
glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, texsize/2, texsize/2);
|
|
|
|
|
|
}
|
|
|
|
if (blur2_enabled)
|
|
{
|
|
glProgramUniform4f(glGetUniformLocation(blur1Program, "srctexsize"), 4, texsize/2, texsize/2, 2 / (float) texsize,
|
|
2 / (float) texsize);
|
|
glProgramUniform4f(glGetUniformLocation(blur2Program, "srctexsize"), 4, texsize/2, texsize/2, 2 / (float) texsize,
|
|
2 / (float) texsize);
|
|
|
|
|
|
|
|
float points[4][2] =
|
|
{
|
|
{ 0, 0.25 },
|
|
{ 0, 0 },
|
|
{ 0.25, 0 },
|
|
{ 0.25, 0.25 } };
|
|
|
|
glVertexPointer(2, GL_FLOAT, 0, points);
|
|
glBlendFunc(GL_ONE,GL_ZERO);
|
|
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
|
|
|
|
|
|
|
|
glBindTexture(GL_TEXTURE_2D, blur2_tex);
|
|
glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, texsize/4, texsize/4);
|
|
|
|
|
|
}
|
|
|
|
if (blur3_enabled)
|
|
{
|
|
glProgramUniform4f(glGetUniformLocation(blur2Program, "srctexsize"), 4, texsize/4, texsize/4, 4 / (float) texsize,
|
|
4/ (float) texsize);
|
|
glProgramUniform4f(glGetUniformLocation(blur2Program, "srctexsize"), 4, texsize / 4, texsize / 4, 4
|
|
/ (float) texsize, 4 / (float) texsize);
|
|
float points[4][2] =
|
|
{
|
|
{ 0, 0.125 },
|
|
{ 0, 0 },
|
|
{ 0.125, 0 },
|
|
{ 0.125, 0.125 } };
|
|
|
|
glVertexPointer(2, GL_FLOAT, 0, points);
|
|
glBlendFunc(GL_ONE,GL_ZERO);
|
|
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
|
|
|
|
|
|
|
|
glBindTexture(GL_TEXTURE_2D, blur3_tex);
|
|
glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, texsize/8, texsize/8);
|
|
|
|
|
|
}
|
|
glDisable(GL_TEXTURE_2D);
|
|
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
|
|
|
}
|
|
#endif
|
|
}
|
|
|
|
void ShaderEngine::relinkProgram() {
|
|
glLinkProgram(programID);
|
|
|
|
GLint program_linked;
|
|
glGetProgramiv(programID, GL_LINK_STATUS, &program_linked);
|
|
if (program_linked != GL_TRUE) {
|
|
GLsizei log_length = 0;
|
|
GLchar message[1024];
|
|
glGetProgramInfoLog(programID, 1024, &log_length, message);
|
|
std::cerr << "Failed to link program: " << message << std::endl;
|
|
return;
|
|
}
|
|
|
|
printf("LINK OK\n");
|
|
}
|
|
|
|
#pragma mark Preset Shaders
|
|
void ShaderEngine::loadPresetShader(Shader &presetShader, std::string &shaderFilename)
|
|
{
|
|
assert(!presetShader.enabled);
|
|
// i think they're always fragment shaders? not positive -mischa
|
|
auto shader = compilePresetShader(GL_FRAGMENT_SHADER, presetShader, shaderFilename);
|
|
|
|
if (!shader) {
|
|
// failed to compile
|
|
return;
|
|
}
|
|
|
|
presetShaders[&presetShader] = shader;
|
|
|
|
// pass texture info from preset to shader
|
|
for (auto &userTexture : presetShader.textures) {
|
|
setupUserTextureState(userTexture.second);
|
|
setupUserTexture(userTexture.second);
|
|
}
|
|
|
|
// turn shader on
|
|
glAttachShader(programID, shader);
|
|
presetShader.enabled = true;
|
|
printf("linked shader %s\n", presetShader.presetPath.c_str());
|
|
|
|
relinkProgram();
|
|
}
|
|
|
|
void ShaderEngine::deletePresetShader(Shader &presetShader)
|
|
{
|
|
printf("deleting shader... enabled=%d, path=%s\n", presetShader.enabled, presetShader.presetPath.c_str());
|
|
if (! presetShader.enabled)
|
|
return;
|
|
|
|
auto shader = presetShaders[&presetShader];
|
|
glDeleteShader(shader);
|
|
glDetachShader(programID, shader);
|
|
presetShader.enabled = false;
|
|
}
|
|
|
|
// disable all preset shaders
|
|
void ShaderEngine::disablePresetShaders() {
|
|
if (presetShaders.size() == 0) {
|
|
// nothing to do
|
|
return;
|
|
}
|
|
|
|
for (auto &i : presetShaders) {
|
|
deletePresetShader(*i.first);
|
|
}
|
|
presetShaders.clear();
|
|
printf("DISABLED ALL\n");
|
|
relinkProgram();
|
|
}
|
|
|
|
void ShaderEngine::reset()
|
|
{
|
|
disablePresetShaders();
|
|
rand_preset[0] = (rand() % 100) * .01;
|
|
rand_preset[1] = (rand() % 100) * .01;
|
|
rand_preset[2] = (rand() % 100) * .01;
|
|
rand_preset[3] = (rand() % 100) * .01;
|
|
}
|
|
|
|
GLuint ShaderEngine::CompileShaderProgram(const std::string & VertexShaderCode, const std::string & FragmentShaderCode){
|
|
|
|
// Create the shaders
|
|
GLuint VertexShaderID = glCreateShader(GL_VERTEX_SHADER);
|
|
GLuint FragmentShaderID = glCreateShader(GL_FRAGMENT_SHADER);
|
|
|
|
GLint Result = GL_FALSE;
|
|
int InfoLogLength;
|
|
|
|
|
|
// Compile Vertex Shader
|
|
char const * VertexSourcePointer = VertexShaderCode.c_str();
|
|
glShaderSource(VertexShaderID, 1, &VertexSourcePointer , NULL);
|
|
glCompileShader(VertexShaderID);
|
|
|
|
// Check Vertex Shader
|
|
glGetShaderiv(VertexShaderID, GL_COMPILE_STATUS, &Result);
|
|
glGetShaderiv(VertexShaderID, GL_INFO_LOG_LENGTH, &InfoLogLength);
|
|
if ( InfoLogLength > 0 ){
|
|
std::vector<char> VertexShaderErrorMessage(InfoLogLength+1);
|
|
glGetShaderInfoLog(VertexShaderID, InfoLogLength, NULL, &VertexShaderErrorMessage[0]);
|
|
fprintf(stderr, "Error compiling base vertex shader: %s\n", &VertexShaderErrorMessage[0]);
|
|
}
|
|
|
|
|
|
// Compile Fragment Shader
|
|
char const * FragmentSourcePointer = FragmentShaderCode.c_str();
|
|
glShaderSource(FragmentShaderID, 1, &FragmentSourcePointer , NULL);
|
|
glCompileShader(FragmentShaderID);
|
|
|
|
// Check Fragment Shader
|
|
glGetShaderiv(FragmentShaderID, GL_COMPILE_STATUS, &Result);
|
|
glGetShaderiv(FragmentShaderID, GL_INFO_LOG_LENGTH, &InfoLogLength);
|
|
if ( InfoLogLength > 0 ){
|
|
std::vector<char> FragmentShaderErrorMessage(InfoLogLength+1);
|
|
glGetShaderInfoLog(FragmentShaderID, InfoLogLength, NULL, &FragmentShaderErrorMessage[0]);
|
|
fprintf(stderr, "Error compiling base fragment shader: %s\n", &FragmentShaderErrorMessage[0]);
|
|
}
|
|
|
|
|
|
// Link the program
|
|
programID = glCreateProgram();
|
|
glAttachShader(programID, VertexShaderID);
|
|
glAttachShader(programID, FragmentShaderID);
|
|
glLinkProgram(programID);
|
|
|
|
// Check the program
|
|
glGetProgramiv(programID, GL_LINK_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]);
|
|
}
|
|
|
|
|
|
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]);
|
|
}
|
|
|
|
|
|
glDetachShader(programID, VertexShaderID);
|
|
glDetachShader(programID, FragmentShaderID);
|
|
|
|
glDeleteShader(VertexShaderID);
|
|
glDeleteShader(FragmentShaderID);
|
|
|
|
return programID;
|
|
}
|