mirror of
https://github.com/Almamu/linux-wallpaperengine.git
synced 2025-09-14 13:56:48 +08:00
~ Moved Shader compiler to the proper, new namespace
Signed-off-by: Alexis Maiquez <almamu@almamu.com>
This commit is contained in:
parent
db89bf2e17
commit
5c56e0860b
@ -20,8 +20,8 @@ include_directories(${X11_INCLUDE_DIR} ${IRRLICHT_INCLUDE_DIR} ${LZ4_INCLUDE_DIR
|
|||||||
add_executable(
|
add_executable(
|
||||||
wallengine
|
wallengine
|
||||||
main.cpp
|
main.cpp
|
||||||
WallpaperEngine/shaders/compiler.h
|
WallpaperEngine/Render/Shaders/Compiler.h
|
||||||
WallpaperEngine/shaders/compiler.cpp
|
WallpaperEngine/Render/Shaders/Compiler.cpp
|
||||||
WallpaperEngine/project.cpp
|
WallpaperEngine/project.cpp
|
||||||
WallpaperEngine/project.h
|
WallpaperEngine/project.h
|
||||||
WallpaperEngine/scene.cpp
|
WallpaperEngine/scene.cpp
|
||||||
|
635
WallpaperEngine/Render/Shaders/Compiler.cpp
Normal file
635
WallpaperEngine/Render/Shaders/Compiler.cpp
Normal file
@ -0,0 +1,635 @@
|
|||||||
|
#include <irrlicht/irrlicht.h>
|
||||||
|
#include <iostream>
|
||||||
|
#include <fstream>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
// filesystem
|
||||||
|
#include <WallpaperEngine/FileSystem/utils.h>
|
||||||
|
|
||||||
|
// video engine
|
||||||
|
#include <WallpaperEngine/Irrlicht/Irrlicht.h>
|
||||||
|
|
||||||
|
// shader compiler
|
||||||
|
#include <WallpaperEngine/Render/Shaders/Compiler.h>
|
||||||
|
#include <WallpaperEngine/Core/Core.h>
|
||||||
|
|
||||||
|
namespace WallpaperEngine::Render::Shaders
|
||||||
|
{
|
||||||
|
Compiler::Compiler (irr::io::path& file, Type type, std::map<std::string, int>* combos, bool recursive)
|
||||||
|
{
|
||||||
|
this->m_recursive = recursive;
|
||||||
|
this->m_combos = combos;
|
||||||
|
|
||||||
|
// begin with an space so it gets ignored properly on parse
|
||||||
|
if (recursive == false)
|
||||||
|
{
|
||||||
|
// compatibility layer for OpenGL shaders
|
||||||
|
this->m_content = "#version 120\n"
|
||||||
|
"#define highp\n"
|
||||||
|
"#define mediump\n"
|
||||||
|
"#define lowp\n"
|
||||||
|
"#define mul(x, y) (y * x)\n"
|
||||||
|
"#define frac fract\n"
|
||||||
|
"#define CAST2(x) (vec2(x))\n"
|
||||||
|
"#define CAST3(x) (vec3(x))\n"
|
||||||
|
"#define CAST4(x) (vec4(x))\n"
|
||||||
|
"#define CAST3X3(x) (mat3(x))\n"
|
||||||
|
"#define saturate(x) (clamp(x, 0.0, 1.0))\n"
|
||||||
|
"#define texSample2D texture2D\n"
|
||||||
|
"#define texSample2DLod texture2DLod\n"
|
||||||
|
"#define texture2DLod texture2D\n"
|
||||||
|
"#define atan2 atan\n"
|
||||||
|
"#define ddx dFdx\n"
|
||||||
|
"#define ddy(x) dFdy(-(x))\n"
|
||||||
|
"#define GLSL 1\n\n";
|
||||||
|
|
||||||
|
std::map<std::string, int>::const_iterator cur = this->m_combos->begin ();
|
||||||
|
std::map<std::string, int>::const_iterator end = this->m_combos->end ();
|
||||||
|
|
||||||
|
for (; cur != end; cur ++)
|
||||||
|
{
|
||||||
|
this->m_content += "#define " + (*cur).first + " " + std::to_string ((*cur).second) + "\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
this->m_content = "";
|
||||||
|
}
|
||||||
|
|
||||||
|
this->m_content.append (WallpaperEngine::FileSystem::loadFullFile (file));
|
||||||
|
|
||||||
|
// append file content
|
||||||
|
this->m_type = type;
|
||||||
|
|
||||||
|
this->m_file = file;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Compiler::peekString(std::string str, std::string::const_iterator& it)
|
||||||
|
{
|
||||||
|
std::string::const_iterator check = str.begin();
|
||||||
|
std::string::const_iterator cur = it;
|
||||||
|
|
||||||
|
while (cur != this->m_content.end () && check != str.end ())
|
||||||
|
{
|
||||||
|
if (*cur != *check) return false;
|
||||||
|
|
||||||
|
cur ++; check ++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cur == this->m_content.end ())
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (check != str.end ())
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
it = cur;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Compiler::expectSemicolon (std::string::const_iterator& it)
|
||||||
|
{
|
||||||
|
if (*it != ';')
|
||||||
|
{
|
||||||
|
this->m_error = true;
|
||||||
|
this->m_errorInfo = "Expected semicolon but got " + *it;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
it ++;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Compiler::ignoreSpaces(std::string::const_iterator &it)
|
||||||
|
{
|
||||||
|
while (it != this->m_content.end() && (*it == ' ' || *it == '\t')) it ++;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Compiler::ignoreUpToNextLineFeed (std::string::const_iterator& it)
|
||||||
|
{
|
||||||
|
while (it != this->m_content.end() && *it != '\n') it ++;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Compiler::ignoreUpToBlockCommentEnd (std::string::const_iterator& it)
|
||||||
|
{
|
||||||
|
while (it != this->m_content.end() && this->peekString ("*/", it) == false) it ++;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string Compiler::extractType (std::string::const_iterator& it)
|
||||||
|
{
|
||||||
|
std::vector<std::string>::const_iterator cur = sTypes.begin ();
|
||||||
|
std::vector<std::string>::const_iterator end = sTypes.end ();
|
||||||
|
|
||||||
|
while (cur != end)
|
||||||
|
{
|
||||||
|
if (this->peekString (*cur, it) == true)
|
||||||
|
{
|
||||||
|
return *cur;
|
||||||
|
}
|
||||||
|
|
||||||
|
cur ++;
|
||||||
|
}
|
||||||
|
|
||||||
|
this->m_error = true;
|
||||||
|
this->m_errorInfo = "Expected type";
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string Compiler::extractName (std::string::const_iterator& it)
|
||||||
|
{
|
||||||
|
std::string::const_iterator cur = it;
|
||||||
|
std::string::const_iterator begin = cur;
|
||||||
|
|
||||||
|
// first character has to be a valid alphabetic characer
|
||||||
|
if (this->isChar (cur) == false && *cur != '_')
|
||||||
|
{
|
||||||
|
this->m_error = true;
|
||||||
|
this->m_errorInfo = "Expected name doesn't start with a valid character";
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
cur ++;
|
||||||
|
|
||||||
|
while (cur != this->m_content.end () && (this->isChar (cur) == true || *cur == '_' || this->isNumeric (cur) == true)) cur ++;
|
||||||
|
|
||||||
|
it = cur;
|
||||||
|
|
||||||
|
return std::string (begin, cur);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Compiler::isChar (std::string::const_iterator& it)
|
||||||
|
{
|
||||||
|
return ((*it) >= 'A' && (*it) <= 'Z') || ((*it) >= 'a' && (*it) <= 'z');
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Compiler::isNumeric (std::string::const_iterator& it)
|
||||||
|
{
|
||||||
|
return (*it) >= '0' && (*it) <= '9';
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string Compiler::extractQuotedValue(std::string::const_iterator& it)
|
||||||
|
{
|
||||||
|
std::string::const_iterator cur = it;
|
||||||
|
|
||||||
|
if (*cur != '"')
|
||||||
|
{
|
||||||
|
m_error = true;
|
||||||
|
m_errorInfo = "Expected opening \" but got " + (*cur);
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
cur ++;
|
||||||
|
|
||||||
|
while (cur != this->m_content.end () && *cur != '\n' && *cur != '"') cur ++;
|
||||||
|
|
||||||
|
if (cur == this->m_content.end ())
|
||||||
|
{
|
||||||
|
m_error = true;
|
||||||
|
m_errorInfo = "Expected closing \" not found";
|
||||||
|
it = cur;
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string filename = std::string (++it, cur);
|
||||||
|
|
||||||
|
it = ++cur;
|
||||||
|
|
||||||
|
return filename;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string Compiler::lookupShaderFile (std::string filename)
|
||||||
|
{
|
||||||
|
// get file information
|
||||||
|
irr::io::path shader = ("shaders/" + filename).c_str ();
|
||||||
|
|
||||||
|
if (shader == "")
|
||||||
|
{
|
||||||
|
this->m_error = true;
|
||||||
|
this->m_errorInfo = "Cannot find file " + filename + " to include";
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
// now compile the new shader
|
||||||
|
// do not include the default header (as it's already included in the parent)
|
||||||
|
Compiler loader (shader, this->m_type, this->m_combos, true);
|
||||||
|
|
||||||
|
return loader.precompile ();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string Compiler::lookupReplaceSymbol (std::string symbol)
|
||||||
|
{
|
||||||
|
std::map<std::string, std::string>::const_iterator cur = sVariableReplacement.begin ();
|
||||||
|
std::map<std::string, std::string>::const_iterator end = sVariableReplacement.end ();
|
||||||
|
|
||||||
|
while (cur != end)
|
||||||
|
{
|
||||||
|
if (cur->first == symbol)
|
||||||
|
{
|
||||||
|
return cur->second;
|
||||||
|
}
|
||||||
|
|
||||||
|
cur ++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// if there is no replacement, return the original
|
||||||
|
return symbol;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string Compiler::precompile()
|
||||||
|
{
|
||||||
|
#define BREAK_IF_ERROR if (this->m_error == true) { WallpaperEngine::Irrlicht::device->getLogger ()->log ("ERROR PRE-COMPILING SHADER", irr::ELL_ERROR); WallpaperEngine::Irrlicht::device->getLogger ()->log (this->m_errorInfo.c_str (), irr::ELL_ERROR); return ""; }
|
||||||
|
// parse the shader and find #includes and such things and translate them to the correct name
|
||||||
|
// also remove any #version definition to prevent errors
|
||||||
|
std::string::const_iterator it = this->m_content.begin ();
|
||||||
|
|
||||||
|
// reset error indicator
|
||||||
|
this->m_error = false;
|
||||||
|
this->m_errorInfo = "";
|
||||||
|
|
||||||
|
// search preprocessor macros and parse them
|
||||||
|
while (it != this->m_content.end () && this->m_error == false)
|
||||||
|
{
|
||||||
|
if (*it == ' ' || *it == '\t' || *it == '\n' || *it == '\r' || *it == '\0' || *it == '{' || *it == '}' || *it == '[' || *it == ']' || *it == '.')
|
||||||
|
{
|
||||||
|
this->m_compiledContent += *it;
|
||||||
|
it ++;
|
||||||
|
}
|
||||||
|
else if (*it == '#')
|
||||||
|
{
|
||||||
|
if (this->peekString ("#include", it) == true)
|
||||||
|
{
|
||||||
|
std::string filename = "";
|
||||||
|
|
||||||
|
// ignore whitespaces
|
||||||
|
this->ignoreSpaces (it); BREAK_IF_ERROR
|
||||||
|
// extract value between quotes
|
||||||
|
filename = this->extractQuotedValue (it); BREAK_IF_ERROR
|
||||||
|
|
||||||
|
// try to find the file first
|
||||||
|
this->m_compiledContent += "// begin of included from file " + filename + "\r\n";
|
||||||
|
this->m_compiledContent += this->lookupShaderFile (filename);
|
||||||
|
this->m_compiledContent += "\r\n// end of included from file " + filename + "\r\n";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
this->m_compiledContent += '#';
|
||||||
|
it ++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (*it == 'u')
|
||||||
|
{
|
||||||
|
// uniforms might have extra information for their values
|
||||||
|
if (this->peekString ("uniform", it) == true)
|
||||||
|
{
|
||||||
|
this->ignoreSpaces (it);
|
||||||
|
std::string type = this->extractType (it); BREAK_IF_ERROR
|
||||||
|
this->ignoreSpaces (it);
|
||||||
|
std::string name = this->extractName (it); BREAK_IF_ERROR
|
||||||
|
this->ignoreSpaces (it);
|
||||||
|
this->expectSemicolon (it); BREAK_IF_ERROR
|
||||||
|
this->ignoreSpaces (it);
|
||||||
|
|
||||||
|
// check if there is any actual extra information and parse it
|
||||||
|
if (this->peekString ("//", it) == true)
|
||||||
|
{
|
||||||
|
this->ignoreSpaces (it);
|
||||||
|
std::string::const_iterator begin = it;
|
||||||
|
this->ignoreUpToNextLineFeed (it);
|
||||||
|
|
||||||
|
std::string configuration; configuration.append (begin, it);
|
||||||
|
|
||||||
|
// parse the parameter information
|
||||||
|
this->parseParameterConfiguration (type, name, configuration); BREAK_IF_ERROR
|
||||||
|
this->m_compiledContent += "uniform " + type + " " + name + "; // " + configuration;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
this->m_compiledContent += "uniform " + type + " " + name + ";";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (*it == 'a')
|
||||||
|
{
|
||||||
|
// find attribute definitions
|
||||||
|
if (this->peekString ("attribute", it) == true)
|
||||||
|
{
|
||||||
|
this->ignoreSpaces (it);
|
||||||
|
std::string type = this->extractType (it); BREAK_IF_ERROR
|
||||||
|
this->ignoreSpaces (it);
|
||||||
|
std::string name = this->extractName (it); BREAK_IF_ERROR
|
||||||
|
this->ignoreSpaces (it);
|
||||||
|
this->expectSemicolon (it); BREAK_IF_ERROR
|
||||||
|
|
||||||
|
this->m_compiledContent += "// attribute";
|
||||||
|
this->m_compiledContent += " " + type + " ";
|
||||||
|
this->m_compiledContent += name;
|
||||||
|
this->m_compiledContent += "; /* replaced by " + this->lookupReplaceSymbol (name) + " */";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// check for types first
|
||||||
|
std::string type = this->extractType (it);
|
||||||
|
|
||||||
|
// types not found, try names
|
||||||
|
if (this->m_error == false)
|
||||||
|
{
|
||||||
|
this->m_compiledContent += type;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
this->m_error = false;
|
||||||
|
std::string name = this->extractName (it);
|
||||||
|
|
||||||
|
if (this->m_error == false)
|
||||||
|
{
|
||||||
|
// check if the name is a translated one or not
|
||||||
|
this->m_compiledContent += this->lookupReplaceSymbol (name);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
this->m_error = false;
|
||||||
|
this->m_compiledContent += *it;
|
||||||
|
it ++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (*it == '/')
|
||||||
|
{
|
||||||
|
if (this->peekString ("//", it) == true)
|
||||||
|
{
|
||||||
|
std::string::const_iterator begin = it - 2;
|
||||||
|
// is there a COMBO mark to take care of?
|
||||||
|
this->ignoreSpaces (it);
|
||||||
|
|
||||||
|
if (this->peekString ("[COMBO]", it) == true)
|
||||||
|
{
|
||||||
|
// parse combo json data to define the proper variables
|
||||||
|
this->ignoreSpaces (it);
|
||||||
|
begin = it;
|
||||||
|
this->ignoreUpToNextLineFeed (it);
|
||||||
|
|
||||||
|
std::string configuration; configuration.append (begin, it);
|
||||||
|
|
||||||
|
this->m_compiledContent += "// [COMBO] " + configuration;
|
||||||
|
|
||||||
|
this->parseComboConfiguration (configuration); BREAK_IF_ERROR;
|
||||||
|
}
|
||||||
|
else if (this->peekString ("[COMBO_OFF]", it) == true)
|
||||||
|
{
|
||||||
|
// parse combo json data to define the proper variables
|
||||||
|
this->ignoreSpaces (it);
|
||||||
|
begin = it;
|
||||||
|
this->ignoreUpToNextLineFeed (it);
|
||||||
|
|
||||||
|
std::string configuration; configuration.append (begin, it);
|
||||||
|
|
||||||
|
this->m_compiledContent += "// [COMBO_OFF] " + configuration;
|
||||||
|
|
||||||
|
this->parseComboConfiguration (configuration); BREAK_IF_ERROR;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
this->ignoreUpToNextLineFeed (it);
|
||||||
|
this->m_compiledContent.append (begin, it);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (this->peekString ("/*", it) == true)
|
||||||
|
{
|
||||||
|
std::string::const_iterator begin = it - 2;
|
||||||
|
this->ignoreUpToBlockCommentEnd (it);
|
||||||
|
this->m_compiledContent.append (begin, it);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
this->m_compiledContent += *it;
|
||||||
|
it ++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// check for types first
|
||||||
|
std::string type = this->extractType (it);
|
||||||
|
|
||||||
|
// types not found, try names
|
||||||
|
if (this->m_error == false)
|
||||||
|
{
|
||||||
|
this->m_compiledContent += type;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
this->m_error = false;
|
||||||
|
std::string name = this->extractName (it);
|
||||||
|
|
||||||
|
if (this->m_error == false)
|
||||||
|
{
|
||||||
|
// check if the name is a translated one or not
|
||||||
|
this->m_compiledContent += this->lookupReplaceSymbol (name);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
this->m_error = false;
|
||||||
|
this->m_compiledContent += *it;
|
||||||
|
it ++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this->m_recursive == false)
|
||||||
|
{
|
||||||
|
WallpaperEngine::Irrlicht::device->getLogger ()->log ("Compiled shader output for", this->m_file.c_str ());
|
||||||
|
WallpaperEngine::Irrlicht::device->getLogger ()->log (this->m_compiledContent.c_str ());
|
||||||
|
}
|
||||||
|
|
||||||
|
return this->m_compiledContent;
|
||||||
|
#undef BREAK_IF_ERROR
|
||||||
|
}
|
||||||
|
|
||||||
|
void Compiler::parseComboConfiguration (const std::string& content)
|
||||||
|
{
|
||||||
|
json data = json::parse (content);
|
||||||
|
json::const_iterator combo = data.find ("combo");
|
||||||
|
json::const_iterator defvalue = data.find ("default");
|
||||||
|
|
||||||
|
// add line feed just in case
|
||||||
|
this->m_compiledContent += "\n";
|
||||||
|
|
||||||
|
if (combo == data.end () || defvalue == data.end ())
|
||||||
|
{
|
||||||
|
WallpaperEngine::Irrlicht::device->getLogger ()->log ("Cannot parse combo information", irr::ELL_ERROR);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// check the combos
|
||||||
|
std::map<std::string, int>::const_iterator entry = this->m_combos->find ((*combo).get <std::string> ());
|
||||||
|
|
||||||
|
// if the combo was not found in the predefined values this means that the default value in the JSON data can be used
|
||||||
|
// so only define the ones that are not already defined
|
||||||
|
if (entry == this->m_combos->end ())
|
||||||
|
{
|
||||||
|
// if no combo is defined just load the default settings
|
||||||
|
if ((*defvalue).is_number_float ())
|
||||||
|
{
|
||||||
|
this->m_compiledContent += "#define " + (*combo).get <std::string> () + " " + std::to_string ((*defvalue).get <irr::f32> ()) + "\n";
|
||||||
|
}
|
||||||
|
else if ((*defvalue).is_number_integer ())
|
||||||
|
{
|
||||||
|
this->m_compiledContent += "#define " + (*combo).get <std::string> () + " " + std::to_string ((*defvalue).get <irr::s32> ()) + "\n";
|
||||||
|
}
|
||||||
|
else if ((*defvalue).is_string ())
|
||||||
|
{
|
||||||
|
this->m_compiledContent += "#define " + (*combo).get <std::string> () + " " + (*defvalue).get <std::string> () + "\n";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
WallpaperEngine::Irrlicht::device->getLogger ()->log ("Cannot parse combo information, unknown type", irr::ELL_ERROR);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Compiler::parseParameterConfiguration (const std::string& type, const std::string& name, const std::string& content)
|
||||||
|
{
|
||||||
|
json data = json::parse (content);
|
||||||
|
json::const_iterator material = data.find ("material");
|
||||||
|
json::const_iterator defvalue = data.find ("default");
|
||||||
|
json::const_iterator range = data.find ("range");
|
||||||
|
|
||||||
|
// this is not a real parameter
|
||||||
|
if (material == data.end () || defvalue == data.end ())
|
||||||
|
{
|
||||||
|
if (type != "sampler2D")
|
||||||
|
WallpaperEngine::Irrlicht::device->getLogger ()->log ("Cannot parse parameter info for ", name.c_str (), irr::ELL_ERROR);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ShaderParameter* param = new ShaderParameter;
|
||||||
|
|
||||||
|
param->identifierName = (*material).get <std::string> ();
|
||||||
|
param->variableName = name;
|
||||||
|
param->type = type;
|
||||||
|
|
||||||
|
if (type == "vec4" || type == "vec3")
|
||||||
|
{
|
||||||
|
if ((*defvalue).is_string () == false)
|
||||||
|
{
|
||||||
|
irr::core::vector3df* vector = new irr::core::vector3df;
|
||||||
|
|
||||||
|
vector->X = 0.0f;
|
||||||
|
vector->Y = 0.0f;
|
||||||
|
vector->Z = 0.0f;
|
||||||
|
|
||||||
|
param->defaultValue = vector;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
irr::core::vector3df tmp = WallpaperEngine::Core::ato3vf ((*defvalue).get <std::string> ().c_str ());
|
||||||
|
irr::core::vector3df* vector = new irr::core::vector3df;
|
||||||
|
|
||||||
|
vector->X = tmp.X;
|
||||||
|
vector->Y = tmp.Y;
|
||||||
|
vector->Z = tmp.Z;
|
||||||
|
|
||||||
|
param->defaultValue = vector;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (type == "vec2")
|
||||||
|
{
|
||||||
|
if ((*defvalue).is_string () == false)
|
||||||
|
{
|
||||||
|
irr::core::vector2df* vector = new irr::core::vector2df;
|
||||||
|
|
||||||
|
vector->X = 0.0f;
|
||||||
|
vector->Y = 0.0f;
|
||||||
|
|
||||||
|
param->defaultValue = vector;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
irr::core::vector2df* vector = new irr::core::vector2df;
|
||||||
|
irr::core::vector2df tmp = WallpaperEngine::Core::ato2vf ((*defvalue).get <std::string> ().c_str ());
|
||||||
|
|
||||||
|
vector->X = tmp.X;
|
||||||
|
vector->Y = tmp.Y;
|
||||||
|
|
||||||
|
param->defaultValue = vector;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (type == "float")
|
||||||
|
{
|
||||||
|
if ((*defvalue).is_number () == false)
|
||||||
|
{
|
||||||
|
irr::f32* val = new irr::f32;
|
||||||
|
|
||||||
|
*val = 0.0f;
|
||||||
|
|
||||||
|
param->defaultValue = val;
|
||||||
|
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
irr::f32* val = new irr::f32;
|
||||||
|
|
||||||
|
*val = (*defvalue).get <irr::f32> ();
|
||||||
|
|
||||||
|
param->defaultValue = val;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (type == "sampler2D")
|
||||||
|
{
|
||||||
|
// samplers are not saved, we can ignore them for now
|
||||||
|
delete param;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
this->m_error = true;
|
||||||
|
this->m_errorInfo = "Unknown parameter type: " + type + " for " + param->identifierName + " (" + param->variableName + ")";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this->m_parameters.push_back (param);
|
||||||
|
}
|
||||||
|
|
||||||
|
Compiler::ShaderParameter* Compiler::findParameter (std::string identifier)
|
||||||
|
{
|
||||||
|
std::vector<ShaderParameter*>::const_iterator cur = this->m_parameters.begin ();
|
||||||
|
std::vector<ShaderParameter*>::const_iterator end = this->m_parameters.end ();
|
||||||
|
|
||||||
|
for (; cur != end; cur ++)
|
||||||
|
{
|
||||||
|
if ((*cur)->identifierName == identifier)
|
||||||
|
{
|
||||||
|
return (*cur);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector <Compiler::ShaderParameter*>& Compiler::getParameters ()
|
||||||
|
{
|
||||||
|
return this->m_parameters;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::map<std::string, std::string> Compiler::sVariableReplacement =
|
||||||
|
{
|
||||||
|
// attribute vec3 a_position
|
||||||
|
{"a_Position", "gl_Vertex.xyz"},
|
||||||
|
// attribute vec2 a_TexCoord
|
||||||
|
{"a_TexCoord", "gl_MultiTexCoord0.xy"},
|
||||||
|
// attribute vec3 a_Normal
|
||||||
|
{"a_Normal", "gl_Normal.xyz"}
|
||||||
|
};
|
||||||
|
|
||||||
|
std::vector<std::string> Compiler::sTypes =
|
||||||
|
{
|
||||||
|
"vec4", "vec3", "vec2", "float", "sampler2D", "mat4"
|
||||||
|
};
|
||||||
|
}
|
240
WallpaperEngine/Render/Shaders/Compiler.h
Normal file
240
WallpaperEngine/Render/Shaders/Compiler.h
Normal file
@ -0,0 +1,240 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <irrlicht/irrlicht.h>
|
||||||
|
#include <iostream>
|
||||||
|
#include <vector>
|
||||||
|
#include <map>
|
||||||
|
#include <nlohmann/json.hpp>
|
||||||
|
|
||||||
|
#include <WallpaperEngine/FileSystem/utils.h>
|
||||||
|
|
||||||
|
namespace WallpaperEngine::Render::Shaders
|
||||||
|
{
|
||||||
|
using json = nlohmann::json;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A basic shader loader that adds basic function definitions to every loaded shader
|
||||||
|
*/
|
||||||
|
class Compiler
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* Basic struct used to define all the shader variables
|
||||||
|
* the compiler will replace in pre-processing time
|
||||||
|
* to make sure the shaders compile under OpenGL
|
||||||
|
*/
|
||||||
|
struct VariableReplacement
|
||||||
|
{
|
||||||
|
const char* original;
|
||||||
|
const char* replacement;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct TypeName
|
||||||
|
{
|
||||||
|
const char* name;
|
||||||
|
int size;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ShaderParameter
|
||||||
|
{
|
||||||
|
std::string type;
|
||||||
|
std::string variableName;
|
||||||
|
std::string identifierName;
|
||||||
|
void* defaultValue;
|
||||||
|
void* range [2];
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Types of shaders
|
||||||
|
*/
|
||||||
|
enum Type
|
||||||
|
{
|
||||||
|
Type_Vertex = 0,
|
||||||
|
Type_Pixel = 1,
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* List of variables to replace when pre-process is performed
|
||||||
|
*/
|
||||||
|
static std::map<std::string, std::string> sVariableReplacement;
|
||||||
|
/**
|
||||||
|
* Types of variables the pre-processor understands
|
||||||
|
*/
|
||||||
|
static std::vector<std::string> sTypes;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Compiler constructor, loads the given shader file and prepares
|
||||||
|
* the pre-processing and compilation of the shader, adding
|
||||||
|
* required definitions if needed
|
||||||
|
*
|
||||||
|
* @param file The file to load
|
||||||
|
* @param type The type of shader
|
||||||
|
* @param recursive Whether the compiler should add base definitions or not
|
||||||
|
*/
|
||||||
|
Compiler (irr::io::path& file, Type type, std::map<std::string, int>* combos, bool recursive = false);
|
||||||
|
/**
|
||||||
|
* Performs the actual pre-compilation/pre-processing over the shader files
|
||||||
|
* This step is kinda big, replaces variables names on sVariableReplacement,
|
||||||
|
* ensures #include directives are correctly handled
|
||||||
|
* and takes care of attribute comments for the wallpaper engine specifics
|
||||||
|
*
|
||||||
|
* @return The shader contents ready to be used by OpenGL
|
||||||
|
*/
|
||||||
|
std::string precompile ();
|
||||||
|
/**
|
||||||
|
* Searches the list of parameters available for the parameter with the given value
|
||||||
|
*
|
||||||
|
* @param identifier The identifier to search for
|
||||||
|
* @return The shader information
|
||||||
|
*/
|
||||||
|
ShaderParameter* findParameter (std::string identifier);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return The list of parameters available for this shader with their default values
|
||||||
|
*/
|
||||||
|
std::vector <ShaderParameter*>& getParameters ();
|
||||||
|
|
||||||
|
private:
|
||||||
|
/**
|
||||||
|
* Checks if there is "str" in the current position without advancing the
|
||||||
|
* iterator in use
|
||||||
|
*
|
||||||
|
* @param str The string to check for
|
||||||
|
* @param it The position to start checking at
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
bool peekString (std::string str, std::string::const_iterator& it);
|
||||||
|
/**
|
||||||
|
* Checks for a semicolon as current character, advancing the iterator
|
||||||
|
* after finding it, otherwise returns an error
|
||||||
|
*
|
||||||
|
* @param it The position where to expect the semicolon
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
bool expectSemicolon (std::string::const_iterator& it);
|
||||||
|
/**
|
||||||
|
* Ignores contiguous space characters in the string advancing the iterator
|
||||||
|
* until the first non-space character
|
||||||
|
*
|
||||||
|
* @param it The iterator to increase
|
||||||
|
*/
|
||||||
|
void ignoreSpaces (std::string::const_iterator& it);
|
||||||
|
/**
|
||||||
|
* Ignores all characters until next line-fee (\n) advancing the interator
|
||||||
|
*
|
||||||
|
* @param it The iterator to increase
|
||||||
|
*/
|
||||||
|
void ignoreUpToNextLineFeed (std::string::const_iterator& it);
|
||||||
|
/**
|
||||||
|
* Ignores all characters until a block comment end is found, advancing the iterator
|
||||||
|
*
|
||||||
|
* @param it The iterator to increase
|
||||||
|
*/
|
||||||
|
void ignoreUpToBlockCommentEnd (std::string::const_iterator& it);
|
||||||
|
/**
|
||||||
|
* Parses the current position as a variable type, extracts it and compares it
|
||||||
|
* to the registered types in the pre-processor, returning it's name if valid
|
||||||
|
* increasing the iterator at the same time
|
||||||
|
*
|
||||||
|
* @param it The position to extract it from
|
||||||
|
*
|
||||||
|
* @return The type name
|
||||||
|
*/
|
||||||
|
std::string extractType (std::string::const_iterator& it);
|
||||||
|
/**
|
||||||
|
* Parses the current position as a variable name, extractig it's name and
|
||||||
|
* increasing the iterator as the name is extracted
|
||||||
|
*
|
||||||
|
* @param it The position to start extracting the variable name from
|
||||||
|
*
|
||||||
|
* @return The variable name
|
||||||
|
*/
|
||||||
|
std::string extractName (std::string::const_iterator& it);
|
||||||
|
/**
|
||||||
|
* Parses the current position as a quoted value, extracting it's value
|
||||||
|
* and increasing the iterator at the same time
|
||||||
|
*
|
||||||
|
* @param it The position to start extracting the value from
|
||||||
|
*
|
||||||
|
* @return The value
|
||||||
|
*/
|
||||||
|
std::string extractQuotedValue (std::string::const_iterator& it);
|
||||||
|
/**
|
||||||
|
* Tries to find the given shader file and compile it
|
||||||
|
*
|
||||||
|
* @param filename The shader's filename
|
||||||
|
*
|
||||||
|
* @return The compiled contents
|
||||||
|
*/
|
||||||
|
std::string lookupShaderFile (std::string filename);
|
||||||
|
/**
|
||||||
|
* Searches for the given symbol in the replace table
|
||||||
|
*
|
||||||
|
* @param symbol The symbol to look for
|
||||||
|
*
|
||||||
|
* @return The symbol it should be replaced with
|
||||||
|
*/
|
||||||
|
std::string lookupReplaceSymbol (std::string symbol);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Whether the character in the current position is a character or not
|
||||||
|
*/
|
||||||
|
bool isChar (std::string::const_iterator& it);
|
||||||
|
/**
|
||||||
|
* @return Whether the character in the current position is a number or not
|
||||||
|
*/
|
||||||
|
bool isNumeric (std::string::const_iterator& it);
|
||||||
|
/**
|
||||||
|
* Parses a COMBO value to add the proper define to the code
|
||||||
|
*
|
||||||
|
* @param content The parameter configuration
|
||||||
|
*/
|
||||||
|
void parseComboConfiguration (const std::string& content);
|
||||||
|
/**
|
||||||
|
* Parses a parameter extra metadata created by wallpaper engine
|
||||||
|
*
|
||||||
|
* @param type The type of variable to parse
|
||||||
|
* @param name The name of the variable in the shader (for actual variable declaration)
|
||||||
|
* @param content The parameter configuration
|
||||||
|
*/
|
||||||
|
void parseParameterConfiguration (const std::string& type, const std::string& name, const std::string& content);
|
||||||
|
/**
|
||||||
|
* The shader file this instance is loading
|
||||||
|
*/
|
||||||
|
irr::io::path m_file;
|
||||||
|
/**
|
||||||
|
* The original file content
|
||||||
|
*/
|
||||||
|
std::string m_content;
|
||||||
|
/**
|
||||||
|
* The final, compiled content ready to be used by OpenGL
|
||||||
|
*/
|
||||||
|
std::string m_compiledContent;
|
||||||
|
/**
|
||||||
|
* Whether there was any kind of error in the compilation or not
|
||||||
|
*/
|
||||||
|
bool m_error;
|
||||||
|
/**
|
||||||
|
* Extra information about the error (if any)
|
||||||
|
*/
|
||||||
|
std::string m_errorInfo;
|
||||||
|
/**
|
||||||
|
* The type of shader
|
||||||
|
*/
|
||||||
|
Type m_type;
|
||||||
|
/**
|
||||||
|
* The parameters the shader needs
|
||||||
|
*/
|
||||||
|
std::vector <ShaderParameter*> m_parameters;
|
||||||
|
/**
|
||||||
|
* The combos the shader should be generated with
|
||||||
|
*/
|
||||||
|
std::map <std::string, int>* m_combos;
|
||||||
|
/**
|
||||||
|
* Whether this compilation is a recursive one or not
|
||||||
|
*/
|
||||||
|
bool m_recursive;
|
||||||
|
};
|
||||||
|
}
|
@ -1,6 +1,6 @@
|
|||||||
#include <WallpaperEngine/FileSystem/utils.h>
|
#include <WallpaperEngine/FileSystem/utils.h>
|
||||||
|
|
||||||
#include "shaders/compiler.h"
|
#include "WallpaperEngine/Render/Shaders/Compiler.h"
|
||||||
#include "effect.h"
|
#include "effect.h"
|
||||||
#include "WallpaperEngine/Irrlicht/Irrlicht.h"
|
#include "WallpaperEngine/Irrlicht/Irrlicht.h"
|
||||||
#include "WallpaperEngine/Core/Core.h"
|
#include "WallpaperEngine/Core/Core.h"
|
||||||
@ -94,8 +94,8 @@ namespace WallpaperEngine
|
|||||||
irr::io::path fragpath = shaderpath + ".frag";
|
irr::io::path fragpath = shaderpath + ".frag";
|
||||||
irr::io::path vertpath = shaderpath + ".vert";
|
irr::io::path vertpath = shaderpath + ".vert";
|
||||||
|
|
||||||
this->m_fragShader = new WallpaperEngine::shaders::compiler (fragpath, WallpaperEngine::shaders::compiler::Type::Type_Pixel, &this->m_combos, false);
|
this->m_fragShader = new WallpaperEngine::Render::Shaders::Compiler (fragpath, WallpaperEngine::Render::Shaders::Compiler::Type::Type_Pixel, &this->m_combos, false);
|
||||||
this->m_vertShader = new WallpaperEngine::shaders::compiler (vertpath, WallpaperEngine::shaders::compiler::Type::Type_Vertex, &this->m_combos, false);
|
this->m_vertShader = new WallpaperEngine::Render::Shaders::Compiler (vertpath, WallpaperEngine::Render::Shaders::Compiler::Type::Type_Vertex, &this->m_combos, false);
|
||||||
|
|
||||||
this->m_materialType = WallpaperEngine::Irrlicht::driver->getGPUProgrammingServices ()
|
this->m_materialType = WallpaperEngine::Irrlicht::driver->getGPUProgrammingServices ()
|
||||||
->addHighLevelShaderMaterial (
|
->addHighLevelShaderMaterial (
|
||||||
@ -111,8 +111,8 @@ namespace WallpaperEngine
|
|||||||
this->parseConstantValues ((*constantvalues));
|
this->parseConstantValues ((*constantvalues));
|
||||||
|
|
||||||
// last step is creating the actual variables for the shaders
|
// last step is creating the actual variables for the shaders
|
||||||
std::vector <shaders::compiler::ShaderParameter*>::const_iterator cur;
|
std::vector <Render::Shaders::Compiler::ShaderParameter*>::const_iterator cur;
|
||||||
std::vector <shaders::compiler::ShaderParameter*>::const_iterator end;
|
std::vector <Render::Shaders::Compiler::ShaderParameter*>::const_iterator end;
|
||||||
|
|
||||||
cur = this->m_fragShader->getParameters ().begin ();
|
cur = this->m_fragShader->getParameters ().begin ();
|
||||||
end = this->m_fragShader->getParameters ().end ();
|
end = this->m_fragShader->getParameters ().end ();
|
||||||
@ -120,7 +120,7 @@ namespace WallpaperEngine
|
|||||||
// first do fragment shaders
|
// first do fragment shaders
|
||||||
for (; cur != end; cur ++)
|
for (; cur != end; cur ++)
|
||||||
{
|
{
|
||||||
WallpaperEngine::shaders::compiler::ShaderParameter* param = (*cur);
|
WallpaperEngine::Render::Shaders::Compiler::ShaderParameter* param = (*cur);
|
||||||
ShaderParameter* parameter = new ShaderParameter;
|
ShaderParameter* parameter = new ShaderParameter;
|
||||||
void* defaultValue = param->defaultValue;
|
void* defaultValue = param->defaultValue;
|
||||||
|
|
||||||
@ -203,7 +203,7 @@ namespace WallpaperEngine
|
|||||||
// second do vertex shaders
|
// second do vertex shaders
|
||||||
for (;cur != end; cur ++)
|
for (;cur != end; cur ++)
|
||||||
{
|
{
|
||||||
WallpaperEngine::shaders::compiler::ShaderParameter* param = (*cur);
|
WallpaperEngine::Render::Shaders::Compiler::ShaderParameter* param = (*cur);
|
||||||
|
|
||||||
if (param == nullptr)
|
if (param == nullptr)
|
||||||
continue;
|
continue;
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
|
|
||||||
#include "texture.h"
|
#include "texture.h"
|
||||||
#include "object.h"
|
#include "object.h"
|
||||||
#include "shaders/compiler.h"
|
#include "WallpaperEngine/Render/Shaders/Compiler.h"
|
||||||
|
|
||||||
namespace WallpaperEngine
|
namespace WallpaperEngine
|
||||||
{
|
{
|
||||||
@ -42,8 +42,8 @@ namespace WallpaperEngine
|
|||||||
void parseConstantValues (json data);
|
void parseConstantValues (json data);
|
||||||
void parseCombos (json data);
|
void parseCombos (json data);
|
||||||
|
|
||||||
WallpaperEngine::shaders::compiler* m_fragShader;
|
WallpaperEngine::Render::Shaders::Compiler* m_fragShader;
|
||||||
WallpaperEngine::shaders::compiler* m_vertShader;
|
WallpaperEngine::Render::Shaders::Compiler* m_vertShader;
|
||||||
|
|
||||||
std::map <std::string, ShaderParameter*> m_vertexVariables;
|
std::map <std::string, ShaderParameter*> m_vertexVariables;
|
||||||
std::map <std::string, ShaderParameter*> m_pixelVariables;
|
std::map <std::string, ShaderParameter*> m_pixelVariables;
|
||||||
|
@ -1,638 +0,0 @@
|
|||||||
#include <irrlicht/irrlicht.h>
|
|
||||||
#include <iostream>
|
|
||||||
#include <fstream>
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
// filesystem
|
|
||||||
#include <WallpaperEngine/FileSystem/utils.h>
|
|
||||||
|
|
||||||
// video engine
|
|
||||||
#include <WallpaperEngine/Irrlicht/Irrlicht.h>
|
|
||||||
|
|
||||||
// shader compiler
|
|
||||||
#include <WallpaperEngine/shaders/compiler.h>
|
|
||||||
#include <WallpaperEngine/Core/Core.h>
|
|
||||||
|
|
||||||
namespace WallpaperEngine
|
|
||||||
{
|
|
||||||
namespace shaders
|
|
||||||
{
|
|
||||||
compiler::compiler (irr::io::path& file, Type type, std::map<std::string, int>* combos, bool recursive)
|
|
||||||
{
|
|
||||||
this->m_recursive = recursive;
|
|
||||||
this->m_combos = combos;
|
|
||||||
|
|
||||||
// begin with an space so it gets ignored properly on parse
|
|
||||||
if (recursive == false)
|
|
||||||
{
|
|
||||||
// compatibility layer for OpenGL shaders
|
|
||||||
this->m_content = "#version 120\n"
|
|
||||||
"#define highp\n"
|
|
||||||
"#define mediump\n"
|
|
||||||
"#define lowp\n"
|
|
||||||
"#define mul(x, y) (y * x)\n"
|
|
||||||
"#define frac fract\n"
|
|
||||||
"#define CAST2(x) (vec2(x))\n"
|
|
||||||
"#define CAST3(x) (vec3(x))\n"
|
|
||||||
"#define CAST4(x) (vec4(x))\n"
|
|
||||||
"#define CAST3X3(x) (mat3(x))\n"
|
|
||||||
"#define saturate(x) (clamp(x, 0.0, 1.0))\n"
|
|
||||||
"#define texSample2D texture2D\n"
|
|
||||||
"#define texSample2DLod texture2DLod\n"
|
|
||||||
"#define texture2DLod texture2D\n"
|
|
||||||
"#define atan2 atan\n"
|
|
||||||
"#define ddx dFdx\n"
|
|
||||||
"#define ddy(x) dFdy(-(x))\n"
|
|
||||||
"#define GLSL 1\n\n";
|
|
||||||
|
|
||||||
std::map<std::string, int>::const_iterator cur = this->m_combos->begin ();
|
|
||||||
std::map<std::string, int>::const_iterator end = this->m_combos->end ();
|
|
||||||
|
|
||||||
for (; cur != end; cur ++)
|
|
||||||
{
|
|
||||||
this->m_content += "#define " + (*cur).first + " " + std::to_string ((*cur).second) + "\n";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
this->m_content = "";
|
|
||||||
}
|
|
||||||
|
|
||||||
this->m_content.append (WallpaperEngine::FileSystem::loadFullFile (file));
|
|
||||||
|
|
||||||
// append file content
|
|
||||||
this->m_type = type;
|
|
||||||
|
|
||||||
this->m_file = file;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool compiler::peekString(std::string str, std::string::const_iterator& it)
|
|
||||||
{
|
|
||||||
std::string::const_iterator check = str.begin();
|
|
||||||
std::string::const_iterator cur = it;
|
|
||||||
|
|
||||||
while (cur != this->m_content.end () && check != str.end ())
|
|
||||||
{
|
|
||||||
if (*cur != *check) return false;
|
|
||||||
|
|
||||||
cur ++; check ++;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (cur == this->m_content.end ())
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (check != str.end ())
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
it = cur;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool compiler::expectSemicolon (std::string::const_iterator& it)
|
|
||||||
{
|
|
||||||
if (*it != ';')
|
|
||||||
{
|
|
||||||
this->m_error = true;
|
|
||||||
this->m_errorInfo = "Expected semicolon but got " + *it;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
it ++;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void compiler::ignoreSpaces(std::string::const_iterator &it)
|
|
||||||
{
|
|
||||||
while (it != this->m_content.end() && (*it == ' ' || *it == '\t')) it ++;
|
|
||||||
}
|
|
||||||
|
|
||||||
void compiler::ignoreUpToNextLineFeed (std::string::const_iterator& it)
|
|
||||||
{
|
|
||||||
while (it != this->m_content.end() && *it != '\n') it ++;
|
|
||||||
}
|
|
||||||
|
|
||||||
void compiler::ignoreUpToBlockCommentEnd (std::string::const_iterator& it)
|
|
||||||
{
|
|
||||||
while (it != this->m_content.end() && this->peekString ("*/", it) == false) it ++;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string compiler::extractType (std::string::const_iterator& it)
|
|
||||||
{
|
|
||||||
std::vector<std::string>::const_iterator cur = sTypes.begin ();
|
|
||||||
std::vector<std::string>::const_iterator end = sTypes.end ();
|
|
||||||
|
|
||||||
while (cur != end)
|
|
||||||
{
|
|
||||||
if (this->peekString (*cur, it) == true)
|
|
||||||
{
|
|
||||||
return *cur;
|
|
||||||
}
|
|
||||||
|
|
||||||
cur ++;
|
|
||||||
}
|
|
||||||
|
|
||||||
this->m_error = true;
|
|
||||||
this->m_errorInfo = "Expected type";
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string compiler::extractName (std::string::const_iterator& it)
|
|
||||||
{
|
|
||||||
std::string::const_iterator cur = it;
|
|
||||||
std::string::const_iterator begin = cur;
|
|
||||||
|
|
||||||
// first character has to be a valid alphabetic characer
|
|
||||||
if (this->isChar (cur) == false && *cur != '_')
|
|
||||||
{
|
|
||||||
this->m_error = true;
|
|
||||||
this->m_errorInfo = "Expected name doesn't start with a valid character";
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
|
|
||||||
cur ++;
|
|
||||||
|
|
||||||
while (cur != this->m_content.end () && (this->isChar (cur) == true || *cur == '_' || this->isNumeric (cur) == true)) cur ++;
|
|
||||||
|
|
||||||
it = cur;
|
|
||||||
|
|
||||||
return std::string (begin, cur);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool compiler::isChar (std::string::const_iterator& it)
|
|
||||||
{
|
|
||||||
return ((*it) >= 'A' && (*it) <= 'Z') || ((*it) >= 'a' && (*it) <= 'z');
|
|
||||||
}
|
|
||||||
|
|
||||||
bool compiler::isNumeric (std::string::const_iterator& it)
|
|
||||||
{
|
|
||||||
return (*it) >= '0' && (*it) <= '9';
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string compiler::extractQuotedValue(std::string::const_iterator& it)
|
|
||||||
{
|
|
||||||
std::string::const_iterator cur = it;
|
|
||||||
|
|
||||||
if (*cur != '"')
|
|
||||||
{
|
|
||||||
m_error = true;
|
|
||||||
m_errorInfo = "Expected opening \" but got " + (*cur);
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
|
|
||||||
cur ++;
|
|
||||||
|
|
||||||
while (cur != this->m_content.end () && *cur != '\n' && *cur != '"') cur ++;
|
|
||||||
|
|
||||||
if (cur == this->m_content.end ())
|
|
||||||
{
|
|
||||||
m_error = true;
|
|
||||||
m_errorInfo = "Expected closing \" not found";
|
|
||||||
it = cur;
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string filename = std::string (++it, cur);
|
|
||||||
|
|
||||||
it = ++cur;
|
|
||||||
|
|
||||||
return filename;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string compiler::lookupShaderFile (std::string filename)
|
|
||||||
{
|
|
||||||
// get file information
|
|
||||||
irr::io::path shader = ("shaders/" + filename).c_str ();
|
|
||||||
|
|
||||||
if (shader == "")
|
|
||||||
{
|
|
||||||
this->m_error = true;
|
|
||||||
this->m_errorInfo = "Cannot find file " + filename + " to include";
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
|
|
||||||
// now compile the new shader
|
|
||||||
// do not include the default header (as it's already included in the parent)
|
|
||||||
compiler loader (shader, this->m_type, this->m_combos, true);
|
|
||||||
|
|
||||||
return loader.precompile ();
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string compiler::lookupReplaceSymbol (std::string symbol)
|
|
||||||
{
|
|
||||||
std::map<std::string, std::string>::const_iterator cur = sVariableReplacement.begin ();
|
|
||||||
std::map<std::string, std::string>::const_iterator end = sVariableReplacement.end ();
|
|
||||||
|
|
||||||
while (cur != end)
|
|
||||||
{
|
|
||||||
if (cur->first == symbol)
|
|
||||||
{
|
|
||||||
return cur->second;
|
|
||||||
}
|
|
||||||
|
|
||||||
cur ++;
|
|
||||||
}
|
|
||||||
|
|
||||||
// if there is no replacement, return the original
|
|
||||||
return symbol;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string compiler::precompile()
|
|
||||||
{
|
|
||||||
#define BREAK_IF_ERROR if (this->m_error == true) { WallpaperEngine::Irrlicht::device->getLogger ()->log ("ERROR PRE-COMPILING SHADER", irr::ELL_ERROR); WallpaperEngine::Irrlicht::device->getLogger ()->log (this->m_errorInfo.c_str (), irr::ELL_ERROR); return ""; }
|
|
||||||
// parse the shader and find #includes and such things and translate them to the correct name
|
|
||||||
// also remove any #version definition to prevent errors
|
|
||||||
std::string::const_iterator it = this->m_content.begin ();
|
|
||||||
|
|
||||||
// reset error indicator
|
|
||||||
this->m_error = false;
|
|
||||||
this->m_errorInfo = "";
|
|
||||||
|
|
||||||
// search preprocessor macros and parse them
|
|
||||||
while (it != this->m_content.end () && this->m_error == false)
|
|
||||||
{
|
|
||||||
if (*it == ' ' || *it == '\t' || *it == '\n' || *it == '\r' || *it == '\0' || *it == '{' || *it == '}' || *it == '[' || *it == ']' || *it == '.')
|
|
||||||
{
|
|
||||||
this->m_compiledContent += *it;
|
|
||||||
it ++;
|
|
||||||
}
|
|
||||||
else if (*it == '#')
|
|
||||||
{
|
|
||||||
if (this->peekString ("#include", it) == true)
|
|
||||||
{
|
|
||||||
std::string filename = "";
|
|
||||||
|
|
||||||
// ignore whitespaces
|
|
||||||
this->ignoreSpaces (it); BREAK_IF_ERROR
|
|
||||||
// extract value between quotes
|
|
||||||
filename = this->extractQuotedValue (it); BREAK_IF_ERROR
|
|
||||||
|
|
||||||
// try to find the file first
|
|
||||||
this->m_compiledContent += "// begin of included from file " + filename + "\r\n";
|
|
||||||
this->m_compiledContent += this->lookupShaderFile (filename);
|
|
||||||
this->m_compiledContent += "\r\n// end of included from file " + filename + "\r\n";
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
this->m_compiledContent += '#';
|
|
||||||
it ++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (*it == 'u')
|
|
||||||
{
|
|
||||||
// uniforms might have extra information for their values
|
|
||||||
if (this->peekString ("uniform", it) == true)
|
|
||||||
{
|
|
||||||
this->ignoreSpaces (it);
|
|
||||||
std::string type = this->extractType (it); BREAK_IF_ERROR
|
|
||||||
this->ignoreSpaces (it);
|
|
||||||
std::string name = this->extractName (it); BREAK_IF_ERROR
|
|
||||||
this->ignoreSpaces (it);
|
|
||||||
this->expectSemicolon (it); BREAK_IF_ERROR
|
|
||||||
this->ignoreSpaces (it);
|
|
||||||
|
|
||||||
// check if there is any actual extra information and parse it
|
|
||||||
if (this->peekString ("//", it) == true)
|
|
||||||
{
|
|
||||||
this->ignoreSpaces (it);
|
|
||||||
std::string::const_iterator begin = it;
|
|
||||||
this->ignoreUpToNextLineFeed (it);
|
|
||||||
|
|
||||||
std::string configuration; configuration.append (begin, it);
|
|
||||||
|
|
||||||
// parse the parameter information
|
|
||||||
this->parseParameterConfiguration (type, name, configuration); BREAK_IF_ERROR
|
|
||||||
this->m_compiledContent += "uniform " + type + " " + name + "; // " + configuration;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
this->m_compiledContent += "uniform " + type + " " + name + ";";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (*it == 'a')
|
|
||||||
{
|
|
||||||
// find attribute definitions
|
|
||||||
if (this->peekString ("attribute", it) == true)
|
|
||||||
{
|
|
||||||
this->ignoreSpaces (it);
|
|
||||||
std::string type = this->extractType (it); BREAK_IF_ERROR
|
|
||||||
this->ignoreSpaces (it);
|
|
||||||
std::string name = this->extractName (it); BREAK_IF_ERROR
|
|
||||||
this->ignoreSpaces (it);
|
|
||||||
this->expectSemicolon (it); BREAK_IF_ERROR
|
|
||||||
|
|
||||||
this->m_compiledContent += "// attribute";
|
|
||||||
this->m_compiledContent += " " + type + " ";
|
|
||||||
this->m_compiledContent += name;
|
|
||||||
this->m_compiledContent += "; /* replaced by " + this->lookupReplaceSymbol (name) + " */";
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// check for types first
|
|
||||||
std::string type = this->extractType (it);
|
|
||||||
|
|
||||||
// types not found, try names
|
|
||||||
if (this->m_error == false)
|
|
||||||
{
|
|
||||||
this->m_compiledContent += type;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
this->m_error = false;
|
|
||||||
std::string name = this->extractName (it);
|
|
||||||
|
|
||||||
if (this->m_error == false)
|
|
||||||
{
|
|
||||||
// check if the name is a translated one or not
|
|
||||||
this->m_compiledContent += this->lookupReplaceSymbol (name);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
this->m_error = false;
|
|
||||||
this->m_compiledContent += *it;
|
|
||||||
it ++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (*it == '/')
|
|
||||||
{
|
|
||||||
if (this->peekString ("//", it) == true)
|
|
||||||
{
|
|
||||||
std::string::const_iterator begin = it - 2;
|
|
||||||
// is there a COMBO mark to take care of?
|
|
||||||
this->ignoreSpaces (it);
|
|
||||||
|
|
||||||
if (this->peekString ("[COMBO]", it) == true)
|
|
||||||
{
|
|
||||||
// parse combo json data to define the proper variables
|
|
||||||
this->ignoreSpaces (it);
|
|
||||||
begin = it;
|
|
||||||
this->ignoreUpToNextLineFeed (it);
|
|
||||||
|
|
||||||
std::string configuration; configuration.append (begin, it);
|
|
||||||
|
|
||||||
this->m_compiledContent += "// [COMBO] " + configuration;
|
|
||||||
|
|
||||||
this->parseComboConfiguration (configuration); BREAK_IF_ERROR;
|
|
||||||
}
|
|
||||||
else if (this->peekString ("[COMBO_OFF]", it) == true)
|
|
||||||
{
|
|
||||||
// parse combo json data to define the proper variables
|
|
||||||
this->ignoreSpaces (it);
|
|
||||||
begin = it;
|
|
||||||
this->ignoreUpToNextLineFeed (it);
|
|
||||||
|
|
||||||
std::string configuration; configuration.append (begin, it);
|
|
||||||
|
|
||||||
this->m_compiledContent += "// [COMBO_OFF] " + configuration;
|
|
||||||
|
|
||||||
this->parseComboConfiguration (configuration); BREAK_IF_ERROR;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
this->ignoreUpToNextLineFeed (it);
|
|
||||||
this->m_compiledContent.append (begin, it);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (this->peekString ("/*", it) == true)
|
|
||||||
{
|
|
||||||
std::string::const_iterator begin = it - 2;
|
|
||||||
this->ignoreUpToBlockCommentEnd (it);
|
|
||||||
this->m_compiledContent.append (begin, it);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
this->m_compiledContent += *it;
|
|
||||||
it ++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// check for types first
|
|
||||||
std::string type = this->extractType (it);
|
|
||||||
|
|
||||||
// types not found, try names
|
|
||||||
if (this->m_error == false)
|
|
||||||
{
|
|
||||||
this->m_compiledContent += type;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
this->m_error = false;
|
|
||||||
std::string name = this->extractName (it);
|
|
||||||
|
|
||||||
if (this->m_error == false)
|
|
||||||
{
|
|
||||||
// check if the name is a translated one or not
|
|
||||||
this->m_compiledContent += this->lookupReplaceSymbol (name);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
this->m_error = false;
|
|
||||||
this->m_compiledContent += *it;
|
|
||||||
it ++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this->m_recursive == false)
|
|
||||||
{
|
|
||||||
WallpaperEngine::Irrlicht::device->getLogger ()->log ("Compiled shader output for", this->m_file.c_str ());
|
|
||||||
WallpaperEngine::Irrlicht::device->getLogger ()->log (this->m_compiledContent.c_str ());
|
|
||||||
}
|
|
||||||
|
|
||||||
return this->m_compiledContent;
|
|
||||||
#undef BREAK_IF_ERROR
|
|
||||||
}
|
|
||||||
|
|
||||||
void compiler::parseComboConfiguration (const std::string& content)
|
|
||||||
{
|
|
||||||
json data = json::parse (content);
|
|
||||||
json::const_iterator combo = data.find ("combo");
|
|
||||||
json::const_iterator defvalue = data.find ("default");
|
|
||||||
|
|
||||||
// add line feed just in case
|
|
||||||
this->m_compiledContent += "\n";
|
|
||||||
|
|
||||||
if (combo == data.end () || defvalue == data.end ())
|
|
||||||
{
|
|
||||||
WallpaperEngine::Irrlicht::device->getLogger ()->log ("Cannot parse combo information", irr::ELL_ERROR);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// check the combos
|
|
||||||
std::map<std::string, int>::const_iterator entry = this->m_combos->find ((*combo).get <std::string> ());
|
|
||||||
|
|
||||||
// if the combo was not found in the predefined values this means that the default value in the JSON data can be used
|
|
||||||
// so only define the ones that are not already defined
|
|
||||||
if (entry == this->m_combos->end ())
|
|
||||||
{
|
|
||||||
// if no combo is defined just load the default settings
|
|
||||||
if ((*defvalue).is_number_float ())
|
|
||||||
{
|
|
||||||
this->m_compiledContent += "#define " + (*combo).get <std::string> () + " " + std::to_string ((*defvalue).get <irr::f32> ()) + "\n";
|
|
||||||
}
|
|
||||||
else if ((*defvalue).is_number_integer ())
|
|
||||||
{
|
|
||||||
this->m_compiledContent += "#define " + (*combo).get <std::string> () + " " + std::to_string ((*defvalue).get <irr::s32> ()) + "\n";
|
|
||||||
}
|
|
||||||
else if ((*defvalue).is_string ())
|
|
||||||
{
|
|
||||||
this->m_compiledContent += "#define " + (*combo).get <std::string> () + " " + (*defvalue).get <std::string> () + "\n";
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
WallpaperEngine::Irrlicht::device->getLogger ()->log ("Cannot parse combo information, unknown type", irr::ELL_ERROR);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void compiler::parseParameterConfiguration (const std::string& type, const std::string& name, const std::string& content)
|
|
||||||
{
|
|
||||||
json data = json::parse (content);
|
|
||||||
json::const_iterator material = data.find ("material");
|
|
||||||
json::const_iterator defvalue = data.find ("default");
|
|
||||||
json::const_iterator range = data.find ("range");
|
|
||||||
|
|
||||||
// this is not a real parameter
|
|
||||||
if (material == data.end () || defvalue == data.end ())
|
|
||||||
{
|
|
||||||
if (type != "sampler2D")
|
|
||||||
WallpaperEngine::Irrlicht::device->getLogger ()->log ("Cannot parse parameter info for ", name.c_str (), irr::ELL_ERROR);
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
ShaderParameter* param = new ShaderParameter;
|
|
||||||
|
|
||||||
param->identifierName = (*material).get <std::string> ();
|
|
||||||
param->variableName = name;
|
|
||||||
param->type = type;
|
|
||||||
|
|
||||||
if (type == "vec4" || type == "vec3")
|
|
||||||
{
|
|
||||||
if ((*defvalue).is_string () == false)
|
|
||||||
{
|
|
||||||
irr::core::vector3df* vector = new irr::core::vector3df;
|
|
||||||
|
|
||||||
vector->X = 0.0f;
|
|
||||||
vector->Y = 0.0f;
|
|
||||||
vector->Z = 0.0f;
|
|
||||||
|
|
||||||
param->defaultValue = vector;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
irr::core::vector3df tmp = WallpaperEngine::Core::ato3vf ((*defvalue).get <std::string> ().c_str ());
|
|
||||||
irr::core::vector3df* vector = new irr::core::vector3df;
|
|
||||||
|
|
||||||
vector->X = tmp.X;
|
|
||||||
vector->Y = tmp.Y;
|
|
||||||
vector->Z = tmp.Z;
|
|
||||||
|
|
||||||
param->defaultValue = vector;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (type == "vec2")
|
|
||||||
{
|
|
||||||
if ((*defvalue).is_string () == false)
|
|
||||||
{
|
|
||||||
irr::core::vector2df* vector = new irr::core::vector2df;
|
|
||||||
|
|
||||||
vector->X = 0.0f;
|
|
||||||
vector->Y = 0.0f;
|
|
||||||
|
|
||||||
param->defaultValue = vector;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
irr::core::vector2df* vector = new irr::core::vector2df;
|
|
||||||
irr::core::vector2df tmp = WallpaperEngine::Core::ato2vf ((*defvalue).get <std::string> ().c_str ());
|
|
||||||
|
|
||||||
vector->X = tmp.X;
|
|
||||||
vector->Y = tmp.Y;
|
|
||||||
|
|
||||||
param->defaultValue = vector;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (type == "float")
|
|
||||||
{
|
|
||||||
if ((*defvalue).is_number () == false)
|
|
||||||
{
|
|
||||||
irr::f32* val = new irr::f32;
|
|
||||||
|
|
||||||
*val = 0.0f;
|
|
||||||
|
|
||||||
param->defaultValue = val;
|
|
||||||
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
irr::f32* val = new irr::f32;
|
|
||||||
|
|
||||||
*val = (*defvalue).get <irr::f32> ();
|
|
||||||
|
|
||||||
param->defaultValue = val;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (type == "sampler2D")
|
|
||||||
{
|
|
||||||
// samplers are not saved, we can ignore them for now
|
|
||||||
delete param;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
this->m_error = true;
|
|
||||||
this->m_errorInfo = "Unknown parameter type: " + type + " for " + param->identifierName + " (" + param->variableName + ")";
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this->m_parameters.push_back (param);
|
|
||||||
}
|
|
||||||
|
|
||||||
compiler::ShaderParameter* compiler::findParameter (std::string identifier)
|
|
||||||
{
|
|
||||||
std::vector<ShaderParameter*>::const_iterator cur = this->m_parameters.begin ();
|
|
||||||
std::vector<ShaderParameter*>::const_iterator end = this->m_parameters.end ();
|
|
||||||
|
|
||||||
for (; cur != end; cur ++)
|
|
||||||
{
|
|
||||||
if ((*cur)->identifierName == identifier)
|
|
||||||
{
|
|
||||||
return (*cur);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector <compiler::ShaderParameter*>& compiler::getParameters ()
|
|
||||||
{
|
|
||||||
return this->m_parameters;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::map<std::string, std::string> compiler::sVariableReplacement =
|
|
||||||
{
|
|
||||||
// attribute vec3 a_position
|
|
||||||
{"a_Position", "gl_Vertex.xyz"},
|
|
||||||
// attribute vec2 a_TexCoord
|
|
||||||
{"a_TexCoord", "gl_MultiTexCoord0.xy"},
|
|
||||||
// attribute vec3 a_Normal
|
|
||||||
{"a_Normal", "gl_Normal.xyz"}
|
|
||||||
};
|
|
||||||
|
|
||||||
std::vector<std::string> compiler::sTypes =
|
|
||||||
{
|
|
||||||
"vec4", "vec3", "vec2", "float", "sampler2D", "mat4"
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,246 +0,0 @@
|
|||||||
#ifndef __BASIC_SHADER_LOADER_H__
|
|
||||||
#define __BASIC_SHADER_LOADER_H__
|
|
||||||
|
|
||||||
#include <irrlicht/irrlicht.h>
|
|
||||||
#include <iostream>
|
|
||||||
#include <vector>
|
|
||||||
#include <map>
|
|
||||||
#include <nlohmann/json.hpp>
|
|
||||||
|
|
||||||
#include <WallpaperEngine/FileSystem/utils.h>
|
|
||||||
|
|
||||||
namespace WallpaperEngine
|
|
||||||
{
|
|
||||||
namespace shaders
|
|
||||||
{
|
|
||||||
using json = nlohmann::json;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A basic shader loader that adds basic function definitions to every loaded shader
|
|
||||||
*/
|
|
||||||
class compiler
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
/**
|
|
||||||
* Basic struct used to define all the shader variables
|
|
||||||
* the compiler will replace in pre-processing time
|
|
||||||
* to make sure the shaders compile under OpenGL
|
|
||||||
*/
|
|
||||||
struct VariableReplacement
|
|
||||||
{
|
|
||||||
const char* original;
|
|
||||||
const char* replacement;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct TypeName
|
|
||||||
{
|
|
||||||
const char* name;
|
|
||||||
int size;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct ShaderParameter
|
|
||||||
{
|
|
||||||
std::string type;
|
|
||||||
std::string variableName;
|
|
||||||
std::string identifierName;
|
|
||||||
void* defaultValue;
|
|
||||||
void* range [2];
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Types of shaders
|
|
||||||
*/
|
|
||||||
enum Type
|
|
||||||
{
|
|
||||||
Type_Vertex = 0,
|
|
||||||
Type_Pixel = 1,
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* List of variables to replace when pre-process is performed
|
|
||||||
*/
|
|
||||||
static std::map<std::string, std::string> sVariableReplacement;
|
|
||||||
/**
|
|
||||||
* Types of variables the pre-processor understands
|
|
||||||
*/
|
|
||||||
static std::vector<std::string> sTypes;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Compiler constructor, loads the given shader file and prepares
|
|
||||||
* the pre-processing and compilation of the shader, adding
|
|
||||||
* required definitions if needed
|
|
||||||
*
|
|
||||||
* @param file The file to load
|
|
||||||
* @param type The type of shader
|
|
||||||
* @param recursive Whether the compiler should add base definitions or not
|
|
||||||
*/
|
|
||||||
compiler (irr::io::path& file, Type type, std::map<std::string, int>* combos, bool recursive = false);
|
|
||||||
/**
|
|
||||||
* Performs the actual pre-compilation/pre-processing over the shader files
|
|
||||||
* This step is kinda big, replaces variables names on sVariableReplacement,
|
|
||||||
* ensures #include directives are correctly handled
|
|
||||||
* and takes care of attribute comments for the wallpaper engine specifics
|
|
||||||
*
|
|
||||||
* @return The shader contents ready to be used by OpenGL
|
|
||||||
*/
|
|
||||||
std::string precompile ();
|
|
||||||
/**
|
|
||||||
* Searches the list of parameters available for the parameter with the given value
|
|
||||||
*
|
|
||||||
* @param identifier The identifier to search for
|
|
||||||
* @return The shader information
|
|
||||||
*/
|
|
||||||
ShaderParameter* findParameter (std::string identifier);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return The list of parameters available for this shader with their default values
|
|
||||||
*/
|
|
||||||
std::vector <ShaderParameter*>& getParameters ();
|
|
||||||
|
|
||||||
private:
|
|
||||||
/**
|
|
||||||
* Checks if there is "str" in the current position without advancing the
|
|
||||||
* iterator in use
|
|
||||||
*
|
|
||||||
* @param str The string to check for
|
|
||||||
* @param it The position to start checking at
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
bool peekString (std::string str, std::string::const_iterator& it);
|
|
||||||
/**
|
|
||||||
* Checks for a semicolon as current character, advancing the iterator
|
|
||||||
* after finding it, otherwise returns an error
|
|
||||||
*
|
|
||||||
* @param it The position where to expect the semicolon
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
bool expectSemicolon (std::string::const_iterator& it);
|
|
||||||
/**
|
|
||||||
* Ignores contiguous space characters in the string advancing the iterator
|
|
||||||
* until the first non-space character
|
|
||||||
*
|
|
||||||
* @param it The iterator to increase
|
|
||||||
*/
|
|
||||||
void ignoreSpaces (std::string::const_iterator& it);
|
|
||||||
/**
|
|
||||||
* Ignores all characters until next line-fee (\n) advancing the interator
|
|
||||||
*
|
|
||||||
* @param it The iterator to increase
|
|
||||||
*/
|
|
||||||
void ignoreUpToNextLineFeed (std::string::const_iterator& it);
|
|
||||||
/**
|
|
||||||
* Ignores all characters until a block comment end is found, advancing the iterator
|
|
||||||
*
|
|
||||||
* @param it The iterator to increase
|
|
||||||
*/
|
|
||||||
void ignoreUpToBlockCommentEnd (std::string::const_iterator& it);
|
|
||||||
/**
|
|
||||||
* Parses the current position as a variable type, extracts it and compares it
|
|
||||||
* to the registered types in the pre-processor, returning it's name if valid
|
|
||||||
* increasing the iterator at the same time
|
|
||||||
*
|
|
||||||
* @param it The position to extract it from
|
|
||||||
*
|
|
||||||
* @return The type name
|
|
||||||
*/
|
|
||||||
std::string extractType (std::string::const_iterator& it);
|
|
||||||
/**
|
|
||||||
* Parses the current position as a variable name, extractig it's name and
|
|
||||||
* increasing the iterator as the name is extracted
|
|
||||||
*
|
|
||||||
* @param it The position to start extracting the variable name from
|
|
||||||
*
|
|
||||||
* @return The variable name
|
|
||||||
*/
|
|
||||||
std::string extractName (std::string::const_iterator& it);
|
|
||||||
/**
|
|
||||||
* Parses the current position as a quoted value, extracting it's value
|
|
||||||
* and increasing the iterator at the same time
|
|
||||||
*
|
|
||||||
* @param it The position to start extracting the value from
|
|
||||||
*
|
|
||||||
* @return The value
|
|
||||||
*/
|
|
||||||
std::string extractQuotedValue (std::string::const_iterator& it);
|
|
||||||
/**
|
|
||||||
* Tries to find the given shader file and compile it
|
|
||||||
*
|
|
||||||
* @param filename The shader's filename
|
|
||||||
*
|
|
||||||
* @return The compiled contents
|
|
||||||
*/
|
|
||||||
std::string lookupShaderFile (std::string filename);
|
|
||||||
/**
|
|
||||||
* Searches for the given symbol in the replace table
|
|
||||||
*
|
|
||||||
* @param symbol The symbol to look for
|
|
||||||
*
|
|
||||||
* @return The symbol it should be replaced with
|
|
||||||
*/
|
|
||||||
std::string lookupReplaceSymbol (std::string symbol);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return Whether the character in the current position is a character or not
|
|
||||||
*/
|
|
||||||
bool isChar (std::string::const_iterator& it);
|
|
||||||
/**
|
|
||||||
* @return Whether the character in the current position is a number or not
|
|
||||||
*/
|
|
||||||
bool isNumeric (std::string::const_iterator& it);
|
|
||||||
/**
|
|
||||||
* Parses a COMBO value to add the proper define to the code
|
|
||||||
*
|
|
||||||
* @param content The parameter configuration
|
|
||||||
*/
|
|
||||||
void parseComboConfiguration (const std::string& content);
|
|
||||||
/**
|
|
||||||
* Parses a parameter extra metadata created by wallpaper engine
|
|
||||||
*
|
|
||||||
* @param type The type of variable to parse
|
|
||||||
* @param name The name of the variable in the shader (for actual variable declaration)
|
|
||||||
* @param content The parameter configuration
|
|
||||||
*/
|
|
||||||
void parseParameterConfiguration (const std::string& type, const std::string& name, const std::string& content);
|
|
||||||
/**
|
|
||||||
* The shader file this instance is loading
|
|
||||||
*/
|
|
||||||
irr::io::path m_file;
|
|
||||||
/**
|
|
||||||
* The original file content
|
|
||||||
*/
|
|
||||||
std::string m_content;
|
|
||||||
/**
|
|
||||||
* The final, compiled content ready to be used by OpenGL
|
|
||||||
*/
|
|
||||||
std::string m_compiledContent;
|
|
||||||
/**
|
|
||||||
* Whether there was any kind of error in the compilation or not
|
|
||||||
*/
|
|
||||||
bool m_error;
|
|
||||||
/**
|
|
||||||
* Extra information about the error (if any)
|
|
||||||
*/
|
|
||||||
std::string m_errorInfo;
|
|
||||||
/**
|
|
||||||
* The type of shader
|
|
||||||
*/
|
|
||||||
Type m_type;
|
|
||||||
/**
|
|
||||||
* The parameters the shader needs
|
|
||||||
*/
|
|
||||||
std::vector <ShaderParameter*> m_parameters;
|
|
||||||
/**
|
|
||||||
* The combos the shader should be generated with
|
|
||||||
*/
|
|
||||||
std::map <std::string, int>* m_combos;
|
|
||||||
/**
|
|
||||||
* Whether this compilation is a recursive one or not
|
|
||||||
*/
|
|
||||||
bool m_recursive;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif /* !__BASIC_SHADER_LOADER_H__ */
|
|
2
main.cpp
2
main.cpp
@ -8,7 +8,7 @@
|
|||||||
#include <SDL_mixer.h>
|
#include <SDL_mixer.h>
|
||||||
#include <SDL.h>
|
#include <SDL.h>
|
||||||
|
|
||||||
#include "WallpaperEngine/shaders/compiler.h"
|
#include "WallpaperEngine/Render/Shaders/Compiler.h"
|
||||||
#include "WallpaperEngine/project.h"
|
#include "WallpaperEngine/project.h"
|
||||||
#include "WallpaperEngine/Irrlicht/Irrlicht.h"
|
#include "WallpaperEngine/Irrlicht/Irrlicht.h"
|
||||||
#include "WallpaperEngine/Irrlicht/CImageLoaderTEX.h"
|
#include "WallpaperEngine/Irrlicht/CImageLoaderTEX.h"
|
||||||
|
Loading…
Reference in New Issue
Block a user