+ Basic parsing for json files on project (just scene, project objects and basic images)

+ Re-structured some code to its (hopefully) final form (shader compiler, file finding, etc)

Signed-off-by: Alexis Maiquez Murcia <almamu@almamu.com>
This commit is contained in:
Alexis Maiquez Murcia 2018-07-06 13:47:11 +02:00
parent c8534b9a6e
commit 1821731d5a
39 changed files with 1772 additions and 966 deletions

File diff suppressed because it is too large Load Diff

View File

@ -1,366 +0,0 @@
#include <irrlicht/irrlicht.h>
#include <iostream>
#include <fstream>
#include <string>
#include "BasicShaderLoader.h"
#include "nier_test.h"
#include "common.h"
BasicShaderLoader::BasicShaderLoader (irr::io::path file, Type type, bool recursive)
{
// begin with an space so it gets ignored properly on parse
if (recursive == false)
{
this->m_content = "#version 120\n"
"#define texSample2D texture2D\n"
"#define frac fract\n"
"vec4 mul(vec4 x, mat4 y) { return x * y; }\n";
}
else
{
this->m_content = "";
}
std::ifstream _in (file.c_str ());
this->m_content.append (std::istreambuf_iterator<char> (_in), std::istreambuf_iterator<char> ());
this->m_type = type;
}
bool BasicShaderLoader::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 BasicShaderLoader::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 BasicShaderLoader::ignoreSpaces(std::string::const_iterator &it)
{
while (it != this->m_content.end() && (*it == ' ' || *it == '\t')) it ++;
}
void BasicShaderLoader::ignoreUpToNextLineFeed (std::string::const_iterator& it)
{
while (it != this->m_content.end() && *it != '\n') it ++;
}
void BasicShaderLoader::ignoreUpToBlockCommentEnd (std::string::const_iterator& it)
{
while (it != this->m_content.end() && this->peekString ("*/", it) == false) it ++;
}
std::string BasicShaderLoader::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 BasicShaderLoader::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 BasicShaderLoader::isChar (std::string::const_iterator& it)
{
return ((*it) >= 'A' && (*it) <= 'Z') || ((*it) >= 'a' && (*it) <= 'z');
}
bool BasicShaderLoader::isNumeric (std::string::const_iterator& it)
{
return (*it) >= '0' && (*it) <= '9';
}
std::string BasicShaderLoader::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 BasicShaderLoader::lookupShaderFile (std::string filename)
{
irr::io::path shaderTest = _example_base_folder; shaderTest += "/"; shaderTest += filename.c_str ();
irr::io::IFileSystem *fs = device->getFileSystem ();
// by default try to load from current folder
// we might want, in the future, to load things from different folders
// to provide standard functionality
if (fs->existFile (shaderTest) == false)
{
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)
BasicShaderLoader loader (shaderTest, this->m_type, true);
return *loader.precompile ();
}
std::string BasicShaderLoader::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* BasicShaderLoader::precompile ()
{
#define BREAK_IF_ERROR if (this->m_error == true) { device->getLogger ()->log ("ERROR COMPILING SHADER"); device->getLogger ()->log (this->m_errorInfo.c_str ()); return nullptr; }
// 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 == '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;
this->ignoreUpToNextLineFeed (it);
this->m_compiledContent.append (begin, it);
device->getLogger ()->log (*it + "asdf");
}
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 ++;
}
}
}
}
device->getLogger ()->log ("Compiled shader output");
device->getLogger ()->log (this->m_compiledContent.c_str ());
return &this->m_compiledContent;
#undef BREAK_IF_ERROR
}
std::map<std::string, std::string> BasicShaderLoader::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> BasicShaderLoader::sTypes =
{
"vec4", "vec3", "vec2", "float"
};

View File

@ -1,61 +0,0 @@
#ifndef __BASIC_SHADER_LOADER_H__
#define __BASIC_SHADER_LOADER_H__
#include <irrlicht/irrlicht.h>
#include <iostream>
#include <vector>
#include <map>
/**
* A basic shader loader that adds basic function definitions to every loaded shader
*/
class BasicShaderLoader
{
public:
struct VariableReplacement
{
const char* original;
const char* replacement;
};
struct TypeName
{
const char* name;
int size;
};
enum Type
{
Type_Vertex = 0,
Type_Pixel = 1,
};
static std::map<std::string, std::string> sVariableReplacement;
static std::vector<std::string> sTypes;
BasicShaderLoader (irr::io::path file, Type type, bool recursive = false);
std::string* precompile ();
private:
bool peekString (std::string str, std::string::const_iterator& it);
bool expectSemicolon (std::string::const_iterator& it);
void ignoreSpaces (std::string::const_iterator& it);
void ignoreUpToNextLineFeed (std::string::const_iterator& it);
void ignoreUpToBlockCommentEnd (std::string::const_iterator& it);
std::string extractType (std::string::const_iterator& it);
std::string extractName (std::string::const_iterator& it);
std::string extractQuotedValue (std::string::const_iterator& it);
std::string lookupShaderFile (std::string filename);
std::string lookupReplaceSymbol (std::string symbol);
bool isChar (std::string::const_iterator& it);
bool isNumeric (std::string::const_iterator& it);
std::string m_content;
std::string m_compiledContent;
bool m_error;
std::string m_errorInfo;
Type m_type;
};
#endif /* !__BASIC_SHADER_LOADER_H__ */

View File

@ -13,6 +13,6 @@ find_package(Irrlicht REQUIRED)
include_directories(${X11_INCLUDE_DIR} ${IRRLICHT_INCLUDE_DIR} .)
add_executable(wallengine main.cpp common.h nier_test.cpp BasicShaderLoader.h BasicShaderLoader.cpp nier_test.h wallpaperengine/Project.cpp wallpaperengine/Project.h wallpaperengine/Scene.cpp wallpaperengine/Scene.h wallpaperengine/Object.cpp wallpaperengine/Object.h)
add_executable(wallengine main.cpp common.h nier_test.cpp wallpaperengine/shaders/compiler.h wallpaperengine/shaders/compiler.cpp nier_test.h wallpaperengine/project.cpp wallpaperengine/project.h wallpaperengine/scene.cpp wallpaperengine/scene.h wallpaperengine/object.cpp wallpaperengine/object.h wallpaperengine/camera.cpp wallpaperengine/camera.h wallpaperengine/core.cpp wallpaperengine/core.h wallpaperengine/image.cpp wallpaperengine/image.h wallpaperengine/object3d.cpp wallpaperengine/object3d.h wallpaperengine/effect.cpp wallpaperengine/effect.h wallpaperengine/material.cpp wallpaperengine/material.h wallpaperengine/fs/fileResolver.cpp wallpaperengine/fs/fileResolver.h wallpaperengine/irrlicht.cpp wallpaperengine/irrlicht.h wallpaperengine/config.cpp wallpaperengine/config.h)
target_link_libraries(wallengine ${X11_LIBRARIES} ${X11_Xxf86vm_LIB} ${OPENGL_LIBRARIES} ${GLUT_LIBRARIES} ${ZLIB_LIBRARIES} ${IRRLICHT_LIBRARY})

View File

@ -1,7 +1,9 @@
#include <iostream>
#include <irrlicht/irrlicht.h>
#include <sstream>
#include <wallpaperengine/config.h>
#include "nier_test.h"
#include "wallpaperengine/irrlicht.h"
int WinID = 0;
@ -22,11 +24,9 @@ int main(int argc, char* argv[])
return game_test_main ();
}
irr::IrrlichtDevice* device = nullptr;
irr::video::IVideoDriver* driver = nullptr;
irr::SIrrlichtCreationParameters _irr_params;
int init_driver ()
int init_irrlicht()
{
// prepare basic configuration for irrlicht
_irr_params.AntiAlias = 8;
@ -46,26 +46,34 @@ int init_driver ()
_irr_params.LoggingLevel = irr::ELL_DEBUG;
_irr_params.WindowId = reinterpret_cast<void*> (WinID);
device = irr::createDeviceEx (_irr_params);
wp::irrlicht::device = irr::createDeviceEx (_irr_params);
if (device == nullptr)
if (wp::irrlicht::device == nullptr)
{
return 1;
}
device->setWindowCaption (L"Test game");
driver = device->getVideoDriver();
wp::irrlicht::device->setWindowCaption (L"Test game");
wp::irrlicht::driver = wp::irrlicht::device->getVideoDriver();
return 0;
}
void preconfigure_wallpaper_engine ()
{
wp::config::path::base = wp::irrlicht::device->getFileSystem ()->getAbsolutePath ("../");
wp::config::path::resources = wp::config::path::base + "/res";
wp::config::path::shaders = wp::config::path::resources + "/shaders";
}
int game_test_main ()
{
if (init_driver())
if (init_irrlicht())
{
return 1;
}
preconfigure_wallpaper_engine ();
nier_test ();
return 0;

View File

@ -3,8 +3,10 @@
#include <iostream>
#include "common.h"
#include "BasicShaderLoader.h"
#include "wallpaperengine/Project.h"
#include "wallpaperengine/shaders/compiler.h"
#include "wallpaperengine/fs/fileResolver.h"
#include "wallpaperengine/project.h"
#include "wallpaperengine/irrlicht.h"
irr::io::path _example_base_folder = "../res/";
irr::f32 g_AnimationSpeed = 0.1f;
@ -127,17 +129,30 @@ public:
int nier_test ()
{
irr::io::path _wp_engine_folder = "/home/almamu/Development/tmp/nier__automata_-_become_as_gods_edition";
irr::io::path _wp_engine_folder = "/home/almamu/Downloads/nier__automata_-_become_as_gods_edition/";
Project* wp_project = new Project (_wp_engine_folder);
// set our working directory
wp::fs::resolver.changeWorkingDirectory (_wp_engine_folder);
// also append base folder for resources
wp::fs::resolver.appendEnvironment ("");
irr::io::path _water_example = _example_base_folder; _water_example += "materials/water-intact.png";
irr::io::path _mud_example = _example_base_folder; _mud_example += "materials/plant-on-water.png";
irr::io::path _background_example = _example_base_folder; _background_example += "materials/top-part.png";
irr::io::path _waterripple_normal = _example_base_folder; _waterripple_normal += "materials/effects/waterripplenormal.png";
irr::io::path _waterripple_frag_shader = _example_base_folder; _waterripple_frag_shader += "shaders/effects/waterripple_opengl.frag";
irr::io::path _waterripple_vert_shader = _example_base_folder; _waterripple_vert_shader += "shaders/effects/waterripple_opengl.vert";
irr::io::path _white = _example_base_folder; _white += "materials/white.png";
wp::project* wp_project = new wp::project (_wp_engine_folder);
wp::fs::resolver.changeWorkingDirectory ("../res");
irr::io::path _water_example = wp::fs::resolver.resolve ("materials/water-intact.png");
irr::io::path _mud_example = wp::fs::resolver.resolve ("materials/plant-on-water.png");
irr::io::path _background_example = wp::fs::resolver.resolve ("materials/top-part.png");
irr::io::path _waterripple_normal = wp::fs::resolver.resolve ("materials/effects/waterripplenormal.png");
irr::io::path _waterripple_frag_shader = wp::fs::resolver.resolve ("shaders/effects/waterripple_opengl.frag");
irr::io::path _waterripple_vert_shader = wp::fs::resolver.resolve ("shaders/effects/waterripple_opengl.vert");
irr::io::path _white = wp::fs::resolver.resolve ("materials/white.png");
// irr::io::path _water_example = _example_base_folder; _water_example += "materials/water-intact.png";
// irr::io::path _mud_example = _example_base_folder; _mud_example += "materials/plant-on-water.png";
// irr::io::path _background_example = _example_base_folder; _background_example += "materials/top-part.png";
// irr::io::path _waterripple_normal = _example_base_folder; _waterripple_normal += "materials/effects/waterripplenormal.png";
// irr::io::path _waterripple_frag_shader = _example_base_folder; _waterripple_frag_shader += "shaders/effects/waterripple_opengl.frag";
// irr::io::path _waterripple_vert_shader = _example_base_folder; _waterripple_vert_shader += "shaders/effects/waterripple_opengl.vert";
// irr::io::path _white = _example_base_folder; _white += "materials/white.png";
/*irr::video::E_DRIVER_TYPE driverType = irr::video::E_DRIVER_TYPE::EDT_OPENGL;
device = irr::createDevice (driverType, irr::core::dimension2d<uint32_t>(1280, 720));
@ -146,19 +161,19 @@ int nier_test ()
driver = device->getVideoDriver ();*/
// check for ps and vs support
if (driver->queryFeature (irr::video::EVDF_PIXEL_SHADER_1_1) == false && driver->queryFeature (irr::video::EVDF_ARB_FRAGMENT_PROGRAM_1) == false)
if (wp::irrlicht::driver->queryFeature (irr::video::EVDF_PIXEL_SHADER_1_1) == false && wp::irrlicht::driver->queryFeature (irr::video::EVDF_ARB_FRAGMENT_PROGRAM_1) == false)
{
device->getLogger ()->log ("WARNING: Pixel shaders disabled because of missing driver/hardware support");
wp::irrlicht::device->getLogger ()->log ("WARNING: Pixel shaders disabled because of missing driver/hardware support");
_waterripple_frag_shader = "";
}
if (driver->queryFeature (irr::video::EVDF_VERTEX_SHADER_1_1) == false && driver->queryFeature (irr::video::EVDF_ARB_VERTEX_PROGRAM_1) == false)
if (wp::irrlicht::driver->queryFeature (irr::video::EVDF_VERTEX_SHADER_1_1) == false && wp::irrlicht::driver->queryFeature (irr::video::EVDF_ARB_VERTEX_PROGRAM_1) == false)
{
device->getLogger ()->log ("WARNING: Vertex shaders disabled because of missing driver/hardware support");
wp::irrlicht::device->getLogger ()->log ("WARNING: Vertex shaders disabled because of missing driver/hardware support");
_waterripple_vert_shader = "";
}
irr::video::IGPUProgrammingServices* gpuProgrammingServices = driver->getGPUProgrammingServices ();
irr::video::IGPUProgrammingServices* gpuProgrammingServices = wp::irrlicht::driver->getGPUProgrammingServices ();
int32_t materialType1 = 0;
@ -166,12 +181,12 @@ int nier_test ()
{
MyShaderCallback* shader = new MyShaderCallback ();
BasicShaderLoader _vert(_waterripple_vert_shader, BasicShaderLoader::Type::Type_Vertex);
BasicShaderLoader _frag(_waterripple_frag_shader, BasicShaderLoader::Type::Type_Pixel);
wp::shaders::compiler _vert(_waterripple_vert_shader, wp::shaders::compiler::Type::Type_Vertex);
wp::shaders::compiler _frag(_waterripple_frag_shader, wp::shaders::compiler::Type::Type_Pixel);
materialType1 = gpuProgrammingServices->addHighLevelShaderMaterial(
_vert.precompile ()->c_str (), "vertexMain", irr::video::EVST_VS_2_0,
_frag.precompile ()->c_str (), "pixelMain", irr::video::EPST_PS_2_0,
_vert.precompile ().c_str (), "vertexMain", irr::video::EVST_VS_2_0,
_frag.precompile ().c_str (), "pixelMain", irr::video::EPST_PS_2_0,
shader, irr::video::EMT_TRANSPARENT_ALPHA_CHANNEL, 0, irr::video::EGSL_DEFAULT
);
@ -179,14 +194,14 @@ int nier_test ()
}
// load some basic textures
irr::video::ITexture* waterTexture = driver->getTexture (_water_example.c_str ());
irr::video::ITexture* mudTexture = driver->getTexture (_mud_example.c_str ());
irr::video::ITexture* backgroundExample = driver->getTexture (_background_example.c_str ());
irr::video::ITexture* waterRippleNormalTexture = driver->getTexture (_waterripple_normal.c_str ());
irr::video::ITexture* whiteTexture = driver->getTexture (_white.c_str ());
irr::video::ITexture* waterTexture = wp::irrlicht::driver->getTexture (_water_example.c_str ());
irr::video::ITexture* mudTexture = wp::irrlicht::driver->getTexture (_mud_example.c_str ());
irr::video::ITexture* backgroundExample = wp::irrlicht::driver->getTexture (_background_example.c_str ());
irr::video::ITexture* waterRippleNormalTexture = wp::irrlicht::driver->getTexture (_waterripple_normal.c_str ());
irr::video::ITexture* whiteTexture = wp::irrlicht::driver->getTexture (_white.c_str ());
// get scene manager
irr::scene::ISceneManager* sceneManager = device->getSceneManager ();
irr::scene::ISceneManager* sceneManager = wp::irrlicht::device->getSceneManager ();
sceneManager->addCameraSceneNode (0, irr::core::vector3df (0.0f, 0.0f, -_map_size.Z), irr::core::vector3df (0.0f, 0.0f, _map_size.Z));
@ -211,35 +226,33 @@ int nier_test ()
irr::core::matrix4 identity; identity.makeIdentity ();
irr::core::matrix4 orthoProjection; orthoProjection.buildProjectionMatrixOrthoLH (1.0f, 1.0f, 0.0f, 1.0f);
driver->setTransform (irr::video::ETS_PROJECTION, orthoProjection);
driver->setTransform (irr::video::ETS_VIEW, identity);
driver->setTransform (irr::video::ETS_WORLD, identity);
wp::irrlicht::driver->setTransform (irr::video::ETS_PROJECTION, orthoProjection);
wp::irrlicht::driver->setTransform (irr::video::ETS_VIEW, identity);
wp::irrlicht::driver->setTransform (irr::video::ETS_WORLD, identity);
int32_t lastTime = 0;
int32_t minimumTime = 1000 / 90;
int32_t currentTime = 0;
while (device->run () && driver)
while (wp::irrlicht::device->run () && wp::irrlicht::driver)
{
// if (device->isWindowActive ())
{
currentTime = device->getTimer ()->getTime ();
currentTime = wp::irrlicht::device->getTimer ()->getTime ();
g_Time = currentTime / 1000.0f;
if (currentTime - lastTime > minimumTime)
{
driver->beginScene (true, true, irr::video::SColor(0, 0, 0, 0));
wp::irrlicht::driver->beginScene (true, true, irr::video::SColor(0, 0, 0, 0));
sceneManager->drawAll ();
driver->endScene ();
wp::irrlicht::driver->endScene ();
lastTime = currentTime;
}
else
{
device->sleep (1, false);
wp::irrlicht::device->sleep (1, false);
}
// printf ("FPS: %d\n", driver->getFPS ());
}
}

View File

@ -1,45 +0,0 @@
#include <irrlicht/irrlicht.h>
#include <iostream>
#include <fstream>
#include <nlohmann/json.hpp>
#include "Object.h"
using json = nlohmann::json;
Object::Object (json json_data)
{
json::const_iterator angles = json_data.find ("angles");
json::const_iterator image = json_data.find ("image");
json::const_iterator id = json_data.find ("id");
json::const_iterator visible = json_data.find ("visible");
json::const_iterator model = json_data.find ("model");
if (angles != json_data.end () && angles.value ().is_null() == false)
{
this->m_angles = json_data ["angles"];
}
if (image != json_data.end () && image.value ().is_null() == false)
{
this->m_image = json_data ["image"];
}
if (id != json_data.end () && id.value ().is_null() == false)
{
this->m_id = json_data ["id"];
}
if (visible != json_data.end () && visible.value ().is_null() == false)
{
this->m_visible = json_data ["visible"];
}
else
{
this->m_visible = true;
}
if (model != json_data.end () && model.value ().is_null() == false)
{
this->m_model = json_data ["model"];
}
}

View File

@ -1,26 +0,0 @@
#ifndef WALLENGINE_OBJECT_H
#define WALLENGINE_OBJECT_H
#include <iostream>
#include <irrlicht/irrlicht.h>
#include <nlohmann/json.hpp>
using json = nlohmann::json;
class Object
{
public:
Object (json json_data);
private:
int m_id;
bool m_visible;
std::string m_model;
std::string m_angles;
std::string m_image;
};
#endif //WALLENGINE_OBJECT_H

View File

@ -1,39 +0,0 @@
#include <irrlicht/irrlicht.h>
#include <iostream>
#include <fstream>
#include "Project.h"
Project::Project (irr::io::path baseDirectory)
{
irr::io::path projectFile = baseDirectory + "/project.json";
std::ifstream _in (projectFile.c_str ());
this->m_content = "";
this->m_content.append (std::istreambuf_iterator<char> (_in), std::istreambuf_iterator<char> ());
this->m_projectFile = json::parse (this->m_content);
json::const_iterator file_it = this->m_projectFile.find ("file");
json::const_iterator name_it = this->m_projectFile.find ("title");
json::const_iterator type_it = this->m_projectFile.find ("type");
if (file_it != this->m_projectFile.end ())
{
// load scene file
this->m_file = file_it.value ();
this->m_file = baseDirectory.c_str ();
this->m_file += "/";
this->m_file += this->m_projectFile ["file"];
this->m_scene = new Scene (this->m_file.c_str ());
}
if (type_it != this->m_projectFile.end ())
{
this->m_type = type_it.value ();
}
if (name_it != this->m_projectFile.end ())
{
this->m_title = name_it.value ();
}
}

View File

@ -1,26 +0,0 @@
#ifndef WALLENGINE_PROJECT_H
#define WALLENGINE_PROJECT_H
#include <irrlicht/irrlicht.h>
#include <nlohmann/json.hpp>
#include "Scene.h"
using json = nlohmann::json;
class Project
{
public:
Project (irr::io::path baseDirectory);
private:
json m_projectFile;
std::string m_content;
std::string m_title;
std::string m_type;
std::string m_file;
Scene* m_scene;
};
#endif //WALLENGINE_PROJECT_H

View File

@ -1,31 +0,0 @@
#include <irrlicht/irrlicht.h>
#include <iostream>
#include <fstream>
#include <nlohmann/json.hpp>
#include "Scene.h"
using json = nlohmann::json;
Scene::Scene(irr::io::path file)
{
std::ifstream _in (file.c_str ());
this->m_content = "";
this->m_content.append (std::istreambuf_iterator<char> (_in), std::istreambuf_iterator<char> ());
this->m_json = json::parse (this->m_content);
// check basic elements
json::const_iterator camera_it = this->m_json.find ("camera");
json::const_iterator general_it = this->m_json.find ("general");
json::const_iterator objects_it = this->m_json.find ("objects");
if (objects_it != this->m_json.end () && objects_it.value ().is_array() == true)
{
json::const_iterator cur = this->m_json ["objects"].begin ();
json::const_iterator end = this->m_json ["objects"].end ();
for (; cur != end; cur ++)
{
this->m_objects.push_back (new Object (*cur));
}
}
}

View File

@ -1,24 +0,0 @@
#ifndef WALLENGINE_SCENE_H
#define WALLENGINE_SCENE_H
#include <iostream>
#include <irrlicht/irrlicht.h>
#include <nlohmann/json.hpp>
#include "Object.h"
using json = nlohmann::json;
class Scene
{
public:
Scene(irr::io::path file);
private:
irr::io::path m_file;
std::string m_content;
std::vector<Object*> m_objects;
json m_json;
};
#endif //WALLENGINE_SCENE_H

View File

@ -0,0 +1,34 @@
#include "camera.h"
#include "core.h"
namespace wp
{
camera::camera (json json_data)
{
json::const_iterator center_it = json_data.find ("center");
json::const_iterator eye_it = json_data.find ("eye");
json::const_iterator up_it = json_data .find ("up");
if (center_it != json_data.end ())
{
// get center value first
std::string center = *center_it;
this->m_center = core::ato3vf(center.c_str());
}
if (eye_it != json_data.end ())
{
std::string eye = *eye_it;
this->m_eye = core::ato3vf(eye.c_str());
}
if (up_it != json_data.end ())
{
std::string up = *up_it;
this->m_up = core::ato3vf(up.c_str());
}
}
}

20
wallpaperengine/camera.h Normal file
View File

@ -0,0 +1,20 @@
#ifndef WALLENGINE_CAMERA_H
#define WALLENGINE_CAMERA_H
#include <irrlicht/irrlicht.h>
#include <nlohmann/json.hpp>
namespace wp
{
using json = nlohmann::json;
class camera
{
public:
camera (json json_data);
private:
irr::core::vector3df m_center, m_eye, m_up;
};
};
#endif //WALLENGINE_CAMERA_H

View File

@ -0,0 +1,15 @@
//
// Created by almamu on 6/07/18.
//
#include "config.h"
namespace wp
{
namespace config
{
static irr::io::path path::resources;
static irr::io::path path::base;
static irr::io::path path::shaders;
}
}

22
wallpaperengine/config.h Normal file
View File

@ -0,0 +1,22 @@
#ifndef WALLENGINE_CONFIG_H
#define WALLENGINE_CONFIG_H
#include <string>
#include <irrlicht/path.h>
namespace wp
{
namespace config
{
class path
{
public:
static irr::io::path resources;
static irr::io::path base;
static irr::io::path shaders;
};
};
}
#endif //WALLENGINE_CONFIG_H

22
wallpaperengine/core.cpp Normal file
View File

@ -0,0 +1,22 @@
#include <irrlicht/fast_atof.h>
#include "core.h"
namespace wp
{
irr::core::vector3df core::ato3vf(const char *str)
{
irr::f32 x = irr::core::fast_atof (str, &str); while (*str == ' ') str ++;
irr::f32 y = irr::core::fast_atof (str, &str); while (*str == ' ') str ++;
irr::f32 z = irr::core::fast_atof (str, &str);
return irr::core::vector3df (x, y, z);
}
irr::core::vector2df core::ato2vf (const char *str)
{
irr::f32 x = irr::core::fast_atof (str, &str); while (*str == ' ') str ++;
irr::f32 y = irr::core::fast_atof (str, &str);
return irr::core::vector2df (x, y);
}
}

19
wallpaperengine/core.h Normal file
View File

@ -0,0 +1,19 @@
#ifndef WALLENGINE_CORE_H
#define WALLENGINE_CORE_H
#include <iostream>
#include <irrlicht/vector3d.h>
#include <irrlicht/vector2d.h>
namespace wp
{
class core
{
public:
static irr::core::vector3df ato3vf (const char *str);
static irr::core::vector2df ato2vf (const char *str);
};
};
#endif //WALLENGINE_CORE_H

View File

@ -0,0 +1,17 @@
#include "effect.h"
namespace wp
{
effect::effect (json json_data, irr::io::path basepath)
{
json::const_iterator file = json_data.find ("file");
json::const_iterator pass = json_data.find ("passes");
if (file != json_data.end () && (*file).is_string () == true)
{
std::string file_s = *file;
this->m_file = basepath + "/" + file_s.c_str ();
}
}
};

23
wallpaperengine/effect.h Normal file
View File

@ -0,0 +1,23 @@
#ifndef WALLENGINE_EFFECT_H
#define WALLENGINE_EFFECT_H
#include <nlohmann/json.hpp>
#include <irrlicht/path.h>
namespace wp
{
using json = nlohmann::json;
class effect
{
public:
effect (json json_data, irr::io::path basepath);
private:
irr::io::path m_file;
std::vector<void*> m_passes;
};
}
#endif //WALLENGINE_EFFECT_H

View File

@ -0,0 +1,86 @@
#include <sys/stat.h>
#include <wallpaperengine/irrlicht.h>
#include "fileResolver.h"
namespace wp
{
namespace fs
{
fileResolver::fileResolver ()
{
this->m_environment.push_back (".");
}
fileResolver::fileResolver (std::vector<irr::io::path> environment)
{
this->m_environment.push_back (".");
this->m_environment.insert (this->m_environment.end (), environment.begin (), environment.end ());
}
void fileResolver::appendEnvironment (irr::io::path path)
{
this->m_environment.push_back (wp::irrlicht::device->getFileSystem ()->getAbsolutePath (path));
}
void fileResolver::removeEnvironment(irr::io::path path)
{
std::vector<irr::io::path>::const_iterator cur = this->m_environment.begin ();
std::vector<irr::io::path>::const_iterator end = this->m_environment.end ();
irr::io::path absolute = wp::irrlicht::device->getFileSystem ()->getAbsolutePath (path);
for (; cur != end; cur ++)
{
if (*cur == path)
{
this->m_environment.erase (cur);
return;
}
}
}
void fileResolver::prependEnvironment (irr::io::path path)
{
this->m_environment.insert (
this->m_environment.begin (),
wp::irrlicht::device->getFileSystem ()->getAbsolutePath (path)
);
}
void fileResolver::changeWorkingDirectory (irr::io::path newpath)
{
this->m_environment.erase (this->m_environment.begin ());
this->prependEnvironment (newpath);
}
fileResolver fileResolver::clone ()
{
return fileResolver (this->m_environment);
}
irr::io::path fileResolver::resolve (irr::io::path name)
{
std::vector<irr::io::path>::const_iterator cur = this->m_environment.begin ();
std::vector<irr::io::path>::const_iterator end = this->m_environment.end ();
irr::io::path tmp = "";
// try to resolve the path
for (; cur != end; cur ++)
{
tmp = *cur;
tmp += "/";
tmp += name;
struct stat buffer;
if (stat (tmp.c_str (), &buffer) == 0)
{
wp::irrlicht::device->getLogger ()->log ("Resolved file to", tmp.c_str ());
return tmp;
}
}
wp::irrlicht::device->getLogger ()->log ("Failed resolving file ", name.c_str ());
return "";
}
}
}

View File

@ -0,0 +1,36 @@
#ifndef WALLENGINE_RESOLVER_H
#define WALLENGINE_RESOLVER_H
#include <string>
#include <vector>
#include <irrlicht/path.h>
namespace wp
{
namespace fs
{
class fileResolver
{
public:
fileResolver ();
fileResolver (std::vector<irr::io::path> environment);
void appendEnvironment (irr::io::path path);
void removeEnvironment (irr::io::path path);
void changeWorkingDirectory (irr::io::path newpath);
fileResolver clone ();
irr::io::path resolve (irr::io::path name);
protected:
void prependEnvironment (irr::io::path path);
private:
std::vector<irr::io::path> m_environment;
};
static fileResolver resolver;
}
}
#endif //WALLENGINE_RESOLVER_H

24
wallpaperengine/image.cpp Normal file
View File

@ -0,0 +1,24 @@
#include <irrlicht/path.h>
#include "object3d.h"
#include "image.h"
namespace wp
{
image::image (json json_data, irr::io::path basepath) : object3d (object3d::Type::Type_Image)
{
json::const_iterator visible = json_data.find ("visible");
json::const_iterator file = json_data.find ("image");
if (visible != json_data.end () && (*visible).is_boolean () == true)
{
this->m_visible = *visible;
}
if (file != json_data.end () && (*file).is_string () == true)
{
std::string file_s = *file;
this->m_file = basepath + "/" + file_s.c_str ();
}
}
}

23
wallpaperengine/image.h Normal file
View File

@ -0,0 +1,23 @@
#ifndef WALLENGINE_MODEL_H
#define WALLENGINE_MODEL_H
#include <nlohmann/json.hpp>
#include <irrlicht/path.h>
namespace wp
{
using json = nlohmann::json;
class image : public object3d
{
public:
image(json json_data, irr::io::path basepath);
private:
bool m_visible;
irr::io::path m_file;
};
};
#endif //WALLENGINE_MODEL_H

View File

@ -0,0 +1,7 @@
#include "irrlicht.h"
namespace wp
{
irr::video::IVideoDriver* irrlicht::driver = nullptr;
irr::IrrlichtDevice* irrlicht::device = nullptr;
}

View File

@ -0,0 +1,17 @@
#ifndef WALLENGINE_IRRLICHT_H
#define WALLENGINE_IRRLICHT_H
#include <irrlicht/irrlicht.h>
namespace wp
{
class irrlicht
{
public:
static irr::video::IVideoDriver* driver;
static irr::IrrlichtDevice* device;
};
}
#endif //WALLENGINE_IRRLICHT_H

View File

@ -0,0 +1,13 @@
//
// Created by almamu on 6/07/18.
//
#include "material.h"
namespace wp
{
material::material(json json_data)
{
}
};

View File

@ -0,0 +1,17 @@
#ifndef WALLENGINE_MATERIAL_H
#define WALLENGINE_MATERIAL_H
#include <nlohmann/json.hpp>
namespace wp
{
using json = nlohmann::json;
class material
{
material(json json_data);
};
}
#endif //WALLENGINE_MATERIAL_H

118
wallpaperengine/object.cpp Normal file
View File

@ -0,0 +1,118 @@
#include <irrlicht/irrlicht.h>
#include <iostream>
#include <fstream>
#include <nlohmann/json.hpp>
#include "object.h"
#include "core.h"
#include "object3d.h"
#include "image.h"
namespace wp
{
using json = nlohmann::json;
object::object (json json_data, irr::io::path basepath)
{
json::const_iterator size = json_data.find ("size");
json::const_iterator scale = json_data.find ("scale");
json::const_iterator origin = json_data.find ("origin");
if (size != json_data.end () && size.value ().is_string () == true)
{
std::string size_s = *size;
this->m_size = core::ato2vf (size_s.c_str ());
}
if (scale != json_data.end () && scale.value ().is_string () == true)
{
std::string scale_s = *scale;
this->m_scale = core::ato3vf (scale_s.c_str ());
}
if (origin != json_data.end () && origin.value ().is_string () == true)
{
std::string origin_s = *origin;
this->m_origin = core::ato3vf (origin_s.c_str ());
}
json::const_iterator angles = json_data.find ("angles");
json::const_iterator id = json_data.find ("id");
json::const_iterator name = json_data.find ("name");
if (angles != json_data.end () && (*angles).is_string () == true)
{
std::string angles_s = *angles;
this->m_angles = core::ato3vf (angles_s.c_str ());
}
if (id != json_data.end () && (*id).is_null () == false)
{
this->m_id = *id;
}
if (name != json_data.end () && (*name).is_string () == true)
{
this->m_name = *name;
}
json::const_iterator image = json_data.find ("image");
json::const_iterator model = json_data.find ("model");
json::const_iterator particle = json_data.find ("particle");
object3d::Type _type = object3d::Type::Type_None;
if (image != json_data.end () && (*image).is_null () == false)
{
_type = object3d::Type::Type_Image;
}
if (model != json_data.end () && (*model).is_null () == false)
{
_type = object3d::Type::Type_Model;
}
if (particle != json_data.end () && (*particle).is_null () == false)
{
_type = object3d::Type::Type_Particle;
}
switch (_type)
{
case object3d::Type::Type_Image:
this->m_object3d = new wp::image (json_data, basepath);
break;
case object3d::Type::Type_Model:
break;
case object3d::Type::Type_Particle:
break;
}
json::const_iterator effects = json_data.find ("effects");
if (effects != json_data.end () && (*effects).is_array () == true)
{
json::const_iterator cur = (*effects).begin ();
json::const_iterator end = (*effects).end ();
for (; cur != end; cur ++)
{
this->m_effects.push_back (new effect (*cur, basepath));
}
}
}
object::~object ()
{
if (this->m_object3d != nullptr)
{
delete this->m_object3d;
}
}
}

36
wallpaperengine/object.h Normal file
View File

@ -0,0 +1,36 @@
#ifndef WALLENGINE_OBJECT_H
#define WALLENGINE_OBJECT_H
#include <iostream>
#include <irrlicht/irrlicht.h>
#include <nlohmann/json.hpp>
#include "effect.h"
namespace wp
{
using json = nlohmann::json;
class object3d;
class object
{
public:
object (json json_data, irr::io::path basepath);
~object ();
private:
int m_id;
std::string m_name;
irr::core::vector2df m_size;
irr::core::vector3df m_scale;
irr::core::vector3df m_origin;
irr::core::vector3df m_angles;
wp::object3d* m_object3d;
std::vector<effect*> m_effects;
};
};
#endif //WALLENGINE_OBJECT_H

View File

@ -0,0 +1,25 @@
#include "object3d.h"
#include "image.h"
namespace wp
{
object3d::object3d (object3d::Type type)
{
this->m_type = type;
}
template <class T> T* object3d::as()
{
return (T*) this;
}
template <class T> bool object3d::is()
{
return false;
}
template <> bool object3d::is<image>()
{
return this->m_type == Type::Type_Image;
}
}

View File

@ -0,0 +1,27 @@
#ifndef WALLENGINE_OBJECT3D_H
#define WALLENGINE_OBJECT3D_H
namespace wp
{
class object3d
{
public:
enum Type
{
Type_Image = 0,
Type_Model = 1,
Type_Particle = 2,
Type_None = 3
};
object3d (Type type);
template <class T> T* as();
template <class T> bool is();
private:
Type m_type;
};
};
#endif //WALLENGINE_OBJECT3D_H

View File

@ -0,0 +1,42 @@
#include <irrlicht/irrlicht.h>
#include <iostream>
#include <fstream>
#include "project.h"
namespace wp
{
project::project (irr::io::path baseDirectory)
{
irr::io::path projectFile = baseDirectory + "/project.json";
std::ifstream _in (projectFile.c_str ());
this->m_content = "";
this->m_content.append (std::istreambuf_iterator<char> (_in), std::istreambuf_iterator<char> ());
this->m_projectFile = json::parse (this->m_content);
json::const_iterator file_it = this->m_projectFile.find ("file");
json::const_iterator name_it = this->m_projectFile.find ("title");
json::const_iterator type_it = this->m_projectFile.find ("type");
if (file_it != this->m_projectFile.end ())
{
// load scene file
this->m_file = file_it.value ();
this->m_file = baseDirectory.c_str ();
this->m_file += "/";
this->m_file += this->m_projectFile ["file"];
this->m_scene = new scene (this->m_file.c_str (), baseDirectory);
}
if (type_it != this->m_projectFile.end ())
{
this->m_type = type_it.value ();
}
if (name_it != this->m_projectFile.end ())
{
this->m_title = name_it.value ();
}
}
}

28
wallpaperengine/project.h Normal file
View File

@ -0,0 +1,28 @@
#ifndef WALLENGINE_PROJECT_H
#define WALLENGINE_PROJECT_H
#include <irrlicht/irrlicht.h>
#include <nlohmann/json.hpp>
#include "scene.h"
namespace wp
{
using json = nlohmann::json;
class project
{
public:
project (irr::io::path baseDirectory);
private:
json m_projectFile;
std::string m_content;
std::string m_title;
std::string m_type;
std::string m_file;
scene* m_scene;
};
};
#endif //WALLENGINE_PROJECT_H

58
wallpaperengine/scene.cpp Normal file
View File

@ -0,0 +1,58 @@
#include <irrlicht/irrlicht.h>
#include <iostream>
#include <fstream>
#include <nlohmann/json.hpp>
#include "scene.h"
#include "camera.h"
namespace wp
{
using json = nlohmann::json;
scene::scene (irr::io::path file, irr::io::path basepath)
{
std::ifstream _in (file.c_str ());
this->m_content = "";
this->m_content.append (std::istreambuf_iterator<char> (_in), std::istreambuf_iterator<char> ());
this->m_json = json::parse (this->m_content);
// check basic elements
json::const_iterator camera_it = this->m_json.find ("camera");
json::const_iterator general_it = this->m_json.find ("general");
json::const_iterator objects_it = this->m_json.find ("objects");
if (camera_it != this->m_json.end () && objects_it.value ().is_array () == true)
{
this->m_camera = new camera (*camera_it);
}
if (objects_it != this->m_json.end () && objects_it.value ().is_array () == true)
{
json::const_iterator cur = this->m_json ["objects"].begin ();
json::const_iterator end = this->m_json ["objects"].end ();
for (; cur != end; cur ++)
{
this->m_objects.push_back (new object (*cur, basepath));
}
}
}
scene::~scene ()
{
// free memory used by the objects
std::vector<object*>::const_iterator cur = this->m_objects.begin ();
std::vector<object*>::const_iterator end = this->m_objects.end ();
for (; cur != end; cur ++)
{
delete *cur;
}
// remove elements from the vector
this->m_objects.erase (this->m_objects.begin (), this->m_objects.end ());
// free camera
delete this->m_camera;
}
}

29
wallpaperengine/scene.h Normal file
View File

@ -0,0 +1,29 @@
#ifndef WALLENGINE_SCENE_H
#define WALLENGINE_SCENE_H
#include <iostream>
#include <irrlicht/irrlicht.h>
#include <nlohmann/json.hpp>
#include "object.h"
#include "camera.h"
namespace wp
{
using json = nlohmann::json;
class scene
{
public:
scene (irr::io::path file, irr::io::path basepath);
~scene ();
private:
irr::io::path m_file;
std::string m_content;
camera* m_camera;
std::vector<object*> m_objects;
json m_json;
};
};
#endif //WALLENGINE_SCENE_H

View File

@ -0,0 +1,380 @@
#include <irrlicht/irrlicht.h>
#include <iostream>
#include <fstream>
#include <string>
#include <wallpaperengine/config.h>
#include "compiler.h"
#include "nier_test.h"
#include "common.h"
#include "../irrlicht.h"
#include "../fs/fileResolver.h"
namespace wp
{
namespace shaders
{
compiler::compiler (irr::io::path file, Type type, bool recursive)
{
// begin with an space so it gets ignored properly on parse
if (recursive == false)
{
this->m_content = "#version 120\n"
"#define texSample2D texture2D\n"
"#define frac fract\n"
"vec4 mul(vec4 x, mat4 y) { return x * y; }\n";
}
else
{
this->m_content = "";
}
std::ifstream _in (file.c_str ());
this->m_content.append (std::istreambuf_iterator<char> (_in), std::istreambuf_iterator<char> ());
this->m_type = type;
this->m_resolver = wp::fs::resolver.clone ();
this->m_resolver.appendEnvironment (wp::config::path::shaders);
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)
{
irr::io::path shader = this->m_resolver.resolve (filename.c_str ());
irr::io::IFileSystem *fs = wp::irrlicht::device->getFileSystem ();
// by default try to load from current folder
// we might want, in the future, to load things from different folders
// to provide standard functionality
if (fs->existFile (shader) == false)
{
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, 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) { wp::irrlicht::device->getLogger ()->log ("ERROR COMPILING SHADER"); wp::irrlicht::device->getLogger ()->log (this->m_errorInfo.c_str ()); 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 == '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;
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 ++;
}
}
}
}
wp::irrlicht::device->getLogger ()->log ("Compiled shader output for", this->m_file.c_str ());
wp::irrlicht::device->getLogger ()->log (this->m_compiledContent.c_str ());
return this->m_compiledContent;
#undef BREAK_IF_ERROR
}
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"
};
}
}

View File

@ -0,0 +1,71 @@
#ifndef __BASIC_SHADER_LOADER_H__
#define __BASIC_SHADER_LOADER_H__
#include <irrlicht/irrlicht.h>
#include <iostream>
#include <vector>
#include <map>
#include "../fs/fileResolver.h"
namespace wp
{
namespace shaders
{
/**
* A basic shader loader that adds basic function definitions to every loaded shader
*/
class compiler
{
public:
struct VariableReplacement
{
const char* original;
const char* replacement;
};
struct TypeName
{
const char* name;
int size;
};
enum Type
{
Type_Vertex = 0,
Type_Pixel = 1,
};
static std::map<std::string, std::string> sVariableReplacement;
static std::vector<std::string> sTypes;
compiler (irr::io::path file, Type type, bool recursive = false);
std::string precompile();
private:
bool peekString (std::string str, std::string::const_iterator& it);
bool expectSemicolon (std::string::const_iterator& it);
void ignoreSpaces (std::string::const_iterator& it);
void ignoreUpToNextLineFeed (std::string::const_iterator& it);
void ignoreUpToBlockCommentEnd (std::string::const_iterator& it);
std::string extractType (std::string::const_iterator& it);
std::string extractName (std::string::const_iterator& it);
std::string extractQuotedValue (std::string::const_iterator& it);
std::string lookupShaderFile (std::string filename);
std::string lookupReplaceSymbol (std::string symbol);
bool isChar (std::string::const_iterator& it);
bool isNumeric (std::string::const_iterator& it);
irr::io::path m_file;
std::string m_content;
std::string m_compiledContent;
bool m_error;
std::string m_errorInfo;
Type m_type;
wp::fs::fileResolver m_resolver;
};
}
}
#endif /* !__BASIC_SHADER_LOADER_H__ */