Getting close on shader preproc.
This commit is contained in:
parent
13d8e17d01
commit
0a737bf044
@ -9,6 +9,7 @@
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <map>
|
||||
#include <regex>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
@ -20,6 +21,9 @@
|
||||
|
||||
namespace NB {
|
||||
|
||||
typedef std::pair<std::string, std::string> 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<unsigned int, std::shared_ptr<File>> include_map;
|
||||
};
|
||||
|
||||
class ShaderPreprocessor;
|
||||
struct ShaderUnit {
|
||||
friend ShaderPreprocessor;
|
||||
typedef std::pair<std::string, std::stringstream> File;
|
||||
std::stringstream rawSource;
|
||||
File file;
|
||||
std::stringstream preprocSource;
|
||||
std::map<std::string, std::string> defines;
|
||||
std::map<uint8_t, File> 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<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},
|
||||
{"#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 {
|
||||
|
||||
6
main.cpp
6
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();
|
||||
|
||||
197
shader.cpp
197
shader.cpp
@ -2,6 +2,36 @@
|
||||
|
||||
namespace NB{
|
||||
|
||||
FileLocation get_file_path(std::string name) {
|
||||
const std::vector<char> allowed_special_chars = {
|
||||
'!', '#', '$', '%', '&', '\'', '(', ')', '+', ',', '-', ';', '=', '@', '[', ']', '^', '_', '`', '~'
|
||||
};
|
||||
std::vector<std::string> 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<std::string> 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<std::string> 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<size_t>(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;
|
||||
|
||||
@ -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;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user