From 3a0dcffceed227684f0b4ca59913159f637d707e Mon Sep 17 00:00:00 2001 From: Kai Blaschke Date: Thu, 16 Feb 2023 23:41:35 +0100 Subject: [PATCH] Shader refactoring. Move Milkdrop-specific shader code into MilkdropPreset, only keep generic and potentially reusable stuff in Renderer. Also adding some abstraction to reduce the number of direct OpenGL calls to make it easier to add other rendering APIs in the future. --- .../MilkdropPreset/CustomShape.cpp | 20 +- .../MilkdropPreset/MilkdropPreset.hpp | 11 +- .../MilkdropPreset/MilkdropPresetFactory.cpp | 238 +----------------- .../MilkdropPreset/MilkdropShader.cpp | 163 ++++++++++++ .../MilkdropPreset/MilkdropShader.hpp | 53 ++++ .../MilkdropPreset/PresetFrameIO.hpp | 146 ----------- src/libprojectM/PipelineMerger.cpp | 4 - src/libprojectM/ProjectM.hpp | 16 +- src/libprojectM/Renderer/Pipeline.hpp | 2 - src/libprojectM/Renderer/Renderer.cpp | 1 - src/libprojectM/Renderer/Renderer.hpp | 5 +- src/libprojectM/Renderer/Shader.cpp | 225 ++++++++++++++++- src/libprojectM/Renderer/Shader.hpp | 165 ++++++++++-- src/libprojectM/Renderer/ShaderEngine.cpp | 76 +++--- src/libprojectM/Renderer/ShaderEngine.hpp | 26 +- 15 files changed, 641 insertions(+), 510 deletions(-) diff --git a/src/libprojectM/MilkdropPreset/CustomShape.cpp b/src/libprojectM/MilkdropPreset/CustomShape.cpp index 9664e7191..640cb97a2 100644 --- a/src/libprojectM/MilkdropPreset/CustomShape.cpp +++ b/src/libprojectM/MilkdropPreset/CustomShape.cpp @@ -75,20 +75,20 @@ void CustomShape::Initialize(FileParser& parsedFile, int index) m_thickOutline = parsedFile.GetInt(shapecodePrefix + "thickOutline", m_thickOutline); m_textured = parsedFile.GetInt(shapecodePrefix + "textured", m_textured); m_instances = parsedFile.GetInt(shapecodePrefix + "num_inst", m_instances); - m_x = parsedFile.GetBool(shapecodePrefix + "x", m_x); - m_y = parsedFile.GetBool(shapecodePrefix + "y", m_y); - m_radius = parsedFile.GetBool(shapecodePrefix + "rad", m_radius); - m_angle = parsedFile.GetBool(shapecodePrefix + "ang", m_angle); - m_tex_ang = parsedFile.GetBool(shapecodePrefix + "tex_ang", m_tex_ang); - m_tex_zoom = parsedFile.GetBool(shapecodePrefix + "tex_zoom", m_tex_zoom); + m_x = parsedFile.GetFloat(shapecodePrefix + "x", m_x); + m_y = parsedFile.GetFloat(shapecodePrefix + "y", m_y); + m_radius = parsedFile.GetFloat(shapecodePrefix + "rad", m_radius); + m_angle = parsedFile.GetFloat(shapecodePrefix + "ang", m_angle); + m_tex_ang = parsedFile.GetFloat(shapecodePrefix + "tex_ang", m_tex_ang); + m_tex_zoom = parsedFile.GetFloat(shapecodePrefix + "tex_zoom", m_tex_zoom); m_r = parsedFile.GetFloat(shapecodePrefix + "r", m_r); m_g = parsedFile.GetFloat(shapecodePrefix + "g", m_g); m_b = parsedFile.GetFloat(shapecodePrefix + "b", m_b); m_a = parsedFile.GetFloat(shapecodePrefix + "a", m_a); - m_r2 = parsedFile.GetBool(shapecodePrefix + "r2", m_r2); - m_g2 = parsedFile.GetBool(shapecodePrefix + "g2", m_g2); - m_b2 = parsedFile.GetBool(shapecodePrefix + "b2", m_b2); - m_a2 = parsedFile.GetBool(shapecodePrefix + "a2", m_a2); + m_r2 = parsedFile.GetFloat(shapecodePrefix + "r2", m_r2); + m_g2 = parsedFile.GetFloat(shapecodePrefix + "g2", m_g2); + m_b2 = parsedFile.GetFloat(shapecodePrefix + "b2", m_b2); + m_a2 = parsedFile.GetFloat(shapecodePrefix + "a2", m_a2); m_border_r = parsedFile.GetFloat(shapecodePrefix + "border_r", m_border_r); m_border_g = parsedFile.GetFloat(shapecodePrefix + "border_g", m_border_g); m_border_b = parsedFile.GetFloat(shapecodePrefix + "border_b", m_border_b); diff --git a/src/libprojectM/MilkdropPreset/MilkdropPreset.hpp b/src/libprojectM/MilkdropPreset/MilkdropPreset.hpp index 0ddb04390..eb2d80b4f 100644 --- a/src/libprojectM/MilkdropPreset/MilkdropPreset.hpp +++ b/src/libprojectM/MilkdropPreset/MilkdropPreset.hpp @@ -23,13 +23,6 @@ */ #pragma once -#ifdef DEBUG -/* 0 for no debugging, 1 for normal, 2 for insane */ -#define MILKDROP_PRESET_DEBUG 1 -#else -#define MILKDROP_PRESET_DEBUG 0 -#endif - #include "CustomShape.hpp" #include "CustomWaveform.hpp" #include "PerFrameContext.hpp" @@ -51,14 +44,14 @@ class MilkdropPreset : public Preset public: /** - * @brief Load a MilkdropPreset by filename with input and output buffers specified. + * @brief LoadCode a MilkdropPreset by filename with input and output buffers specified. * @param factory The factory class that created this preset instance. * @param absoluteFilePath the absolute file path of a MilkdropPreset to load from the file system */ MilkdropPreset(MilkdropPresetFactory* factory, const std::string& absoluteFilePath); /** - * @brief Load a MilkdropPreset from an input stream with input and output buffers specified. + * @brief LoadCode a MilkdropPreset from an input stream with input and output buffers specified. * @param presetData an already initialized input stream to read the MilkdropPreset file from * @param presetOutputs initialized and filled with data parsed from a MilkdropPreset */ diff --git a/src/libprojectM/MilkdropPreset/MilkdropPresetFactory.cpp b/src/libprojectM/MilkdropPreset/MilkdropPresetFactory.cpp index 7912af44a..9ed499ec0 100644 --- a/src/libprojectM/MilkdropPreset/MilkdropPresetFactory.cpp +++ b/src/libprojectM/MilkdropPreset/MilkdropPresetFactory.cpp @@ -11,225 +11,32 @@ // // #include "MilkdropPresetFactory.hpp" + #include "MilkdropPreset.hpp" #include "IdlePreset.hpp" -#include "PresetFrameIO.hpp" MilkdropPresetFactory::MilkdropPresetFactory(int meshX, int meshY) : m_meshX(meshX) , m_meshY(meshY) { - /* Initializes the builtin function database */ - BuiltinFuncs::init_builtin_func_db(); - - /* Initializes all infix operators */ - Eval::init_infix_ops(); } MilkdropPresetFactory::~MilkdropPresetFactory() { - Eval::destroy_infix_ops(); - BuiltinFuncs::destroy_builtin_func_db(); } -/* Reinitializes the engine variables to a default (conservative and sane) value */ -void MilkdropPresetFactory::ResetPresetOutputs(PresetOutputs* presetOutputs) -{ - if (presetOutputs == nullptr) - { - return; - } - - presetOutputs->zoom = 1.0; - presetOutputs->zoomexp = 1.0; - presetOutputs->rot = 0.0; - presetOutputs->warp = 0.0; - - presetOutputs->sx = 1.0; - presetOutputs->sy = 1.0; - presetOutputs->dx = 0.0; - presetOutputs->dy = 0.0; - presetOutputs->cx = 0.5; - presetOutputs->cy = 0.5; - - presetOutputs->screenDecay = .98; - - presetOutputs->wave.r = 1.0; - presetOutputs->wave.g = 0.2; - presetOutputs->wave.b = 0.0; - presetOutputs->wave.x = 0.5; - presetOutputs->wave.y = 0.5; - presetOutputs->wave.mystery = 0.0; - - presetOutputs->border.outer_size = 0.0; - presetOutputs->border.outer_r = 0.0; - presetOutputs->border.outer_g = 0.0; - presetOutputs->border.outer_b = 0.0; - presetOutputs->border.outer_a = 0.0; - - presetOutputs->border.inner_size = 0.0; - presetOutputs->border.inner_r = 0.0; - presetOutputs->border.inner_g = 0.0; - presetOutputs->border.inner_b = 0.0; - presetOutputs->border.inner_a = 0.0; - - presetOutputs->mv.a = 0.0; - presetOutputs->mv.r = 0.0; - presetOutputs->mv.g = 0.0; - presetOutputs->mv.b = 0.0; - presetOutputs->mv.length = 1.0; - presetOutputs->mv.x_num = 16.0; - presetOutputs->mv.y_num = 12.0; - presetOutputs->mv.x_offset = 0.02; - presetOutputs->mv.y_offset = 0.02; - - - /* PER_FRAME CONSTANTS END */ - presetOutputs->fRating = 0; - presetOutputs->fGammaAdj = 1.0; - presetOutputs->videoEcho.zoom = 1.0; - presetOutputs->videoEcho.a = 0; - presetOutputs->videoEcho.orientation = Normal; - - presetOutputs->wave.additive = false; - presetOutputs->wave.dots = false; - presetOutputs->wave.thick = false; - presetOutputs->wave.modulateAlphaByVolume = 0; - presetOutputs->wave.maximizeColors = 0; - presetOutputs->textureWrap = 0; - presetOutputs->bDarkenCenter = 0; - presetOutputs->bRedBlueStereo = 0; - presetOutputs->bBrighten = 0; - presetOutputs->bDarken = 0; - presetOutputs->bSolarize = 0; - presetOutputs->bInvert = 0; - presetOutputs->bMotionVectorsOn = 1; - - presetOutputs->wave.a = 1.0; - presetOutputs->wave.scale = 1.0; - presetOutputs->wave.smoothing = 0; - presetOutputs->wave.mystery = 0; - presetOutputs->wave.modOpacityEnd = 0; - presetOutputs->wave.modOpacityStart = 0; - presetOutputs->fWarpAnimSpeed = 0; - presetOutputs->fWarpScale = 0; - presetOutputs->fShader = 0; - - /* PER_PIXEL CONSTANT END */ - /* Q VARIABLES START */ - - for (int i = 0; i < 32; i++) - { - presetOutputs->q[i] = 0; - } - -// for ( std::vector::iterator pos = presetOutputs->customWaves.begin(); -// pos != presetOutputs->customWaves.end(); ++pos ) -// if ( *pos != 0 ) delete ( *pos ); - -// for ( std::vector::iterator pos = presetOutputs->customShapes.begin(); -// pos != presetOutputs->customShapes.end(); ++pos ) -// if ( *pos != 0 ) delete ( *pos ); - - presetOutputs->customWaves.clear(); - presetOutputs->customShapes.clear(); - - /* Q VARIABLES END */ - -} - - -/* Reinitializes the engine variables to a default (conservative and sane) value */ -void MilkdropPresetFactory::reset() -{ - if (m_presetOutputsCache) - { - ResetPresetOutputs(m_presetOutputsCache); - } -} - -PresetOutputs* MilkdropPresetFactory::CreatePresetOutputs(int meshX, int meshY) -{ - auto* presetOutputs = new PresetOutputs(); - - presetOutputs->Initialize(meshX, meshY); - - /* PER FRAME CONSTANTS BEGIN */ - presetOutputs->zoom = 1.0; - presetOutputs->zoomexp = 1.0; - presetOutputs->rot = 0.0; - presetOutputs->warp = 0.0; - - presetOutputs->sx = 1.0; - presetOutputs->sy = 1.0; - presetOutputs->dx = 0.0; - presetOutputs->dy = 0.0; - presetOutputs->cx = 0.5; - presetOutputs->cy = 0.5; - - presetOutputs->screenDecay = 0.98f; - - /* PER_FRAME CONSTANTS END */ - presetOutputs->fRating = 0.0f; - presetOutputs->fGammaAdj = 1.0f; - presetOutputs->videoEcho.zoom = 1.0f; - presetOutputs->videoEcho.a = 0.0f; - presetOutputs->videoEcho.orientation = Orientation::Normal; - - presetOutputs->textureWrap = false; - presetOutputs->bDarkenCenter = false; - presetOutputs->bRedBlueStereo = false; - presetOutputs->bBrighten = false; - presetOutputs->bDarken = false; - presetOutputs->bSolarize = false; - presetOutputs->bInvert = false; - presetOutputs->bMotionVectorsOn = true; - presetOutputs->fWarpAnimSpeed = 0.0f; - presetOutputs->fWarpScale = 0.0f; - presetOutputs->fShader = 0.0f; - - /* PER_PIXEL CONSTANTS BEGIN */ - - /* PER_PIXEL CONSTANT END */ - - /* Q AND T VARIABLES START */ - - for (unsigned int i = 0; i < numQVariables; i++) - { - presetOutputs->q[i] = 0; - } - - /* Q AND T VARIABLES END */ - return presetOutputs; -} - - std::unique_ptr MilkdropPresetFactory::LoadPresetFromFile(const std::string& filename) { - PresetOutputs* presetOutputs; - // use cached PresetOutputs if there is one, otherwise allocate - if (m_presetOutputsCache) - { - presetOutputs = m_presetOutputsCache; - m_presetOutputsCache = nullptr; - } - else - { - presetOutputs = CreatePresetOutputs(m_meshX, m_meshY); - } - - ResetPresetOutputs(presetOutputs); - std::string path; auto protocol = PresetFactory::Protocol(filename, path); if (protocol == PresetFactory::IDLE_PRESET_PROTOCOL) { - return IdlePresets::allocate(this, presetOutputs); + return IdlePresets::allocate(this); } else if (protocol == "" || protocol == "file") { - return std::make_unique(this, path, presetOutputs); + return std::make_unique(this, path); } else { @@ -240,42 +47,5 @@ MilkdropPresetFactory::LoadPresetFromFile(const std::string& filename) std::unique_ptr MilkdropPresetFactory::LoadPresetFromStream(std::istream& data) { - - PresetOutputs* presetOutputs; - // use cached PresetOutputs if there is one, otherwise allocate - if (m_presetOutputsCache) - { - presetOutputs = m_presetOutputsCache; - m_presetOutputsCache = nullptr; - } - else - { - presetOutputs = CreatePresetOutputs(m_meshX, m_meshY); - } - - ResetPresetOutputs(presetOutputs); - - return std::make_unique(this, data, presetOutputs); + return std::make_unique(this, data); } - -// this gives the preset a way to return the PresetOutput w/o dependency on class projectM behavior -void MilkdropPresetFactory::releasePreset(Preset* preset) -{ - auto milkdropPreset = dynamic_cast(preset); - - if (!milkdropPreset || !milkdropPreset->_presetOutputs) - { - // Instance is not a MilkdropPreset or has no PresetOutput object. - return; - } - - // return PresetOutputs to the cache - if (!m_presetOutputsCache) - { - m_presetOutputsCache = milkdropPreset->_presetOutputs; - } - else - { - delete milkdropPreset->_presetOutputs; - } -} \ No newline at end of file diff --git a/src/libprojectM/MilkdropPreset/MilkdropShader.cpp b/src/libprojectM/MilkdropPreset/MilkdropShader.cpp index f598bf4e0..379ffb1e5 100644 --- a/src/libprojectM/MilkdropPreset/MilkdropShader.cpp +++ b/src/libprojectM/MilkdropPreset/MilkdropShader.cpp @@ -1 +1,164 @@ #include "MilkdropShader.hpp" + +#include + +MilkdropShader::MilkdropShader(ShaderType type) + : m_type(type) +{ +} + + +void MilkdropShader::LoadCode(std::string presetShaderCode) +{ + m_presetShaderCode = std::move(presetShaderCode); + + std::string program = m_presetShaderCode; + PreprocessPresetShader(program); + +} + +void MilkdropShader::LoadTextures(TextureManager& textureManager) +{ + // Add Milkdrop built-in textures + m_shader.SetUniformTexture("main", textureManager.getTexture("main", GL_REPEAT, GL_LINEAR)); + m_shader.SetUniformTexture("main", textureManager->getTexture("main", GL_REPEAT, GL_LINEAR)); + m_shader.SetUniformTexture("fc_main", textureManager->getTexture("main", GL_CLAMP_TO_EDGE, GL_LINEAR)); + m_shader.SetUniformTexture("pc_main", textureManager->getTexture("main", GL_CLAMP_TO_EDGE, GL_NEAREST)); + m_shader.SetUniformTexture("fw_main", textureManager->getTexture("main", GL_REPEAT, GL_LINEAR)); + m_shader.SetUniformTexture("pw_main", textureManager->getTexture("main", GL_REPEAT, GL_NEAREST)); + + m_shader.SetUniformTexture("noise_lq", textureManager->getTexture("noise_lq", GL_REPEAT, GL_LINEAR)); + m_shader.SetUniformTexture("noise_lq_lite", textureManager->getTexture("noise_lq_lite", GL_REPEAT, GL_LINEAR)); + m_shader.SetUniformTexture("noise_mq", textureManager->getTexture("noise_mq", GL_REPEAT, GL_LINEAR)); + m_shader.SetUniformTexture("noise_hq", textureManager->getTexture("noise_hq", GL_REPEAT, GL_LINEAR)); + m_shader.SetUniformTexture("noisevol_lq", textureManager->getTexture("noisevol_lq", GL_REPEAT, GL_LINEAR)); + m_shader.SetUniformTexture("noisevol_hq", textureManager->getTexture("noisevol_hq", GL_REPEAT, GL_LINEAR)); + +} + +void MilkdropShader::PreprocessPresetShader(std::string& program) +{ + + if (program.length() <= 0) + { + throw ShaderException("Preset shader is declared, but empty."); + } + + size_t found; + + // replace shader_body with entry point function + found = program.find("shader_body"); + if (found != std::string::npos) + { +#ifdef MILKDROP_PRESET_DEBUG + std::cerr << "[MilkdropShader] First 'shader_body' found at: " << int(found) << std::endl; +#endif + + if (m_type == ShaderType::WarpShader) + { + 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 + { + throw ShaderException("Preset shader is missing \"shader_body\" entry point."); + } + + // replace the "{" immediately following shader_body with some variable declarations + found = program.find('{', found); + if (found != std::string::npos) + { +#ifdef MILKDROP_PRESET_DEBUG + std::cerr << "[MilkdropShader] First '{' found at: " << int(found) << std::endl; +#endif + const char* progMain = + "{\n" + "float3 ret = 0;\n"; + program.replace(int(found), 1, progMain); + } + else + { + throw ShaderException("Preset shader has no opening braces."); + } + + // replace "}" with return statement (this can probably be optimized for the GLSL conversion...) + found = program.rfind('}'); + if (found != std::string::npos) + { +#ifdef MILKDROP_PRESET_DEBUG + std::cerr << "[MilkdropShader] Last '}' found at: " << int(found) << std::endl; +#endif + program.replace(int(found), 1, "_return_value = float4(ret.xyz, 1.0);\n" + "}\n"); + } + else + { + throw ShaderException("Preset shader has no closing brace."); + } + + // Find matching closing brace and cut off excess text after shader's main function + int bracesOpen = 1; + size_t pos = found + 1; + for (; pos < program.length() && bracesOpen > 0; ++pos) + { + switch (program.at(pos)) + { + case '/': + // Skip comments until EoL to prevent false counting + if (pos < program.length() - 1 && program.at(pos + 1) == '/') + { + for (; pos < program.length(); ++pos) + { + if (program.at(pos) == '\n') + { + break; + } + } + } + continue; + + case '{': + bracesOpen++; + continue; + + case '}': + bracesOpen--; + } + } + + if (pos < program.length() - 1) + { + program.resize(pos); + } + +} + +void MilkdropShader::GetReferencedSamplers(const std::string& program) +{ + // set up texture samplers for all samplers references in the shader program + auto found = program.find("sampler_", 0); + 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); + + m_samplerNames.push_back(lowerCaseName); + } + + found = program.find("sampler_", found); + } + + + found = program.find("GetBlur3"); + +} diff --git a/src/libprojectM/MilkdropPreset/MilkdropShader.hpp b/src/libprojectM/MilkdropPreset/MilkdropShader.hpp index 6bf216f47..83d53084a 100644 --- a/src/libprojectM/MilkdropPreset/MilkdropShader.hpp +++ b/src/libprojectM/MilkdropPreset/MilkdropShader.hpp @@ -4,6 +4,9 @@ */ #pragma once +#include "Renderer/Shader.hpp" +#include "Renderer/TextureManager.hpp" + /** * @brief Holds a warp or composite shader of Milkdrop presets. * Also does the required shader translation from HLSL to GLSL using hlslparser. @@ -11,7 +14,57 @@ class MilkdropShader { public: + enum class ShaderType + { + WarpShader, //!< Warp shader + CompositeShader //!< Composite shader + }; + + /** + * Maximum main texture blur level used in the shader + */ + enum class BlurLevel : int + { + None, //!< No blur used. + Blur1, //!< First blur level (2 passes) + Blur2, //!< Second blur level (4 passes) + Blur3 //!< Third blur level (6 passes) + }; + + /** + * constructor. + * @param type The preset shader type. + */ + explicit MilkdropShader(ShaderType type); + + /** + * @brief Translates and compiles the shader code. + * @param presetShaderCode The preset shader code. + */ + void LoadCode(std::string presetShaderCode); + + /** + * @brief Loads the required texture references into the shader. + */ + void LoadTextures(TextureManager& textureManager); private: + /** + * @brief Prepares the shader code to be translated into GLSL. + * @param program The program code to work on. + */ + void PreprocessPresetShader(std::string& program); + /** + * @brief Searches for sampler references in the program and stores them in m_samplerNames. + * @param program The program code to work on. + */ + void GetReferencedSamplers(const std::string& program); + + ShaderType m_type{ShaderType::WarpShader}; //!< Type of this shader. + std::string m_presetShaderCode; //!< The original preset shader code. + + std::vector m_samplerNames; //!< Names of all referenced samplers in the shader code. + + Shader m_shader; }; diff --git a/src/libprojectM/MilkdropPreset/PresetFrameIO.hpp b/src/libprojectM/MilkdropPreset/PresetFrameIO.hpp index 22ac54a4c..91196efc0 100644 --- a/src/libprojectM/MilkdropPreset/PresetFrameIO.hpp +++ b/src/libprojectM/MilkdropPreset/PresetFrameIO.hpp @@ -12,149 +12,3 @@ #include "Waveform.hpp" #include - -/// Container for all *read only* engine variables a preset requires to -/// evaluate milkdrop equations. Every preset object needs a reference to one of these. -class PresetInputs : public PipelineContext { - -public: - /* PER_PIXEL VARIBLES BEGIN */ - - float x_per_pixel; - float y_per_pixel; - float rad_per_pixel; - float ang_per_pixel; - - /* PER_PIXEL VARIBLES END */ - - float bass; - float mid; - float treb; - float bass_att; - float mid_att; - float treb_att; - - /* variables were added in milkdrop 1.04 */ - int gx, gy; - - float **x_mesh; - float **y_mesh; - - int pixelsx; - int pixelsy; - - float aspectx; - float aspecty; - - float **rad_mesh; - float **theta_mesh; - - float **origtheta; //grid containing interpolated mesh reference values - float **origrad; - float **origx; //original mesh - float **origy; - - void resetMesh(); - - ~PresetInputs(); - PresetInputs(); - - /// Initializes this preset inputs given a mesh size. - /// \param gx the width of the mesh - /// \param gy the height of the mesh - /// \note This must be called before reading values from this class - void Initialize(int _gx, int _gy); - - /// Updates this preset inputs with the latest values from the - /// the pipeline context and beat detection unit - void update (const BeatDetect & music, const PipelineContext & context); - - private: -}; - - -/// Container class for all preset writeable engine variables. This is the important glue -/// between the presets and renderer to facilitate smooth preset switching -/// Every preset object needs a reference to one of these. -class PresetOutputs : public Pipeline { -public: - typedef std::vector cwave_container; - typedef std::vector cshape_container; - - cwave_container customWaves; - cshape_container customShapes; - - void Initialize(int _gx, int _gy); - PresetOutputs(); - ~PresetOutputs(); - virtual void Render(const BeatDetect &music, const PipelineContext &context); - void PerPixelMath( const PipelineContext &context); - /* PER FRAME VARIABLES BEGIN */ - - float zoom; - float zoomexp; - float rot; - float warp; - - float sx; - float sy; - float dx; - float dy; - float cx; - float cy; - - VideoEcho videoEcho; - - Waveform wave; - Border border; - MotionVectors mv; - DarkenCenter darkenCenter; - - Brighten brighten; - Darken darken; - Invert invert; - Solarize solarize; - - // ToDo: Check if redeclaration here is wanted, as the Pipeline base class also defines these. - int gy; - int gx; - - /* PER_FRAME VARIABLES END */ - - float fRating; - float fGammaAdj; - - bool bDarkenCenter; - bool bRedBlueStereo; - bool bBrighten; - bool bDarken; - bool bSolarize; - bool bInvert; - bool bMotionVectorsOn; - - float fWarpAnimSpeed; - float fWarpScale; - float fShader; - - float **zoom_mesh; - float **zoomexp_mesh; - float **rot_mesh; - - float **sx_mesh; - float **sy_mesh; - float **dx_mesh; - float **dy_mesh; - float **cx_mesh; - float **cy_mesh; - float **warp_mesh; - - float **orig_x; //original mesh - float **orig_y; - float **rad_mesh; - -private: - void PerPixelMath_c( const PipelineContext &context); -#ifdef __SSE2__ - void PerPixelMath_sse( const PipelineContext &context); -#endif -}; diff --git a/src/libprojectM/PipelineMerger.cpp b/src/libprojectM/PipelineMerger.cpp index e76b3c0c8..ba8422c72 100644 --- a/src/libprojectM/PipelineMerger.cpp +++ b/src/libprojectM/PipelineMerger.cpp @@ -77,14 +77,10 @@ void PipelineMerger::mergePipelines(const Pipeline& a, const Pipeline& b, Pipeli { out.compositeShader = a.compositeShader; out.warpShader = a.warpShader; - out.warpShaderFilename = a.warpShaderFilename; - out.compositeShaderFilename = a.compositeShaderFilename; } else { out.compositeShader = b.compositeShader; out.warpShader = b.warpShader; - out.warpShaderFilename = b.warpShaderFilename; - out.compositeShaderFilename = b.compositeShaderFilename; } } diff --git a/src/libprojectM/ProjectM.hpp b/src/libprojectM/ProjectM.hpp index 834106559..2b48a52a7 100644 --- a/src/libprojectM/ProjectM.hpp +++ b/src/libprojectM/ProjectM.hpp @@ -48,7 +48,11 @@ class BackgroundWorkerSync; +namespace libprojectM { +namespace Audio { class BeatDetect; +} +} // namespace libprojectM class Pcm; @@ -240,7 +244,7 @@ private: #endif - class Pcm m_pcm; //!< Audio data buffer and analyzer instance. + class libprojectM::Audio::PCM m_pcm; //!< Audio data buffer and analyzer instance. size_t m_meshX{32}; //!< Per-point mesh horizontal resolution. size_t m_meshY{24}; //!< Per-point mesh vertical resolution. @@ -269,11 +273,11 @@ private: std::unique_ptr m_pipelineContext; //!< Pipeline context for the first/current preset. std::unique_ptr m_pipelineContext2; //!< Pipeline context for the next/transitioning preset. - std::unique_ptr m_renderer; //!< The Preset renderer. - std::unique_ptr m_beatDetect; //!< The beat detection class. - std::unique_ptr m_activePreset; //!< Currently loaded preset. - std::unique_ptr m_transitioningPreset; //!< Destination preset when smooth preset switching. - std::unique_ptr m_timeKeeper; //!< Keeps the different timers used to render and switch presets. + std::unique_ptr m_renderer; //!< The Preset renderer. + std::unique_ptr m_beatDetect; //!< The beat detection class. + std::unique_ptr m_activePreset; //!< Currently loaded preset. + std::unique_ptr m_transitioningPreset; //!< Destination preset when smooth preset switching. + std::unique_ptr m_timeKeeper; //!< Keeps the different timers used to render and switch presets. #if PROJECTM_USE_THREADS mutable std::recursive_mutex m_presetSwitchMutex; //!< Mutex for locking preset switching while rendering and vice versa. diff --git a/src/libprojectM/Renderer/Pipeline.hpp b/src/libprojectM/Renderer/Pipeline.hpp index 2a87f5294..0fc7b5e7f 100644 --- a/src/libprojectM/Renderer/Pipeline.hpp +++ b/src/libprojectM/Renderer/Pipeline.hpp @@ -41,9 +41,7 @@ public: float blur1ed; Shader warpShader; - std::string warpShaderFilename; Shader compositeShader; - std::string compositeShaderFilename; std::vector drawables; std::vector compositeDrawables; diff --git a/src/libprojectM/Renderer/Renderer.cpp b/src/libprojectM/Renderer/Renderer.cpp index 29da1957c..b7f7b0fc7 100644 --- a/src/libprojectM/Renderer/Renderer.cpp +++ b/src/libprojectM/Renderer/Renderer.cpp @@ -174,7 +174,6 @@ void Renderer::RenderItems(const Pipeline& pipeline, const PipelineContext& pipe m_renderContext.invAspectX = m_fInvAspectX; m_renderContext.invAspectY = m_fInvAspectY; m_renderContext.textureManager = m_textureManager.get(); - m_renderContext.beatDetect = m_beatDetect; for (std::vector::const_iterator pos = pipeline.drawables.begin(); pos != pipeline.drawables.end(); ++pos) { diff --git a/src/libprojectM/Renderer/Renderer.hpp b/src/libprojectM/Renderer/Renderer.hpp index d5f90b28f..eece2d2a4 100644 --- a/src/libprojectM/Renderer/Renderer.hpp +++ b/src/libprojectM/Renderer/Renderer.hpp @@ -1,5 +1,4 @@ -#ifndef Renderer_HPP -#define Renderer_HPP +#pragma once #include "Audio/BeatDetect.hpp" #include "Pipeline.hpp" @@ -174,5 +173,3 @@ private: float m_fInvAspectX{1.0}; float m_fInvAspectY{1.0}; }; - -#endif diff --git a/src/libprojectM/Renderer/Shader.cpp b/src/libprojectM/Renderer/Shader.cpp index 9bea3bba4..0b812d9f9 100644 --- a/src/libprojectM/Renderer/Shader.cpp +++ b/src/libprojectM/Renderer/Shader.cpp @@ -1,10 +1,219 @@ -/* - * Shader.cpp - * - * Created on: Jun 29, 2008 - * Author: pete - */ - #include "Shader.hpp" -Shader::Shader() {} +#include + +Shader::Shader() + : m_shaderProgram(glCreateProgram()) +{ +} + +Shader::~Shader() +{ + if (m_shaderProgram) + { + glDeleteProgram(m_shaderProgram); + } +} + +void Shader::CompileProgram(const std::string& vertexShaderSource, std::string& fragmentShaderSource) +{ + auto vertexShader = CompileShader(vertexShaderSource, GL_VERTEX_SHADER); + auto fragmentShader = CompileShader(fragmentShaderSource, GL_FRAGMENT_SHADER); + + glAttachShader(m_shaderProgram, vertexShader); + glAttachShader(m_shaderProgram, fragmentShader); + + glLinkProgram(m_shaderProgram); + + // Shader objects are no longer needed after linking, free the memory. + glDetachShader(m_shaderProgram, vertexShader); + glDetachShader(m_shaderProgram, fragmentShader); + glDeleteShader(vertexShader); + glDeleteShader(fragmentShader); + + GLint programLinked; + glGetProgramiv(m_shaderProgram, GL_LINK_STATUS, &programLinked); + if (programLinked == GL_TRUE) + { + return; + } + + GLint infoLogLength{}; + glGetProgramiv(m_shaderProgram, GL_INFO_LOG_LENGTH, &infoLogLength); + std::vector message(infoLogLength + 1); + glGetProgramInfoLog(m_shaderProgram, infoLogLength, nullptr, message.data()); + + throw ShaderException("Error compiling shader: " + std::string(message.data())); +} + +bool Shader::Validate(std::string& validationMessage) const +{ + GLint result{GL_FALSE}; + int infoLogLength; + + glValidateProgram(m_shaderProgram); + + glGetProgramiv(m_shaderProgram, GL_VALIDATE_STATUS, &result); + glGetProgramiv(m_shaderProgram, GL_INFO_LOG_LENGTH, &infoLogLength); + if (infoLogLength > 0) + { + std::vector validationErrorMessage(infoLogLength + 1); + glGetProgramInfoLog(m_shaderProgram, infoLogLength, nullptr, validationErrorMessage.data()); + validationMessage = std::string(validationErrorMessage.data()); + } + + return result; +} + +void Shader::Bind() +{ + if (m_shaderProgram > 0) + { + glUseProgram(m_shaderProgram); + } +} + +void Shader::Unbind() +{ + glUseProgram(0); +} + +void Shader::BindTextures() +{ + int texNum{0}; + std::map texSizes; + + // Set samplers + for (const auto& samplerIt : m_textures) + { + std::string const texName = samplerIt.first; + Texture* texture = samplerIt.second.first; + Sampler* sampler = samplerIt.second.second; + + std::string const samplerName = "sampler_" + texName; + + texSizes[texName] = texture; + texSizes[texture->name] = texture; + + // https://www.khronos.org/opengl/wiki/Sampler_(GLSL)#Binding_textures_to_samplers + glActiveTexture(GL_TEXTURE0 + texNum); + glBindTexture(texture->type, texture->texID); + glBindSampler(texNum, sampler->samplerID); + + SetUniformInt(samplerName.c_str(), texNum); + + texNum++; + } + + // Set texture size uniforms + for (const auto& texSize : texSizes) + { + Texture* texture = texSize.second; + + std::string const texSizeName = "texsize_" + texSize.first; + + SetUniformFloat4(texSizeName.c_str(), {texture->width, + texture->height, + 1 / (float) texture->width, + 1 / (float) texture->height}); + } +} + +void Shader::SetUniformTexture(const char* uniform, TextureSamplerDesc texture) +{ +} + +void Shader::SetUniformFloat(const char* uniform, float value) +{ + auto location = glGetUniformLocation(m_shaderProgram, uniform); + if (location < 0) + { + return; + } + glUniform1fv(location, 1, &value); +} + +void Shader::SetUniformInt(const char* uniform, int value) +{ + auto location = glGetUniformLocation(m_shaderProgram, uniform); + if (location < 0) + { + return; + } + glUniform1iv(location, 1, &value); +} + +void Shader::SetUniformFloat2(const char* uniform, const glm::vec2& values) +{ + auto location = glGetUniformLocation(m_shaderProgram, uniform); + if (location < 0) + { + return; + } + glUniform2fv(location, 1, glm::value_ptr(values)); +} + +void Shader::SetUniformFloat3(const char* uniform, const glm::vec3& values) +{ + auto location = glGetUniformLocation(m_shaderProgram, uniform); + if (location < 0) + { + return; + } + glUniform3fv(location, 1, glm::value_ptr(values)); +} + +void Shader::SetUniformFloat4(const char* uniform, const glm::vec4& values) +{ + auto location = glGetUniformLocation(m_shaderProgram, uniform); + if (location < 0) + { + return; + } + glUniform4fv(location, 1, glm::value_ptr(values)); +} + +void Shader::SetUniformMat3x4(const char* uniform, const glm::mat3x4& values) +{ + auto location = glGetUniformLocation(m_shaderProgram, uniform); + if (location < 0) + { + return; + } + glUniformMatrix3x4fv(location, 1, GL_FALSE, glm::value_ptr(values)); +} + +void Shader::SetUniformMat4x4(const char* uniform, const glm::mat4x4& values) +{ + auto location = glGetUniformLocation(m_shaderProgram, uniform); + if (location < 0) + { + return; + } + glUniformMatrix4fv(location, 1, GL_FALSE, glm::value_ptr(values)); +} + +GLuint Shader::CompileShader(const std::string& source, GLenum type) +{ + GLint shaderCompiled{}; + + auto shader = glCreateShader(type); + const auto *shaderSourceCStr = source.c_str(); + glShaderSource(shader, 1, &shaderSourceCStr, nullptr); + + glCompileShader(shader); + + glGetShaderiv(shader, GL_COMPILE_STATUS, &shaderCompiled); + if (shaderCompiled == GL_TRUE) + { + return shader; + } + + GLint infoLogLength{}; + glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLogLength); + std::vector message(infoLogLength + 1); + glGetShaderInfoLog(shader, infoLogLength, nullptr, message.data()); + glDeleteShader(shader); + + throw ShaderException("Error compiling shader: " + std::string(message.data())); +} diff --git a/src/libprojectM/Renderer/Shader.hpp b/src/libprojectM/Renderer/Shader.hpp index bccf5ecfc..0acf108d8 100644 --- a/src/libprojectM/Renderer/Shader.hpp +++ b/src/libprojectM/Renderer/Shader.hpp @@ -1,27 +1,160 @@ -/* - * Shader.hpp - * - * Created on: Jun 29, 2008 - * Author: pete +/** + * @file Shader.hpp + * @brief Implements an interface to a single shader program instance. */ +#pragma once -#ifndef SHADER_HPP_ -#define SHADER_HPP_ - -#include -#include #include "Texture.hpp" +#include +#include +#include +#include +#include + +#include +#include + +/** + * @brief Shader compilation exception. + */ +class ShaderException : public std::exception +{ +public: + inline ShaderException(std::string message) + : m_message(std::move(message)) + { + } + + virtual ~ShaderException() = default; + + const std::string& message() const + { + return m_message; + } + +private: + std::string m_message; +}; + + +/** + * @brief Base class containing a shader program, consisting of a vertex and fragment shader. + */ class Shader { public: + /** + * Creates a new shader. + */ + Shader(); - std::map textures; + /** + * Destructor. + */ + ~Shader(); - std::string programSource; - std::string presetPath; + /** + * @brief Compiles a vertex and fragment shader into a program. + * @throws ShaderException Thrown if compilation of a shader or program linking failed. + * @param vertexShaderSource The vertex shader source. + * @param fragmentShaderSource The fragment shader source. + */ + void CompileProgram(const std::string& vertexShaderSource, std::string& fragmentShaderSource); - Shader(); + /** + * @brief Validates that the program can run in the current state. + * @param validationMessage The error message if validation failed. + * @return true if the shader program is valid and can run, false if it broken. + */ + bool Validate(std::string& validationMessage) const; + + /** + * Binds the program into the current context. + */ + void Bind(); + + /** + * Unbinds the program. + */ + static void Unbind(); + + /** + * @brief Binds the registered textures to the current program context. + * The program must be bound before calling this method! + */ + void BindTextures(); + + void SetUniformTexture(const char* uniform, TextureSamplerDesc texture); + + /** + * @brief Sets a single float uniform. + * The program must be bound before calling this method! + * @param uniform The uniform name + * @param value The value to set. + */ + void SetUniformFloat(const char* uniform, float value); + + /** + * @brief Sets a single integer uniform. + * The program must be bound before calling this method! + * @param uniform The uniform name + * @param value The value to set. + */ + void SetUniformInt(const char* uniform, int value); + + /** + * @brief Sets a float vec2 uniform. + * The program must be bound before calling this method! + * @param uniform The uniform name + * @param values The values to set. + */ + void SetUniformFloat2(const char* uniform, const glm::vec2& values); + + /** + * @brief Sets a float vec3 uniform. + * The program must be bound before calling this method! + * @param uniform The uniform name + * @param values The values to set. + */ + void SetUniformFloat3(const char* uniform, const glm::vec3& values); + + /** + * @brief Sets a float vec4 uniform. + * The program must be bound before calling this method! + * @param uniform The uniform name + * @param values The values to set. + */ + void SetUniformFloat4(const char* uniform, const glm::vec4& values); + + /** + * @brief Sets a float 3x4 matrix uniform. + * The program must be bound before calling this method! + * @param uniform The uniform name + * @param values The matrix to set. + */ + void SetUniformMat3x4(const char* uniform, const glm::mat3x4& values); + + /** + * @brief Sets a float 4x4 matrix uniform. + * The program must be bound before calling this method! + * @param uniform The uniform name + * @param values The matrix to set. + */ + void SetUniformMat4x4(const char* uniform, const glm::mat4x4& values); + + +private: + /** + * @brief Compiles a single shader. + * @throws ShaderException Thrown if compilation of the shader failed. + * @param source The shader source. + * @param type The shader type, e.g. GL_VERTEX_SHADER. + * @return The shader ID. + */ + auto CompileShader(const std::string& source, GLenum type) -> GLuint; + + std::map m_textures; //!< Textures used in this program. + + GLuint m_shaderProgram{}; //!< The program ID. }; - -#endif /* SHADER_HPP_ */ diff --git a/src/libprojectM/Renderer/ShaderEngine.cpp b/src/libprojectM/Renderer/ShaderEngine.cpp index 832968cf6..2ae3c0b21 100644 --- a/src/libprojectM/Renderer/ShaderEngine.cpp +++ b/src/libprojectM/Renderer/ShaderEngine.cpp @@ -127,7 +127,7 @@ void ShaderEngine::setParams(int _texsizeX, int _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; + std::string program = pmShader.m_programSource; if (program.length() <= 0) { @@ -218,22 +218,22 @@ GLuint ShaderEngine::compilePresetShader(const PresentShaderType shaderType, Sha program.resize(pos); } - pmShader.textures.clear(); + pmShader.m_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.m_textures["main"] = textureManager->getTexture("main", GL_REPEAT, GL_LINEAR); + pmShader.m_textures["fc_main"] = textureManager->getTexture("main", GL_CLAMP_TO_EDGE, GL_LINEAR); + pmShader.m_textures["pc_main"] = textureManager->getTexture("main", GL_CLAMP_TO_EDGE, GL_NEAREST); + pmShader.m_textures["fw_main"] = textureManager->getTexture("main", GL_REPEAT, GL_LINEAR); + pmShader.m_textures["pw_main"] = textureManager->getTexture("main", GL_REPEAT, GL_NEAREST); - pmShader.textures["noise_lq"] = textureManager->getTexture("noise_lq", GL_REPEAT, GL_LINEAR); - pmShader.textures["noise_lq_lite"] = textureManager->getTexture("noise_lq_lite", GL_REPEAT, GL_LINEAR); - pmShader.textures["noise_mq"] = textureManager->getTexture("noise_mq", GL_REPEAT, GL_LINEAR); - pmShader.textures["noise_hq"] = textureManager->getTexture("noise_hq", GL_REPEAT, GL_LINEAR); - pmShader.textures["noisevol_lq"] = textureManager->getTexture("noisevol_lq", GL_REPEAT, GL_LINEAR); - pmShader.textures["noisevol_hq"] = textureManager->getTexture("noisevol_hq", GL_REPEAT, GL_LINEAR); + pmShader.m_textures["noise_lq"] = textureManager->getTexture("noise_lq", GL_REPEAT, GL_LINEAR); + pmShader.m_textures["noise_lq_lite"] = textureManager->getTexture("noise_lq_lite", GL_REPEAT, GL_LINEAR); + pmShader.m_textures["noise_mq"] = textureManager->getTexture("noise_mq", GL_REPEAT, GL_LINEAR); + pmShader.m_textures["noise_hq"] = textureManager->getTexture("noise_hq", GL_REPEAT, GL_LINEAR); + pmShader.m_textures["noisevol_lq"] = textureManager->getTexture("noisevol_lq", GL_REPEAT, GL_LINEAR); + pmShader.m_textures["noisevol_hq"] = textureManager->getTexture("noisevol_hq", GL_REPEAT, GL_LINEAR); @@ -272,15 +272,15 @@ GLuint ShaderEngine::compilePresetShader(const PresentShaderType shaderType, Sha } else { - std::map::const_iterator iter = pmShader.textures.cbegin(); - for ( ; iter != pmShader.textures.cend(); ++iter) + std::map::const_iterator iter = pmShader.m_textures.cbegin(); + for ( ; iter != pmShader.m_textures.cend(); ++iter) { if (iter->first == sampler) break; } - if (iter == pmShader.textures.cend()) - pmShader.textures[sampler] = texDesc; + if (iter == pmShader.m_textures.cend()) + pmShader.m_textures[sampler] = texDesc; } } @@ -293,9 +293,9 @@ GLuint ShaderEngine::compilePresetShader(const PresentShaderType shaderType, Sha if (found != std::string::npos) { blur1_enabled = blur2_enabled = blur3_enabled = true; - pmShader.textures["blur3"] = textureManager->getTexture("blur3", GL_REPEAT, GL_LINEAR); - pmShader.textures["blur2"] = textureManager->getTexture("blur2", GL_REPEAT, GL_LINEAR); - pmShader.textures["blur1"] = textureManager->getTexture("blur1", GL_REPEAT, GL_LINEAR); + pmShader.m_textures["blur3"] = textureManager->getTexture("blur3", GL_REPEAT, GL_LINEAR); + pmShader.m_textures["blur2"] = textureManager->getTexture("blur2", GL_REPEAT, GL_LINEAR); + pmShader.m_textures["blur1"] = textureManager->getTexture("blur1", GL_REPEAT, GL_LINEAR); } else { @@ -303,8 +303,8 @@ GLuint ShaderEngine::compilePresetShader(const PresentShaderType shaderType, Sha if (found != std::string::npos) { blur1_enabled = blur2_enabled = true; - pmShader.textures["blur2"] = textureManager->getTexture("blur2", GL_REPEAT, GL_LINEAR); - pmShader.textures["blur1"] = textureManager->getTexture("blur1", GL_REPEAT, GL_LINEAR); + pmShader.m_textures["blur2"] = textureManager->getTexture("blur2", GL_REPEAT, GL_LINEAR); + pmShader.m_textures["blur1"] = textureManager->getTexture("blur1", GL_REPEAT, GL_LINEAR); } else { @@ -312,7 +312,7 @@ GLuint ShaderEngine::compilePresetShader(const PresentShaderType shaderType, Sha if (found != std::string::npos) { blur1_enabled = true; - pmShader.textures["blur1"] = textureManager->getTexture("blur1", GL_REPEAT, GL_LINEAR); + pmShader.m_textures["blur1"] = textureManager->getTexture("blur1", GL_REPEAT, GL_LINEAR); } } } @@ -377,8 +377,8 @@ GLuint ShaderEngine::compilePresetShader(const PresentShaderType shaderType, Sha // Declare samplers std::set texsizes; - std::map::const_iterator iter_samplers = pmShader.textures.cbegin(); - for ( ; iter_samplers != pmShader.textures.cend(); ++iter_samplers) + std::map::const_iterator iter_samplers = pmShader.m_textures.cbegin(); + for ( ; iter_samplers != pmShader.m_textures.cend(); ++iter_samplers) { Texture * texture = iter_samplers->second.first; @@ -572,8 +572,8 @@ void ShaderEngine::SetupTextures(GLuint program, const Shader &shader) std::map texsizes; // Set samplers - for (std::map::const_iterator iter_samplers = shader.textures.begin(); iter_samplers - != shader.textures.end(); ++iter_samplers) + for (std::map::const_iterator iter_samplers = shader.m_textures.begin(); iter_samplers + != shader.m_textures.end(); ++iter_samplers) { std::string texName = iter_samplers->first; Texture * texture = iter_samplers->second.first; @@ -813,13 +813,13 @@ void ShaderEngine::loadPresetShaders(Pipeline &pipeline) programID_presetComp = GL_FALSE; // compile and link warp and composite shaders from pipeline - if (!pipeline.warpShader.programSource.empty()) { + if (!pipeline.warpShader.m_programSource.empty()) { programID_presetWarp = loadPresetShader(PresentWarpShader, pipeline.warpShader, pipeline.warpShaderFilename); uniform_vertex_transf_warp_shader = glGetUniformLocation(programID_presetWarp, "vertex_transformation"); presetWarpShaderLoaded = true; } - if (!pipeline.compositeShader.programSource.empty()) { + if (!pipeline.compositeShader.m_programSource.empty()) { programID_presetComp = loadPresetShader(PresentCompositeShader, pipeline.compositeShader, pipeline.compositeShaderFilename); presetCompShaderLoaded = true; } @@ -927,28 +927,14 @@ GLuint ShaderEngine::CompileShaderProgram(const std::string & VertexShaderCode, 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 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); + shader.Bind(); + shader.BindTextures(); SetupTextures(programID_presetWarp, shader); SetupShaderVariables(programID_presetWarp, pipeline, pipelineContext); diff --git a/src/libprojectM/Renderer/ShaderEngine.hpp b/src/libprojectM/Renderer/ShaderEngine.hpp index 6434e745c..9a0f20cbf 100644 --- a/src/libprojectM/Renderer/ShaderEngine.hpp +++ b/src/libprojectM/Renderer/ShaderEngine.hpp @@ -23,26 +23,6 @@ class ShaderEngine; #include "Shader.hpp" #include -class ShaderException : public std::exception -{ -public: - inline ShaderException(std::string message) - : m_message(std::move(message)) - { - } - - virtual ~ShaderException() = default; - - const std::string& message() const - { - return m_message; - } - -private: - std::string m_message; -}; - - class ShaderEngine { public: @@ -56,6 +36,7 @@ public: ShaderEngine(); virtual ~ShaderEngine(); + void loadPresetShaders(Pipeline &pipeline); bool enableWarpShader(Shader &shader, const Pipeline &pipeline, const PipelineContext &pipelineContext, const glm::mat4 & mat_ortho); bool enableCompositeShader(Shader &shader, const Pipeline &pipeline, const PipelineContext &pipelineContext); @@ -88,7 +69,6 @@ private: int texsizeY; float aspectX; float aspectY; - BeatDetect *beatDetect; TextureManager *textureManager; GLint uniform_vertex_transf_warp_shader; @@ -127,10 +107,6 @@ private: void disablePresetShaders(); GLuint loadPresetShader(const PresentShaderType shaderType, Shader &shader, std::string &shaderFilename); - void deletePresetShader(Shader &shader); - void validateProgram(const GLuint programID); - - // programs generated from preset shader code GLuint programID_presetComp, programID_presetWarp;