(In the process of) Adding shader units and customizable preprocess functions
This commit is contained in:
parent
c3316810f5
commit
13d8e17d01
@ -47,21 +47,31 @@ protected:
|
|||||||
std::string formatString(const std::string&, const char* shad=nullptr, const std::string& file="", int line=-1);
|
std::string formatString(const std::string&, const char* shad=nullptr, const std::string& file="", int line=-1);
|
||||||
};
|
};
|
||||||
|
|
||||||
class ShaderUnit {
|
struct ShaderUnit {
|
||||||
std::string rawSource;
|
friend ShaderPreprocessor;
|
||||||
std::string preprocSource;
|
typedef std::pair<std::string, std::stringstream> File;
|
||||||
|
std::stringstream rawSource;
|
||||||
|
std::stringstream preprocSource;
|
||||||
std::map<std::string, std::string> defines;
|
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;
|
uint8_t vMajor=0, vMinor=0;
|
||||||
};
|
};
|
||||||
|
|
||||||
class ShaderPreprocessor {
|
class ShaderPreprocessor {
|
||||||
public:
|
public:
|
||||||
typedef ShaderPreprocessorError::Codes Codes;
|
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> AcceptedExtensions = {"frag", "vert", "tess", "geom", "comp", "shad", "glsl"};
|
||||||
std::vector<std::string> Directories;
|
std::vector<std::string> Directories;
|
||||||
std::map<std::string, std::string> BuiltIns;
|
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();
|
ShaderPreprocessor();
|
||||||
|
|
||||||
@ -70,7 +80,7 @@ public:
|
|||||||
std::stringstream loadFromRelative(const std::string&, const std::string& base="") const;
|
std::stringstream loadFromRelative(const std::string&, const std::string& base="") const;
|
||||||
std::stringstream loadFromDirectory(const std::string&) const;
|
std::stringstream loadFromDirectory(const std::string&) const;
|
||||||
std::stringstream loadFromBuiltIn(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;
|
virtual std::stringstream process(std::string) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
250
shader.cpp
250
shader.cpp
@ -60,6 +60,17 @@ std::string ShaderError::formatString(
|
|||||||
return ret;
|
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 class
|
||||||
ShaderPreprocessor::ShaderPreprocessor() {}
|
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 ShaderPreprocessor::process(std::stringstream& code, ShaderUnit& shad) 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 ret;
|
std::stringstream ret;
|
||||||
std::string line;
|
std::string line;
|
||||||
const std::vector<std::string> preprocKeys = {
|
|
||||||
"#include",
|
|
||||||
"#define",
|
|
||||||
"#ifdef",
|
|
||||||
"#ifndef",
|
|
||||||
"#endif"
|
|
||||||
};
|
|
||||||
enum Context : uint8_t {
|
enum Context : uint8_t {
|
||||||
Code,
|
Code,
|
||||||
BlockComment,
|
BlockComment,
|
||||||
FalseBranch
|
FalseBranch
|
||||||
};
|
};
|
||||||
Context currcontext = Code;
|
Context currcontext = Code;
|
||||||
const size_t keysListSize = preprocKeys.size();
|
const size_t keySize = Keywords.size();
|
||||||
std::vector<size_t> keysIdx(keysListSize);
|
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;
|
size_t linecom, blockstart, blockend;
|
||||||
// Use linked list to count char len of each line
|
// Use linked list to count char len of each line
|
||||||
while(std::getline(code, line)) {
|
while(std::getline(code, line)) {
|
||||||
|
keyIdxs = std::vector<size_t>(keySize, std::string::npos);
|
||||||
|
linecom = 0;
|
||||||
|
blockstart = 0;
|
||||||
|
blockend = 0;
|
||||||
switch (currcontext) {
|
switch (currcontext) {
|
||||||
case Code:
|
case Code:
|
||||||
if (linecom != std::string::npos) {
|
if (linecom != std::string::npos) {
|
||||||
size_t preprocIdx;
|
size_t preprocIdx;
|
||||||
for (int i = 0; i < keysListSize; ++i) {
|
for (int i = 0; i < keySize; ++i) {
|
||||||
preprocIdx = line.find(preprocKeys[i]);
|
preprocIdx = line.find(keys[i]);
|
||||||
keysIdx[i] = (preprocIdx < linecom) ? preprocIdx: std::string::npos;
|
keyIdxs[i] = (preprocIdx < linecom) ? preprocIdx: std::string::npos;
|
||||||
}
|
}
|
||||||
} else if (blockstart != std::string::npos) {
|
} else if (blockstart != std::string::npos) {
|
||||||
size_t preprocIdx;
|
size_t preprocIdx;
|
||||||
for (int i = 0; i < keysListSize; ++i) {
|
for (int i = 0; i < keySize; ++i) {
|
||||||
preprocIdx = line.find(preprocKeys[i]);
|
preprocIdx = line.find(keys[i]);
|
||||||
keysIdx[i] = (preprocIdx < blockstart) ? preprocIdx: std::string::npos;
|
keyIdxs[i] = (preprocIdx < blockstart) ? preprocIdx: std::string::npos;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
for (int i = 0; i < keysListSize; ++i) {
|
for (int i = 0; i < keySize; ++i) {
|
||||||
keysIdx[i] = line.find(preprocKeys[i]);
|
keyIdxs[i] = line.find(keys[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < keySize; ++i) {
|
||||||
|
if (keyIdxs[i] != std::string::npos) {
|
||||||
|
keyFuncs[i](*this, shad, ret, );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (keysIdx)
|
|
||||||
break;
|
break;
|
||||||
case BlockComment:
|
case BlockComment:
|
||||||
if (blockend == std::string::npos) {
|
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 class
|
||||||
Shader::Shader(const std::stringstream& vertexShader, const std::stringstream& fragmentShader) {
|
Shader::Shader(const std::stringstream& vertexShader, const std::stringstream& fragmentShader) {
|
||||||
std::string vertexCode, fragmentCode;
|
std::string vertexCode, fragmentCode;
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user