(In the process of) Adding shader units and customizable preprocess functions

This commit is contained in:
NaifBanana 2025-02-14 03:23:03 -06:00
parent c3316810f5
commit 13d8e17d01
2 changed files with 56 additions and 216 deletions

View File

@ -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<std::string, std::stringstream> File;
std::stringstream rawSource;
std::stringstream preprocSource;
std::map<std::string, std::string> defines;
std::map<uint8_t, ShaderUnit*> includes;
std::map<uint8_t, File> 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<std::string> AcceptedExtensions = {"frag", "vert", "tess", "geom", "comp", "shad", "glsl"};
std::vector<std::string> Directories;
std::map<std::string, std::string> BuiltIns;
std::map<std::string, PreprocFunc> 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;
};

View File

@ -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<std::string> 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<std::string, State> const NewState = {"", Start};
std::vector<std::pair<std::string, State>> 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<std::string> PreprocessorKeywords = {"#include"};
enum State : unsigned char {
Symbol,
Directive,
BlockCommentStart,
BlockCommentEnd,
LinecommentStart,
Whitespace,
Pound,
SingleQuote,
DoubleQuote,
OpenAngle,
CloseAngle,
FSlash,
Semicolon,
Star,
Newline,
Operator
};
std::vector<std::pair<State, std::string>> 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<std::string> preprocKeys = {
"#include",
"#define",
"#ifdef",
"#ifndef",
"#endif"
};
enum Context : uint8_t {
Code,
BlockComment,
FalseBranch
};
Context currcontext = Code;
const size_t keysListSize = preprocKeys.size();
std::vector<size_t> keysIdx(keysListSize);
const size_t keySize = Keywords.size();
std::vector<size_t> keyIdxs(keySize);
std::vector<std::string> keys(keySize);
std::vector<PreprocFunc> 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<size_t>(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;