diff --git a/include/shader.h b/include/shader.h index a8e83f6..37c3a91 100644 --- a/include/shader.h +++ b/include/shader.h @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -20,6 +21,9 @@ namespace NB { +typedef std::pair FileLocation; +FileLocation get_file_path(std::string); + class ShaderPreprocessorError : public std::runtime_error { public: enum Codes : unsigned char { @@ -47,27 +51,37 @@ protected: std::string formatString(const std::string&, const char* shad=nullptr, const std::string& file="", int line=-1); }; +struct File { + FileLocation loc; + std::stringstream src; + std::map> include_map; +}; + +class ShaderPreprocessor; struct ShaderUnit { friend ShaderPreprocessor; - typedef std::pair File; - std::stringstream rawSource; + File file; std::stringstream preprocSource; std::map defines; - std::map includes; uint8_t vMajor=0, vMinor=0; }; +void preprocessor_include(const ShaderPreprocessor&, ShaderUnit&, unsigned int, const std::string&); +void preprocessor_define(const ShaderPreprocessor&, ShaderUnit&, unsigned int, const std::string&); +void preprocessor_version(const ShaderPreprocessor&, ShaderUnit&, unsigned int, const std::string&); + class ShaderPreprocessor { public: typedef ShaderPreprocessorError::Codes Codes; - typedef void (*PreprocFunc)(const ShaderPreprocessor&, ShaderUnit&, std::stringstream&, unsigned int, const std::string&); + typedef void (*PreprocFunc)(const ShaderPreprocessor&, ShaderUnit&, unsigned int, const std::string&); std::vector AcceptedExtensions = {"frag", "vert", "tess", "geom", "comp", "shad", "glsl"}; std::vector Directories; std::map BuiltIns; std::map Keywords = { {"#include", preprocessor_include}, - {"#define", nullptr}, + {"#define", preprocessor_define}, + {"#version", preprocessor_version}, {"#ifdef", nullptr}, {"#ifndef", nullptr}, {"#endif", nullptr} @@ -76,12 +90,11 @@ public: ShaderPreprocessor(); std::stringstream load(const std::string&) const; - std::stringstream include(const std::string&, const std::string& base="", bool relativeFirst=false) const; std::stringstream loadFromRelative(const std::string&, const std::string& base="") const; std::stringstream loadFromDirectory(const std::string&) const; std::stringstream loadFromBuiltIn(const std::string&) const; - virtual std::stringstream process(std::stringstream&, ShaderUnit&) const; - virtual std::stringstream process(std::string) const; + void process(std::stringstream&, ShaderUnit&) const; + ShaderUnit process(std::stringstream&) const; }; class Shader { diff --git a/main.cpp b/main.cpp index f26d974..89ec6ca 100644 --- a/main.cpp +++ b/main.cpp @@ -30,7 +30,11 @@ int main() { NB::ShaderPreprocessor myPre; myPre.Directories.push_back("../shaders/"); - std::cout << myPre.process(std::string("vert.vs")).rdbuf(); + std::stringstream myCode = myPre.loadFromDirectory("vert.vs"); + NB::ShaderUnit myShad = myPre.process(myCode); + std::cout << "-----------------------------\n"; + std::cout << myShad.preprocSource.rdbuf() << "\n"; + std::cout << "-----------------------------\n"; /* NB::Shader myShader(myPre.load("vert.vs"), myPre.load("frag.fs")); myShader.use(); diff --git a/shader.cpp b/shader.cpp index 46cc38a..555482b 100644 --- a/shader.cpp +++ b/shader.cpp @@ -2,6 +2,36 @@ namespace NB{ +FileLocation get_file_path(std::string name) { + const std::vector allowed_special_chars = { + '!', '#', '$', '%', '&', '\'', '(', ')', '+', ',', '-', ';', '=', '@', '[', ']', '^', '_', '`', '~' + }; + std::vector path = {""}; + for (const char c : name) { + if (c == '/' || c == '\\') { + path.push_back(""); + } else if (std::isalnum(c)) { + path.back() += c; + } else { + for (const char sc : allowed_special_chars) { + if (c == sc) { + path.back() += c; + } + } + throw std::runtime_error("Not valid filepath."); + } + } + FileLocation ret; + for (const auto& tk : path) { + if (tk == path.back()) { + ret.second = tk; + } else { + ret.first += '/' + tk; + } + } + return ret; +} + // ShaderPreprocessorError class ShaderPreprocessorError::ShaderPreprocessorError( const std::string& msg, @@ -60,15 +90,87 @@ std::string ShaderError::formatString( return ret; } -static void preprocessor_include(const ShaderPreprocessor& proc, ShaderUnit& shad, std::stringstream& stream, unsigned int linenum, const std::string& line) { +void preprocessor_include(const ShaderPreprocessor& proc, ShaderUnit& shad, unsigned int linenum, const std::string& line) { + typedef ShaderPreprocessor::Codes Codes; std::stringstream lstream(line); std::vector tokens; - std::string token; - while (std::getline(lstream, token, ' ')) { - tokens.push_back(token); + std::string tk; + while (std::getline(lstream, tk, ' ')) { + tokens.push_back(tk); } + // Error? When #include isn't at beginning of line if (tokens[0] != "#include") { return; } - shad.preprocSource << proc.include(" ", "", false); + std::stringstream include_code; + std::regex dir_pattern("\".*\""); + std::cmatch matches; + std::stringstream raw; + std::string filename; + std::regex bin_pattern("<.*>"); + if (std::regex_match(tokens[1].c_str(), matches, dir_pattern)) { + filename = matches[0]; + filename = filename.substr(1, filename.size()-2); + try { + raw = proc.loadFromRelative(filename, shad.file.loc.first); + proc.process(raw, shad); + std::cout << "b1\n"; + } catch (ShaderPreprocessorError e) { + if (e.code == Codes::FILE_NOT_FOUND) { + try { + raw = proc.loadFromDirectory(filename); + proc.process(raw, shad); + } catch (ShaderPreprocessorError f) { + if (f.code == Codes::FILE_NOT_FOUND) { + raw = proc.loadFromBuiltIn(filename); + proc.process(raw, shad); + } else { + throw f; + } + } + } else { + throw e; + } + } + } else if (std::regex_match(tokens[1].c_str(), matches, bin_pattern)) { + filename = matches[0]; + filename = filename.substr(1, filename.size()-2); + try { + raw = proc.loadFromDirectory(filename); + proc.process(raw, shad); + } catch (ShaderPreprocessorError e) { + if (e.code == Codes::FILE_NOT_FOUND) { + try { + raw = proc.loadFromBuiltIn(filename); + proc.process(raw, shad); + } catch (ShaderPreprocessorError f) { + if (f.code == Codes::BUILTIN_NOT_FOUND) { + raw = proc.loadFromRelative(filename, shad.file.loc.first); + proc.process(raw, shad); + } else { + throw f; + } + } + } else { + throw e; + } + } + } + +} + +void preprocessor_define(const ShaderPreprocessor& proc, ShaderUnit& shad, unsigned int linenum, const std::string& line) { + std::stringstream lstream(line); + std::vector tokens; + std::string tk; + while (std::getline(lstream, tk, ' ')) { + tokens.push_back(tk); + } + if (tokens[0] != "#define") { return; } + shad.defines[tokens[1]] = (tokens.size() > 2) ? tokens[2] : ""; + shad.preprocSource << line << "\n"; +} + +void preprocessor_version(const ShaderPreprocessor& proc, ShaderUnit& shad, unsigned int linenum, const std::string& line) { + shad.preprocSource << line << "\n" ; } // ShaderPreprocessor class @@ -140,47 +242,8 @@ std::stringstream ShaderPreprocessor::load(const std::string& path) const { } } -std::stringstream ShaderPreprocessor::include(const std::string& name, const std::string& base, bool relativeFirst) const { - if (relativeFirst) { - try { - return loadFromRelative(name, base); - } catch (ShaderPreprocessorError e) { - if (e.code == Codes::FILE_NOT_FOUND) { - try { - return loadFromDirectory(name); - } catch (ShaderPreprocessorError f) { - if (f.code == Codes::FILE_NOT_FOUND) { - return loadFromBuiltIn(name); - } else { - throw f; - } - } - } else { - throw e; - } - } - } - try { - return loadFromDirectory(name); - } catch (ShaderPreprocessorError e) { - if (e.code == Codes::FILE_NOT_FOUND) { - try { - return loadFromBuiltIn(name); - } catch (ShaderPreprocessorError f) { - if (f.code == Codes::BUILTIN_NOT_FOUND) { - return loadFromRelative(name, base); - } else { - throw f; - } - } - } else { - throw e; - } - } -} - -std::stringstream ShaderPreprocessor::process(std::stringstream& code, ShaderUnit& shad) const { - std::stringstream ret; +void ShaderPreprocessor::process(std::stringstream& code, ShaderUnit& shad) const { + // std::stringstream ret; std::string line; enum Context : uint8_t { Code, @@ -199,20 +262,27 @@ std::stringstream ShaderPreprocessor::process(std::stringstream& code, ShaderUni idx++; } size_t linecom, blockstart, blockend; + int lineidx = -1; + bool loaded; // Use linked list to count char len of each line while(std::getline(code, line)) { + lineidx++; keyIdxs = std::vector(keySize, std::string::npos); - linecom = 0; - blockstart = 0; - blockend = 0; + linecom = line.find("//"); + blockstart = line.find("/*"); + blockend = line.find("*/"); + loaded = false; switch (currcontext) { case Code: + // Figure out how to activate new contexts + // while also handling mid-line context switching if (linecom != std::string::npos) { size_t preprocIdx; for (int i = 0; i < keySize; ++i) { preprocIdx = line.find(keys[i]); keyIdxs[i] = (preprocIdx < linecom) ? preprocIdx: std::string::npos; } + } else if (blockstart != std::string::npos) { size_t preprocIdx; for (int i = 0; i < keySize; ++i) { @@ -227,32 +297,47 @@ std::stringstream ShaderPreprocessor::process(std::stringstream& code, ShaderUni for (int i = 0; i < keySize; ++i) { if (keyIdxs[i] != std::string::npos) { - keyFuncs[i](*this, shad, ret, ); + keyFuncs[i](*this, shad, 0, line); + loaded = true; + break; } - } - + } + if (!loaded) { + shad.preprocSource << line << "\n"; + } break; case BlockComment: + std::cout << "In a comment!\n"; if (blockend == std::string::npos) { - ret << line; + shad.preprocSource << line << "\n"; + loaded = true; } else { size_t newpos = code.tellg() - line.size() + blockend; line.resize(blockend); - ret << line; + shad.preprocSource << line; + loaded = true; code.seekg(newpos); continue; } break; case FalseBranch: - ret << line; + shad.preprocSource << line << "\n"; + loaded = true; break; default: - ret << line; + shad.preprocSource << line << "\n"; + loaded = true; break; } } } +ShaderUnit ShaderPreprocessor::process(std::stringstream& code) const { + ShaderUnit ret; + process(code, ret); + return ret; +} + // Shader class Shader::Shader(const std::stringstream& vertexShader, const std::stringstream& fragmentShader) { std::string vertexCode, fragmentCode; diff --git a/shaders/vert.vs b/shaders/vert.vs index 2c74e96..b3aa50e 100644 --- a/shaders/vert.vs +++ b/shaders/vert.vs @@ -1,4 +1,7 @@ #version 330 core +#define poop +glag +#define nm layout (location=0) in vec3 vPos; layout (location=1) in vec3 vColor; @@ -6,6 +9,12 @@ layout (location=1) in vec3 vColor; uniform mat4 look; +/* +#include "frag.fs" + hey +poop +*/ + out vec3 vertColor; void main() { vertColor = vColor;