diff --git a/Engine/res/Shaders/TintedTexture/TintedTexture_PS.glsl b/Engine/res/Shaders/TintedTexture/TintedTexture_PS.glsl new file mode 100644 index 0000000..0aa19e7 --- /dev/null +++ b/Engine/res/Shaders/TintedTexture/TintedTexture_PS.glsl @@ -0,0 +1,13 @@ +#version 440 core + +in vec4 vso_Tint; +in vec2 vso_TexCoord; + +uniform sampler2D u_Texture; + +out vec4 fso_FragmentColor; + +void main() +{ + fso_FragmentColor = texture(u_Texture, vso_TexCoord) * vso_Tint; +} \ No newline at end of file diff --git a/Engine/res/Shaders/TintedTexture/TintedTexture_PS.hlsl b/Engine/res/Shaders/TintedTexture/TintedTexture_PS.hlsl new file mode 100644 index 0000000..012c6d2 --- /dev/null +++ b/Engine/res/Shaders/TintedTexture/TintedTexture_PS.hlsl @@ -0,0 +1,7 @@ +sampler samplerState : register(s0); +Texture2D myTexture : register(t0); + +float4 main(float2 InTexChoord : TEXCOORD, float4 InTint : TINT) : SV_Target +{ + return myTexture.Sample(samplerState, InTexChoord) * InTint; +} \ No newline at end of file diff --git a/Engine/res/Shaders/TintedTexture/TintedTexture_VS.glsl b/Engine/res/Shaders/TintedTexture/TintedTexture_VS.glsl new file mode 100644 index 0000000..642b4ef --- /dev/null +++ b/Engine/res/Shaders/TintedTexture/TintedTexture_VS.glsl @@ -0,0 +1,21 @@ +#version 440 core + +layout(location = 0) in vec4 a_Position; +layout(location = 1) in vec4 a_Tint; +layout(location = 2) in vec2 a_TexCoord; + +layout(std140, binding = 0) uniform ub_ViewProjection +{ + mat4 u_ViewProjection; +}; + +out vec4 vso_Tint; +out vec2 vso_TexCoord; + +void main() +{ + gl_Position = u_ViewProjection * a_Position; + + vso_Tint = a_Tint; + vso_TexCoord = a_TexCoord; +} \ No newline at end of file diff --git a/Engine/res/Shaders/TintedTexture/TintedTexture_VS.hlsl b/Engine/res/Shaders/TintedTexture/TintedTexture_VS.hlsl new file mode 100644 index 0000000..3b69a8a --- /dev/null +++ b/Engine/res/Shaders/TintedTexture/TintedTexture_VS.hlsl @@ -0,0 +1,21 @@ +struct VertexOut +{ + float2 TexChoord : TEXCOORD; + float4 Tint : TINT; + float4 Position : SV_Position; +}; + +cbuffer cb_ViewProjection : register(b0) +{ + row_major matrix viewProjection; +} + +VertexOut main(float4 InPosition : POSITION, float4 InTint : TINT,float2 InTexChoord : TEXCOORD) +{ + VertexOut vso; + vso.Position = mul(float4(InPosition), viewProjection); + vso.Tint = InTint; + vso.TexChoord = InTexChoord; + + return vso; +} \ No newline at end of file diff --git a/Engine/src/Engine/Graphics/Renderer.cpp b/Engine/src/Engine/Graphics/Renderer.cpp index e26f382..baa715a 100644 --- a/Engine/src/Engine/Graphics/Renderer.cpp +++ b/Engine/src/Engine/Graphics/Renderer.cpp @@ -22,6 +22,7 @@ namespace Light { Renderer::Renderer(GLFWwindow* windowHandle, Ref sharedContext) : m_QuadRenderer(LT_MAX_QUAD_RENDERER_VERTICES, sharedContext), m_TextureRenderer(LT_MAX_TEXTURE_RENDERER_VERTICES, sharedContext), + m_TintedTextureRenderer(LT_MAX_TEXTURE_RENDERER_VERTICES, sharedContext), m_ViewProjectionBuffer(nullptr), m_RenderCommand(nullptr), m_Blender(nullptr), @@ -49,6 +50,13 @@ namespace Light { } //======================================== DRAW_QUAD ========================================// + /* tinted textures */ + void Renderer::DrawQuadImpl(const glm::vec3& position, const glm::vec2& size, const glm::vec4& tint, Ref texture) + { + DrawQuad(glm::translate(glm::mat4(1.0f), position) * glm::scale(glm::mat4(1.0f), { size.x, size.y, 1.0f }), + tint, texture); + } + /* tint */ void Renderer::DrawQuadImpl(const glm::vec3& position, const glm::vec2& size, const glm::vec4& tint) { @@ -128,6 +136,42 @@ namespace Light { } } + void Renderer::DrawQuadImpl(const glm::mat4& transform, const glm::vec4& tint, Ref texture) + { + // #todo: implement a proper binding + texture->Bind(); + + // locals + TintedTextureRendererProgram::TintedTextureVertexData* bufferMap = m_TintedTextureRenderer.GetMapCurrent(); + + // top left + bufferMap[0].position = transform * glm::vec4(-0.5f, -0.5f, 0.0f, 1.0f); + bufferMap[0].tint = tint; + bufferMap[0].texcoord = { 0.0f, 0.0f }; + + // top right + bufferMap[1].position = transform * glm::vec4(0.5f, -0.5f, 0.0f, 1.0f); + bufferMap[1].tint = tint; + bufferMap[1].texcoord = { 1.0f, 0.0f }; + + // bottom right + bufferMap[2].position = transform * glm::vec4(0.5f, 0.5f, 0.0f, 1.0f); + bufferMap[2].tint = tint; + bufferMap[2].texcoord = { 1.0f, 1.0f }; + + // bottom left + bufferMap[3].position = transform * glm::vec4(-0.5f, 0.5f, 0.0f, 1.0f); + bufferMap[3].tint = tint; + bufferMap[3].texcoord = { 0.0f, 1.0f }; + + // advance + if (!m_TintedTextureRenderer.Advance()) + { + LT_ENGINE_WARN("Renderer::DrawQuadImpl: exceeded LT_MAX_TEXTURE_RENDERER_VERTICES: {}", LT_MAX_TEXTURE_RENDERER_VERTICES); + FlushScene(); + } + } + //==================== DRAW_QUAD_TEXTURE ====================// void Renderer::BeginFrame() @@ -163,6 +207,7 @@ namespace Light { // map renderers m_QuadRenderer.Map(); m_TextureRenderer.Map(); + m_TintedTextureRenderer.Map(); } void Renderer::FlushScene() @@ -171,6 +216,7 @@ namespace Light { m_QuadRenderer.Map(); m_TextureRenderer.Map(); + m_TintedTextureRenderer.Map(); } void Renderer::EndSceneImpl() @@ -178,6 +224,15 @@ namespace Light { // enable blending m_Blender->Enable(BlendFactor::SRC_ALPHA, BlendFactor::INVERSE_SRC_ALPHA); + + /* tinted texture renderer */ + m_TintedTextureRenderer.UnMap(); + if (m_TintedTextureRenderer.GetQuadCount()) + { + m_TintedTextureRenderer.Bind(); + m_RenderCommand->DrawIndexed(m_TintedTextureRenderer.GetQuadCount() * 6u); + } + /* quad renderer */ m_QuadRenderer.UnMap(); if (m_QuadRenderer.GetQuadCount()) @@ -186,7 +241,7 @@ namespace Light { m_RenderCommand->DrawIndexed(m_QuadRenderer.GetQuadCount() * 6u); } - /* text renderer */ + /* texture renderer */ m_TextureRenderer.UnMap(); if (m_TextureRenderer.GetQuadCount()) { diff --git a/Engine/src/Engine/Graphics/Renderer.h b/Engine/src/Engine/Graphics/Renderer.h index 35ae179..93f2a90 100644 --- a/Engine/src/Engine/Graphics/Renderer.h +++ b/Engine/src/Engine/Graphics/Renderer.h @@ -4,6 +4,7 @@ #include "RendererPrograms/QuadRendererProgram.h" #include "RendererPrograms/TextureRendererProgram.h" +#include "RendererPrograms/TintedTextureRendererProgram.h" #define LT_MAX_QUAD_RENDERER_VERTICES 1028u * 4u #define LT_MAX_TEXTURE_RENDERER_VERTICES 1028u * 4u @@ -32,6 +33,7 @@ namespace Light { // renderer programs QuadRendererProgram m_QuadRenderer; TextureRendererProgram m_TextureRenderer; + TintedTextureRendererProgram m_TintedTextureRenderer; // constant buffers Scope m_ViewProjectionBuffer; @@ -47,9 +49,11 @@ namespace Light { public: static Scope Create(GLFWwindow* windowHandle, Ref sharedContext); + static inline void DrawQuad(const glm::vec3& position, const glm::vec2& size, const glm::vec4& tint, Ref texture) { s_Context->DrawQuadImpl(position, size, tint, texture); } static inline void DrawQuad(const glm::vec3& position, const glm::vec2& size, const glm::vec4& tint) { s_Context->DrawQuadImpl(position, size, tint); } static inline void DrawQuad(const glm::vec3& position, const glm::vec2& size, Ref texture) { s_Context->DrawQuadImpl(position, size, texture); } + static void DrawQuad(const glm::mat4& transform, const glm::vec4& tint, Ref texture) { s_Context->DrawQuadImpl(transform, tint, texture); } static void DrawQuad(const glm::mat4& transform, const glm::vec4& tint) { s_Context->DrawQuadImpl(transform, tint); } static void DrawQuad(const glm::mat4& transform, Ref texture) { s_Context->DrawQuadImpl(transform, texture); } @@ -64,9 +68,12 @@ namespace Light { private: Renderer(GLFWwindow* windowHandle, Ref sharedContext); + + void DrawQuadImpl(const glm::vec3& position, const glm::vec2& size, const glm::vec4& tint, Ref texture); void DrawQuadImpl(const glm::vec3& position, const glm::vec2& size, const glm::vec4& tint); void DrawQuadImpl(const glm::vec3& position, const glm::vec2& size, Ref texture); + void DrawQuadImpl(const glm::mat4& transform, const glm::vec4& tint, Ref texture); void DrawQuadImpl(const glm::mat4& transform, const glm::vec4& tint); void DrawQuadImpl(const glm::mat4& transform, Ref texture); diff --git a/Engine/src/Engine/Graphics/RendererPrograms/TintedTextureRendererProgram.cpp b/Engine/src/Engine/Graphics/RendererPrograms/TintedTextureRendererProgram.cpp new file mode 100644 index 0000000..af944f1 --- /dev/null +++ b/Engine/src/Engine/Graphics/RendererPrograms/TintedTextureRendererProgram.cpp @@ -0,0 +1,68 @@ +#include "ltpch.h" +#include "TintedTextureRendererProgram.h" + +#include "Camera/Camera.h" + +#include "Graphics/Shader.h" +#include "Graphics/Buffers.h" +#include "Graphics/VertexLayout.h" + +#include "Utility/ResourceManager.h" + +namespace Light { + + TintedTextureRendererProgram::TintedTextureRendererProgram(unsigned int maxVertices, Ref sharedContext) + : m_Shader(nullptr), + m_IndexBuffer(nullptr), + m_VertexLayout(nullptr), + m_MapCurrent(nullptr), + m_MapEnd(nullptr), + m_QuadCount(0u), + m_MaxVertices(maxVertices) + { + // #todo: don't use relative path + ResourceManager::LoadShader("LT_ENGINE_RESOURCES_TINTED_TEXTURE_SHADER", "../Engine/res/Shaders/TintedTexture/TintedTexture_VS", "../Engine/res/Shaders/TintedTexture/TintedTexture_PS"); + + m_Shader = ResourceManager::GetShader("LT_ENGINE_RESOURCES_TINTED_TEXTURE_SHADER"); + m_VertexBuffer = Ref(VertexBuffer::Create(nullptr, sizeof(TintedTextureVertexData), maxVertices, sharedContext)); + m_IndexBuffer = Ref(IndexBuffer::Create(nullptr, (maxVertices / 4) * 6, sharedContext)); + m_VertexLayout = Ref(VertexLayout::Create(m_VertexBuffer, m_Shader, { { "POSITION", VertexElementType::Float4 }, + { "TINT" , VertexElementType::Float4 }, + { "TEXCOORD", VertexElementType::Float2 }}, sharedContext)); + } + + bool TintedTextureRendererProgram::Advance() + { + if (m_MapCurrent + 4 >= m_MapEnd) + { + LT_ENGINE_WARN("TintedTextureRendererProgram::Advance: 'VertexBuffer' map went beyond 'MaxVertices': {}", m_MaxVertices); + return false; + } + + m_MapCurrent += 4; + m_QuadCount++; + return true; + } + + void TintedTextureRendererProgram::Map() + { + m_QuadCount = 0u; + + m_MapCurrent = (TintedTextureRendererProgram::TintedTextureVertexData*)m_VertexBuffer->Map(); + m_MapEnd = m_MapCurrent + m_MaxVertices; + } + + void TintedTextureRendererProgram::UnMap() + { + m_VertexBuffer->UnMap(); + } + + void TintedTextureRendererProgram::Bind() + { + m_Shader->Bind(); + m_VertexLayout->Bind(); + m_VertexBuffer->Bind(); + m_IndexBuffer->Bind(); + } + +} \ No newline at end of file diff --git a/Engine/src/Engine/Graphics/RendererPrograms/TintedTextureRendererProgram.h b/Engine/src/Engine/Graphics/RendererPrograms/TintedTextureRendererProgram.h new file mode 100644 index 0000000..107cec0 --- /dev/null +++ b/Engine/src/Engine/Graphics/RendererPrograms/TintedTextureRendererProgram.h @@ -0,0 +1,59 @@ +#pragma once + +#include "RendererProgram.h" + +#include "Base/Base.h" + +#include + +namespace Light { + + class Shader; + class VertexBuffer; + class IndexBuffer; + class VertexLayout; + + class OrthographicCamera; + + class SharedContext; + + class TintedTextureRendererProgram : RendererProgram + { + public: + struct TintedTextureVertexData + { + glm::vec4 position; + glm::vec4 tint; + glm::vec2 texcoord; + }; + + private: + Ref m_Shader; + Ref m_VertexBuffer; + Ref m_IndexBuffer; + Ref m_VertexLayout; + + TintedTextureVertexData* m_MapCurrent = nullptr; + TintedTextureVertexData* m_MapEnd = nullptr; + + unsigned int m_QuadCount; + unsigned int m_MaxVertices; + + public: + TintedTextureRendererProgram(unsigned int maxVertices, Ref sharedContext); + + bool Advance(); + + void Map() override; + void UnMap() override; + + void Bind() override; + + inline TintedTextureVertexData* GetMapCurrent() { return m_MapCurrent; } + + inline unsigned int GetQuadCount() const { return m_QuadCount; } + + inline constexpr unsigned int GetVertexSize() const { return sizeof(TintedTextureVertexData); } + }; + +} \ No newline at end of file diff --git a/Engine/src/Engine/Scene/Components/SpriteRendererComponent.h b/Engine/src/Engine/Scene/Components/SpriteRendererComponent.h index 8cc828b..3d103b0 100644 --- a/Engine/src/Engine/Scene/Components/SpriteRendererComponent.h +++ b/Engine/src/Engine/Scene/Components/SpriteRendererComponent.h @@ -9,12 +9,14 @@ namespace Light { struct SpriteRendererComponent { Ref texture; + glm::vec4 tint; SpriteRendererComponent() = default; SpriteRendererComponent(const SpriteRendererComponent&) = default; - SpriteRendererComponent(Ref _texture) - : texture(_texture) + SpriteRendererComponent(Ref _texture, const glm::vec4& _tint = glm::vec4(1.0f, 1.0f, 1.0f, 1.0f)) + : texture(_texture), + tint(_tint) { } diff --git a/Engine/src/Engine/Scene/Scene.cpp b/Engine/src/Engine/Scene/Scene.cpp index f62d3ab..eebf988 100644 --- a/Engine/src/Engine/Scene/Scene.cpp +++ b/Engine/src/Engine/Scene/Scene.cpp @@ -75,7 +75,7 @@ namespace Light { m_Registry.group(entt::get). each([](TransformComponent& transformComp, SpriteRendererComponent& spriteRendererComp) { - Renderer::DrawQuad(transformComp.transform, spriteRendererComp.texture); + Renderer::DrawQuad(transformComp.transform, spriteRendererComp.tint, spriteRendererComp.texture); }); Renderer::EndScene();