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 <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 {

View File

@ -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();

View File

@ -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;

View File

@ -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;