mirror of
https://github.com/projectM-visualizer/projectm.git
synced 2026-03-19 13:55:26 +00:00
Fix texture management
This commit is contained in:
@ -9,10 +9,13 @@
|
||||
#include "ShaderEngine.hpp"
|
||||
#include "BeatDetect.hpp"
|
||||
#include "Texture.hpp"
|
||||
#include "HLSLTranslator.hpp"
|
||||
#include "HLSLParser.h"
|
||||
#include "GLSLGenerator.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>
|
||||
|
||||
#ifdef USE_GLES
|
||||
#define GLSL_VERSION "300 es"
|
||||
@ -255,12 +258,6 @@ std::string PresetShaderIncludes = ""
|
||||
"#define blur3_min _c13.z\n"
|
||||
"#define blur3_max _c13.w\n"
|
||||
|
||||
"// previous-frame-image samplers:\n"
|
||||
"uniform sampler2D sampler_main;\n"
|
||||
"uniform sampler2D sampler_fc_main;\n"
|
||||
"uniform sampler2D sampler_pc_main;\n"
|
||||
"uniform sampler2D sampler_fw_main;\n"
|
||||
"uniform sampler2D sampler_pw_main;\n"
|
||||
"#define sampler_FC_main sampler_fc_main\n"
|
||||
"#define sampler_PC_main sampler_pc_main\n"
|
||||
"#define sampler_FW_main sampler_fw_main\n"
|
||||
@ -275,27 +272,6 @@ std::string PresetShaderIncludes = ""
|
||||
"#define lum(x) (dot(x,float3(0.32,0.49,0.29)))\n"
|
||||
"#define tex2d tex2D\n"
|
||||
"#define tex3d tex3D\n"
|
||||
|
||||
|
||||
|
||||
"// built-in noise textures:\n"
|
||||
"uniform sampler2D sampler_noise_lq;\n"
|
||||
"uniform sampler2D sampler_noise_lq_lite;\n"
|
||||
"uniform sampler2D sampler_noise_mq;\n"
|
||||
"uniform sampler2D sampler_noise_hq;\n"
|
||||
"uniform sampler3D sampler_noisevol_lq;\n"
|
||||
"uniform sampler3D sampler_noisevol_hq;\n"
|
||||
"uniform float4 texsize_noise_lq;\n"
|
||||
"uniform float4 texsize_noise_lq_lite;\n"
|
||||
"uniform float4 texsize_noise_mq;\n"
|
||||
"uniform float4 texsize_noise_hq;\n"
|
||||
"uniform float4 texsize_noisevol_lq;\n"
|
||||
"uniform float4 texsize_noisevol_hq;\n"
|
||||
|
||||
"// procedural blur textures:\n"
|
||||
"uniform sampler2D sampler_blur1;\n"
|
||||
"uniform sampler2D sampler_blur2;\n"
|
||||
"uniform sampler2D sampler_blur3;\n"
|
||||
;
|
||||
|
||||
|
||||
@ -543,7 +519,6 @@ GLuint ShaderEngine::compilePresetShader(const PresentShaderType shaderType, Sha
|
||||
|
||||
// replace shader_body with entry point function
|
||||
found = program.find("shader_body");
|
||||
size_t program_start = found;
|
||||
if (found != std::string::npos)
|
||||
{
|
||||
//std::cout << "first 'shader_body' found at: " << int(found) << std::endl;
|
||||
@ -573,6 +548,23 @@ GLuint ShaderEngine::compilePresetShader(const PresentShaderType shaderType, Sha
|
||||
|
||||
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);
|
||||
@ -591,13 +583,9 @@ GLuint ShaderEngine::compilePresetShader(const PresentShaderType shaderType, Sha
|
||||
|
||||
if (texDesc.first == NULL)
|
||||
{
|
||||
if (lowerCaseName.substr(0, 4) == "rand")
|
||||
if (lowerCaseName.substr(0, 4) == "rand" || lowerCaseName.substr(2, 5) == "_rand")
|
||||
{
|
||||
std::string random_name = textureManager->getRandomTextureName(lowerCaseName);
|
||||
if (random_name.size() > 0)
|
||||
{
|
||||
texDesc = textureManager->getTexture(random_name, GL_REPEAT, GL_LINEAR);
|
||||
}
|
||||
texDesc = textureManager->getRandomTextureName(sampler);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -611,31 +599,15 @@ GLuint ShaderEngine::compilePresetShader(const PresentShaderType shaderType, Sha
|
||||
}
|
||||
else
|
||||
{
|
||||
// The shader declares a new sampler -> declaring it with a "uniform" outside the shader body
|
||||
if (texDesc.first->userTexture) {
|
||||
if (found < program_start) {
|
||||
int index = found;
|
||||
while(index >= 0 && program[index] != '\n') { index--; }
|
||||
program.insert(index+1, "uniform ");
|
||||
found += 8;
|
||||
program_start += 8;
|
||||
}
|
||||
}
|
||||
|
||||
// Add built-in textures
|
||||
// Add user textures only if used
|
||||
if (!texDesc.first->userTexture || found > program_start)
|
||||
std::map<std::string, TextureSamplerDesc>::const_iterator iter = pmShader.textures.cbegin();
|
||||
for ( ; iter != pmShader.textures.cend(); ++iter)
|
||||
{
|
||||
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;
|
||||
if (iter->first == sampler)
|
||||
break;
|
||||
}
|
||||
|
||||
if (iter == pmShader.textures.cend())
|
||||
pmShader.textures[sampler] = texDesc;
|
||||
}
|
||||
}
|
||||
|
||||
@ -644,21 +616,13 @@ GLuint ShaderEngine::compilePresetShader(const PresentShaderType shaderType, Sha
|
||||
|
||||
textureManager->clearRandomTextures();
|
||||
|
||||
// blur programs
|
||||
blur1_enabled = false;
|
||||
blur2_enabled = false;
|
||||
blur3_enabled = false;
|
||||
|
||||
if (program.find("GetMain") != std::string::npos || program.find("GetPixel") != std::string::npos)
|
||||
{
|
||||
pmShader.textures["main"] = textureManager->getTexture("main", GL_REPEAT, GL_LINEAR);
|
||||
}
|
||||
|
||||
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
|
||||
{
|
||||
@ -667,6 +631,7 @@ GLuint ShaderEngine::compilePresetShader(const PresentShaderType shaderType, Sha
|
||||
{
|
||||
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
|
||||
{
|
||||
@ -709,11 +674,89 @@ GLuint ShaderEngine::compilePresetShader(const PresentShaderType shaderType, Sha
|
||||
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;
|
||||
|
||||
#ifndef 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)
|
||||
HLSLTranslator translator = HLSLTranslator();
|
||||
std::string glslSource = translator.parse(shaderTypeString, shaderFilename.c_str(), fullSource);
|
||||
if (glslSource.empty()) {
|
||||
std::cerr << "Failed to translate " << shaderTypeString << std::endl;
|
||||
|
||||
// parse
|
||||
if( !parser.Parse(shaderFilename.c_str(), sourcePreprocessed.c_str(), sourcePreprocessed.size()) ) {
|
||||
std::cerr << "Failed to parse HLSL(step2) " << shaderTypeString << " shader" << std::endl;
|
||||
|
||||
#ifndef 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, M4::GLSLGenerator::Version_140, "PS")) {
|
||||
std::cerr << "Failed to transpile HLSL(step3) " << shaderTypeString << " shader to GLSL" << std::endl;
|
||||
#ifndef 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;
|
||||
}
|
||||
|
||||
@ -721,22 +764,22 @@ GLuint ShaderEngine::compilePresetShader(const PresentShaderType shaderType, Sha
|
||||
// copmile the preset shader fragment shader with the standard vertex shader and cross our fingers
|
||||
GLuint ret = 0;
|
||||
if (shaderType == PresentWarpShader) {
|
||||
ret = CompileShaderProgram(presetWarpVertexShader, glslSource, shaderTypeString); // returns new program
|
||||
ret = CompileShaderProgram(presetWarpVertexShader, generator.GetResult(), shaderTypeString); // returns new program
|
||||
} else {
|
||||
ret = CompileShaderProgram(presetCompVertexShader, glslSource, shaderTypeString); // returns new program
|
||||
ret = CompileShaderProgram(presetCompVertexShader, generator.GetResult(), shaderTypeString); // returns new program
|
||||
}
|
||||
|
||||
if (ret != GL_FALSE) {
|
||||
std::cerr << "Successfull compilation of " << shaderTypeString << std::endl;
|
||||
} else {
|
||||
std::cerr << "Compilation error of " << shaderTypeString << std::endl;
|
||||
std::cerr << "Compilation error (step3) of " << shaderTypeString << std::endl;
|
||||
|
||||
#ifndef DUMP_SHADERS_ON_ERROR
|
||||
std::cerr << "Source:" << std::endl << *glslSource.get() << std::endl;
|
||||
std::cerr << "Source:" << std::endl << generator.GetResult() << std::endl;
|
||||
#else
|
||||
std::ofstream out2("/tmp/shader_glsl_" + shaderTypeString + ".txt");
|
||||
out2 << glslSource;
|
||||
out2.close();
|
||||
std::ofstream out3("/tmp/shader_" + shaderTypeString + "_step3.txt");
|
||||
out3 << generator.GetResult();
|
||||
out3.close();
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -862,12 +905,15 @@ void ShaderEngine::SetupTextures(GLuint program, const Shader &shader)
|
||||
{
|
||||
|
||||
uint texNum = 0;
|
||||
for (std::map<std::string, TextureSamplerDesc>::const_iterator iter = shader.textures.begin(); iter
|
||||
!= shader.textures.end(); ++iter)
|
||||
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->first;
|
||||
Texture * texture = iter->second.first;
|
||||
Sampler * sampler = iter->second.second;
|
||||
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
|
||||
@ -877,24 +923,33 @@ void ShaderEngine::SetupTextures(GLuint program, const Shader &shader)
|
||||
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++;
|
||||
}
|
||||
|
||||
std::string texsizeName = "texsize_" + texName;
|
||||
|
||||
// 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 (param >= 0) {
|
||||
if (textSizeParam >= 0) {
|
||||
glUniform4f(textSizeParam, texture->width, texture->height,
|
||||
1 / (float) texture->width, 1 / (float) texture->height);
|
||||
} else {
|
||||
std::cerr << "invalid texsize name " << texsizeName << std::endl;
|
||||
return;
|
||||
// unused uniform have been optimized out by glsl compiler
|
||||
continue;
|
||||
}
|
||||
|
||||
texNum++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user