From 13d8e17d01d986e9f45c71fd8d16ee23c09bffc3 Mon Sep 17 00:00:00 2001 From: NaifBanana Date: Fri, 14 Feb 2025 03:23:03 -0600 Subject: [PATCH] (In the process of) Adding shader units and customizable preprocess functions --- include/shader.h | 22 +++-- shader.cpp | 250 ++++++++--------------------------------------- 2 files changed, 56 insertions(+), 216 deletions(-) diff --git a/include/shader.h b/include/shader.h index f3cd721..a8e83f6 100644 --- a/include/shader.h +++ b/include/shader.h @@ -47,21 +47,31 @@ protected: std::string formatString(const std::string&, const char* shad=nullptr, const std::string& file="", int line=-1); }; -class ShaderUnit { - std::string rawSource; - std::string preprocSource; +struct ShaderUnit { + friend ShaderPreprocessor; + typedef std::pair File; + std::stringstream rawSource; + std::stringstream preprocSource; std::map defines; - std::map includes; + std::map includes; uint8_t vMajor=0, vMinor=0; }; class ShaderPreprocessor { public: typedef ShaderPreprocessorError::Codes Codes; - + typedef void (*PreprocFunc)(const ShaderPreprocessor&, ShaderUnit&, std::stringstream&, 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}, + {"#ifdef", nullptr}, + {"#ifndef", nullptr}, + {"#endif", nullptr} + }; ShaderPreprocessor(); @@ -70,7 +80,7 @@ public: 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&) const; + virtual std::stringstream process(std::stringstream&, ShaderUnit&) const; virtual std::stringstream process(std::string) const; }; diff --git a/shader.cpp b/shader.cpp index df43d4c..46cc38a 100644 --- a/shader.cpp +++ b/shader.cpp @@ -60,6 +60,17 @@ 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) { + std::stringstream lstream(line); + std::vector tokens; + std::string token; + while (std::getline(lstream, token, ' ')) { + tokens.push_back(token); + } + if (tokens[0] != "#include") { return; } + shad.preprocSource << proc.include(" ", "", false); +} + // ShaderPreprocessor class ShaderPreprocessor::ShaderPreprocessor() {} @@ -168,234 +179,58 @@ std::stringstream ShaderPreprocessor::include(const std::string& name, const std } } -std::stringstream ShaderPreprocessor::process(std::stringstream& code) const { -/* std::stringstream ret; - std::string line; - enum State : unsigned char { - Start, - Token, - PreProcToken, - Number, - WhiteSpace, - FSlash, - Operator, - BlockComment, - LineComment - }; - std::pair const NewState = {"", Start}; - std::vector> tokens({NewState}); - State currState; - char n; - for (char c; code.good() && !code.eof(); code.get(c)) { - currState = tokens.back().second; - if (std::isblank(c) && currState != BlockComment && currState != LineComment) { - if (c == '\n') { - - } - switch (currState) { - case WhiteSpace: - tokens.back().first += c; - continue; - break; - case Start: - tokens.back() = {"" + c, WhiteSpace}; - continue; - break; - default: - tokens.push_back({"" + c, WhiteSpace}); - continue; - break; - } - } - switch (currState) { - case Start: - if (c == '_' || std::isalpha(c)) { - tokens.back() = {"" + c, Token}; - continue; - } else if (c == '#') { - tokens.back() = {"#", PreProcToken}; - continue; - } else if (std::isdigit(c)) { - tokens.back() = {"" + c, Number}; - continue; - } else if (c == '.') { - code.get(n); - if (std::isdigit(n)) { - tokens.back() = {"" + c + n, Number}; - continue; - } else { - code.unget(); - tokens.back() = {".", Operator}; - tokens.push_back(NewState); - continue; - } - } else { - tokens.back() = {"" + c, Operator}; - tokens.push_back(NewState); - } - break; - case FSlash: - if (c == '*') { - tokens.back() = {"/*", BlockComment}; - } else if (c == '/') { - tokens.back() = {"//", LineComment}; - } else { - tokens.back().second = Operator; - } - continue; - break; - case BlockComment: - tokens.back().first += c; - code.get(n); - tokens.back().first += n; - if (c == '*' && n == '/') { - tokens.push_back(NewState); - } - break; - case LineComment: - tokens.back().first += c; - if (c == '\n') { - tokens.push_back(NewState); - } - break; - } - } - - return ret; */ - std::stringstream ret; - const std::vector PreprocessorKeywords = {"#include"}; - - enum State : unsigned char { - Symbol, - Directive, - BlockCommentStart, - BlockCommentEnd, - LinecommentStart, - Whitespace, - Pound, - SingleQuote, - DoubleQuote, - OpenAngle, - CloseAngle, - FSlash, - Semicolon, - Star, - Newline, - Operator - }; - std::vector> stack = {}; - for (char c; code.good() && !code.eof(); code.get(c)) { - State currstate = stack.back().first; - bool editstack = false; - switch (c) { - case '#': - stack.push_back({Pound, "#"}); - break; - case '"': - stack.push_back({DoubleQuote, "\""}); - break; - case '\'': - stack.push_back({SingleQuote, "'"}); - break; - case '<': - stack.push_back({OpenAngle, "<"}); - break; - case '>': - stack.push_back({CloseAngle, ">"}); - break; - case '/': - stack.push_back({FSlash, "/"}); - break; - case '*': - stack.push_back({Star, "*"}); - break; - case '\n': - stack.push_back({Newline, "\n"}); - break; - default: - if (isblank(c)) { - stack.push_back({Whitespace, std::string(1, c)}); - } else if (isalnum(c)) { - if (currstate == Symbol) { - stack.back().second += c; - } else { - stack.push_back({Symbol, std::string(1, c)}); - } - } else { - stack.push_back({Operator, std::string(1, c)}); - } - break; - } - - auto endIt = stack.end(); - State secondlast = endIt[-2].first; - switch (endIt[-1].first) { - case FSlash: - if (secondlast == FSlash) { - stack.erase(endIt-2, endIt); - stack.push_back({LinecommentStart, "//"}); - } else if (secondlast == Star) { - stack.erase(endIt-2, endIt); - stack.push_back({BlockCommentEnd, "*/"}); - } - break; - case Star: - if (secondlast == FSlash) { - stack.erase(endIt-2, endIt); - stack.push_back({BlockCommentStart, "/*"}); - } - break; - case Newline: - for (auto i : stack) { - - } - - } - } -} - -std::stringstream ShaderPreprocessor::process(std::stringstream& code) const { +std::stringstream ShaderPreprocessor::process(std::stringstream& code, ShaderUnit& shad) const { std::stringstream ret; std::string line; - const std::vector preprocKeys = { - "#include", - "#define", - "#ifdef", - "#ifndef", - "#endif" - }; enum Context : uint8_t { Code, BlockComment, FalseBranch }; Context currcontext = Code; - const size_t keysListSize = preprocKeys.size(); - std::vector keysIdx(keysListSize); + const size_t keySize = Keywords.size(); + std::vector keyIdxs(keySize); + std::vector keys(keySize); + std::vector keyFuncs(keySize); + unsigned int idx = 0; + for (const auto& kv : Keywords) { + keys[idx] = kv.first; + keyFuncs[idx] = kv.second; + idx++; + } size_t linecom, blockstart, blockend; // Use linked list to count char len of each line while(std::getline(code, line)) { + keyIdxs = std::vector(keySize, std::string::npos); + linecom = 0; + blockstart = 0; + blockend = 0; switch (currcontext) { case Code: if (linecom != std::string::npos) { size_t preprocIdx; - for (int i = 0; i < keysListSize; ++i) { - preprocIdx = line.find(preprocKeys[i]); - keysIdx[i] = (preprocIdx < linecom) ? preprocIdx: std::string::npos; + 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 < keysListSize; ++i) { - preprocIdx = line.find(preprocKeys[i]); - keysIdx[i] = (preprocIdx < blockstart) ? preprocIdx: std::string::npos; + for (int i = 0; i < keySize; ++i) { + preprocIdx = line.find(keys[i]); + keyIdxs[i] = (preprocIdx < blockstart) ? preprocIdx: std::string::npos; } } else { - for (int i = 0; i < keysListSize; ++i) { - keysIdx[i] = line.find(preprocKeys[i]); + for (int i = 0; i < keySize; ++i) { + keyIdxs[i] = line.find(keys[i]); } } - if (keysIdx) + for (int i = 0; i < keySize; ++i) { + if (keyIdxs[i] != std::string::npos) { + keyFuncs[i](*this, shad, ret, ); + } + } + break; case BlockComment: if (blockend == std::string::npos) { @@ -418,11 +253,6 @@ std::stringstream ShaderPreprocessor::process(std::stringstream& code) const { } } -std::stringstream ShaderPreprocessor::process(std::string name) const { - std::stringstream code = load(name); - return process(code); -} - // Shader class Shader::Shader(const std::stringstream& vertexShader, const std::stringstream& fragmentShader) { std::string vertexCode, fragmentCode;