#pragma once #ifndef _NB_SHADER #define _NB_SHADER #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include // #define _PREPROC_FUNC_PARAMS_ (const ShaderPreprocessor&, ShaderUnit&, unsigned int, const std::string&, std::vector&) 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 FilePath; struct FilePath { std::string dir; std::string basename; std::string ext; }; FilePath path; std::stringstream src; std::map> 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 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 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&); private: ShaderProgram(std::vector& shaders) : _shader_units(shaders){} std::vector _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 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 AcceptedProfiles { {"core", Core}, {"compatibility", Compatibility}, {"es", ES} }; std::vector Directories; std::map 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) const; private: typedef std::pair Token; typedef std::vector StringVec; inline bool directive_dispatch(ShaderUnit&, const std::string&) const; inline std::vector 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