2026-04-04 15:01:39 -05:00

193 lines
5.4 KiB
C++

#pragma once
#ifndef _NB_SHADER
#define _NB_SHADER
#include <GLLoad.h>
#include <cctype>
#include <cstring>
#include <exception>
#include <fstream>
#include <iostream>
#include <map>
#include <regex>
#include <sstream>
#include <string>
#include <utility>
#include <vector>
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>
// #define _PREPROC_FUNC_PARAMS_ (const ShaderPreprocessor&, ShaderUnit&, unsigned int, const std::string&, std::vector<uint8_t>&)
namespace NB {
class ShaderPreprocessorError : public std::runtime_error {
public:
enum Codes : unsigned char {
NONE,
FILE_NOT_FOUND,
BUILTIN_NOT_FOUND,
CUSTOM,
UNDEFINED
};
const Codes code;
ShaderPreprocessorError(const std::string&, const std::string& file="", int line=-1);
ShaderPreprocessorError(Codes, const std::string& arg="", const std::string& file="", int line=-1);
protected:
static std::string errorCodeParser(Codes, const std::string& arg="");
};
class ShaderError : public std::runtime_error {
public:
ShaderError(const std::string&, const char* shad=nullptr, const std::string& file="", int line=-1);
protected:
std::string formatString(const std::string&, const char* shad=nullptr, const std::string& file="", int line=-1);
};
struct File {
// typedef std::tuple<std::string, std::string, std::string> FilePath;
struct FilePath {
std::string dir;
std::string basename;
std::string ext;
};
FilePath path;
std::stringstream src;
std::map<unsigned int, std::shared_ptr<File>> include_map;
File() {}
File(const File& rhs) { *this = rhs; }
File& operator=(const File& rhs) {
path = rhs.path;
src.str("");
src << rhs.src.rdbuf();
include_map = rhs.include_map;
return *this;
}
};
// File::FilePath get_file_path(std::string);
class ShaderPreprocessor;
enum OpenGLProfiles {
Core,
Compatibility,
ES
};
struct ShaderUnit {
GLenum type = 0x0;
File file;
std::string preprocSource;
std::map<std::string, std::string> defines;
short vMajor=0, vMinor=0;
OpenGLProfiles profile = Core;
};
class ShaderPreprocessor;
class ShaderProgram {
friend ShaderPreprocessor;
public:
ShaderProgram() {}
ShaderProgram(const ShaderProgram& rhs) = delete;
ShaderProgram(ShaderProgram&& rhs);
~ShaderProgram();
ShaderProgram& operator=(const ShaderProgram& rhs) = delete;
ShaderProgram& operator=(ShaderProgram&& rhs);
std::vector<ShaderUnit> getShaders() const;
ShaderUnit getShaders(unsigned int) const;
void use() const;
unsigned int id() const;
void setBool(const std::string& name, bool value) const;
void setInt(const std::string& name, int value) const;
void setUnsigned(const std::string& name, int value) const;
void setFloat(const std::string& name, float value) const;
void setMat4(const std::string& name, glm::mat4& value) const;
static ShaderProgram CreateShaderProgram(std::vector<ShaderUnit>&);
private:
ShaderProgram(std::vector<ShaderUnit>& shaders) : _shader_units(shaders){}
std::vector<ShaderUnit> _shader_units;
unsigned int _id;
};
class ShaderPreprocessor {
public:
typedef ShaderPreprocessorError::Codes Codes;
enum TokenType {
TK,
DR,
WS,
NL,
LC,
BC
};
static std::string TokenName(const TokenType&);
std::map<std::string, GLenum> AcceptedExtensions = {
{".frag", GL_FRAGMENT_SHADER},
{".fs", GL_FRAGMENT_SHADER},
{".vert", GL_VERTEX_SHADER},
{".vs", GL_VERTEX_SHADER},
{".tess", 0x0},
{".geom", GL_GEOMETRY_SHADER},
{".comp", 0x0},
{".shad", 0x0},
{".glsl", 0x0}
};
std::map<std::string, OpenGLProfiles> AcceptedProfiles {
{"core", Core},
{"compatibility", Compatibility},
{"es", ES}
};
std::vector<std::string> Directories;
std::map<std::string, std::string> BuiltIns;
ShaderPreprocessor();
File load(const std::string, bool builtin_first=false) const;
ShaderUnit& preprocess(const std::string&, ShaderUnit&) const;
ShaderUnit preprocess(File, GLenum shader_type=0x0) const;
ShaderUnit preprocess(const std::string&, GLenum shader_type=0x0) const;
ShaderProgram ReloadFromFile(const ShaderProgram& rhs) const;
ShaderProgram CreateShaderProgram(std::vector<std::string>) const;
private:
typedef std::pair<TokenType, std::string> Token;
typedef std::vector<std::string> StringVec;
inline bool directive_dispatch(ShaderUnit&, const std::string&) const;
inline std::vector<Token> tokenize(const std::string&) const;
inline bool preprocessor_include(ShaderUnit&, const StringVec&, const std::string&) const;
inline bool preprocessor_version(ShaderUnit&, const StringVec&, const std::string&) const;
inline bool preprocessor_define(ShaderUnit&, const StringVec&, const std::string&) const;
// inline bool preprocessor_uniform(ShaderUnit&, const std::string&, const std::string&) const;
File loadFromBase(const std::string, const std::string base="") const;
File loadFromDirectories(const std::string) const;
File loadFromBuiltIn(const std::string) const;
File load_BuiltInFirst(const std::string) const;
File load_FilesFirst(const std::string) const;
};
}
#endif