diff options
Diffstat (limited to 'source/30-game/Shader.hpp')
-rw-r--r-- | source/30-game/Shader.hpp | 173 |
1 files changed, 173 insertions, 0 deletions
diff --git a/source/30-game/Shader.hpp b/source/30-game/Shader.hpp new file mode 100644 index 0000000..707e6cc --- /dev/null +++ b/source/30-game/Shader.hpp @@ -0,0 +1,173 @@ +#pragma once + +#include "GraphicsTags.hpp" +#include "Ires.hpp" +#include "RcPtr.hpp" +#include "Utils.hpp" + +#include <glad/glad.h> +#include <robin_hood.h> +#include <memory> +#include <string_view> +#include <vector> + +// TODO move to variable after pattern matching is in the language + +// Forward declarations +class Shader; +class IresShader; + +struct ShaderVariable { + enum Kind { + KD_Math, + KD_Sampler, + }; + + std::string name; + Kind kind; + GLuint location; + Tags::VertexElementSemantic semantic = Tags::VES_Generic; + + virtual void ShowInfo() const = 0; + +protected: + ShaderVariable(Kind kind) + : kind{ kind } {} +}; + +struct ShaderMathVariable : public ShaderVariable { + GLenum scalarType; + int arrayLength; + int width; + int height; + + ShaderMathVariable() + : ShaderVariable(KD_Math) {} + + virtual void ShowInfo() const override; +}; + +struct ShaderSamplerVariable : public ShaderVariable { + GLenum type; + int arrayLength; + + ShaderSamplerVariable() + : ShaderVariable(KD_Sampler) {} + + virtual void ShowInfo() const override; +}; + +struct ShaderThingId { + enum Kind { + KD_Input, + KD_Output, + KD_Uniform, + KD_Invalid, + }; + + Kind kind = KD_Invalid; + int index = 0; + + bool IsValid() const; +}; + +struct ShaderInfo { + robin_hood::unordered_map<std::string, ShaderThingId, StringHash, StringEqual> things; + std::vector<ShaderMathVariable> inputs; + std::vector<ShaderMathVariable> outputs; + std::vector<std::unique_ptr<ShaderVariable>> uniforms; + + GLuint FindInputLocation(Tags::VertexElementSemantic semantic); + GLuint FindOutputLocation(Tags::VertexElementSemantic semantic); + ShaderVariable* FindVariable(const ShaderThingId& thing); +}; + +class Shader : public RefCounted { + friend class IresShader; + +private: + IresShader* mIres = nullptr; + ShaderInfo mInfo; + GLuint mProgram = 0; + +public: + GLuint autofill_Transform = Tags::kInvalidLocation; + GLuint autofill_Time = Tags::kInvalidLocation; + GLuint autofill_DeltaTime = Tags::kInvalidLocation; + GLuint autofill_TextureAtlas = Tags::kInvalidLocation; + +public: + Shader(); + ~Shader(); + Shader(const Shader&) = delete; + Shader& operator=(const Shader&) = delete; + Shader(Shader&&) = default; + Shader& operator=(Shader&&) = default; + + enum ErrorCode { + EC_Success, + /// Generated when Init*() functions are called on an already initialized Shader object. + EC_AlreadyInitialized, + /// Generated when the one-source-file text contains invalid or duplicate shader variants. + EC_InvalidShaderVariant, + EC_FileIoFailed, + EC_CompilationFailed, + EC_LinkingFailed, + }; + + struct ShaderSources { + std::string_view vertex; + std::string_view geometry; + std::string_view tessControl; + std::string_view tessEval; + std::string_view fragment; + }; + + /// Create shader by compiling each shader source file separately and then combining them together + /// into a Shader object. + ErrorCode InitFromSources(const ShaderSources& sources); + + /// The given text will be split into different shader sections according to #type directives, + /// and combined to form a Shader object. + /// For OpenGL, this process involves compililng each section separately and then linking them + /// together. + /// + /// There are a directive for each shader type + /// - `#type vertex`: Vertex shader + /// - `#type geometry`: Geometry shader + /// - `#type tessellation_control`: Tessellation control shader + /// - `#type tessellation_evaluation`: Tessellation evaluation shader + /// - `#type fragment`: Fragment shader + ErrorCode InitFromSource(std::string_view source); + + /// Rebuild info object using OpenGL shader introspection API. Requires OpenGL 4.3 or above. Overrides existing info object. + bool GatherInfoShaderIntrospection(); + const ShaderInfo& GetInfo() const { return mInfo; } + ShaderInfo& GetInfo() { return mInfo; } + /// If not empty, this name must not duplicate with any other shader object in the process. + GLuint GetProgram() const { return mProgram; } + + IresShader* GetIres() const { return mIres; } + + bool IsValid() const; +}; + +// Initialized in main() +inline RcPtr<Shader> gDefaultShader; + +class IresShader : public IresObject { +private: + RcPtr<Shader> mInstance; + std::string mSourceFile; + +public: + IresShader(); + + Shader* GetInstance() const; + void InvalidateInstance(); + + void ShowEditor(IEditor& editor) override; + + void Write(IresWritingContext& ctx, rapidjson::Value& value, rapidjson::Document& root) const override; + void Read(IresLoadingContext& ctx, const rapidjson::Value& value) override; +}; |