diff --git a/TSE_Core/src/elements/ShaderRegistry.hpp b/TSE_Core/src/elements/ShaderRegistry.hpp index dea04ec..01a3595 100644 --- a/TSE_Core/src/elements/ShaderRegistry.hpp +++ b/TSE_Core/src/elements/ShaderRegistry.hpp @@ -12,15 +12,15 @@ namespace TSE inline static std::unordered_map registeredShaders = {}; public: - inline static void SetShader(string& name, IShader* shader) + inline static void SetShader(const string& name, IShader* shader) { registeredShaders[name] = shader; }; - inline static IShader* GetShader(string& name) + inline static IShader* GetShader(const string& name) { return registeredShaders.at(name); }; - inline static void RemoveShader(string& name) + inline static void RemoveShader(const string& name) { registeredShaders.erase(name); }; diff --git a/TSE_Core/src/interfaces/IRenderTarget.hpp b/TSE_Core/src/interfaces/IRenderTarget.hpp index 2a9913e..a511ce3 100644 --- a/TSE_Core/src/interfaces/IRenderTarget.hpp +++ b/TSE_Core/src/interfaces/IRenderTarget.hpp @@ -9,7 +9,7 @@ namespace TSE public: int UnitScaler = 32; - virtual void Update() const = 0; + virtual void Update() = 0; virtual void Bind() = 0; virtual void Unbind() = 0; }; diff --git a/TSE_GlfwImpl/src/WindowGlfw.cpp b/TSE_GlfwImpl/src/WindowGlfw.cpp index 0711f95..9850ac3 100644 --- a/TSE_GlfwImpl/src/WindowGlfw.cpp +++ b/TSE_GlfwImpl/src/WindowGlfw.cpp @@ -132,7 +132,7 @@ void TSE::GLFW::WindowGlfw::Clear() const renderingBackend->onClear(); } -void TSE::GLFW::WindowGlfw::Update() const +void TSE::GLFW::WindowGlfw::Update() { BaseUpdate(); glfwPollEvents(); diff --git a/TSE_GlfwImpl/src/WindowGlfw.hpp b/TSE_GlfwImpl/src/WindowGlfw.hpp index 0ef0f10..af06d24 100644 --- a/TSE_GlfwImpl/src/WindowGlfw.hpp +++ b/TSE_GlfwImpl/src/WindowGlfw.hpp @@ -31,7 +31,7 @@ namespace TSE::GLFW public: void Clear() const override; - void Update() const override; + void Update() override; void ClearDepthBuffer() const override; bool ShouldClose() const override; inline void Bind() override { }; diff --git a/TSE_GlfwOpenGlImpl/src/RenderTexture.cpp b/TSE_GlfwOpenGlImpl/src/RenderTexture.cpp new file mode 100644 index 0000000..264f9a1 --- /dev/null +++ b/TSE_GlfwOpenGlImpl/src/RenderTexture.cpp @@ -0,0 +1,54 @@ +#include "RenderTexture.hpp" + +TSE::GLFW::RenderTexture::RenderTexture(Vector2 v) : buffer(v) +{ + buffer.AddResizeNotifiable(this); +} + +TSE::Vector2 TSE::GLFW::RenderTexture::size() const +{ + return buffer.GetSize(); +} + +void TSE::GLFW::RenderTexture::SetSize(Vector2 v) +{ + buffer.Resize(v); +} + +float TSE::GLFW::RenderTexture::width() const +{ + return buffer.GetSize().x; +} + +float TSE::GLFW::RenderTexture::height() const +{ + return buffer.GetSize().y; +} + +uint TSE::GLFW::RenderTexture::GetTextureId() const +{ + return buffer.GetTextureId(); +} + +void TSE::GLFW::RenderTexture::Update() +{ + buffer.Update(); +} + +void TSE::GLFW::RenderTexture::Bind() +{ + buffer.Bind(); +} + +void TSE::GLFW::RenderTexture::Unbind() +{ + buffer.Unbind(); +} + +void TSE::GLFW::RenderTexture::OnResize(float width, float height, IResizable *wnd) +{ + for (auto const& i : objectsToResize) + { + i->OnResize(width, height, this); + } +} diff --git a/TSE_GlfwOpenGlImpl/src/RenderTexture.hpp b/TSE_GlfwOpenGlImpl/src/RenderTexture.hpp new file mode 100644 index 0000000..46eb852 --- /dev/null +++ b/TSE_GlfwOpenGlImpl/src/RenderTexture.hpp @@ -0,0 +1,29 @@ +#pragma once + +#include "buffer/FrameBuffer.hpp" +#include "interfaces/IRenderTarget.hpp" +#include "interfaces/ITexture.hpp" +#include "interfaces/IResizeNotifiable.hpp" + +namespace TSE::GLFW +{ + class RenderTexture : public IRenderTarget, public ITexture, public IResizeNotifiable + { + public: + FrameBuffer buffer; + + RenderTexture(Vector2 v); + + Vector2 size() const override; + void SetSize(Vector2 v); + float width() const override; + float height() const override; + uint GetTextureId() const override; + + void Update() override; + void Bind() override; + void Unbind() override; + + void OnResize(float width, float height, IResizable* wnd) override; + }; +} // namespace TSE::GLFW diff --git a/TSE_GlfwOpenGlImpl/src/buffer/FrameBuffer.cpp b/TSE_GlfwOpenGlImpl/src/buffer/FrameBuffer.cpp new file mode 100644 index 0000000..25ca93d --- /dev/null +++ b/TSE_GlfwOpenGlImpl/src/buffer/FrameBuffer.cpp @@ -0,0 +1,97 @@ +#include "FrameBuffer.hpp" +#include "Debug.hpp" + +TSE::GLFW::FrameBuffer::FrameBuffer(const Vector2 &size) +{ + this->size = size; + CreateFBTexture(); + for (auto const& i : objectsToResize) + { + i->OnResize(size.x, size.y, this); + } + Initialize(); +} + +void TSE::GLFW::FrameBuffer::Bind() +{ + glBindFramebuffer(GL_FRAMEBUFFER, bufferID); +} + +void TSE::GLFW::FrameBuffer::Unbind() +{ + glBindFramebuffer(GL_FRAMEBUFFER, 0); +} + +TSE::GLFW::FrameBuffer::~FrameBuffer() +{ + glDeleteFramebuffers(1,&bufferID); + glDeleteTextures(1, &textureID); + glDeleteRenderbuffers(1, &depthRboID); +} + +void TSE::GLFW::FrameBuffer::Resize(Vector2 size) +{ + this->size = size; + shouldResize = true; +} + +void TSE::GLFW::FrameBuffer::Update() +{ + if (!shouldResize) return; + shouldResize = false; + CreateFBTexture(); + for (auto const& i : objectsToResize) + { + i->OnResize(size.x, size.y, this); + } +} + +TSE::uint TSE::GLFW::FrameBuffer::GetTextureId() const +{ + return textureID; +} + +TSE::Vector2 TSE::GLFW::FrameBuffer::GetSize() const +{ + return size; +} + +void TSE::GLFW::FrameBuffer::Initialize() +{ + glGenFramebuffers(1, &bufferID); + Bind(); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, textureID, 0); + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depthRboID); + + if(glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) + { + TSE_ERROR("Failed to create OpenGL FBO."); + TSE_LOG(std::to_string(glGetError())); + } + Unbind(); +} + +void TSE::GLFW::FrameBuffer::LoadFBTexture() +{ + glBindTexture(GL_TEXTURE_2D, textureID); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, size.x, size.y, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + + glBindRenderbuffer(GL_RENDERBUFFER, depthRboID); + glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, size.x, size.y); +} + +void TSE::GLFW::FrameBuffer::CreateFBTexture() +{ + glViewport(0,0, size.x, size.y); + //resize + if(textureID == 0) + glGenTextures(1, &textureID); + if(depthRboID == 0) + glGenRenderbuffers(1, &depthRboID); + LoadFBTexture(); +} diff --git a/TSE_GlfwOpenGlImpl/src/buffer/FrameBuffer.hpp b/TSE_GlfwOpenGlImpl/src/buffer/FrameBuffer.hpp new file mode 100644 index 0000000..eec9cf2 --- /dev/null +++ b/TSE_GlfwOpenGlImpl/src/buffer/FrameBuffer.hpp @@ -0,0 +1,32 @@ +#pragma once + +#include "buffer.hpp" +#include "interfaces/IResizable.hpp" +#include "Vector2.hpp" + +namespace TSE::GLFW +{ + class FrameBuffer : public buffer, public IResizable + { + private: + uint textureID = 0; + uint depthRboID = 0; + Vector2 size; + bool shouldResize = false; + + public: + FrameBuffer(const Vector2& size); + void Bind() override; + void Unbind() override; + ~FrameBuffer() override; + void Resize(Vector2 size); + void Update(); + uint GetTextureId() const; + Vector2 GetSize() const; + + private: + void Initialize(); + void LoadFBTexture(); + void CreateFBTexture(); + }; +} // namespace TSE diff --git a/TSE_GlfwOpenGlImpl/src/buffer/IndexBuffer.cpp b/TSE_GlfwOpenGlImpl/src/buffer/IndexBuffer.cpp new file mode 100644 index 0000000..195e988 --- /dev/null +++ b/TSE_GlfwOpenGlImpl/src/buffer/IndexBuffer.cpp @@ -0,0 +1,24 @@ +#include "IndexBuffer.hpp" + +TSE::GLFW::IndexBuffer::IndexBuffer(ushort *data, ushort count) +{ + glGenBuffers(1, &bufferID); + WriteData(data, count); +} + +void TSE::GLFW::IndexBuffer::WriteData(ushort *data, ushort count) +{ + Bind(); + glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(ushort) * count, data, GL_DYNAMIC_DRAW); + Unbind(); +} + +void TSE::GLFW::IndexBuffer::Bind() +{ + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, bufferID); +} + +void TSE::GLFW::IndexBuffer::Unbind() +{ + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); +} diff --git a/TSE_GlfwOpenGlImpl/src/buffer/IndexBuffer.hpp b/TSE_GlfwOpenGlImpl/src/buffer/IndexBuffer.hpp new file mode 100644 index 0000000..9e49fec --- /dev/null +++ b/TSE_GlfwOpenGlImpl/src/buffer/IndexBuffer.hpp @@ -0,0 +1,17 @@ +#pragma once + +#include "buffer.hpp" +#include "Types.hpp" + +namespace TSE::GLFW +{ + class IndexBuffer : public buffer + { + public: + IndexBuffer(ushort* data, ushort count); + inline IndexBuffer() = default; + void WriteData(ushort* data, ushort count); + void Bind() override; + void Unbind() override; + }; +} // namespace TSE::GLFW diff --git a/TSE_GlfwOpenGlImpl/src/buffer/VertexBuffer.cpp b/TSE_GlfwOpenGlImpl/src/buffer/VertexBuffer.cpp new file mode 100644 index 0000000..b4c5f6f --- /dev/null +++ b/TSE_GlfwOpenGlImpl/src/buffer/VertexBuffer.cpp @@ -0,0 +1,39 @@ +#include "VertexBuffer.hpp" + +TSE::uint TSE::GLFW::VertexBuffer::boundBuffer = 0; + +TSE::GLFW::VertexBuffer::VertexBuffer() +{ + glGenBuffers(1, &bufferID); +} + +void TSE::GLFW::VertexBuffer::SetData(int size, void *buffer, GLenum usage) +{ + glBufferData(GL_ARRAY_BUFFER, size, buffer, usage); +} + +void TSE::GLFW::VertexBuffer::Bind() +{ + glBindBuffer(GL_ARRAY_BUFFER, bufferID); + boundBuffer = bufferID; +} + +void TSE::GLFW::VertexBuffer::Unbind() +{ + glBindBuffer(GL_ARRAY_BUFFER, 0); + boundBuffer = 0; +} + +bool TSE::GLFW::VertexBuffer::IsBound() +{ + return boundBuffer == bufferID; +} + +TSE::GLFW::VertexBuffer::~VertexBuffer() +{ + if(bufferID != 0) + { + if(IsBound()) Unbind(); + glDeleteBuffers(1, &bufferID); + } +} diff --git a/TSE_GlfwOpenGlImpl/src/buffer/VertexBuffer.hpp b/TSE_GlfwOpenGlImpl/src/buffer/VertexBuffer.hpp new file mode 100644 index 0000000..6584581 --- /dev/null +++ b/TSE_GlfwOpenGlImpl/src/buffer/VertexBuffer.hpp @@ -0,0 +1,18 @@ +#pragma once + +#include "buffer.hpp" + +namespace TSE::GLFW +{ + class VertexBuffer : public buffer + { + public: + static uint boundBuffer; + VertexBuffer(); + void SetData(int size, void* buffer, GLenum usage); + void Bind() override; + void Unbind() override; + bool IsBound(); + ~VertexBuffer(); + }; +} // namespace TSE::GLFW diff --git a/TSE_GlfwOpenGlImpl/src/buffer/buffer.hpp b/TSE_GlfwOpenGlImpl/src/buffer/buffer.hpp new file mode 100644 index 0000000..aa33315 --- /dev/null +++ b/TSE_GlfwOpenGlImpl/src/buffer/buffer.hpp @@ -0,0 +1,26 @@ +#pragma once + +#include "GL/gl3w.h" +#include "Types.hpp" + +namespace TSE::GLFW +{ + class buffer + { + protected: + uint bufferID = 0; + + public: + inline bool Initialized() + { + return bufferID != 0; + } + virtual void Bind() = 0; + virtual void Unbind() = 0; + + inline virtual ~buffer() + { + glDeleteBuffers(1, &bufferID); + } + }; +} // namespace TSE diff --git a/TSE_GlfwOpenGlImpl/src/shader/Shader.cpp b/TSE_GlfwOpenGlImpl/src/shader/Shader.cpp new file mode 100644 index 0000000..0658666 --- /dev/null +++ b/TSE_GlfwOpenGlImpl/src/shader/Shader.cpp @@ -0,0 +1,137 @@ +#include "Shader.hpp" +#include "GL/gl3w.h" +#include "Debug.hpp" + +TSE::uint TSE::GLFW::Shader::activeProgramID = 0; + +void TSE::GLFW::Shader::Bind() const +{ + Enable(true); +} + +void TSE::GLFW::Shader::Unbind() const +{ + Disable(true); +} + +void TSE::GLFW::Shader::Enable(bool notify) const +{ + activeProgramID = programID; + glUseProgram(programID); + if(notify) OnEnable(); +} + +void TSE::GLFW::Shader::Disable(bool notify) const +{ + activeProgramID = 0; + glUseProgram(0); + if(notify) OnDisable(); +} + +void TSE::GLFW::Shader::Flush() +{ + OnFlush(); +} + +void TSE::GLFW::Shader::DrawCall(int indexCount) +{ + OnDrawCall(indexCount); +} + +void TSE::GLFW::Shader::Submit(const Transformable &t, float *&target, TransformationStack &stack, void (*restartDrawcall)(IRenderer &), IRenderer &rnd) +{ + OnSubmit(t, target, stack, restartDrawcall, rnd); +} + +bool TSE::GLFW::Shader::IsEnabled() const +{ + return programID == activeProgramID; +} + +int TSE::GLFW::Shader::packageSize() +{ + return PackageSize; +} + +TSE::GLFW::Shader::Shader(const std::vector> &parts) +{ + programID = glCreateProgram(); + + for (const auto& part : parts) { + glAttachShader(programID, part->shaderPartID); + } + + glLinkProgram(programID); + + int success; + + glGetProgramiv(programID, GL_LINK_STATUS, &success); + + if(!success) + { + char log[512]; + glGetProgramInfoLog(programID, 512, nullptr, log); + TSE_ERROR(log); + } + + for (const auto& part : parts) { + glDetachShader(programID, part->shaderPartID); + } +} + +TSE::GLFW::Shader::~Shader() +{ + glDeleteProgram(programID); +} + +int TSE::GLFW::Shader::GetUniformLocation(const char *name) +{ + auto it = uniformLocations.find(name); + if (it != uniformLocations.end()) return it->second; + + int loc = glGetUniformLocation(programID, name); + uniformLocations[name] = loc; + return loc; +} + +void TSE::GLFW::Shader::SetUniform(const char *name, int value) +{ + glUniform1i(GetUniformLocation(name), value); +} + +void TSE::GLFW::Shader::SetUniform(const char *name, const int *value, const int count) +{ + glUniform1iv(GetUniformLocation(name), count, value); +} + +void TSE::GLFW::Shader::SetUniform(const char *name, const Matrix4x4 *value) +{ + float colmbMajor[16]; + value->ToArrayColumnMajor(colmbMajor); + glUniformMatrix4fv(GetUniformLocation(name),1, false, colmbMajor); +} + +void TSE::GLFW::Shader::SetUniform(const char *name, float value) +{ + glUniform1f(GetUniformLocation(name), value); +} + +void TSE::GLFW::Shader::SetUniform(const char *name, const float *value, const int count) +{ + glUniform1fv(GetUniformLocation(name), count, value); +} + +void TSE::GLFW::Shader::SetUniform(const char *name, const Vector2 *value) +{ + glUniform2f(GetUniformLocation(name), value->x, value->y); +} + +void TSE::GLFW::Shader::SetUniform(const char *name, const Vector3 *value) +{ + glUniform3f(GetUniformLocation(name), value->x, value->y, value->z); +} + +void TSE::GLFW::Shader::SetUniform(const char *name, const Vector4 *value) +{ + glUniform4f(GetUniformLocation(name), value->x, value->y, value->z, value->w); +} diff --git a/TSE_GlfwOpenGlImpl/src/shader/Shader.hpp b/TSE_GlfwOpenGlImpl/src/shader/Shader.hpp new file mode 100644 index 0000000..4039cf4 --- /dev/null +++ b/TSE_GlfwOpenGlImpl/src/shader/Shader.hpp @@ -0,0 +1,55 @@ +#pragma once + +#include "ShaderPart.hpp" +#include +#include +#include "Types.hpp" +#include "interfaces/IShader.hpp" +#include "elements/Transformable.hpp" +#include "TransformationStack.hpp" +#include "interfaces/IRenderer.hpp" + +namespace TSE::GLFW +{ + class Shader : public IShader + { + private: + static uint activeProgramID; + uint programID; + mutable std::unordered_map uniformLocations; + + protected: + int PackageSize; + virtual void OnEnable() const {}; + virtual void OnDisable() const {}; + virtual void OnFlush() {}; + virtual void OnDrawCall(int indexCount) {}; + virtual void OnSubmit(const Transformable& t, float*& target, TransformationStack& stack, void (*restartDrawcall)(IRenderer&), IRenderer& rnd) {}; + + public: + void Bind() const override; + void Unbind() const override; + void Enable(bool notify = false) const; + void Disable(bool notify = false) const; + void Flush(); + void DrawCall(int indexCount); + void Submit(const Transformable& t, float*& target, TransformationStack& stack, void (*restartDrawcall)(IRenderer&), IRenderer& rnd); + bool IsEnabled() const; + int packageSize(); + Shader(const std::vector>& parts); + virtual ~Shader(); + + protected: + int GetUniformLocation(const char* name); + + public: + void SetUniform(const char* name, int value) override; + void SetUniform(const char* name, const int* value, const int count) override; + void SetUniform(const char* name, const Matrix4x4* value) override; + void SetUniform(const char* name, float value) override; + void SetUniform(const char* name, const float* value, const int count) override; + void SetUniform(const char* name, const Vector2* value) override; + void SetUniform(const char* name, const Vector3* value) override; + void SetUniform(const char* name, const Vector4* value) override; + }; +} // namespace TSE::GLFW diff --git a/TSE_GlfwOpenGlImpl/src/shader/ShaderPart.cpp b/TSE_GlfwOpenGlImpl/src/shader/ShaderPart.cpp new file mode 100644 index 0000000..74a2326 --- /dev/null +++ b/TSE_GlfwOpenGlImpl/src/shader/ShaderPart.cpp @@ -0,0 +1,49 @@ +#include "ShaderPart.hpp" + +#include "GL/gl3w.h" +#include "GL/gl.h" +#include "Debug.hpp" +#include +#include "PathHelper.hpp" + +void TSE::GLFW::ShaderPart::Init(const string &str, int shaderType) +{ + shaderPartID = glCreateShader(shaderType); + const char * cstr = str.c_str(); + int length = str.length(); + glShaderSource(shaderPartID, 1, &cstr, &length); + glCompileShader(shaderPartID); + + int success; + glGetShaderiv(shaderPartID, GL_COMPILE_STATUS, &success); + + if(success == GL_FALSE) + { + int errorLength = 255; + char* log = new char[errorLength]; + glGetShaderInfoLog(shaderPartID, errorLength, &errorLength, log); + + TSE_ERROR(log); + } +} + +TSE::GLFW::ShaderPart::~ShaderPart() +{ + glDeleteShader(shaderPartID); +} + +std::unique_ptr TSE::GLFW::ShaderPart::LoadFromString(const std::string &str, int shaderType) +{ + if (str.length() == 0) throw; + std::unique_ptr shader = std::make_unique(); + shader->Init(str, shaderType); + return shader; +} + +std::unique_ptr TSE::GLFW::ShaderPart::LoadFromPath(const std::string &path, int shaderType) +{ + std::ifstream stream; + OpenFileReading(stream, path); + std::string filecontent((std::istreambuf_iterator(stream)), std::istreambuf_iterator()); + return LoadFromString(filecontent, shaderType); +} diff --git a/TSE_GlfwOpenGlImpl/src/shader/ShaderPart.hpp b/TSE_GlfwOpenGlImpl/src/shader/ShaderPart.hpp new file mode 100644 index 0000000..48bad5f --- /dev/null +++ b/TSE_GlfwOpenGlImpl/src/shader/ShaderPart.hpp @@ -0,0 +1,23 @@ +#pragma once + +#include "Types.hpp" +#include + +namespace TSE::GLFW +{ + class ShaderPart + { + public: + uint shaderPartID = 0; + + ShaderPart() = default; + + private: + void Init(const string& str, int shaderType); + + public: + ~ShaderPart(); + static std::unique_ptr LoadFromString(const std::string& str, int shaderType); + static std::unique_ptr LoadFromPath(const std::string& path, int shaderType); + }; +} // namespace TSE diff --git a/TSE_GlfwOpenGlImpl/src/shader/basicParticleShader.cpp b/TSE_GlfwOpenGlImpl/src/shader/basicParticleShader.cpp new file mode 100644 index 0000000..9645a78 --- /dev/null +++ b/TSE_GlfwOpenGlImpl/src/shader/basicParticleShader.cpp @@ -0,0 +1,190 @@ +#include "basicParticleShader.hpp" +#include "basicParticleShaderGLSL.hpp" +#include "BehaviourScripts/Renderable.hpp" +#include "BehaviourScripts/ParticleSystem.hpp" +#include "Color.hpp" + +#define SHADER_MESH_INDEX 0 +#define SHADER_POS_INDEX 1 +#define SHADER_SIZE_INDEX 2 +#define SHADER_ROT_INDEX 3 +#define SHADER_COLOR_INDEX 4 + +#define SHADER_PACKAGE_SIZE sizeof(float) * (3 + 1 + 1 + 4) + +TSE::GLFW::BasicParticleShader* TSE::GLFW::BasicParticleShader::instance = nullptr; + +TSE::GLFW::BasicParticleShader *TSE::GLFW::BasicParticleShader::Instance() +{ + return instance; +} + +void TSE::GLFW::BasicParticleShader::Destroy() +{ + if(instance != nullptr) + delete instance; + instance = nullptr; +} + +void TSE::GLFW::BasicParticleShader::Init(float width, float height) +{ + std::vector> parts; + parts.push_back(ShaderPart::LoadFromString(vertPart, GL_VERTEX_SHADER)); + parts.push_back(ShaderPart::LoadFromString(fragPart, GL_FRAGMENT_SHADER)); + instance = new BasicParticleShader(std::move(parts)); +} + +TSE::GLFW::BasicParticleShader::BasicParticleShader(std::vector> &&parts) : Shader(parts) +{ + PackageSize = SHADER_PACKAGE_SIZE; +} + +TSE::GLFW::BasicParticleShader::~BasicParticleShader() +{ + if (meshVBO) glDeleteBuffers(1, &meshVBO); + if (meshIBO) glDeleteBuffers(1, &meshIBO); +} + +void TSE::GLFW::BasicParticleShader::SetMesh(const void *verts, int vertCount, int stride, int floatCountPerVertex, int posOffsetBytes, GLenum primitive, const void *indices, int indexCount, GLenum indexType) +{ + GLint prevVAO = 0, prevArrayBuffer = 0, prevElementBuffer = 0; + glGetIntegerv(GL_VERTEX_ARRAY_BINDING, &prevVAO); + glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &prevArrayBuffer); + glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING, &prevElementBuffer); + + if (!meshVBO) glGenBuffers(1, &meshVBO); + glBindBuffer(GL_ARRAY_BUFFER, meshVBO); + glBufferData(GL_ARRAY_BUFFER, vertCount * stride, verts, GL_STATIC_DRAW); + + if (indices && indexCount > 0) + { + if (!meshIBO) glGenBuffers(1, &meshIBO); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, meshIBO); + GLsizeiptr idxSize = + (indexType == GL_UNSIGNED_INT ? 4 : + indexType == GL_UNSIGNED_SHORT? 2 : 1) * indexCount; + glBufferData(GL_ELEMENT_ARRAY_BUFFER, idxSize, indices, GL_STATIC_DRAW); + meshIndexCount = indexCount; + meshIndexType = indexType; + } + else + { + // Kein Index-Buffer + if (meshIBO) { glDeleteBuffers(1, &meshIBO); meshIBO = 0; } + meshIndexCount = 0; + } + + meshVertexCount = vertCount; + meshStride = stride; + meshPosOffset = posOffsetBytes; + meshPosSize = floatCountPerVertex; + meshPrimitive = primitive; + meshReady = true; + + glBindBuffer(GL_ARRAY_BUFFER, prevArrayBuffer); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, prevElementBuffer); + glBindVertexArray(prevVAO); +} + +void TSE::GLFW::BasicParticleShader::OnEnable() const +{ + if (!meshReady) + { + // Fallback: unit-Quad als TRIANGLE_FAN (4 Vertices, 2D Positionen) + const float quad[8] = { -0.5f,-0.5f, 0.5f,-0.5f, 0.5f,0.5f, -0.5f,0.5f }; + const_cast(this)->SetMesh( + quad, 4, sizeof(float)*2, 2, 0, GL_TRIANGLE_FAN + ); + } + + GLint prevArrayBuffer = 0; + glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &prevArrayBuffer); + + glBindBuffer(GL_ARRAY_BUFFER, meshVBO); + glEnableVertexAttribArray(SHADER_MESH_INDEX); // LOC_QUAD/pos + glVertexAttribPointer(SHADER_MESH_INDEX, meshPosSize, GL_FLOAT, GL_FALSE, meshStride, (void*)meshPosOffset); + glVertexAttribDivisor(SHADER_MESH_INDEX, 0); // per-vertex (Mesh) + + glBindBuffer(GL_ARRAY_BUFFER, prevArrayBuffer); + + // layout 1: position (vec3) + glEnableVertexAttribArray(SHADER_POS_INDEX); + glVertexAttribPointer(SHADER_POS_INDEX, 3, GL_FLOAT, GL_FALSE, PackageSize, (void*)0); + glVertexAttribDivisor(SHADER_POS_INDEX, 1); + + // layout 2: size (float) + glEnableVertexAttribArray(SHADER_SIZE_INDEX); + glVertexAttribPointer(SHADER_SIZE_INDEX, 1, GL_FLOAT, GL_FALSE, PackageSize, (void*)(sizeof(float)*3)); + glVertexAttribDivisor(SHADER_SIZE_INDEX, 1); + + // layout 3: rotationRad (float) + glEnableVertexAttribArray(SHADER_ROT_INDEX); + glVertexAttribPointer(SHADER_ROT_INDEX, 1, GL_FLOAT, GL_FALSE, PackageSize, (void*)(sizeof(float)*4)); + glVertexAttribDivisor(SHADER_ROT_INDEX, 1); + + // layout 4: color (vec4) + glEnableVertexAttribArray(SHADER_COLOR_INDEX); + glVertexAttribPointer(SHADER_COLOR_INDEX, 4, GL_FLOAT, GL_FALSE, PackageSize, (void*)(sizeof(float)*5)); + glVertexAttribDivisor(SHADER_COLOR_INDEX, 1); +} + +void TSE::GLFW::BasicParticleShader::OnDisable() const +{ + glDisableVertexAttribArray(SHADER_MESH_INDEX); + glDisableVertexAttribArray(SHADER_POS_INDEX); + glDisableVertexAttribArray(SHADER_SIZE_INDEX); + glDisableVertexAttribArray(SHADER_ROT_INDEX); + glDisableVertexAttribArray(SHADER_COLOR_INDEX); +} + +void TSE::GLFW::BasicParticleShader::OnFlush() +{ +} + +void TSE::GLFW::BasicParticleShader::OnDrawCall(int indexCount) +{ + if (instanceCount <= 0) return; + + GLint prevElementBuffer = 0; + glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING, &prevElementBuffer); + + if (meshIBO && meshIndexCount > 0) + { + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, meshIBO); + glDrawElementsInstanced(meshPrimitive, meshIndexCount, meshIndexType, (void*)0, instanceCount); + } + else + { + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); + glDrawArraysInstanced(meshPrimitive, 0, meshVertexCount, instanceCount); + } + + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, (GLuint)prevElementBuffer); + instanceCount = 0; +} + +void TSE::GLFW::BasicParticleShader::OnSubmit(const Transformable &t, float *&target, TransformationStack &stack, void (*restartDrawcall)(IRenderer &), IRenderer &rnd) +{ + auto* r = dynamic_cast(t.GetBehaviourScript(RENDERABLE)); + if (!r) return; + + auto* ps = dynamic_cast(t.GetBehaviourScript(PARTICLESYSTEM)); + if (!ps) return; + + const std::vector& particles = ps->GetParticles(); + + for(auto particle : particles) + { + *target++ = particle->position.x; + *target++ = particle->position.y; + *target++ = particle->position.z; + *target++ = particle->size; + *target++ = particle->rotationRad; + *target++ = particle->color.r; + *target++ = particle->color.g; + *target++ = particle->color.b; + *target++ = particle->color.a; + + ++instanceCount; + } +} diff --git a/TSE_GlfwOpenGlImpl/src/shader/basicParticleShader.hpp b/TSE_GlfwOpenGlImpl/src/shader/basicParticleShader.hpp new file mode 100644 index 0000000..daf17ff --- /dev/null +++ b/TSE_GlfwOpenGlImpl/src/shader/basicParticleShader.hpp @@ -0,0 +1,40 @@ +#pragma once + +#include "Shader.hpp" +#include "Types.hpp" +#include "GL/gl3w.h" + +namespace TSE::GLFW +{ + class BasicParticleShader : public Shader + { + private: + static BasicParticleShader* instance; + mutable bool meshReady = false; + GLuint meshVBO = 0; + GLuint meshIBO = 0; + GLsizei meshVertexCount = 0; // für DrawArraysInstanced + GLsizei meshIndexCount = 0; // für DrawElementsInstanced + GLenum meshPrimitive = GL_TRIANGLES; + GLenum meshIndexType = GL_UNSIGNED_SHORT; + int instanceCount = 0; // eigener Instanzzähler + GLint meshPosSize = 2; // 2D (Billboard-Formen), für 3D Meshes: 3 + GLsizei meshStride = sizeof(float) * 2; + size_t meshPosOffset = 0; + + public: + static BasicParticleShader* Instance(); + static void Destroy(); + static void Init(float width, float height); + BasicParticleShader(std::vector>&& parts); + ~BasicParticleShader(); + void SetMesh(const void* verts, int vertCount, int stride, int floatCountPerVertex, int posOffsetBytes, GLenum primitive, const void* indices = nullptr, int indexCount = 0, GLenum indexType = GL_UNSIGNED_SHORT); + + protected: + void OnEnable() const override; + void OnDisable() const override; + void OnFlush() override; + void OnDrawCall(int indexCount) override; + void OnSubmit(const Transformable& t, float*& target, TransformationStack& stack, void (*restartDrawcall)(IRenderer&), IRenderer& rnd) override; + }; +} // namespace TSE::GLFW diff --git a/TSE_GlfwOpenGlImpl/src/shader/basicParticleShaderGLSL.hpp b/TSE_GlfwOpenGlImpl/src/shader/basicParticleShaderGLSL.hpp new file mode 100644 index 0000000..d5be40b --- /dev/null +++ b/TSE_GlfwOpenGlImpl/src/shader/basicParticleShaderGLSL.hpp @@ -0,0 +1,101 @@ +#pragma once + +inline const char* vertPart = R"( + #version 330 core + + #ifndef USE_2D_BILLBOARD + #define USE_2D_BILLBOARD 1 //2D mesh => 1 ; 3D mesh => 0 + #endif + + // Mesh-Positions-Stream (per-vertex) + #if USE_2D_BILLBOARD + layout(location = 0) in vec2 meshPos; // z.B. Quad-Ecken (-0.5..0.5) + #else + layout(location = 0) in vec3 meshPos; // echte 3D-Mesh-Position + #endif + + // Instanz-Attribute + layout(location = 1) in vec3 inPosition; // Partikelzentrum (Welt) + layout(location = 2) in float inSize; // Uniform-Scale + layout(location = 3) in float inRotation; // Rotation (nur im Billboard-Modus genutzt) + layout(location = 4) in vec4 inColor; // RGBA + + uniform mat4 prMatrix; + uniform mat4 camMatrix; + + out VS_OUT { + vec4 color; + #if USE_2D_BILLBOARD + vec2 uv; // optional: für runde Maske im FS + #endif + } vs; + + // Kameraachsen aus View-Matrix (Spalten 0/1) + vec3 CameraRight(mat4 view) { return vec3(view[0][0], view[1][0], view[2][0]); } + vec3 CameraUp (mat4 view) { return vec3(view[0][1], view[1][1], view[2][1]); } + + + void main() + { + vs.color = inColor; + + #if USE_2D_BILLBOARD + // 2D-Rotation im Billboard-Raum + float c = cos(inRotation); + float s = sin(inRotation); + vec2 q = vec2(c * meshPos.x - s * meshPos.y, + s * meshPos.x + c * meshPos.y); + + vec3 right = CameraRight(camMatrix); + vec3 up = CameraUp(camMatrix); + + // Uniform-Scaling über inSize + vec3 worldPos = inPosition + (q.x * inSize) * right + + (q.y * inSize) * up; + + // optionales UV für Kreis-Maske + vs.uv = meshPos * 0.5 + 0.5; // falls meshPos in -1..1: nimm (meshPos*0.5+0.5) + #else + // echtes 3D-Mesh: nur uniform Scale + Translation + vec3 worldPos = inPosition + meshPos * inSize; + #endif + + gl_Position = prMatrix * camMatrix * vec4(worldPos, 1.0); + } +)"; + +inline const char* fragPart = R"( + #version 330 core + + #ifndef USE_2D_BILLBOARD + #define USE_2D_BILLBOARD 1 + #endif + + // Optional runde Maske an/aus (nur sinnvoll im Billboard-Modus mit z.B. Quad) + #ifndef USE_ROUND_MASK + #define USE_ROUND_MASK 0 + #endif + + in VS_OUT { + vec4 color; + #if USE_2D_BILLBOARD + vec2 uv; + #endif + } fs; + + layout(location = 0) out vec4 outColor; + + void main() + { + #if USE_2D_BILLBOARD && USE_ROUND_MASK + // weiche Kreis-Maske (aus uv ~ 0..1) + vec2 c = fs.uv * 2.0 - 1.0; // nach [-1..1] + float r = length(c); + if (r > 1.0) discard; + float alpha = 1.0 - smoothstep(0.95, 1.0, r); + outColor = vec4(fs.color.rgb, fs.color.a * alpha); + #else + outColor = fs.color; + #endif + } +)"; diff --git a/TSE_GlfwOpenGlImpl/src/shader/basicShader.cpp b/TSE_GlfwOpenGlImpl/src/shader/basicShader.cpp new file mode 100644 index 0000000..1f975df --- /dev/null +++ b/TSE_GlfwOpenGlImpl/src/shader/basicShader.cpp @@ -0,0 +1,91 @@ +#include "basicShader.hpp" + +#include "GL/gl3w.h" +#include "basicShaderGLSL.hpp" +#include "BehaviourScripts/Renderable.hpp" +#include "Color.hpp" + +#define SHADER_VERTEX_INDEX 0 +#define SHADER_COLOR_INDEX 1 + +#define SHADER_PACKAGE_SIZE sizeof(float) * (3 + 4) + +TSE::GLFW::BasicShader* TSE::GLFW::BasicShader::instance = nullptr; + +TSE::GLFW::BasicShader *TSE::GLFW::BasicShader::Instance() +{ + return instance; +} + +void TSE::GLFW::BasicShader::Destroy() +{ + if(instance != nullptr) + delete instance; + instance = nullptr; +} + +void TSE::GLFW::BasicShader::Init(float width, float height) +{ + std::vector> parts; + parts.push_back(ShaderPart::LoadFromString(vert, GL_VERTEX_SHADER)); + parts.push_back(ShaderPart::LoadFromString(frag, GL_FRAGMENT_SHADER)); + instance = new BasicShader(std::move(parts)); +} + +TSE::GLFW::BasicShader::BasicShader(std::vector> &&parts) : Shader(parts) +{ + PackageSize = SHADER_PACKAGE_SIZE; +} + +void TSE::GLFW::BasicShader::OnEnable() const +{ + glEnableVertexAttribArray(SHADER_VERTEX_INDEX); + glVertexAttribPointer(SHADER_VERTEX_INDEX, 3, GL_FLOAT, false, SHADER_PACKAGE_SIZE, (void*)0); + glEnableVertexAttribArray(SHADER_COLOR_INDEX); + glVertexAttribPointer(SHADER_COLOR_INDEX, 4, GL_FLOAT, false, SHADER_PACKAGE_SIZE, (void*)(sizeof(float) * 3)); +} + +void TSE::GLFW::BasicShader::OnDisable() const +{ + glDisableVertexAttribArray(SHADER_VERTEX_INDEX); + glDisableVertexAttribArray(SHADER_COLOR_INDEX); +} + +void TSE::GLFW::BasicShader::OnFlush() +{ +} + +void TSE::GLFW::BasicShader::OnDrawCall(int indexCount) +{ + glDrawElements(GL_TRIANGLES, indexCount, GL_UNSIGNED_SHORT, NULL); +} + +void TSE::GLFW::BasicShader::OnSubmit(const Transformable &t, float *&target, TransformationStack &stack, void (*restartDrawcall)(IRenderer &), IRenderer &rnd) +{ + auto* r = dynamic_cast(t.GetBehaviourScript(RENDERABLE)); + if (!r) return; + + + const Vector3* verts = r->GetVertices(); + ushort vCount = r->GetVertexCount(); + const Color color = r->GetMaterial()->GetValue("mainColor"); + Matrix4x4 matr = t.GetLocalMatrix(); + + stack.Push(matr); + const Matrix4x4& top = stack.Top(); + + //Todo transformable.lastmatrix hier ergänzen + + for (ushort i = 0; i < vCount; i++) { + Vector3 p = top * verts[i]; + *target++ = p.x; + *target++ = p.y; + *target++ = p.z; + *target++ = color.r; + *target++ = color.g; + *target++ = color.b; + *target++ = color.a; + } + + stack.Pop(); +} diff --git a/TSE_GlfwOpenGlImpl/src/shader/basicShader.hpp b/TSE_GlfwOpenGlImpl/src/shader/basicShader.hpp new file mode 100644 index 0000000..b2f6de4 --- /dev/null +++ b/TSE_GlfwOpenGlImpl/src/shader/basicShader.hpp @@ -0,0 +1,25 @@ +#pragma once + +#include "Shader.hpp" + +namespace TSE::GLFW +{ + class BasicShader : public Shader + { + private: + static BasicShader* instance; + + public: + static BasicShader* Instance(); + static void Destroy(); + static void Init(float width, float height); + BasicShader(std::vector>&& parts); + + protected: + void OnEnable() const override; + void OnDisable() const override; + void OnFlush() override; + void OnDrawCall(int indexCount) override; + void OnSubmit(const Transformable& t, float*& target, TransformationStack& stack, void (*restartDrawcall)(IRenderer&), IRenderer& rnd) override; + }; +} // namespace TSE::GLFW diff --git a/TSE_GlfwOpenGlImpl/src/shader/basicShaderGLSL.hpp b/TSE_GlfwOpenGlImpl/src/shader/basicShaderGLSL.hpp new file mode 100644 index 0000000..8ed9be0 --- /dev/null +++ b/TSE_GlfwOpenGlImpl/src/shader/basicShaderGLSL.hpp @@ -0,0 +1,42 @@ +#pragma once + + +inline const char* vert = R"( + #version 330 core + + layout (location = 0) in vec3 position; + layout (location = 1) in vec4 color; + + + uniform mat4 prMatrix; + uniform mat4 camMatrix; + + out DATA + { + vec4 color_out; + } vs_out; + + + void main() + { + gl_Position = prMatrix * camMatrix * vec4(position.x, position.y, position.z, 1.0); + vs_out.color_out = color; + } +)"; + +inline const char* frag = R"( + #version 330 core + layout (location = 0) out vec4 color; + in DATA + { + vec4 color_out; + } fs_in; + void main() + { + if(fs_in.color_out.a < 0.1) + { + discard; + } + color = fs_in.color_out; + } +)"; diff --git a/TSE_GlfwOpenGlImpl/src/shader/basicTextureShader.cpp b/TSE_GlfwOpenGlImpl/src/shader/basicTextureShader.cpp new file mode 100644 index 0000000..1000798 --- /dev/null +++ b/TSE_GlfwOpenGlImpl/src/shader/basicTextureShader.cpp @@ -0,0 +1,134 @@ +#include "basicTextureShader.hpp" +#include "basicTextureShaderGLSL.hpp" +#include "BehaviourScripts/Renderable.hpp" +#include "Color.hpp" +#include "interfaces/ITexture.hpp" +#include "GL/gl3w.h" + +#define SHADER_VERTEX_INDEX 0 +#define SHADER_COLOR_INDEX 1 +#define SHADER_UV_INDEX 2 +#define SHADER_TID_INDEX 3 + +#define SHADER_PACKAGE_SIZE (sizeof(float) * (3 + 4 + 2 + 1)) + +TSE::GLFW::BasicTextureShader* TSE::GLFW::BasicTextureShader::instance = nullptr; +std::map TSE::GLFW::BasicTextureShader::textureSlots; + +TSE::GLFW::BasicTextureShader *TSE::GLFW::BasicTextureShader::Instance() +{ + return instance; +} + +void TSE::GLFW::BasicTextureShader::Destroy() +{ + if(instance != nullptr) + delete instance; + instance = nullptr; +} + +void TSE::GLFW::BasicTextureShader::Init(float width, float height) +{ + std::vector> parts; + parts.push_back(ShaderPart::LoadFromString(vertT, GL_VERTEX_SHADER)); + parts.push_back(ShaderPart::LoadFromString(fragT, GL_FRAGMENT_SHADER)); + instance = new BasicTextureShader(std::move(parts)); + + instance->Enable(); + int texIDs[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32 }; + instance->SetUniform("textures", &texIDs[0], 33); + instance->Disable(); +} + +TSE::GLFW::BasicTextureShader::BasicTextureShader(std::vector> &&parts) : Shader(parts) +{ + PackageSize = SHADER_PACKAGE_SIZE; +} + +void TSE::GLFW::BasicTextureShader::OnEnable() const +{ + glEnableVertexAttribArray(SHADER_VERTEX_INDEX); + glVertexAttribPointer(SHADER_VERTEX_INDEX, 3, GL_FLOAT, false, SHADER_PACKAGE_SIZE, (void*)0); + glEnableVertexAttribArray(SHADER_COLOR_INDEX); + glVertexAttribPointer(SHADER_COLOR_INDEX, 4, GL_FLOAT, false, SHADER_PACKAGE_SIZE, (void*)(sizeof(float) * 3)); + glEnableVertexAttribArray(SHADER_UV_INDEX); + glVertexAttribPointer(SHADER_UV_INDEX, 2, GL_FLOAT, false, SHADER_PACKAGE_SIZE, (void*)(sizeof(float) * 7)); + glEnableVertexAttribArray(SHADER_TID_INDEX); + glVertexAttribPointer(SHADER_TID_INDEX, 1, GL_FLOAT, false, SHADER_PACKAGE_SIZE, (void*)(sizeof(float) * 9)); +} + +void TSE::GLFW::BasicTextureShader::OnDisable() const +{ + glDisableVertexAttribArray(SHADER_VERTEX_INDEX); + glDisableVertexAttribArray(SHADER_COLOR_INDEX); + glDisableVertexAttribArray(SHADER_UV_INDEX); + glDisableVertexAttribArray(SHADER_TID_INDEX); +} + +void TSE::GLFW::BasicTextureShader::OnFlush() +{ + auto it = textureSlots.begin(); + for (int i = 0; i < textureSlots.size(); i++, it++) + { + glActiveTexture(GL_TEXTURE0 + i); + glBindTexture(GL_TEXTURE_2D, it->first); + } +} + +void TSE::GLFW::BasicTextureShader::OnDrawCall(int indexCount) +{ + glDrawElements(GL_TRIANGLES, indexCount, GL_UNSIGNED_SHORT, NULL); +} + +void TSE::GLFW::BasicTextureShader::OnSubmit(const Transformable &t, float *&target, TransformationStack &stack, void (*restartDrawcall)(IRenderer &), IRenderer &rnd) +{ + auto* r = dynamic_cast(t.GetBehaviourScript(RENDERABLE)); + if (!r) return; + if(!r->GetMaterial()->HasValue("mainTex")) return; + const ITexture* tex = r->GetMaterial()->GetValue("mainTex"); + float ts = 0; + auto it = textureSlots.find(tex->GetTextureId()); + if (it != textureSlots.end()) + { + ts = it->second; + } + else + { + if(textureSlots.size() == 32) + { + restartDrawcall(rnd); + textureSlots.clear(); + } + textureSlots[tex->GetTextureId()] = textureSlots.size(); + ts = textureSlots[tex->GetTextureId()]; + } + + + const Vector3* verts = r->GetVertices(); + const Vector2* uvs = r->GetUVs(); + ushort vCount = r->GetVertexCount(); + const Color color = r->GetMaterial()->GetValue("mainColor"); + Matrix4x4 matr = t.GetLocalMatrix(); + + stack.Push(matr); + const Matrix4x4& top = stack.Top(); + + //Todo transformable.lastmatrix hier ergänzen + + for (ushort i = 0; i < vCount; i++) { + Vector3 p = top * verts[i]; + Vector2 uv = uvs[i]; + *target++ = p.x; + *target++ = p.y; + *target++ = p.z; + *target++ = color.r; + *target++ = color.g; + *target++ = color.b; + *target++ = color.a; + *target++ = uv.x; + *target++ = uv.y; + *target++ = ts; + } + + stack.Pop(); +} diff --git a/TSE_GlfwOpenGlImpl/src/shader/basicTextureShader.hpp b/TSE_GlfwOpenGlImpl/src/shader/basicTextureShader.hpp new file mode 100644 index 0000000..7e17ed2 --- /dev/null +++ b/TSE_GlfwOpenGlImpl/src/shader/basicTextureShader.hpp @@ -0,0 +1,28 @@ +#pragma once + +#include "Shader.hpp" +#include "Types.hpp" +#include + +namespace TSE::GLFW +{ + class BasicTextureShader : public Shader + { + private: + static BasicTextureShader* instance; + static std::map textureSlots; + + public: + static BasicTextureShader* Instance(); + static void Destroy(); + static void Init(float width, float height); + BasicTextureShader(std::vector>&& parts); + + protected: + void OnEnable() const override; + void OnDisable() const override; + void OnFlush() override; + void OnDrawCall(int indexCount) override; + void OnSubmit(const Transformable& t, float*& target, TransformationStack& stack, void (*restartDrawcall)(IRenderer&), IRenderer& rnd) override; + }; +} // namespace TSE::GLFW diff --git a/TSE_GlfwOpenGlImpl/src/shader/basicTextureShaderGLSL.hpp b/TSE_GlfwOpenGlImpl/src/shader/basicTextureShaderGLSL.hpp new file mode 100644 index 0000000..2df6bc4 --- /dev/null +++ b/TSE_GlfwOpenGlImpl/src/shader/basicTextureShaderGLSL.hpp @@ -0,0 +1,159 @@ +#pragma once + +inline const char* vertT = R"( + #version 330 core + + layout (location = 0) in vec3 position; + layout (location = 1) in vec4 color; + layout (location = 2) in vec2 uv; + layout (location = 3) in float tid; + + + uniform mat4 prMatrix; + uniform mat4 camMatrix; + + out DATA + { + vec4 color_out; + vec2 uv_out; + float tid_out; + } vs_out; + + + void main() + { + gl_Position = prMatrix * camMatrix * vec4(position.x, position.y, position.z, 1.0); + vs_out.color_out = color; + vs_out.uv_out = uv; + vs_out.tid_out = tid; + } +)"; + +inline const char* fragT = R"( + #version 330 core + layout (location = 0) out vec4 color; + + uniform sampler2D textures[32]; + + in DATA + { + vec4 color_out; + vec2 uv_out; + float tid_out; + } fs_in; + void main() + { + vec4 texColor = vec4(0,0,0,0); + int tid = int(fs_in.tid_out); + switch(tid) + { + case 0: + texColor = texture(textures[0], fs_in.uv_out); + break; + case 1: + texColor = texture(textures[1], fs_in.uv_out); + break; + case 2: + texColor = texture(textures[2], fs_in.uv_out); + break; + case 3: + texColor = texture(textures[3], fs_in.uv_out); + break; + case 4: + texColor = texture(textures[4], fs_in.uv_out); + break; + case 5: + texColor = texture(textures[5], fs_in.uv_out); + break; + case 6: + texColor = texture(textures[6], fs_in.uv_out); + break; + case 7: + texColor = texture(textures[7], fs_in.uv_out); + break; + case 8: + texColor = texture(textures[8], fs_in.uv_out); + break; + case 9: + texColor = texture(textures[9], fs_in.uv_out); + break; + case 10: + texColor = texture(textures[10], fs_in.uv_out); + break; + case 11: + texColor = texture(textures[11], fs_in.uv_out); + break; + case 12: + texColor = texture(textures[12], fs_in.uv_out); + break; + case 13: + texColor = texture(textures[13], fs_in.uv_out); + break; + case 14: + texColor = texture(textures[14], fs_in.uv_out); + break; + case 15: + texColor = texture(textures[15], fs_in.uv_out); + break; + case 16: + texColor = texture(textures[16], fs_in.uv_out); + break; + case 17: + texColor = texture(textures[17], fs_in.uv_out); + break; + case 18: + texColor = texture(textures[18], fs_in.uv_out); + break; + case 19: + texColor = texture(textures[19], fs_in.uv_out); + break; + case 20: + texColor = texture(textures[20], fs_in.uv_out); + break; + case 21: + texColor = texture(textures[21], fs_in.uv_out); + break; + case 22: + texColor = texture(textures[22], fs_in.uv_out); + break; + case 23: + texColor = texture(textures[23], fs_in.uv_out); + break; + case 24: + texColor = texture(textures[24], fs_in.uv_out); + break; + case 25: + texColor = texture(textures[25], fs_in.uv_out); + break; + case 26: + texColor = texture(textures[26], fs_in.uv_out); + break; + case 27: + texColor = texture(textures[27], fs_in.uv_out); + break; + case 28: + texColor = texture(textures[28], fs_in.uv_out); + break; + case 29: + texColor = texture(textures[29], fs_in.uv_out); + break; + case 30: + texColor = texture(textures[30], fs_in.uv_out); + break; + case 31: + texColor = texture(textures[31], fs_in.uv_out); + break; + default: + texColor = vec4(1,1,1,1); + break; + } + vec4 res = texColor * fs_in.color_out; + + if(res.a < 0.1) + { + discard; + } + + color = res; + } +)"; diff --git a/TSE_GlfwOpenGlImpl/src/shader/defaultShaderHandler.cpp b/TSE_GlfwOpenGlImpl/src/shader/defaultShaderHandler.cpp new file mode 100644 index 0000000..0654c46 --- /dev/null +++ b/TSE_GlfwOpenGlImpl/src/shader/defaultShaderHandler.cpp @@ -0,0 +1,30 @@ +#include "defaultShaderHandler.hpp" +#include "basicShader.hpp" +#include "basicTextureShader.hpp" +#include "ditheringShader.hpp" +#include "basicParticleShader.hpp" +#include "elements/ShaderRegistry.hpp" + +void TSE::GLFW::LoadBasicShaders(float width, float height) +{ + BasicShader::Init(width, height); + BasicTextureShader::Init(width, height); + DitheringShader::Init(width, height); + BasicParticleShader::Init(width, height); + ShaderRegistry::SetShader("Basic Unlit Shader", BasicShader::Instance()); + ShaderRegistry::SetShader("Basic Unlit Texture Shader", BasicTextureShader::Instance()); + ShaderRegistry::SetShader("Basic Unlit Dithering Shader", DitheringShader::Instance()); + ShaderRegistry::SetShader("Basic Unlit Particle Shader", BasicParticleShader::Instance()); +} + +void TSE::GLFW::UnLoadBasicShaders() +{ + ShaderRegistry::RemoveShader("Basic Unlit Shader"); + ShaderRegistry::RemoveShader("Basic Unlit Texture Shader"); + ShaderRegistry::RemoveShader("Basic Unlit Dithering Shader"); + ShaderRegistry::RemoveShader("Basic Unlit Particle Shader"); + BasicShader::Destroy(); + BasicTextureShader::Destroy(); + DitheringShader::Destroy(); + BasicParticleShader::Destroy(); +} diff --git a/TSE_GlfwOpenGlImpl/src/shader/defaultShaderHandler.hpp b/TSE_GlfwOpenGlImpl/src/shader/defaultShaderHandler.hpp new file mode 100644 index 0000000..d8ab35a --- /dev/null +++ b/TSE_GlfwOpenGlImpl/src/shader/defaultShaderHandler.hpp @@ -0,0 +1,7 @@ +#pragma once + +namespace TSE::GLFW +{ + void LoadBasicShaders(float width, float height); + void UnLoadBasicShaders(); +} // namespace TSE::GLFW diff --git a/TSE_GlfwOpenGlImpl/src/shader/ditheringShader.cpp b/TSE_GlfwOpenGlImpl/src/shader/ditheringShader.cpp new file mode 100644 index 0000000..c735764 --- /dev/null +++ b/TSE_GlfwOpenGlImpl/src/shader/ditheringShader.cpp @@ -0,0 +1,90 @@ +#include "ditheringShader.hpp" +#include "ditheringShaderGLSL.hpp" +#include "BehaviourScripts/Renderable.hpp" +#include "Color.hpp" +#include "GL/gl3w.h" + +#define SHADER_VERTEX_INDEX 0 +#define SHADER_COLOR_INDEX 1 + +#define SHADER_PACKAGE_SIZE sizeof(float) * (3 + 4) + +TSE::GLFW::DitheringShader* TSE::GLFW::DitheringShader::instance = nullptr; + +TSE::GLFW::DitheringShader *TSE::GLFW::DitheringShader::Instance() +{ + return instance; +} + +void TSE::GLFW::DitheringShader::Destroy() +{ + if(instance != nullptr) + delete instance; + instance = nullptr; +} + +void TSE::GLFW::DitheringShader::Init(float width, float height) +{ + std::vector> parts; + parts.push_back(ShaderPart::LoadFromString(vertD, GL_VERTEX_SHADER)); + parts.push_back(ShaderPart::LoadFromString(fragD, GL_FRAGMENT_SHADER)); + instance = new DitheringShader(std::move(parts)); +} + +TSE::GLFW::DitheringShader::DitheringShader(std::vector> &&parts) : Shader(parts) +{ + PackageSize = SHADER_PACKAGE_SIZE; +} + +void TSE::GLFW::DitheringShader::OnEnable() const +{ + glEnableVertexAttribArray(SHADER_VERTEX_INDEX); + glVertexAttribPointer(SHADER_VERTEX_INDEX, 3, GL_FLOAT, false, SHADER_PACKAGE_SIZE, (void*)0); + glEnableVertexAttribArray(SHADER_COLOR_INDEX); + glVertexAttribPointer(SHADER_COLOR_INDEX, 4, GL_FLOAT, false, SHADER_PACKAGE_SIZE, (void*)(sizeof(float) * 3)); +} + +void TSE::GLFW::DitheringShader::OnDisable() const +{ + glDisableVertexAttribArray(SHADER_VERTEX_INDEX); + glDisableVertexAttribArray(SHADER_COLOR_INDEX); +} + +void TSE::GLFW::DitheringShader::OnFlush() +{ +} + +void TSE::GLFW::DitheringShader::OnDrawCall(int indexCount) +{ + glDrawElements(GL_TRIANGLES, indexCount, GL_UNSIGNED_SHORT, NULL); +} + +void TSE::GLFW::DitheringShader::OnSubmit(const Transformable &t, float *&target, TransformationStack &stack, void (*restartDrawcall)(IRenderer &), IRenderer &rnd) +{ + auto* r = dynamic_cast(t.GetBehaviourScript(RENDERABLE)); + if (!r) return; + + + const Vector3* verts = r->GetVertices(); + ushort vCount = r->GetVertexCount(); + const Color color = r->GetMaterial()->GetValue("mainColor"); + Matrix4x4 matr = t.GetLocalMatrix(); + + stack.Push(matr); + const Matrix4x4& top = stack.Top(); + + //Todo transformable.lastmatrix hier ergänzen + + for (ushort i = 0; i < vCount; i++) { + Vector3 p = top * verts[i]; + *target++ = p.x; + *target++ = p.y; + *target++ = p.z; + *target++ = color.r; + *target++ = color.g; + *target++ = color.b; + *target++ = color.a; + } + + stack.Pop(); +} diff --git a/TSE_GlfwOpenGlImpl/src/shader/ditheringShader.hpp b/TSE_GlfwOpenGlImpl/src/shader/ditheringShader.hpp new file mode 100644 index 0000000..d4e550d --- /dev/null +++ b/TSE_GlfwOpenGlImpl/src/shader/ditheringShader.hpp @@ -0,0 +1,25 @@ +#pragma once + +#include "Shader.hpp" + +namespace TSE::GLFW +{ + class DitheringShader : public Shader + { + private: + static DitheringShader* instance; + + public: + static DitheringShader* Instance(); + static void Destroy(); + static void Init(float width, float height); + DitheringShader(std::vector>&& parts); + + protected: + void OnEnable() const override; + void OnDisable() const override; + void OnFlush() override; + void OnDrawCall(int indexCount) override; + void OnSubmit(const Transformable& t, float*& target, TransformationStack& stack, void (*restartDrawcall)(IRenderer&), IRenderer& rnd) override; + }; +} // namespace TSE::GLFW diff --git a/TSE_GlfwOpenGlImpl/src/shader/ditheringShaderGLSL.hpp b/TSE_GlfwOpenGlImpl/src/shader/ditheringShaderGLSL.hpp new file mode 100644 index 0000000..6762587 --- /dev/null +++ b/TSE_GlfwOpenGlImpl/src/shader/ditheringShaderGLSL.hpp @@ -0,0 +1,80 @@ +#pragma once + + +inline const char* vertD = R"( + #version 330 core + + layout (location = 0) in vec3 position; + layout (location = 1) in vec4 color; + + uniform mat4 prMatrix; + uniform mat4 camMatrix; + + out DATA + { + vec4 color_out; + } vs_out; + + void main() + { + gl_Position = prMatrix * camMatrix * vec4(position, 1.0); + vs_out.color_out = color; + } +)"; + +inline const char* fragD = R"( + #version 330 core + + layout (location = 0) out vec4 color; + + in DATA + { + vec4 color_out; + } fs_in; + + // 8x8 Bayer-Matrix (0..63), als Schwellwerttabelle + float bayer8(vec2 fragXY) + { + int x = int(mod(fragXY.x, 8.0)); + int y = int(mod(fragXY.y, 8.0)); + int idx = x + y * 8; + + // Werte aus klassischer 8x8 Ordered-Dithering-Matrix + int m[64] = int[64]( + 0, 48, 12, 60, 3, 51, 15, 63, + 32, 16, 44, 28, 35, 19, 47, 31, + 8, 56, 4, 52, 11, 59, 7, 55, + 40, 24, 36, 20, 43, 27, 39, 23, + 2, 50, 14, 62, 1, 49, 13, 61, + 34, 18, 46, 30, 33, 17, 45, 29, + 10, 58, 6, 54, 9, 57, 5, 53, + 42, 26, 38, 22, 41, 25, 37, 21 + ); + + // +0.5, damit die Schwellen mittig zwischen Stufen liegen + return (float(m[idx]) + 0.5) / 64.0; + } + + void main() + { + vec4 c = fs_in.color_out; + + // alpha == 0 -> nichts rendern + if (c.a <= 0.0) + discard; + + // Für alpha < 1 verwenden wir Ordered Dithering + if (c.a < 1.0) + { + float threshold = bayer8(gl_FragCoord.xy); + // ist der Schwellenwert größer als alpha? -> Pixel auslassen + if (threshold > c.a) + discard; + } + + // Wenn wir bis hier nicht verworfen haben, zeichnen wir den Pixel. + // Typischerweise setzt man die ausgegebene Alpha dann auf 1.0, + // weil die Transparenz bereits über das Dithering realisiert wurde. + color = vec4(c.rgb, 1.0); + } +)";