Getting close on shader preproc.

This commit is contained in:
NaifBanana 2025-02-27 02:45:52 -06:00
parent 13d8e17d01
commit 0a737bf044
4 changed files with 176 additions and 65 deletions

View File

@ -9,6 +9,7 @@
#include <fstream> #include <fstream>
#include <iostream> #include <iostream>
#include <map> #include <map>
#include <regex>
#include <sstream> #include <sstream>
#include <string> #include <string>
#include <utility> #include <utility>
@ -20,6 +21,9 @@
namespace NB { namespace NB {
typedef std::pair<std::string, std::string> FileLocation;
FileLocation get_file_path(std::string);
class ShaderPreprocessorError : public std::runtime_error { class ShaderPreprocessorError : public std::runtime_error {
public: public:
enum Codes : unsigned char { 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); 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 { struct ShaderUnit {
friend ShaderPreprocessor; friend ShaderPreprocessor;
typedef std::pair<std::string, std::stringstream> File; File file;
std::stringstream rawSource;
std::stringstream preprocSource; std::stringstream preprocSource;
std::map<std::string, std::string> defines; std::map<std::string, std::string> defines;
std::map<uint8_t, File> includes;
uint8_t vMajor=0, vMinor=0; 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 { 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&); 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> 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 = { std::map<std::string, PreprocFunc> Keywords = {
{"#include", preprocessor_include}, {"#include", preprocessor_include},
{"#define", nullptr}, {"#define", preprocessor_define},
{"#version", preprocessor_version},
{"#ifdef", nullptr}, {"#ifdef", nullptr},
{"#ifndef", nullptr}, {"#ifndef", nullptr},
{"#endif", nullptr} {"#endif", nullptr}
@ -76,12 +90,11 @@ public:
ShaderPreprocessor(); ShaderPreprocessor();
std::stringstream load(const std::string&) const; 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 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&, ShaderUnit&) const; void process(std::stringstream&, ShaderUnit&) const;
virtual std::stringstream process(std::string) const; ShaderUnit process(std::stringstream&) const;
}; };
class Shader { class Shader {

View File

@ -30,7 +30,11 @@ int main() {
NB::ShaderPreprocessor myPre; NB::ShaderPreprocessor myPre;
myPre.Directories.push_back("../shaders/"); 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")); /* NB::Shader myShader(myPre.load("vert.vs"), myPre.load("frag.fs"));
myShader.use(); myShader.use();

View File

@ -2,6 +2,36 @@
namespace NB{ 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 class
ShaderPreprocessorError::ShaderPreprocessorError( ShaderPreprocessorError::ShaderPreprocessorError(
const std::string& msg, const std::string& msg,
@ -60,15 +90,87 @@ 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) { void preprocessor_include(const ShaderPreprocessor& proc, ShaderUnit& shad, unsigned int linenum, const std::string& line) {
typedef ShaderPreprocessor::Codes Codes;
std::stringstream lstream(line); std::stringstream lstream(line);
std::vector<std::string> tokens; std::vector<std::string> tokens;
std::string token; std::string tk;
while (std::getline(lstream, token, ' ')) { while (std::getline(lstream, tk, ' ')) {
tokens.push_back(token); tokens.push_back(tk);
} }
// Error? When #include isn't at beginning of line
if (tokens[0] != "#include") { return; } 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 // 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 { void ShaderPreprocessor::process(std::stringstream& code, ShaderUnit& shad) const {
if (relativeFirst) { // std::stringstream ret;
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;
std::string line; std::string line;
enum Context : uint8_t { enum Context : uint8_t {
Code, Code,
@ -199,20 +262,27 @@ std::stringstream ShaderPreprocessor::process(std::stringstream& code, ShaderUni
idx++; idx++;
} }
size_t linecom, blockstart, blockend; size_t linecom, blockstart, blockend;
int lineidx = -1;
bool loaded;
// 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)) {
lineidx++;
keyIdxs = std::vector<size_t>(keySize, std::string::npos); keyIdxs = std::vector<size_t>(keySize, std::string::npos);
linecom = 0; linecom = line.find("//");
blockstart = 0; blockstart = line.find("/*");
blockend = 0; blockend = line.find("*/");
loaded = false;
switch (currcontext) { switch (currcontext) {
case Code: case Code:
// Figure out how to activate new contexts
// while also handling mid-line context switching
if (linecom != std::string::npos) { if (linecom != std::string::npos) {
size_t preprocIdx; size_t preprocIdx;
for (int i = 0; i < keySize; ++i) { for (int i = 0; i < keySize; ++i) {
preprocIdx = line.find(keys[i]); preprocIdx = line.find(keys[i]);
keyIdxs[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 < keySize; ++i) { 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) { for (int i = 0; i < keySize; ++i) {
if (keyIdxs[i] != std::string::npos) { 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; break;
case BlockComment: case BlockComment:
std::cout << "In a comment!\n";
if (blockend == std::string::npos) { if (blockend == std::string::npos) {
ret << line; shad.preprocSource << line << "\n";
loaded = true;
} else { } else {
size_t newpos = code.tellg() - line.size() + blockend; size_t newpos = code.tellg() - line.size() + blockend;
line.resize(blockend); line.resize(blockend);
ret << line; shad.preprocSource << line;
loaded = true;
code.seekg(newpos); code.seekg(newpos);
continue; continue;
} }
break; break;
case FalseBranch: case FalseBranch:
ret << line; shad.preprocSource << line << "\n";
loaded = true;
break; break;
default: default:
ret << line; shad.preprocSource << line << "\n";
loaded = true;
break; break;
} }
} }
} }
ShaderUnit ShaderPreprocessor::process(std::stringstream& code) const {
ShaderUnit ret;
process(code, ret);
return ret;
}
// 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;

View File

@ -1,4 +1,7 @@
#version 330 core #version 330 core
#define poop
glag
#define nm
layout (location=0) in vec3 vPos; layout (location=0) in vec3 vPos;
layout (location=1) in vec3 vColor; layout (location=1) in vec3 vColor;
@ -6,6 +9,12 @@ layout (location=1) in vec3 vColor;
uniform mat4 look; uniform mat4 look;
/*
#include "frag.fs"
hey
poop
*/
out vec3 vertColor; out vec3 vertColor;
void main() { void main() {
vertColor = vColor; vertColor = vColor;