From e66286ebe30afc9acc4531fc2bea29b7fb924f93 Mon Sep 17 00:00:00 2001 From: rtk0c Date: Mon, 30 May 2022 17:03:20 -0700 Subject: Changeset: 56 Buildsystem cleanup: change to layered structure for different targets --- source/30-game/Shader.hpp | 173 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 173 insertions(+) create mode 100644 source/30-game/Shader.hpp (limited to 'source/30-game/Shader.hpp') 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 +#include +#include +#include +#include + +// 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 things; + std::vector inputs; + std::vector outputs; + std::vector> 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 gDefaultShader; + +class IresShader : public IresObject { +private: + RcPtr 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; +}; -- cgit v1.2.3-70-g09d2