diff options
-rw-r--r-- | src/Gal.hpp | 255 | ||||
-rw-r--r-- | src/GalOgl.cpp | 836 | ||||
-rw-r--r-- | src/Render.cpp | 37 | ||||
-rw-r--r-- | src/Rml.cpp | 143 | ||||
-rw-r--r-- | src/Rml.hpp | 5 |
5 files changed, 1189 insertions, 87 deletions
diff --git a/src/Gal.hpp b/src/Gal.hpp new file mode 100644 index 0000000..0f2d162 --- /dev/null +++ b/src/Gal.hpp @@ -0,0 +1,255 @@ +#pragma once + +#include <cstdint> +#include <memory> +#include <vector> +#include <string_view> + +#include <glm/glm.hpp> + +namespace Gal { + + struct Impl; + struct Buffer; + struct BufferBinding; + struct TextureConfig; + struct Texture; + struct PipelineConfig; + struct Pipeline; + struct PipelineInstance; + struct FramebufferConfig; + struct Framebuffer; + struct ShaderParameters; + struct Shader; + + + enum class Type { + Float, + Double, + Uint8, + Uint16, + Uint32, + Int8, + Int16, + Int32, + Vec2, + Vec2u8, + Vec2u16, + Vec2u32, + Vec2i8, + Vec2i16, + Vec2i32, + Vec3, + Vec3u8, + Vec3u16, + Vec3u32, + Vec3i8, + Vec3i16, + Vec3i32, + Vec4, + Vec4u8, + Vec4u16, + Vec4u32, + Vec4i8, + Vec4i16, + Vec4i32, + Mat2, + Mat3, + Mat4, + }; + + enum class Format { + R8G8B8, + R8G8B8A8, + }; + + enum class Filtering { + Nearest, + Bilinear, + Trilinear, + Anisotropy, + }; + + enum class Wrapping { + Repeat, + Mirror, + Clamp, + }; + + struct VertexAttribute { + std::string name; + Type type; + }; + + Impl* GetImplementation(); + + struct Impl { + + virtual void Init() = 0; + + virtual void DeInit() = 0; + + virtual void Cleanup() = 0; + + + virtual std::shared_ptr<Buffer> CreateBuffer() = 0; + + + virtual std::shared_ptr<TextureConfig> CreateTexture2DConfig(size_t width, size_t height, Format format) = 0; + + virtual std::shared_ptr<TextureConfig> CreateTexture3DConfig(size_t width, size_t height, size_t depth, bool interpolateLayers, Format format) = 0; + + virtual std::shared_ptr<Texture> BuildTexture(std::shared_ptr<TextureConfig> config) = 0; + + + virtual std::shared_ptr<PipelineConfig> CreatePipelineConfig() = 0; + + virtual std::shared_ptr<Pipeline> BuildPipeline(std::shared_ptr<PipelineConfig> config) = 0; + + + virtual std::shared_ptr<FramebufferConfig> CreateFramebufferConfig() = 0; + + virtual std::shared_ptr<Framebuffer> BuildFramebuffer(std::shared_ptr<FramebufferConfig> config) = 0; + + virtual std::shared_ptr<Framebuffer> GetDefaultFramebuffer() = 0; + + + virtual std::shared_ptr<ShaderParameters> GetGlobalShaderParameters() = 0; + + virtual std::shared_ptr<Shader> LoadVertexShader(std::string_view code) = 0; + + virtual std::shared_ptr<Shader> LoadPixelShader(std::string_view code) = 0; + + }; + + struct Buffer { + virtual ~Buffer() = default; + + virtual void SetData(std::vector<std::byte>&& data) = 0; + }; + + struct BufferBinding { + virtual ~BufferBinding() = default; + }; + + struct TextureConfig { + virtual ~TextureConfig() = default; + + virtual void SetMinFilter(Filtering filter) = 0; + + virtual void SetMaxFilter(Filtering filter) = 0; + + virtual void SetWrapping(Wrapping wrapping) = 0; + + }; + + struct Texture { + virtual ~Texture() = default; + + virtual void SetData(std::vector<std::byte>&& data, size_t mipLevel = 0) = 0; + }; + + struct PipelineConfig { + virtual ~PipelineConfig() = default; + + virtual void SetVertexShader(std::shared_ptr<Shader> shader) = 0; + + virtual void SetPixelShader(std::shared_ptr<Shader> shader) = 0; + + virtual void AddShaderParameter(std::string_view name, Type type) = 0; + + virtual void SetTarget(std::shared_ptr<Framebuffer> target) = 0; + + virtual std::shared_ptr<BufferBinding> BindVertexBuffer(std::vector<VertexAttribute> &&bufferLayout) = 0; + + virtual std::shared_ptr<BufferBinding> BindIndexBuffer() = 0; + }; + + struct Pipeline { + virtual ~Pipeline() = default; + + virtual void Activate() = 0; + + virtual std::shared_ptr<PipelineInstance> CreateInstance(std::vector<std::pair<std::shared_ptr<BufferBinding>, std::shared_ptr<Buffer>>> &&buffers) = 0; + + virtual void SetShaderParameter(std::string_view name, float value) = 0; + + virtual void SetShaderParameter(std::string_view name, double value) = 0; + + virtual void SetShaderParameter(std::string_view name, int8_t value) = 0; + + virtual void SetShaderParameter(std::string_view name, int16_t value) = 0; + + virtual void SetShaderParameter(std::string_view name, int32_t value) = 0; + + virtual void SetShaderParameter(std::string_view name, uint8_t value) = 0; + + virtual void SetShaderParameter(std::string_view name, uint16_t value) = 0; + + virtual void SetShaderParameter(std::string_view name, uint32_t value) = 0; + + virtual void SetShaderParameter(std::string_view name, glm::vec2 value) = 0; + + virtual void SetShaderParameter(std::string_view name, glm::uvec2 value) = 0; + + virtual void SetShaderParameter(std::string_view name, glm::vec3 value) = 0; + + virtual void SetShaderParameter(std::string_view name, glm::vec4 value) = 0; + + virtual void SetShaderParameter(std::string_view name, glm::mat4 value) = 0; + }; + + struct PipelineInstance { + virtual ~PipelineInstance() = default; + + virtual void Activate() = 0; + + virtual void Render(size_t offset = 0, size_t count = -1) = 0; + }; + + struct Framebuffer { + virtual ~Framebuffer() = default; + + virtual void Clear() = 0; + + virtual void SetViewport(size_t x, size_t y, size_t w, size_t h) = 0; + }; + + struct FramebufferConfig { + virtual ~FramebufferConfig() = default; + }; + + struct ShaderParameters { + virtual ~ShaderParameters() = default; + + virtual void AddGlobalShaderParameter(std::string_view name, Type type) = 0; + + virtual void SetGlobalShaderParameter(std::string_view name, float value) = 0; + + virtual void SetGlobalShaderParameter(std::string_view name, double value) = 0; + + virtual void SetGlobalShaderParameter(std::string_view name, int8_t value) = 0; + + virtual void SetGlobalShaderParameter(std::string_view name, int16_t value) = 0; + + virtual void SetGlobalShaderParameter(std::string_view name, int32_t value) = 0; + + virtual void SetGlobalShaderParameter(std::string_view name, uint8_t value) = 0; + + virtual void SetGlobalShaderParameter(std::string_view name, uint16_t value) = 0; + + virtual void SetGlobalShaderParameter(std::string_view name, uint32_t value) = 0; + + virtual void SetGlobalShaderParameter(std::string_view name, glm::vec2 value) = 0; + + virtual void SetGlobalShaderParameter(std::string_view name, glm::vec3 value) = 0; + + virtual void SetGlobalShaderParameter(std::string_view name, glm::vec4 value) = 0; + + virtual void SetGlobalShaderParameter(std::string_view name, glm::mat4 value) = 0; + }; + + struct Shader { + virtual ~Shader() = default; + }; +} diff --git a/src/GalOgl.cpp b/src/GalOgl.cpp new file mode 100644 index 0000000..4fb2794 --- /dev/null +++ b/src/GalOgl.cpp @@ -0,0 +1,836 @@ +#include "Gal.hpp" + +#include <easylogging++.h> +#include <GL/glew.h> + +#include "Utility.hpp" + +using namespace Gal; + +class ImplOgl; +class FramebufferDefaultOgl; +class ShaderOgl; + +std::unique_ptr<ImplOgl> impl; +std::shared_ptr<FramebufferDefaultOgl> fbDefault; + +size_t GalTypeGetComponents(Gal::Type type) { + switch (type) { + case Type::Float: + case Type::Double: + case Type::Uint8: + case Type::Uint16: + case Type::Uint32: + case Type::Int8: + case Type::Int16: + case Type::Int32: + return 1; + case Type::Vec2: + case Type::Vec2u8: + case Type::Vec2u16: + case Type::Vec2u32: + case Type::Vec2i8: + case Type::Vec2i16: + case Type::Vec2i32: + return 2; + case Type::Vec3: + case Type::Vec3u8: + case Type::Vec3u16: + case Type::Vec3u32: + case Type::Vec3i8: + case Type::Vec3i16: + case Type::Vec3i32: + return 3; + case Type::Vec4: + case Type::Vec4u8: + case Type::Vec4u16: + case Type::Vec4u32: + case Type::Vec4i8: + case Type::Vec4i16: + case Type::Vec4i32: + case Type::Mat2: + return 4; + case Type::Mat3: + return 9; + case Type::Mat4: + return 16; + default: + return 0; + } + return 0; +} + +size_t GalTypeGetComponentSize(Gal::Type type) { + switch (type) { + case Type::Uint8: + case Type::Int8: + case Type::Vec2u8: + case Type::Vec2i8: + case Type::Vec3u8: + case Type::Vec3i8: + case Type::Vec4u8: + case Type::Vec4i8: + return 1; + case Type::Uint16: + case Type::Int16: + case Type::Vec2u16: + case Type::Vec2i16: + case Type::Vec3u16: + case Type::Vec3i16: + case Type::Vec4u16: + case Type::Vec4i16: + return 2; + case Type::Float: + case Type::Uint32: + case Type::Int32: + case Type::Vec2: + case Type::Vec2u32: + case Type::Vec2i32: + case Type::Vec3: + case Type::Vec3u32: + case Type::Vec3i32: + case Type::Vec4: + case Type::Vec4u32: + case Type::Vec4i32: + case Type::Mat2: + case Type::Mat3: + case Type::Mat4: + return 4; + case Type::Double: + return 8; + default: + return 0; + } +} + +size_t GalTypeGetSize(Gal::Type type) { + return GalTypeGetComponents(type) * GalTypeGetComponentSize(type); +} + +GLenum GalTypeGetComponentGlType(Gal::Type type) { + switch (type) { + case Type::Float: + case Type::Vec2: + case Type::Vec3: + case Type::Vec4: + case Type::Mat2: + case Type::Mat3: + case Type::Mat4: + return GL_FLOAT; + case Type::Double: + return GL_DOUBLE; + case Type::Uint8: + case Type::Vec2u8: + case Type::Vec3u8: + case Type::Vec4u8: + return GL_UNSIGNED_BYTE; + case Type::Uint16: + case Type::Vec2u16: + case Type::Vec3u16: + case Type::Vec4u16: + return GL_UNSIGNED_SHORT; + case Type::Uint32: + case Type::Vec2u32: + case Type::Vec3u32: + case Type::Vec4u32: + return GL_UNSIGNED_INT; + case Type::Int8: + case Type::Vec2i8: + case Type::Vec3i8: + case Type::Vec4i8: + return GL_BYTE; + case Type::Int16: + case Type::Vec2i16: + case Type::Vec3i16: + case Type::Vec4i16: + return GL_SHORT; + case Type::Int32: + case Type::Vec2i32: + case Type::Vec3i32: + case Type::Vec4i32: + return GL_INT; + default: + return 0; + } + return 0; +} + +size_t GalFormatGetSize(Format format) { + switch (format) { + case Format::R8G8B8: + return 3; + case Format::R8G8B8A8: + return 4; + default: + return 0; + } + return 0; +} + +GLenum GalFormatGetGlInternalFormat(Format format) { + switch (format) { + case Format::R8G8B8: + return GL_RGB8; + case Format::R8G8B8A8: + return GL_RGBA8; + default: + return 0; + } + return 0; +} + +GLenum GalFormatGetGlFormat(Format format) { + switch (format) { + case Format::R8G8B8: + return GL_RGB; + case Format::R8G8B8A8: + return GL_RGBA; + default: + return 0; + } + return 0; +} + +GLenum GalFormatGetGlType(Format format) { + switch (format) { + case Format::R8G8B8: + return GL_UNSIGNED_BYTE; + case Format::R8G8B8A8: + return GL_UNSIGNED_BYTE; + default: + return 0; + } + return 0; +} + +GLenum GalFilteringGetGlType(Filtering filtering) { + switch (filtering) { + case Filtering::Nearest: + return GL_NEAREST; + case Filtering::Bilinear: + return GL_LINEAR; + case Filtering::Trilinear: + return GL_LINEAR_MIPMAP_LINEAR; + case Filtering::Anisotropy: + return GL_LINEAR; + default: + return 0; + } + return 0; +} + +GLenum GalWrappingGetGlType(Wrapping wrapping) { + switch (wrapping) { + case Wrapping::Repeat: + return GL_REPEAT; + case Wrapping::Clamp: + return GL_CLAMP_TO_EDGE; + case Wrapping::Mirror: + return GL_MIRRORED_REPEAT; + default: + return 0; + } + return 0; +} + + +class ShaderOgl : public Shader { +public: + bool isVertex = true; + std::string code; +}; + +class BufferBindingOgl : public BufferBinding { +public: + BufferBindingOgl(size_t id) : bufferId(id) {} + + const size_t bufferId; + + static constexpr size_t indexValue = (std::numeric_limits<size_t>::max)(); //parenthess for windows' max macro +}; + +class BufferOgl : public Buffer { +public: + GLuint vbo; + + virtual void SetData(std::vector<std::byte>&& data) override { + glBindBuffer(GL_ARRAY_BUFFER, vbo); + glBufferData(GL_ARRAY_BUFFER, data.size(), data.data(), GL_STATIC_DRAW); + glBindBuffer(GL_ARRAY_BUFFER, 0); + glCheckError(); + } +}; + +class TextureConfigOgl : public TextureConfig { +public: + + Format format; + size_t width = 0, height = 0, depth = 0; + bool interpolateLayers = false; + + Filtering min = Filtering::Nearest, max = Filtering::Nearest; + Wrapping wrap = Wrapping::Clamp; + + + virtual void SetMinFilter(Filtering filter) override { + min = filter; + } + + virtual void SetMaxFilter(Filtering filter) override { + max = filter; + } + + virtual void SetWrapping(Wrapping wrapping) override { + wrap = wrapping; + } + +}; + +class TextureOgl : public Texture { +public: + + GLenum type; + GLuint texture; + Format format; + size_t width = 0, height = 0, depth = 0; + + virtual void SetData(std::vector<std::byte>&& data, size_t mipLevel = 0) override { + if (data.size() != width * height * depth * GalFormatGetSize(format)) + throw std::logic_error("Size of data is not valid for this texture"); + + glBindTexture(type, texture); + glCheckError(); + + switch (type) { + case GL_TEXTURE_2D: + case GL_PROXY_TEXTURE_2D: + case GL_TEXTURE_1D_ARRAY: + case GL_PROXY_TEXTURE_1D_ARRAY: + case GL_TEXTURE_RECTANGLE: + case GL_PROXY_TEXTURE_RECTANGLE: + case GL_TEXTURE_CUBE_MAP_POSITIVE_X: + case GL_TEXTURE_CUBE_MAP_NEGATIVE_X: + case GL_TEXTURE_CUBE_MAP_POSITIVE_Y: + case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y: + case GL_TEXTURE_CUBE_MAP_POSITIVE_Z: + case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z: + case GL_PROXY_TEXTURE_CUBE_MAP: + glTexImage2D(type, mipLevel, GalFormatGetGlInternalFormat(format), width, height, 0, GalFormatGetGlFormat(format), GalFormatGetGlType(format), data.data()); + break; + case GL_TEXTURE_3D: + case GL_PROXY_TEXTURE_3D: + case GL_TEXTURE_2D_ARRAY: + case GL_PROXY_TEXTURE_2D_ARRAY: + glTexImage3D(type, mipLevel, GalFormatGetGlInternalFormat(format), width, height, depth, 0, GalFormatGetGlFormat(format), GalFormatGetGlType(format), data.data()); + break; + default: + throw std::runtime_error("Unknown texture type"); + } + + glCheckError(); + + glBindTexture(type, 0); + } + +}; + +class PipelineConfigOgl : public PipelineConfig { +public: + std::shared_ptr<ShaderOgl> vertexShader, pixelShader; + std::map<std::string, Type> shaderParameters; + std::shared_ptr<Framebuffer> targetFb; + std::vector<std::vector<VertexAttribute>> vertexBuffers; + +public: + virtual void SetVertexShader(std::shared_ptr<Shader> shader) override { + vertexShader = std::static_pointer_cast<ShaderOgl,Shader>(shader); + } + + virtual void SetPixelShader(std::shared_ptr<Shader> shader) override { + pixelShader = std::static_pointer_cast<ShaderOgl, Shader>(shader); + } + + virtual void AddShaderParameter(std::string_view name, Type type) override { + shaderParameters.emplace(std::string(name), type); + } + + virtual void SetTarget(std::shared_ptr<Framebuffer> target) override { + targetFb = target; + } + + virtual std::shared_ptr<BufferBinding> BindVertexBuffer(std::vector<VertexAttribute> &&bufferLayout) override { + auto binding = std::make_shared<BufferBindingOgl>(vertexBuffers.size()); + vertexBuffers.push_back(bufferLayout); + return std::static_pointer_cast<BufferBinding, BufferBindingOgl>(binding); + } + + virtual std::shared_ptr<BufferBinding> BindIndexBuffer() override { + auto binding = std::make_shared<BufferBindingOgl>(BufferBindingOgl::indexValue); + return std::static_pointer_cast<BufferBinding, BufferBindingOgl>(binding); + } + +}; + +class PipelineInstanceOgl : public PipelineInstance { +public: + GLuint vao; + + virtual void Activate() override { + glBindVertexArray(vao); + glCheckError(); + } + + virtual void Render(size_t offset = 0, size_t count = -1) override { + glDrawElements(GL_TRIANGLES, count, GL_UNSIGNED_INT, 0); + glCheckError(); + } +}; + +class PipelineOgl : public Pipeline { +public: + std::map<std::string, size_t> shaderParameters; + GLuint program; + struct VertexBindingCommand { + size_t bufferId; + size_t location; + GLenum type; + size_t count; + size_t stride; + size_t offset; + }; + std::vector<VertexBindingCommand> vertexBindCmds; + + virtual void Activate() override { + glUseProgram(program); + glCheckError(); + } + + virtual std::shared_ptr<PipelineInstance> CreateInstance(std::vector<std::pair<std::shared_ptr<BufferBinding>, std::shared_ptr<Buffer>>>&& buffers) override { + auto instance = std::make_shared<PipelineInstanceOgl>(); + + size_t indexBuffer = BufferBindingOgl::indexValue; + std::map<size_t, size_t> bufferBindingId; + + for (auto&& [binding, buffer] : buffers) { + auto bind = std::static_pointer_cast<BufferBindingOgl, BufferBinding>(binding); + auto buff = std::static_pointer_cast<BufferOgl, Buffer>(buffer); + + if (bind->bufferId == BufferBindingOgl::indexValue) + indexBuffer = buff->vbo; + else + bufferBindingId.insert({ bind->bufferId,buff->vbo }); + } + + glGenVertexArrays(1, &instance->vao); + glBindVertexArray(instance->vao); + glCheckError(); + + for (const auto& cmd : vertexBindCmds) { + glBindBuffer(GL_ARRAY_BUFFER, bufferBindingId.find(cmd.bufferId)->second); + glCheckError(); + switch (cmd.type) { + case GL_FLOAT: + case GL_DOUBLE: + glVertexAttribPointer(cmd.location, cmd.count, cmd.type, GL_FALSE, cmd.offset, reinterpret_cast<void*>(cmd.stride)); + break; + case GL_UNSIGNED_BYTE: + case GL_BYTE: + case GL_UNSIGNED_SHORT: + case GL_SHORT: + case GL_UNSIGNED_INT: + case GL_INT: + glVertexAttribIPointer(cmd.location, cmd.count, cmd.type, cmd.offset, reinterpret_cast<void*>(cmd.stride)); + break; + } + + glCheckError(); + glEnableVertexAttribArray(cmd.location); + glCheckError(); + } + + if (indexBuffer != BufferBindingOgl::indexValue) { + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer); + } + + glBindVertexArray(0); + glBindBuffer(GL_ARRAY_BUFFER, 0); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); + glCheckError(); + + return instance; + } + + virtual void SetShaderParameter(std::string_view name, float value) override { + Activate(); + glUniform1f(shaderParameters.at(std::string(name)), value); + glCheckError(); + } + + virtual void SetShaderParameter(std::string_view name, double value) override { + Activate(); + glUniform1d(shaderParameters.at(std::string(name)), value); + glCheckError(); + } + + virtual void SetShaderParameter(std::string_view name, int8_t value) override { + Activate(); + glUniform1i(shaderParameters.at(std::string(name)), value); + glCheckError(); + } + + virtual void SetShaderParameter(std::string_view name, int16_t value) override { + Activate(); + glUniform1i(shaderParameters.at(std::string(name)), value); + glCheckError(); + } + + virtual void SetShaderParameter(std::string_view name, int32_t value) override { + Activate(); + glUniform1i(shaderParameters.at(std::string(name)), value); + glCheckError(); + } + + virtual void SetShaderParameter(std::string_view name, uint8_t value) override { + Activate(); + glUniform1ui(shaderParameters.at(std::string(name)), value); + glCheckError(); + } + + virtual void SetShaderParameter(std::string_view name, uint16_t value) override { + Activate(); + glUniform1ui(shaderParameters.at(std::string(name)), value); + glCheckError(); + } + + virtual void SetShaderParameter(std::string_view name, uint32_t value) override { + Activate(); + glUniform1ui(shaderParameters.at(std::string(name)), value); + glCheckError(); + } + + virtual void SetShaderParameter(std::string_view name, glm::vec2 value) override { + Activate(); + glUniform2f(shaderParameters.at(std::string(name)), value.x, value.y); + glCheckError(); + } + + virtual void SetShaderParameter(std::string_view name, glm::uvec2 value) override { + Activate(); + glUniform2ui(shaderParameters.at(std::string(name)), value.x, value.y); + glCheckError(); + } + + virtual void SetShaderParameter(std::string_view name, glm::vec3 value) override { + Activate(); + glUniform3f(shaderParameters.at(std::string(name)), value.x, value.y, value.z); + glCheckError(); + } + + virtual void SetShaderParameter(std::string_view name, glm::vec4 value) override { + Activate(); + glUniform4f(shaderParameters.at(std::string(name)), value.x, value.y, value.z, value.w); + glCheckError(); + } + + virtual void SetShaderParameter(std::string_view name, glm::mat4 value) override { + Activate(); + glCheckError(); + } +}; + +class ImplOgl : public Impl { + +public: + + virtual void Init() override { + LOG(INFO) << "Initalizing Gal:OpenGL..."; + LOG(INFO) << "Initializing GLEW"; + glewExperimental = GL_TRUE; + GLenum glewStatus = glewInit(); + glCheckError(); + if (glewStatus != GLEW_OK) { + LOG(FATAL) << "Failed to initialize GLEW: " << glewGetErrorString(glewStatus); + } + glClearColor(0.0f, 0.0f, 0.0f, 1.0f); + glEnable(GL_DEPTH_TEST); + glDepthFunc(GL_LEQUAL); + + glEnable(GL_CULL_FACE); + glCullFace(GL_BACK); + glFrontFace(GL_CCW); + + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glCheckError(); + if (glActiveTexture == nullptr) { + throw std::runtime_error("GLEW initialization failed with unknown reason"); + } + } + + virtual void DeInit() override { + LOG(INFO) << "Destroying Gal:OpenGL..."; + } + + virtual void Cleanup() override { + + } + + + virtual std::shared_ptr<Buffer> CreateBuffer() override { + auto buff = std::make_shared<BufferOgl>(); + glGenBuffers(1, &buff->vbo); + buff->SetData({}); + glCheckError(); + return std::static_pointer_cast<Buffer, BufferOgl>(buff); + } + + + virtual std::shared_ptr<TextureConfig> CreateTexture2DConfig(size_t width, size_t height, Format format) override { + auto config = std::make_shared<TextureConfigOgl>(); + + config->width = width; + config->height = height; + config->format = format; + + return std::static_pointer_cast<TextureConfig, TextureConfigOgl>(config); + } + + virtual std::shared_ptr<TextureConfig> CreateTexture3DConfig(size_t width, size_t height, size_t depth, bool interpolateLayers, Format format) override { + auto config = std::make_shared<TextureConfigOgl>(); + + config->width = width; + config->height = height; + config->depth = depth; + config->interpolateLayers = interpolateLayers; + config->format = format; + + return std::static_pointer_cast<TextureConfig, TextureConfigOgl>(config); + } + + virtual std::shared_ptr<Texture> BuildTexture(std::shared_ptr<TextureConfig> config) override { + auto texConfig = std::static_pointer_cast<TextureConfigOgl, TextureConfig>(config); + auto texture = std::make_shared<TextureOgl>(); + + texture->type = GL_TEXTURE_2D; + texture->format = texConfig->format; + texture->width = texConfig->width; + texture->height = texConfig->height; + texture->depth = texConfig->depth; + + glGenTextures(1, &texture->texture); + glCheckError(); + + glTexParameteri(texture->type, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(texture->type, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(texture->type, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(texture->type, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + + glCheckError(); + + texture->SetData(std::vector<std::byte>(texture->width * texture->height * texture->depth * GalFormatGetSize(texture->format))); + glCheckError(); + + return std::static_pointer_cast<Texture, TextureOgl>(texture); + } + + + virtual std::shared_ptr<PipelineConfig> CreatePipelineConfig() override { + auto pipelineConfig = std::make_shared<PipelineConfigOgl>(); + return std::static_pointer_cast<PipelineConfig, PipelineConfigOgl>(pipelineConfig); + } + + virtual std::shared_ptr<Pipeline> BuildPipeline(std::shared_ptr<PipelineConfig> pipelineConfig) override { + auto pipeline = std::make_shared<PipelineOgl>(); + auto config = std::static_pointer_cast<PipelineConfigOgl, PipelineConfig>(pipelineConfig); + + //Shader compilation + + bool vertexFailed = false, pixelFailed = false, linkFailed = false; + + const GLchar* vertexSourcePtr = config->vertexShader->code.c_str(); + const GLchar* pixelSourcePtr = config->pixelShader->code.c_str(); + + GLuint vertex, pixel; + GLint success; + GLuint program; + GLchar infoLog[512]; + + vertex = glCreateShader(GL_VERTEX_SHADER); + glShaderSource(vertex, 1, &vertexSourcePtr, NULL); + glCompileShader(vertex); + + glGetShaderiv(vertex, GL_COMPILE_STATUS, &success); + if (!success) { + glGetShaderInfoLog(vertex, 512, NULL, infoLog); + LOG(ERROR) << "Vertex shader compilation failed: " << std::endl << infoLog; + vertexFailed = true; + }; + + pixel = glCreateShader(GL_FRAGMENT_SHADER); + glShaderSource(pixel, 1, &pixelSourcePtr, NULL); + glCompileShader(pixel); + + glGetShaderiv(pixel, GL_COMPILE_STATUS, &success); + if (!success) { + glGetShaderInfoLog(pixel, 512, NULL, infoLog); + LOG(ERROR) << "Fragment shader compilation failed: " << std::endl << infoLog; + pixelFailed = true; + }; + + if (vertexFailed || pixelFailed) + throw std::runtime_error("Shaders not compiled"); + + program = glCreateProgram(); + glAttachShader(program, vertex); + glAttachShader(program, pixel); + glLinkProgram(program); + glGetProgramiv(program, GL_LINK_STATUS, &success); + if (!success) { + glGetProgramInfoLog(program, 512, NULL, infoLog); + LOG(ERROR) << "Shader program not linked: " << std::endl << infoLog; + linkFailed = true; + } + + glDeleteShader(vertex); + glDeleteShader(pixel); + + if (linkFailed) + throw std::runtime_error("Shader not linked"); + + glUseProgram(program); + + glCheckError(); + + pipeline->program = program; + + //Shader parameters + + for (auto&& [name, type] : config->shaderParameters) { + GLint location = glGetUniformLocation(program, name.c_str()); + if (location < 0) { + glDeleteProgram(program); + LOG(ERROR) << "Uniform name \"" << name << "\" not found in shader"; + throw std::runtime_error("Invalid uniform"); + } + switch (type) { + case Type::Vec2: + glUniform2f(location, 0.0f, 0.0f); + break; + case Type::Vec2u8: + case Type::Vec2u16: + case Type::Vec2u32: + glUniform2ui(location, 0, 0); + break; + case Type::Vec4u8: + glUniform4ui(location, 0, 0, 0, 0); + break; + } + pipeline->shaderParameters.insert({ name,location }); + } + + //Vertex attributes + + size_t bufferId = 0; + for (const auto& buffer : config->vertexBuffers) { + size_t vertexSize = 0; + size_t cmdOffset = pipeline->vertexBindCmds.size(); + for (const auto& [name, type] : buffer) { + if (name.empty()) { + vertexSize += GalTypeGetSize(type); + continue; + } + + GLint location = glGetAttribLocation(program, name.c_str()); + if (location < 0) { + glDeleteProgram(program); + LOG(ERROR) << "Vertex attribute name \"" << name << "\" not found in shader"; + throw std::runtime_error("Invalid attribute"); + } + + size_t attribSize = GalTypeGetSize(type); + + pipeline->vertexBindCmds.push_back({ + bufferId, + static_cast<size_t>(location), + GalTypeGetComponentGlType(type), + GalTypeGetComponents(type), + vertexSize, + 0 + }); + + vertexSize += attribSize; + } + + for (size_t i = cmdOffset; i < pipeline->vertexBindCmds.size(); i++) + pipeline->vertexBindCmds[i].offset = vertexSize; + + bufferId++; + } + + glCheckError(); + + return pipeline; + } + + virtual std::shared_ptr<FramebufferConfig> CreateFramebufferConfig() override { + return nullptr; + } + + virtual std::shared_ptr<Framebuffer> BuildFramebuffer(std::shared_ptr<FramebufferConfig> config) override { + return nullptr; + } + + virtual std::shared_ptr<Framebuffer> GetDefaultFramebuffer() override { + if (!fbDefault) + fbDefault = std::make_shared<FramebufferDefaultOgl>(); + return std::static_pointer_cast<Framebuffer, FramebufferDefaultOgl>(fbDefault); + } + + + virtual std::shared_ptr<ShaderParameters> GetGlobalShaderParameters() override { + return nullptr; + } + + virtual std::shared_ptr<Shader> LoadVertexShader(std::string_view code) override { + auto shader = std::make_shared<ShaderOgl>(); + shader->code = code; + shader->isVertex = true; + return std::static_pointer_cast<Shader, ShaderOgl>(shader); + } + + virtual std::shared_ptr<Shader> LoadPixelShader(std::string_view code) override { + auto shader = std::make_shared<ShaderOgl>(); + shader->code = code; + shader->isVertex = false; + return std::static_pointer_cast<Shader, ShaderOgl>(shader); + } +}; + +class FramebufferDefaultOgl : public Framebuffer { + size_t vpX, vpY, vpW, vpH; +public: + + virtual void Clear() override { + GLbitfield clearBits = 0; + clearBits |= GL_COLOR_BUFFER_BIT; + clearBits |= GL_DEPTH_BUFFER_BIT; + clearBits |= GL_STENCIL_BUFFER_BIT; + glClear(clearBits); + } + + virtual void SetViewport(size_t x, size_t y, size_t w, size_t h) override { + vpX = x; + vpY = y; + vpW = w; + vpH = h; + glViewport(x, y, w, h); + } +}; + +Impl* Gal::GetImplementation() +{ + if (!impl) + impl = std::make_unique<ImplOgl>(); + + return impl.get(); +} diff --git a/src/Render.cpp b/src/Render.cpp index b9b7ab0..8b78efb 100644 --- a/src/Render.cpp +++ b/src/Render.cpp @@ -18,6 +18,7 @@ #include "Framebuffer.hpp" #include "Plugin.hpp" #include "Rml.hpp" +#include "Gal.hpp" const std::map<SDL_Keycode, Rml::Input::KeyIdentifier> keyMapping = { {SDLK_BACKSPACE, Rml::Input::KI_BACK}, @@ -117,30 +118,12 @@ void Render::InitSdl(unsigned int WinWidth, unsigned int WinHeight, std::string } void Render::InitGlew() { - LOG(INFO) << "Initializing GLEW"; - glewExperimental = GL_TRUE; - GLenum glewStatus = glewInit(); - glCheckError(); - if (glewStatus != GLEW_OK) { - LOG(FATAL) << "Failed to initialize GLEW: " << glewGetErrorString(glewStatus); - } + auto gal = Gal::GetImplementation(); + gal->Init(); + int width, height; SDL_GL_GetDrawableSize(window, &width, &height); - glViewport(0, 0, width, height); - glClearColor(0.0f,0.0f,0.0f, 1.0f); - glEnable(GL_DEPTH_TEST); - glDepthFunc(GL_LEQUAL); - - glEnable(GL_CULL_FACE); - glCullFace(GL_BACK); - glFrontFace(GL_CCW); - - glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - glCheckError(); - if (glActiveTexture == nullptr) { - throw std::runtime_error("GLEW initialization failed with unknown reason"); - } + gal->GetDefaultFramebuffer()->SetViewport(0, 0, width, height); } void Render::PrepareToRendering() { @@ -175,19 +158,19 @@ void Render::UpdateKeyboard() { void Render::RenderFrame() { OPTICK_EVENT(); - framebuffer->Clear(); + //framebuffer->Clear(); Framebuffer::GetDefault().Clear(); - if (renderWorld) - framebuffer->Activate(); + //if (renderWorld) + // framebuffer->Activate(); if (isWireframe) glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); if (renderWorld) world->Render(renderState); if (isWireframe) glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); - if (renderWorld) - framebuffer->RenderTo(Framebuffer::GetDefault()); + //if (renderWorld) + // framebuffer->RenderTo(Framebuffer::GetDefault()); RenderGui(); diff --git a/src/Rml.cpp b/src/Rml.cpp index 179d4b9..4e28529 100644 --- a/src/Rml.cpp +++ b/src/Rml.cpp @@ -46,74 +46,98 @@ void RmlSystemInterface::GetClipboardText(Rml::String& text) { } RmlRenderInterface::RmlRenderInterface(RenderState& renderState) : State(&renderState) { - glGenVertexArrays(1, &Vao); - glBindVertexArray(Vao); - glCheckError(); + auto gal = Gal::GetImplementation(); + auto pipelineConfig = gal->CreatePipelineConfig(); + pipelineConfig->AddShaderParameter("viewportSize", Gal::Type::Vec2u32); + pipelineConfig->AddShaderParameter("translation", Gal::Type::Vec2); + pipelineConfig->SetTarget(gal->GetDefaultFramebuffer()); - glGenBuffers(1, &Ebo); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, Ebo); - glBufferData(GL_ELEMENT_ARRAY_BUFFER, 0, nullptr, GL_STREAM_DRAW); - glCheckError(); + auto vertAsset = AssetManager::GetAssetByAssetName("/altcraft/shaders/vert/rml"); + std::string vertSource((char*)vertAsset->data.data(), (char*)vertAsset->data.data() + vertAsset->data.size()); + auto pixelAsset = AssetManager::GetAssetByAssetName("/altcraft/shaders/frag/rml"); + std::string pixelSource((char*)pixelAsset->data.data(), (char*)pixelAsset->data.data() + pixelAsset->data.size()); + pipelineConfig->SetVertexShader(gal->LoadVertexShader(vertSource)); + pipelineConfig->SetPixelShader(gal->LoadPixelShader(pixelSource)); + + auto vertBuffBind = pipelineConfig->BindVertexBuffer({ + {"pos", Gal::Type::Vec2}, + {"color", Gal::Type::Vec4u8}, + {"", Gal::Type::Vec2}, //it's not used in shader, so driver optimizes it away + }); + + auto indexBuffBind = pipelineConfig->BindIndexBuffer(); + + pipeline = gal->BuildPipeline(pipelineConfig); + + vertexBuffer = gal->CreateBuffer(); + + indexBuffer = gal->CreateBuffer(); + + pipelineInstance = pipeline->CreateInstance({ + {vertBuffBind, vertexBuffer}, + {indexBuffBind, indexBuffer}, + }); - glGenBuffers(1, &Vbo); - glBindBuffer(GL_ARRAY_BUFFER, Vbo); - glBufferData(GL_ARRAY_BUFFER, 0, nullptr, GL_STREAM_DRAW); glCheckError(); - - { - //Vertex position (2 float) - GLuint PosAttribPos = 0; - glVertexAttribPointer(PosAttribPos, 2, GL_FLOAT, GL_FALSE, 20, (void*)0); - glEnableVertexAttribArray(PosAttribPos); - - //Vertex colour (4 uint8 RGBA) - GLuint ColAttribPos = 1; - glVertexAttribIPointer(ColAttribPos, 4, GL_UNSIGNED_BYTE, 20, (void*)8); - glEnableVertexAttribArray(ColAttribPos); - - //Vertex tex_coord (2 float) - GLuint TexAttribPos = 2; - glVertexAttribPointer(TexAttribPos, 2, GL_FLOAT, GL_FALSE, 20, (void*)12); - glEnableVertexAttribArray(TexAttribPos); - } - glBindVertexArray(0); - glBindBuffer(GL_ARRAY_BUFFER, 0); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); + + auto texturePipelineConfig = gal->CreatePipelineConfig(); + texturePipelineConfig->AddShaderParameter("viewportSize", Gal::Type::Vec2u32); + texturePipelineConfig->AddShaderParameter("translation", Gal::Type::Vec2); + texturePipelineConfig->AddShaderParameter("fontTexture", Gal::Type::Int32); + texturePipelineConfig->SetTarget(gal->GetDefaultFramebuffer()); + + auto texturePixelAsset = AssetManager::GetAssetByAssetName("/altcraft/shaders/frag/rmltex"); + std::string texturePixelSource((char*)texturePixelAsset->data.data(), (char*)texturePixelAsset->data.data() + texturePixelAsset->data.size()); + texturePipelineConfig->SetVertexShader(gal->LoadVertexShader(vertSource)); + texturePipelineConfig->SetPixelShader(gal->LoadPixelShader(texturePixelSource)); + + auto texVertBuffBind = texturePipelineConfig->BindVertexBuffer({ + {"pos", Gal::Type::Vec2}, + {"color", Gal::Type::Vec4u8}, + {"tex_coord", Gal::Type::Vec2}, + }); + + auto texIndexBuffBind = texturePipelineConfig->BindIndexBuffer(); + + texPipeline = gal->BuildPipeline(texturePipelineConfig); + + texPipelineInstance = texPipeline->CreateInstance({ + {texVertBuffBind, vertexBuffer}, + {texIndexBuffBind, indexBuffer}, + }); glCheckError(); } RmlRenderInterface::~RmlRenderInterface() { - glDeleteVertexArrays(1, &Vao); - glDeleteBuffers(1, &Vbo); - glDeleteBuffers(1, &Ebo); glCheckError(); } void RmlRenderInterface::RenderGeometry(Rml::Vertex* vertices, int num_vertices, int* indices, int num_indices, Rml::TextureHandle texture, const Rml::Vector2f& translation) { + indexBuffer->SetData({ reinterpret_cast<std::byte*>(indices), reinterpret_cast<std::byte*>(indices + num_indices) }); + vertexBuffer->SetData({ reinterpret_cast<std::byte*>(vertices), reinterpret_cast<std::byte*>(vertices + num_vertices) }); + glCheckError(); + + if (texture) { - AssetManager::GetAsset<AssetShader>("/altcraft/shaders/rmltex")->shader->Activate(); - AssetManager::GetAsset<AssetShader>("/altcraft/shaders/rmltex")->shader->SetUniform("translation", glm::vec2(translation.x, translation.y)); + texPipeline->Activate(); + glCheckError(); + texPipeline->SetShaderParameter("translation", glm::vec2(translation.x, translation.y)); + glCheckError(); + texPipelineInstance->Activate(); + glCheckError(); glBindTexture(GL_TEXTURE_2D, texture); + glCheckError(); + texPipelineInstance->Render(0, num_indices); } else { - AssetManager::GetAsset<AssetShader>("/altcraft/shaders/rml")->shader->Activate(); - AssetManager::GetAsset<AssetShader>("/altcraft/shaders/rml")->shader->SetUniform("translation", glm::vec2(translation.x, translation.y)); - } - glCheckError(); - - glBindVertexArray(Vao); - glCheckError(); - - glBindBuffer(GL_ARRAY_BUFFER, Vbo); - glBufferData(GL_ARRAY_BUFFER, num_vertices * sizeof(Rml::Vertex), vertices, GL_STREAM_DRAW); - glCheckError(); - - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, Ebo); - glBufferData(GL_ELEMENT_ARRAY_BUFFER, num_indices * sizeof(int), indices, GL_STREAM_DRAW); - glCheckError(); - - glDrawElements(GL_TRIANGLES, num_indices, GL_UNSIGNED_INT, 0); + pipeline->Activate(); + glCheckError(); + pipeline->SetShaderParameter("translation", glm::vec2(translation.x, translation.y)); + glCheckError(); + pipelineInstance->Activate(); + glCheckError(); + pipelineInstance->Render(0, num_indices); + } glCheckError(); - glBindVertexArray(0); } void RmlRenderInterface::EnableScissorRegion(bool enable) { @@ -158,13 +182,14 @@ void RmlRenderInterface::ReleaseTexture(Rml::TextureHandle texture) { } void RmlRenderInterface::Update(unsigned int windowWidth, unsigned int windowHeight) { - AssetManager::GetAsset<AssetShader>("/altcraft/shaders/rml")->shader->Activate(); - AssetManager::GetAsset<AssetShader>("/altcraft/shaders/rml")->shader->SetUniform("viewportSize", windowWidth, windowHeight); - glCheckError(); - AssetManager::GetAsset<AssetShader>("/altcraft/shaders/rmltex")->shader->Activate(); - AssetManager::GetAsset<AssetShader>("/altcraft/shaders/rmltex")->shader->SetUniform("viewportSize", windowWidth, windowHeight); - AssetManager::GetAsset<AssetShader>("/altcraft/shaders/rmltex")->shader->SetUniform("fontTexture", 0); + glCheckError(); + + + pipeline->SetShaderParameter("viewportSize", glm::uvec2(windowWidth, windowHeight)); + texPipeline->SetShaderParameter("viewportSize", glm::uvec2(windowWidth, windowHeight)); + texPipeline->SetShaderParameter("fontTexture", 0); + vpWidth = windowWidth; vpHeight = windowHeight; } diff --git a/src/Rml.hpp b/src/Rml.hpp index edcdc8b..42203d4 100644 --- a/src/Rml.hpp +++ b/src/Rml.hpp @@ -7,6 +7,7 @@ #include <RmlUi/Core/FileInterface.h> #include "Renderer.hpp" +#include "Gal.hpp" class AssetTreeNode; @@ -32,7 +33,9 @@ public: class RmlRenderInterface : public Rml::RenderInterface { RenderState* State; - GLuint Vao, Vbo, Ebo; + std::shared_ptr<Gal::Pipeline> pipeline, texPipeline; + std::shared_ptr<Gal::PipelineInstance> pipelineInstance, texPipelineInstance; + std::shared_ptr<Gal::Buffer> vertexBuffer, indexBuffer; unsigned int vpWidth, vpHeight; public: |