From c96eb34af509516d285afa66fba647eff84b2422 Mon Sep 17 00:00:00 2001 From: Atdunbg Date: Mon, 1 Dec 2025 22:14:22 +0800 Subject: [PATCH] add MSAA, renderer2D, boundingbox --- Editor/Editor/EditorLayer.cpp | 143 ++++-- Editor/Editor/EditorLayer.h | 9 + Editor/assets/meshes/TestScene.fbx | Bin 0 -> 42524 bytes Editor/assets/shaders/PBRShader_Static.glsl | 6 +- Editor/assets/shaders/Renderer2D.glsl | 43 ++ Editor/assets/shaders/Renderer2D_Line.glsl | 29 ++ .../shaders/{hdr.glsl => SceneComposite.glsl} | 26 +- Prism/CMakeLists.txt | 1 + Prism/src/Prism/Core/Application.h | 4 +- Prism/src/Prism/Core/Buffer.h | 2 +- Prism/src/Prism/Editor/SceneHierachyPanel.cpp | 50 ++- Prism/src/Prism/Editor/SceneHierachyPanel.h | 3 +- .../Platform/OpenGL/OpenGLFrameBuffer.cpp | 136 ++++-- .../Platform/OpenGL/OpenGLRendererAPI.cpp | 40 +- .../Prism/Platform/OpenGL/OpenGLShader.cpp | 21 +- .../src/Prism/Platform/OpenGL/OpenGLShader.h | 5 +- .../Platform/OpenGL/OpenGLShaderUniform.cpp | 4 +- .../Platform/OpenGL/OpenGLShaderUniform.h | 2 +- .../Prism/Platform/OpenGL/OpenGLTexture.cpp | 3 +- .../src/Prism/Platform/OpenGL/OpenGLTexture.h | 9 + .../Prism/Platform/OpenGL/OpenGLVertexArray.h | 5 +- Prism/src/Prism/Renderer/Camera.cpp | 17 +- Prism/src/Prism/Renderer/Camera.h | 8 +- Prism/src/Prism/Renderer/FrameBuffer.h | 1 + Prism/src/Prism/Renderer/Material.cpp | 1 + Prism/src/Prism/Renderer/Material.h | 4 +- Prism/src/Prism/Renderer/Mesh.cpp | 105 ++++- Prism/src/Prism/Renderer/Mesh.h | 1 + Prism/src/Prism/Renderer/Renderer.cpp | 69 ++- Prism/src/Prism/Renderer/Renderer.h | 9 +- Prism/src/Prism/Renderer/Renderer2D.cpp | 418 ++++++++++++++++++ Prism/src/Prism/Renderer/Renderer2D.h | 57 +++ Prism/src/Prism/Renderer/RendererAPI.h | 14 +- Prism/src/Prism/Renderer/SceneRenderer.cpp | 37 +- Prism/src/Prism/Renderer/SceneRenderer.h | 10 + Prism/src/Prism/Renderer/Shader.h | 3 + Prism/src/Prism/Renderer/Texture.h | 2 + Prism/src/Prism/Renderer/VertexArray.h | 1 + Prism/src/Prism/Scene/Entity.cpp | 10 +- Prism/src/Prism/Scene/Entity.h | 10 +- Prism/src/Prism/Scene/Scene.cpp | 14 +- Prism/src/Prism/Scene/Scene.h | 4 +- Sandbox/Sandbox/Layer/TestLayer.cpp | 124 ++---- Sandbox/Sandbox/Layer/TestLayer.h | 14 +- 44 files changed, 1185 insertions(+), 289 deletions(-) create mode 100644 Editor/assets/meshes/TestScene.fbx create mode 100644 Editor/assets/shaders/Renderer2D.glsl create mode 100644 Editor/assets/shaders/Renderer2D_Line.glsl rename Editor/assets/shaders/{hdr.glsl => SceneComposite.glsl} (55%) create mode 100644 Prism/src/Prism/Renderer/Renderer2D.cpp create mode 100644 Prism/src/Prism/Renderer/Renderer2D.h diff --git a/Editor/Editor/EditorLayer.cpp b/Editor/Editor/EditorLayer.cpp index c03c560..a3d5b50 100644 --- a/Editor/Editor/EditorLayer.cpp +++ b/Editor/Editor/EditorLayer.cpp @@ -4,6 +4,8 @@ #include "EditorLayer.h" #include "ImGuizmo.h" +#include "Prism/Core/Input.h" +#include "Prism/Renderer/Renderer2D.h" namespace Prism { @@ -12,16 +14,18 @@ namespace Prism None = 0, ColorProperty = 1 }; - void Property(const std::string& name, bool& value) + bool Property(const std::string& name, bool& value) { ImGui::Text(name.c_str()); ImGui::NextColumn(); ImGui::PushItemWidth(-1); - std::string id = "##" + name; - ImGui::Checkbox(id.c_str(), &value); + const std::string id = "##" + name; + const bool result = ImGui::Checkbox(id.c_str(), &value); ImGui::PopItemWidth(); ImGui::NextColumn(); + + return result; } void Property(const std::string& name, float& value, float min = -1.0f, float max = 1.0f, @@ -137,14 +141,16 @@ namespace Prism m_Scene->SetEnvironment(environment); - m_MeshEntity = m_Scene->CreateEntity(); - - const auto mesh = CreateRef("assets/models/m1911/m1911.fbx"); - //auto mesh = CreateRef("assets/meshes/cerberus/CerberusMaterials.fbx"); - // auto mesh = CreateRef("assets/models/m1911/M1911Materials.fbx"); + m_MeshEntity = m_Scene->CreateEntity("test Entity"); + auto mesh = CreateRef("assets/meshes/TestScene.fbx"); m_MeshEntity->SetMesh(mesh); m_MeshMaterial = mesh->GetMaterial(); + + auto secondEntity = m_Scene->CreateEntity("Gun Entity"); + secondEntity->Transform() = glm::translate(glm::mat4(1.0f), { 5, 5, 5 }) * glm::scale(glm::mat4(1.0f), {10, 10, 10}); + mesh = CreateRef("assets/models/m1911/m1911.fbx"); + secondEntity->SetMesh(mesh); } // Sphere Scene @@ -213,43 +219,55 @@ namespace Prism void EditorLayer::OnUpdate(const TimeStep deltaTime) { + // THINGS TO LOOK AT: + // - BRDF LUT + // - Tonemapping and proper HDR pipeline + using namespace Prism; + using namespace glm; + + m_MeshMaterial->Set("u_AlbedoColor", m_AlbedoInput.Color); + m_MeshMaterial->Set("u_Metalness", m_MetalnessInput.Value); + m_MeshMaterial->Set("u_Roughness", m_RoughnessInput.Value); + m_MeshMaterial->Set("lights", m_Light); + m_MeshMaterial->Set("u_AlbedoTexToggle", m_AlbedoInput.UseTexture ? 1.0f : 0.0f); + m_MeshMaterial->Set("u_NormalTexToggle", m_NormalInput.UseTexture ? 1.0f : 0.0f); + m_MeshMaterial->Set("u_MetalnessTexToggle", m_MetalnessInput.UseTexture ? 1.0f : 0.0f); + m_MeshMaterial->Set("u_RoughnessTexToggle", m_RoughnessInput.UseTexture ? 1.0f : 0.0f); + m_MeshMaterial->Set("u_EnvMapRotation", m_EnvMapRotation); + + m_SphereBaseMaterial->Set("u_AlbedoColor", m_AlbedoInput.Color); + m_SphereBaseMaterial->Set("lights", m_Light); + m_SphereBaseMaterial->Set("u_RadiancePrefilter", m_RadiancePrefilter ? 1.0f : 0.0f); + m_SphereBaseMaterial->Set("u_AlbedoTexToggle", m_AlbedoInput.UseTexture ? 1.0f : 0.0f); + m_SphereBaseMaterial->Set("u_NormalTexToggle", m_NormalInput.UseTexture ? 1.0f : 0.0f); + m_SphereBaseMaterial->Set("u_MetalnessTexToggle", m_MetalnessInput.UseTexture ? 1.0f : 0.0f); + m_SphereBaseMaterial->Set("u_RoughnessTexToggle", m_RoughnessInput.UseTexture ? 1.0f : 0.0f); + m_SphereBaseMaterial->Set("u_EnvMapRotation", m_EnvMapRotation); + + + if (m_AlbedoInput.TextureMap) + m_MeshMaterial->Set("u_AlbedoTexture", m_AlbedoInput.TextureMap); + if (m_NormalInput.TextureMap) + m_MeshMaterial->Set("u_NormalTexture", m_NormalInput.TextureMap); + if (m_MetalnessInput.TextureMap) + m_MeshMaterial->Set("u_MetalnessTexture", m_MetalnessInput.TextureMap); + if (m_RoughnessInput.TextureMap) + m_MeshMaterial->Set("u_RoughnessTexture", m_RoughnessInput.TextureMap); + + if (m_AllowViewportCameraEvents) + m_Scene->GetCamera().OnUpdate(deltaTime); + + m_ActiveScene->OnUpdate(deltaTime); + + if (m_DrawOnTopBoundingBoxes) { - // THINGS TO LOOK AT: - // - BRDF LUT - // - Tonemapping and proper HDR pipeline - using namespace Prism; - using namespace glm; - - m_MeshMaterial->Set("u_AlbedoColor", m_AlbedoInput.Color); - m_MeshMaterial->Set("u_Metalness", m_MetalnessInput.Value); - m_MeshMaterial->Set("u_Roughness", m_RoughnessInput.Value); - m_MeshMaterial->Set("lights", m_Light); - m_MeshMaterial->Set("u_AlbedoTexToggle", m_AlbedoInput.UseTexture ? 1.0f : 0.0f); - m_MeshMaterial->Set("u_NormalTexToggle", m_NormalInput.UseTexture ? 1.0f : 0.0f); - m_MeshMaterial->Set("u_MetalnessTexToggle", m_MetalnessInput.UseTexture ? 1.0f : 0.0f); - m_MeshMaterial->Set("u_RoughnessTexToggle", m_RoughnessInput.UseTexture ? 1.0f : 0.0f); - m_MeshMaterial->Set("u_EnvMapRotation", m_EnvMapRotation); - - m_SphereBaseMaterial->Set("u_AlbedoColor", m_AlbedoInput.Color); - m_SphereBaseMaterial->Set("lights", m_Light); - m_SphereBaseMaterial->Set("u_RadiancePrefilter", m_RadiancePrefilter ? 1.0f : 0.0f); - m_SphereBaseMaterial->Set("u_AlbedoTexToggle", m_AlbedoInput.UseTexture ? 1.0f : 0.0f); - m_SphereBaseMaterial->Set("u_NormalTexToggle", m_NormalInput.UseTexture ? 1.0f : 0.0f); - m_SphereBaseMaterial->Set("u_MetalnessTexToggle", m_MetalnessInput.UseTexture ? 1.0f : 0.0f); - m_SphereBaseMaterial->Set("u_RoughnessTexToggle", m_RoughnessInput.UseTexture ? 1.0f : 0.0f); - m_SphereBaseMaterial->Set("u_EnvMapRotation", m_EnvMapRotation); - - - if (m_AlbedoInput.TextureMap) - m_MeshMaterial->Set("u_AlbedoTexture", m_AlbedoInput.TextureMap); - if (m_NormalInput.TextureMap) - m_MeshMaterial->Set("u_NormalTexture", m_NormalInput.TextureMap); - if (m_MetalnessInput.TextureMap) - m_MeshMaterial->Set("u_MetalnessTexture", m_MetalnessInput.TextureMap); - if (m_RoughnessInput.TextureMap) - m_MeshMaterial->Set("u_RoughnessTexture", m_RoughnessInput.TextureMap); - - m_ActiveScene->OnUpdate(deltaTime); + Renderer::BeginRenderPass(SceneRenderer::GetFinalRenderPass(), false); + auto viewProj = m_Scene->GetCamera().GetViewProjection(); + Renderer2D::BeginScene(viewProj, false); + // Prism::Renderer2D::DrawQuad({ 0, 0, 0 }, { 4.0f, 5.0f }, { 1.0f, 1.0f, 0.5f, 1.0f }); + Renderer::DrawAABB(m_MeshEntity->GetMesh()); + Renderer2D::EndScene(); + Renderer::EndRenderPass(); } } @@ -431,6 +449,11 @@ namespace Prism Property("Radiance Prefiltering", m_RadiancePrefilter); Property("Env Map Rotation", m_EnvMapRotation, -360.0f, 360.0f); + if (Property("Show Bounding Boxes", m_UIShowBoundingBoxes)) + ShowBoundingBoxes(m_UIShowBoundingBoxes, m_UIShowBoundingBoxesOnTop); + if (m_UIShowBoundingBoxes && Property("On Top", m_UIShowBoundingBoxesOnTop)) + ShowBoundingBoxes(m_UIShowBoundingBoxes, m_UIShowBoundingBoxesOnTop); + ImGui::Columns(1); ImGui::End(); @@ -620,12 +643,17 @@ namespace Prism ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0, 0)); ImGui::Begin("Viewport"); auto viewportSize = ImGui::GetContentRegionAvail(); - SceneRenderer::SetViewportSize((uint32_t)viewportSize.x, (uint32_t)viewportSize.y); m_ActiveScene->GetCamera().SetProjectionMatrix(glm::perspectiveFov(glm::radians(45.0f), viewportSize.x, viewportSize.y, 0.1f, 10000.0f)); m_ActiveScene->GetCamera().SetViewportSize((uint32_t)viewportSize.x, (uint32_t)viewportSize.y); ImGui::Image((ImTextureRef)SceneRenderer::GetFinalColorBufferRendererID(), viewportSize, { 0, 1 }, { 1, 0 }); + + auto windowSize = ImGui::GetWindowSize(); + ImVec2 minBound = ImGui::GetWindowPos(); + ImVec2 maxBound = { minBound.x + windowSize.x, minBound.y + windowSize.y }; + m_AllowViewportCameraEvents = ImGui::IsMouseHoveringRect(minBound, maxBound); + // ImGuizmo if (m_GizmoType != -1) { @@ -645,8 +673,11 @@ namespace Prism void EditorLayer::OnEvent(Event& e) { + if (m_AllowViewportCameraEvents) + m_Scene->GetCamera().OnEvent(e); + EventDispatcher dispatcher(e); - dispatcher.Dispatch(HZ_BIND_EVENT_FN(EditorLayer::OnKeyPressedEvent)); + dispatcher.Dispatch(PM_BIND_EVENT_FN(EditorLayer::OnKeyPressedEvent)); } bool EditorLayer::OnKeyPressedEvent(KeyPressedEvent& e) @@ -665,7 +696,27 @@ namespace Prism case PM_KEY_R: m_GizmoType = ImGuizmo::OPERATION::SCALE; break; + case PM_KEY_G: + // Toggle grid + if (Input::IsKeyPressed(PM_KEY_LEFT_CONTROL)) + SceneRenderer::GetOptions().ShowGrid = !SceneRenderer::GetOptions().ShowGrid; + break; + case PM_KEY_B: + // Toggle bounding boxes + if (Input::IsKeyPressed(PM_KEY_LEFT_CONTROL)) + { + m_UIShowBoundingBoxes = !m_UIShowBoundingBoxes; + ShowBoundingBoxes(m_UIShowBoundingBoxes, m_UIShowBoundingBoxesOnTop); + } + break; + } return false; } + + void EditorLayer::ShowBoundingBoxes(bool show, bool onTop) + { + SceneRenderer::GetOptions().ShowBoundingBoxes = show && !onTop; + m_DrawOnTopBoundingBoxes = show && onTop; + } } diff --git a/Editor/Editor/EditorLayer.h b/Editor/Editor/EditorLayer.h index 14db0e4..4bd7b26 100644 --- a/Editor/Editor/EditorLayer.h +++ b/Editor/Editor/EditorLayer.h @@ -25,6 +25,8 @@ namespace Prism private: bool OnKeyPressedEvent(KeyPressedEvent& e); + void ShowBoundingBoxes(bool show, bool onTop = false); + private: Scope m_SceneHierarchyPanel; @@ -54,6 +56,13 @@ namespace Prism // Imguizmo int m_GizmoType = -1; // -1 = no gizmo + // configure button + bool m_AllowViewportCameraEvents = false; + bool m_DrawOnTopBoundingBoxes = false; + + bool m_UIShowBoundingBoxes = false; + bool m_UIShowBoundingBoxesOnTop = false; + struct AlbedoInput { diff --git a/Editor/assets/meshes/TestScene.fbx b/Editor/assets/meshes/TestScene.fbx new file mode 100644 index 0000000000000000000000000000000000000000..e6808dbcd6ee3b2fa34024b393b29add865f10ec GIT binary patch literal 42524 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 - for (Entity* entity : sceneEntities) + for (const auto& entity : sceneEntities) { - auto mesh = entity->GetMesh(); - auto material = entity->GetMaterial(); - const auto& transform = entity->GetTransform(); - - if (mesh) - { - DrawMeshNode(mesh); - } - + DrawEntityNode(entity, entityCount, meshCount); } ImGui::End(); @@ -89,7 +82,26 @@ namespace Prism } - static std::tuple GetTransformDecomposition(const glm::mat4& transform) + void SceneHierarchyPanel::DrawEntityNode(Entity* entity, uint32_t& imguiEntityID, uint32_t& imguiMeshID) + { + const char* name = entity->GetName().c_str(); + static char imguiName[128]; + memset(imguiName, 0, 128); + sprintf(imguiName, "%s##%d", name, imguiEntityID++); + if (ImGui::TreeNode(imguiName)) + { + auto mesh = entity->GetMesh(); + auto material = entity->GetMaterial(); + const auto& transform = entity->GetTransform(); + + if (mesh) + DrawMeshNode(mesh, imguiMeshID); + + ImGui::TreePop(); + } + } + + static std::tuple GetTransformDecomposition(const glm::mat4& transform) { glm::vec3 scale, translation, skew; glm::vec4 perspective; @@ -99,13 +111,23 @@ namespace Prism return { translation, orientation, scale }; } - void SceneHierarchyPanel::DrawMeshNode(const Ref& mesh) + void SceneHierarchyPanel::DrawMeshNode(const Ref& mesh, uint32_t& imguiMeshID) { - auto rootNode = mesh->m_Scene->mRootNode; - MeshNodeHierarchy(mesh, rootNode); + static char imguiName[128]; + memset(imguiName, 0, 128); + sprintf(imguiName, "Mesh##%d", imguiMeshID++); + + // Mesh Hierarchy + if (ImGui::TreeNode(imguiName)) + { + auto rootNode = mesh->m_Scene->mRootNode; + MeshNodeHierarchy(mesh, rootNode); + ImGui::TreePop(); + } } + void SceneHierarchyPanel::MeshNodeHierarchy(const Ref& mesh, aiNode* node, const glm::mat4& parentTransform, uint32_t level) { glm::mat4 localTransform = Mat4FromAssimpMat4(node->mTransformation); diff --git a/Prism/src/Prism/Editor/SceneHierachyPanel.h b/Prism/src/Prism/Editor/SceneHierachyPanel.h index 9d83756..27845c2 100644 --- a/Prism/src/Prism/Editor/SceneHierachyPanel.h +++ b/Prism/src/Prism/Editor/SceneHierachyPanel.h @@ -18,7 +18,8 @@ namespace Prism void OnImGuiRender(); private: - void DrawMeshNode(const Ref& mesh); + void DrawEntityNode(Entity* entity, uint32_t& imguiEntityID, uint32_t& imguiMeshID); + void DrawMeshNode(const Ref& mesh, uint32_t& imguiMeshID); void MeshNodeHierarchy(const Ref& mesh, aiNode* node, const glm::mat4& parentTransform = glm::mat4(1.0f), uint32_t level = 0); private: Ref m_Context; diff --git a/Prism/src/Prism/Platform/OpenGL/OpenGLFrameBuffer.cpp b/Prism/src/Prism/Platform/OpenGL/OpenGLFrameBuffer.cpp index b0a7b96..9243e75 100644 --- a/Prism/src/Prism/Platform/OpenGL/OpenGLFrameBuffer.cpp +++ b/Prism/src/Prism/Platform/OpenGL/OpenGLFrameBuffer.cpp @@ -26,7 +26,7 @@ namespace Prism void OpenGLFrameBuffer::Bind() const { - Renderer::Submit([this](){ + Renderer::Submit([=](){ glBindFramebuffer(GL_FRAMEBUFFER, m_RendererID); glViewport(0, 0, m_Specification.Width, m_Specification.Height); }); @@ -34,66 +34,116 @@ namespace Prism void OpenGLFrameBuffer::Unbind() const { - Renderer::Submit([this](){ + Renderer::Submit([=](){ glBindFramebuffer(GL_FRAMEBUFFER, 0); }); } void OpenGLFrameBuffer::Resize(const uint32_t width, const uint32_t height) { - if (m_RendererID && m_Specification.Width == width && m_Specification.Height == height) - return; + if (m_Specification.Width == width && m_Specification.Height == height) + return; - m_Specification.Width = width; - m_Specification.Height = height; - Renderer::Submit([this](){ - if (m_RendererID) - { - glDeleteFramebuffers(1, &m_RendererID); - glDeleteTextures(1, &m_ColorAttachment); - glDeleteTextures(1, &m_DepthAttachment); - } + m_Specification.Width = width; + m_Specification.Height = height; + Renderer::Submit([this]() + { + if (m_RendererID) + { + glDeleteFramebuffers(1, &m_RendererID); + glDeleteTextures(1, &m_ColorAttachment); + glDeleteTextures(1, &m_DepthAttachment); + } - glGenFramebuffers(1, &m_RendererID); - glBindFramebuffer(GL_FRAMEBUFFER, m_RendererID); + glGenFramebuffers(1, &m_RendererID); + glBindFramebuffer(GL_FRAMEBUFFER, m_RendererID); - glGenTextures(1, &m_ColorAttachment); - glBindTexture(GL_TEXTURE_2D, m_ColorAttachment); + bool multisample = m_Specification.Samples > 1; + if (multisample) + { + glCreateTextures(GL_TEXTURE_2D_MULTISAMPLE, 1, &m_ColorAttachment); + glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, m_ColorAttachment); - // TODO: Create Hazel texture object based on format here - if (m_Specification.Format == FramebufferFormat::RGBA16F) - { - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F, m_Specification.Width, m_Specification.Height, 0, GL_RGBA, GL_FLOAT, nullptr); - } - else if (m_Specification.Format == FramebufferFormat::RGBA8) - { - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, m_Specification.Width, m_Specification.Height, 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); - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_ColorAttachment, 0); + // TODO: Create Hazel texture object based on format here + if (m_Specification.Format == FramebufferFormat::RGBA16F) + { + glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, m_Specification.Samples, GL_RGBA16F, m_Specification.Width, m_Specification.Height, GL_FALSE); + //glTexStorage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, m_Specification.Samples, GL_RGBA16F, m_Specification.Width, m_Specification.Height, GL_FALSE); + } + else if (m_Specification.Format == FramebufferFormat::RGBA8) + { + // glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, 8, GL_RGBA8, m_Specification.Width, m_Specification.Height, GL_TRUE); + glTexStorage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, m_Specification.Samples, GL_RGBA8, m_Specification.Width, m_Specification.Height, GL_FALSE); + } + // glTexParameteri(GL_TEXTURE_2D_MULTISAMPLE, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + // glTexParameteri(GL_TEXTURE_2D_MULTISAMPLE, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + // glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D_MULTISAMPLE, m_ColorAttachment, 0); + glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, 0); + } + else + { + glCreateTextures(GL_TEXTURE_2D, 1, &m_ColorAttachment); + glBindTexture(GL_TEXTURE_2D, m_ColorAttachment); - glGenTextures(1, &m_DepthAttachment); - glBindTexture(GL_TEXTURE_2D, m_DepthAttachment); - glTexImage2D( - GL_TEXTURE_2D, 0, GL_DEPTH24_STENCIL8, m_Specification.Width, m_Specification.Height, 0, - GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, NULL - ); + // TODO: Create Hazel texture object based on format here + if (m_Specification.Format == FramebufferFormat::RGBA16F) + { + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F, m_Specification.Width, m_Specification.Height, 0, GL_RGBA, GL_FLOAT, nullptr); + } + else if (m_Specification.Format == FramebufferFormat::RGBA8) + { + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, m_Specification.Width, m_Specification.Height, 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); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_ColorAttachment, 0); + } - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, m_DepthAttachment, 0); + if (multisample) + { + glCreateTextures(GL_TEXTURE_2D_MULTISAMPLE, 1, &m_DepthAttachment); + glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, m_DepthAttachment); + // glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, 8, GL_DEPTH24_STENCIL8, m_Specification.Width, m_Specification.Height, GL_TRUE); + glTexStorage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, m_Specification.Samples, GL_DEPTH24_STENCIL8, m_Specification.Width, m_Specification.Height, GL_FALSE); + glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, 0); + // glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D_MULTISAMPLE, m_DepthAttachment, 0); + } + else + { + glCreateTextures(GL_TEXTURE_2D, 1, &m_DepthAttachment); + glBindTexture(GL_TEXTURE_2D, m_DepthAttachment); + glTexImage2D( + GL_TEXTURE_2D, 0, GL_DEPTH24_STENCIL8, m_Specification.Width, m_Specification.Height, 0, + GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, NULL + ); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, m_DepthAttachment, 0); + } - if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) - PM_CORE_ERROR("Framebuffer is incomplete!"); + // glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, m_ColorAttachment, 0); + if (multisample) + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D_MULTISAMPLE, m_ColorAttachment, 0); + else + glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, m_ColorAttachment, 0); + glFramebufferTexture(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, m_DepthAttachment, 0); - glBindFramebuffer(GL_FRAMEBUFFER, 0); - }); + PM_CORE_ASSERT(glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE, "Framebuffer is incomplete!"); + + glBindFramebuffer(GL_FRAMEBUFFER, 0); + }); } - void OpenGLFrameBuffer::BindTexture(uint32_t slot) const + void OpenGLFrameBuffer::BindTexture(const uint32_t slot) const { - Renderer::Submit([this, slot](){ + Renderer::Submit([=](){ glActiveTexture(GL_TEXTURE0 + slot); - glBindTexture(GL_TEXTURE_2D, m_ColorAttachment); + + if (m_Specification.Samples > 1) { + glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, m_ColorAttachment); + } else { + glBindTexture(GL_TEXTURE_2D, m_ColorAttachment); + } + + // glBindTexture(GL_TEXTURE_2D, m_ColorAttachment); }); } } diff --git a/Prism/src/Prism/Platform/OpenGL/OpenGLRendererAPI.cpp b/Prism/src/Prism/Platform/OpenGL/OpenGLRendererAPI.cpp index 16b9eb0..14747bf 100644 --- a/Prism/src/Prism/Platform/OpenGL/OpenGLRendererAPI.cpp +++ b/Prism/src/Prism/Platform/OpenGL/OpenGLRendererAPI.cpp @@ -12,17 +12,6 @@ namespace Prism { static void OpenGLLogMessage(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar* message, const void* userParam) { - /* - if (severity != GL_DEBUG_SEVERITY_NOTIFICATION) - { - - PM_CORE_ERROR("{0}", message); - PM_CORE_ASSERT(false, ""); - }else - { - PM_CORE_TRACE("{0}", message); - } - */ if (severity == GL_DEBUG_SEVERITY_NOTIFICATION) { @@ -81,11 +70,10 @@ namespace Prism switch (severity) { case GL_DEBUG_SEVERITY_HIGH: - PM_CORE_ERROR("[OpenGL HIGH] Source: {0}, Type: {1}, ID: {2}\nMessage: {3}", - sourceStr, typeStr, id, message); - if (type == GL_DEBUG_TYPE_ERROR) + PM_CORE_ERROR("[OpenGL HIGH] Source: {0}, Type: {1}, ID: {2}\nMessage: {3}", sourceStr, typeStr, id, message); + if(type == GL_DEBUG_TYPE_ERROR) { - PM_CORE_ASSERT(false, "OpenGL严重错误"); + PM_CORE_ASSERT(false, "ERROR"); } break; @@ -134,6 +122,7 @@ namespace Prism glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glEnable(GL_MULTISAMPLE); auto& caps = GetCapabilities(); @@ -143,6 +132,7 @@ namespace Prism glGetIntegerv(GL_MAX_SAMPLES, &caps.MaxSamples); glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY, &caps.MaxAnisotropy); + glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &caps.MaxTextureUnits); GLenum error = glGetError(); @@ -168,14 +158,30 @@ namespace Prism glClearColor(r, g, b, a); } - void RendererAPI::DrawIndexed(const unsigned int count, const bool depthTest) + void RendererAPI::DrawIndexed(uint32_t count, PrimitiveType type, bool depthTest) { if (!depthTest) glDisable(GL_DEPTH_TEST); - glDrawElements(GL_TRIANGLES, count, GL_UNSIGNED_INT, nullptr); + GLenum glPrimitiveType = 0; + switch (type) + { + case PrimitiveType::Triangles: + glPrimitiveType = GL_TRIANGLES; + break; + case PrimitiveType::Lines: + glPrimitiveType = GL_LINES; + break; + } + + glDrawElements(glPrimitiveType, count, GL_UNSIGNED_INT, nullptr); if (!depthTest) glEnable(GL_DEPTH_TEST); } + + void RendererAPI::SetLineThickness(const float thickness) + { + glLineWidth(thickness); + } } diff --git a/Prism/src/Prism/Platform/OpenGL/OpenGLShader.cpp b/Prism/src/Prism/Platform/OpenGL/OpenGLShader.cpp index a8755f8..456e7e2 100644 --- a/Prism/src/Prism/Platform/OpenGL/OpenGLShader.cpp +++ b/Prism/src/Prism/Platform/OpenGL/OpenGLShader.cpp @@ -40,7 +40,7 @@ namespace Prism if (!m_IsCompute) Parse(); - Renderer::Submit([this](){ + Renderer::Submit([=](){ auto &a = m_RendererID; if (m_RendererID) glDeleteProgram(m_RendererID); @@ -125,6 +125,13 @@ namespace Prism }); } + void OpenGLShader::SetInt(const std::string& name, int value) + { + Renderer::Submit([=]() { + UploadUniformInt(name, value); + }); + } + void OpenGLShader::SetMat4(const std::string& name, const glm::mat4& value) { Renderer::Submit([=]() { @@ -132,6 +139,13 @@ namespace Prism }); } + void OpenGLShader::SetIntArray(const std::string& name, int* values, uint32_t size) + { + Renderer::Submit([=]() { + UploadUniformIntArray(name, values, size); + }); + } + void OpenGLShader::SetVSMaterialUniformBuffer(Buffer buffer) { Renderer::Submit([this, buffer]() { @@ -351,6 +365,7 @@ namespace Prism static bool IsTypeStringResource(const std::string& type) { if (type == "sampler2D") return true; + if (type == "sampler2DMS") return true; if (type == "samplerCube") return true; if (type == "sampler2DShadow") return true; return false; @@ -371,7 +386,7 @@ namespace Prism { int32_t result = glGetUniformLocation(m_RendererID, name.c_str()); if (result == -1) - PM_CORE_WARN("Could not find uniform '{0}' in shader", name); + PM_CORE_WARN("Could not find uniform '{0}' in shader: {1}", name, m_Name); return result; } @@ -932,7 +947,7 @@ namespace Prism } } - void OpenGLShader::UploadUniformIntArray(const std::string& name, const int32_t* values, const int32_t count) const + void OpenGLShader::UploadUniformIntArray(const std::string& name, const int32_t* values, const uint32_t count) const { int32_t location = GetUniformLocation(name); glUniform1iv(location, count, values); diff --git a/Prism/src/Prism/Platform/OpenGL/OpenGLShader.h b/Prism/src/Prism/Platform/OpenGL/OpenGLShader.h index 41b4f6a..cfaed54 100644 --- a/Prism/src/Prism/Platform/OpenGL/OpenGLShader.h +++ b/Prism/src/Prism/Platform/OpenGL/OpenGLShader.h @@ -28,8 +28,11 @@ namespace Prism virtual void AddShaderReloadedCallback(const ShaderReloadedCallback& callback) override; virtual void SetFloat(const std::string& name, float value) override; + virtual void SetInt(const std::string& name, int value) override; virtual void SetMat4(const std::string& name, const glm::mat4& value) override; + virtual void SetIntArray(const std::string& name, int* values, uint32_t size) override; + virtual void SetVSMaterialUniformBuffer(Buffer buffer) override; virtual void SetPSMaterialUniformBuffer(Buffer buffer) override; @@ -81,7 +84,7 @@ namespace Prism void UploadUniformMat4Array(uint32_t location, const glm::mat4& values, uint32_t count); void UploadUniformStruct(const OpenGLShaderUniformDeclaration* uniform, byte* buffer, uint32_t offset); - void UploadUniformIntArray(const std::string& name, const int32_t* values, int32_t count) const; + void UploadUniformIntArray(const std::string& name, const int32_t* values, uint32_t count) const; virtual const ShaderUniformBufferList& GetVSRendererUniforms() const override { return m_VSRendererUniformBuffers; } virtual const ShaderUniformBufferList& GetPSRendererUniforms() const override { return m_PSRendererUniformBuffers; } diff --git a/Prism/src/Prism/Platform/OpenGL/OpenGLShaderUniform.cpp b/Prism/src/Prism/Platform/OpenGL/OpenGLShaderUniform.cpp index 9f2d908..53709a0 100644 --- a/Prism/src/Prism/Platform/OpenGL/OpenGLShaderUniform.cpp +++ b/Prism/src/Prism/Platform/OpenGL/OpenGLShaderUniform.cpp @@ -48,6 +48,7 @@ namespace Prism OpenGLShaderUniformDeclaration::Type OpenGLShaderUniformDeclaration::StringToType(const std::string& type) { + if (type == "int") return Type::INT32; if (type == "int32") return Type::INT32; if (type == "float") return Type::FLOAT32; if (type == "vec2") return Type::VEC2; @@ -112,6 +113,7 @@ namespace Prism OpenGLShaderResourceDeclaration::Type OpenGLShaderResourceDeclaration::StringToType(const std::string& type) { if (type == "sampler2D") return Type::TEXTURE2D; + if (type == "sampler2DMS") return Type::TEXTURE2D; if (type == "samplerCube") return Type::TEXTURECUBE; return Type::NONE; @@ -121,7 +123,7 @@ namespace Prism { switch (type) { - case Type::TEXTURE2D: return "sampler2D"; + case Type::TEXTURE2D: return "sampler2D"; case Type::TEXTURECUBE: return "samplerCube"; } return "Invalid Type"; diff --git a/Prism/src/Prism/Platform/OpenGL/OpenGLShaderUniform.h b/Prism/src/Prism/Platform/OpenGL/OpenGLShaderUniform.h index 444491d..8b66153 100644 --- a/Prism/src/Prism/Platform/OpenGL/OpenGLShaderUniform.h +++ b/Prism/src/Prism/Platform/OpenGL/OpenGLShaderUniform.h @@ -70,7 +70,7 @@ namespace Prism int32_t GetLocation() const { return m_Location; } inline Type GetType() const { return m_Type; } inline bool IsArray() const { return m_Count > 1; } - inline const ShaderStruct& GetShaderUniformStruct() const { PM_CORE_ASSERT(m_Struct, ""); return *m_Struct; } + inline const ShaderStruct& GetShaderUniformStruct() const { PM_CORE_ASSERT(m_Struct); return *m_Struct; } protected: void SetOffset(uint32_t offset) override; public: diff --git a/Prism/src/Prism/Platform/OpenGL/OpenGLTexture.cpp b/Prism/src/Prism/Platform/OpenGL/OpenGLTexture.cpp index 477b550..8c058bd 100644 --- a/Prism/src/Prism/Platform/OpenGL/OpenGLTexture.cpp +++ b/Prism/src/Prism/Platform/OpenGL/OpenGLTexture.cpp @@ -42,11 +42,12 @@ namespace Prism glTextureParameterf(m_RendererID, GL_TEXTURE_MAX_ANISOTROPY, RendererAPI::GetCapabilities().MaxAnisotropy); glTexImage2D(GL_TEXTURE_2D, 0, PrismToOpenGLTextureFormat(m_Format), (GLint)m_Width, (GLint)m_Height, 0, Prism::PrismToOpenGLTextureFormat(m_Format), GL_UNSIGNED_BYTE, nullptr); - glGenerateMipmap(GL_TEXTURE_2D); + // glGenerateMipmap(GL_TEXTURE_2D); glBindTexture(GL_TEXTURE_2D, 0); }); + m_ImageData.Allocate(width * height * GetBPP(m_Format)); } diff --git a/Prism/src/Prism/Platform/OpenGL/OpenGLTexture.h b/Prism/src/Prism/Platform/OpenGL/OpenGLTexture.h index 9f83686..5268f3f 100644 --- a/Prism/src/Prism/Platform/OpenGL/OpenGLTexture.h +++ b/Prism/src/Prism/Platform/OpenGL/OpenGLTexture.h @@ -38,6 +38,11 @@ namespace Prism virtual const std::string& GetPath() const override { return m_FilePath; } virtual RendererID GetRendererID() const override { return m_RendererID; } + + virtual bool operator==(const Texture& other) const override + { + return m_RendererID == ((OpenGLTexture2D&)other).m_RendererID; + } private: RendererID m_RendererID; TextureFormat m_Format; @@ -73,6 +78,10 @@ namespace Prism virtual RendererID GetRendererID() const override { return m_RendererID; } + virtual bool operator==(const Texture& other) const override + { + return m_RendererID == ((OpenGLTextureCube&)other).m_RendererID; + } private: RendererID m_RendererID; TextureFormat m_Format; diff --git a/Prism/src/Prism/Platform/OpenGL/OpenGLVertexArray.h b/Prism/src/Prism/Platform/OpenGL/OpenGLVertexArray.h index c639e9f..ae8da7e 100644 --- a/Prism/src/Prism/Platform/OpenGL/OpenGLVertexArray.h +++ b/Prism/src/Prism/Platform/OpenGL/OpenGLVertexArray.h @@ -21,8 +21,9 @@ namespace Prism virtual void AddVertexBuffer(const Ref& vertexBuffer) override; virtual void SetIndexBuffer(const Ref& indexBuffer) override; - virtual const std::vector>& GetVertexBuffers() const { return m_VertexBuffers; } - virtual const Ref& GetIndexBuffer() const { return m_IndexBuffer; } + virtual const std::vector>& GetVertexBuffers() const override { return m_VertexBuffers; } + virtual const Ref& GetIndexBuffer() const override { return m_IndexBuffer; } + virtual RendererID GetRendererID() const override { return m_RendererID; } private: RendererID m_RendererID = 0; uint32_t m_VertexBufferIndex = 0; diff --git a/Prism/src/Prism/Renderer/Camera.cpp b/Prism/src/Prism/Renderer/Camera.cpp index 61902b7..2ce80de 100644 --- a/Prism/src/Prism/Renderer/Camera.cpp +++ b/Prism/src/Prism/Renderer/Camera.cpp @@ -10,7 +10,9 @@ #include "glm/gtc/quaternion.hpp" #define GLM_ENABLE_EXPERIMENTAL #include "glm/gtx/quaternion.hpp" +#include "Prism/Core/Application.h" #include "Prism/Core/Input.h" +#include "Prism/Core/Events/MouseEvent.h" #ifndef M_PI #define M_PI 3.1415926f @@ -36,7 +38,7 @@ namespace Prism { } - void Camera::Update(TimeStep deltaTime) + void Camera::OnUpdate(TimeStep deltaTime) { if (Input::IsKeyPressed(GLFW_KEY_LEFT_ALT)) { @@ -63,6 +65,12 @@ namespace Prism m_ViewMatrix = glm::inverse(m_ViewMatrix); } + void Camera::OnEvent(Event& e) + { + EventDispatcher dispatcher(e); + dispatcher.Dispatch(PM_BIND_EVENT_FN(Camera::OnMouseScroll)); + } + glm::vec3 Camera::GetUpDirection() { return glm::rotate(GetOrientation(), glm::vec3(0.0f, 1.0f, 0.0f)); @@ -78,6 +86,13 @@ namespace Prism return glm::rotate(GetOrientation(), glm::vec3(0.0f, 0.0f, -1.0f)); } + bool Camera::OnMouseScroll(MouseScrolledEvent& e) + { + const float delta = e.GetOffsetY() * 0.1f; + MouseZoom(delta); + return false; + } + void Camera::MousePan(const glm::vec2& delta) { auto [xSpeed, ySpeed] = PanSpeed(); diff --git a/Prism/src/Prism/Renderer/Camera.h b/Prism/src/Prism/Renderer/Camera.h index fd76140..4042726 100644 --- a/Prism/src/Prism/Renderer/Camera.h +++ b/Prism/src/Prism/Renderer/Camera.h @@ -6,11 +6,12 @@ #define CAMERA_H #include - #include "Prism/Core/TimeStep.h" namespace Prism { + class MouseScrolledEvent; + class Event; class PRISM_API Camera { @@ -19,7 +20,8 @@ namespace Prism Camera(const glm::mat4& projectionMatrix); void Focus(); - void Update(TimeStep deltaTime); + void OnUpdate(TimeStep deltaTime); + void OnEvent(Event& e); inline float GetDistance() const { return m_Distance; } inline void SetDistance(float distance) { m_Distance = distance; } @@ -28,6 +30,7 @@ namespace Prism const glm::mat4& GetProjectionMatrix() const { return m_ProjectionMatrix; } const glm::mat4& GetViewMatrix() const { return m_ViewMatrix; } + glm::mat4 GetViewProjection() const { return m_ProjectionMatrix * m_ViewMatrix; } glm::vec3 GetUpDirection(); glm::vec3 GetRightDirection(); @@ -40,6 +43,7 @@ namespace Prism public: inline void SetViewportSize(const uint32_t width, const uint32_t height) { m_ViewportWidth = width; m_ViewportHeight = height; } private: + bool OnMouseScroll(MouseScrolledEvent& e); void MousePan(const glm::vec2& delta); void MouseRotate(const glm::vec2& delta); void MouseZoom(float delta); diff --git a/Prism/src/Prism/Renderer/FrameBuffer.h b/Prism/src/Prism/Renderer/FrameBuffer.h index 8bf5eda..46dc016 100644 --- a/Prism/src/Prism/Renderer/FrameBuffer.h +++ b/Prism/src/Prism/Renderer/FrameBuffer.h @@ -23,6 +23,7 @@ namespace Prism uint32_t Height = 720; glm::vec4 ClearColor; FramebufferFormat Format; + uint32_t Samples = 1; // SwapChainTarget = screen buffer (i.e. no framebuffer) bool SwapChainTarget = false; diff --git a/Prism/src/Prism/Renderer/Material.cpp b/Prism/src/Prism/Renderer/Material.cpp index 5b33315..0a4a27d 100644 --- a/Prism/src/Prism/Renderer/Material.cpp +++ b/Prism/src/Prism/Renderer/Material.cpp @@ -45,6 +45,7 @@ namespace Prism void Material::OnShaderReloaded() { + return; AllocateStorage(); for (auto mi : m_MaterialInstances) diff --git a/Prism/src/Prism/Renderer/Material.h b/Prism/src/Prism/Renderer/Material.h index c3c0125..90ed755 100644 --- a/Prism/src/Prism/Renderer/Material.h +++ b/Prism/src/Prism/Renderer/Material.h @@ -98,7 +98,7 @@ namespace Prism const auto decl = m_Material->FindUniformDeclaration(name); if (!decl) PM_CORE_WARN("Could not find uniform with name {0}", name); auto& buffer = GetUniformBufferTarget(decl); - buffer.Write((byte*)& value, decl->GetSize(), decl->GetOffset()); + buffer.Write(&value, decl->GetSize(), decl->GetOffset()); m_OverriddenValues.insert(name); } @@ -152,7 +152,7 @@ namespace Prism // HZ_CORE_ASSERT(decl, "Could not find uniform with name '{0}'", name); PM_CORE_ASSERT(decl, "Could not find uniform with name 'x'"); auto& buffer = GetUniformBufferTarget(decl); - buffer.Write((byte*)&value, decl->GetSize(), decl->GetOffset()); + buffer.Write(&value, decl->GetSize(), decl->GetOffset()); for (auto mi : m_MaterialInstances) mi->OnMaterialValueUpdated(decl); diff --git a/Prism/src/Prism/Renderer/Mesh.cpp b/Prism/src/Prism/Renderer/Mesh.cpp index 30020be..29d95f5 100644 --- a/Prism/src/Prism/Renderer/Mesh.cpp +++ b/Prism/src/Prism/Renderer/Mesh.cpp @@ -155,12 +155,23 @@ namespace Prism } }else { - for (size_t i = 0; i < mesh->mNumVertices; i++) + submesh.Min = { FLT_MAX, FLT_MAX, FLT_MAX }; + submesh.Max = { -FLT_MAX, -FLT_MAX, -FLT_MAX }; + + for (size_t i = 0; i < mesh->mNumVertices; i++) { Vertex vertex; vertex.Position = { mesh->mVertices[i].x, mesh->mVertices[i].y, mesh->mVertices[i].z }; vertex.Normal = { mesh->mNormals[i].x, mesh->mNormals[i].y, mesh->mNormals[i].z }; + submesh.Min.x = glm::min(vertex.Position.x, submesh.Min.x); + submesh.Min.y = glm::min(vertex.Position.y, submesh.Min.y); + submesh.Min.z = glm::min(vertex.Position.z, submesh.Min.z); + submesh.Max.x = glm::max(vertex.Position.x, submesh.Max.x); + submesh.Max.y = glm::max(vertex.Position.y, submesh.Max.y); + submesh.Max.z = glm::max(vertex.Position.z, submesh.Max.z); + + if (mesh->HasTangentsAndBitangents()) { vertex.Tangent = { mesh->mTangents[i].x, mesh->mTangents[i].y, mesh->mTangents[i].z }; @@ -273,8 +284,97 @@ namespace Prism { mi->Set("u_AlbedoTexToggle", 0.0f); mi->Set("u_AlbedoColor", glm::vec3 { aiColor.r, aiColor.g, aiColor.b }); + + PM_CORE_INFO("Mesh has no albedo map"); } + // Normal Maps + mi->Set("u_NormalTexToggle", 0.0f); + + if (aiMaterial->GetTexture(aiTextureType_NORMALS, 0, &aiTexPath) == AI_SUCCESS) + { + // TODO: Temp - this should be handled by Hazel's filesystem + std::filesystem::path path = filename; + auto parentPath = path.parent_path(); + parentPath /= std::string(aiTexPath.data); + std::string texturePath = parentPath.string(); + + auto texture = Texture2D::Create(texturePath); + if (texture->Loaded()) + { + PM_CORE_TRACE(" Normal map path = {0}", texturePath); + mi->Set("u_NormalTexture", texture); + mi->Set("u_NormalTexToggle", 1.0f); + } + else + { + PM_CORE_ERROR("Could not load texture: {0}", texturePath); + } + } + else + { + PM_CORE_TRACE("Mesh has no normal map"); + } + + // Roughness map + // mi->Set("u_Roughness", 1.0f); + // mi->Set("u_RoughnessTexToggle", 0.0f); + if (aiMaterial->GetTexture(aiTextureType_SHININESS, 0, &aiTexPath) == AI_SUCCESS) + { + // TODO: Temp - this should be handled by Hazel's filesystem + std::filesystem::path path = filename; + auto parentPath = path.parent_path(); + parentPath /= std::string(aiTexPath.data); + std::string texturePath = parentPath.string(); + + auto texture = Texture2D::Create(texturePath); + if (texture->Loaded()) + { + PM_CORE_TRACE(" Roughness map path = {0}", texturePath); + mi->Set("u_RoughnessTexture", texture); + mi->Set("u_RoughnessTexToggle", 1.0f); + } + else + { + PM_CORE_ERROR("Could not load texture: {0}", texturePath); + } + } + else + { + PM_CORE_TRACE("Mesh has no roughness texture"); + } + + // Metalness map + // mi->Set("u_Metalness", 0.0f); + // mi->Set("u_MetalnessTexToggle", 0.0f); + if (aiMaterial->Get("$raw.ReflectionFactor|file", aiPTI_String, 0, aiTexPath) == AI_SUCCESS) + { + // TODO: Temp - this should be handled by Hazel's filesystem + std::filesystem::path path = filename; + auto parentPath = path.parent_path(); + parentPath /= std::string(aiTexPath.data); + std::string texturePath = parentPath.string(); + + auto texture = Texture2D::Create(texturePath); + if (texture->Loaded()) + { + PM_CORE_TRACE(" Metalness map path = {0}", texturePath); + mi->Set("u_MetalnessTexture", texture); + mi->Set("u_MetalnessTexToggle", 1.0f); + } + else + { + PM_CORE_ERROR("Could not load texture: {0}", texturePath); + } + } + else + { + PM_CORE_TRACE("Mesh has no metalness texture"); + } + continue; + + + for (uint32_t i = 0; i < aiMaterial->mNumProperties; i++) { auto prop = aiMaterial->mProperties[i]; @@ -357,6 +457,7 @@ namespace Prism } + /* // Normal maps if (aiMaterial->GetTexture(aiTextureType_NORMALS, 0, &aiTexPath) == AI_SUCCESS) { @@ -428,6 +529,8 @@ namespace Prism mi->Set("u_MetalnessTexToggle", 1.0f); } } + */ + } } diff --git a/Prism/src/Prism/Renderer/Mesh.h b/Prism/src/Prism/Renderer/Mesh.h index f33a497..12c1cbc 100644 --- a/Prism/src/Prism/Renderer/Mesh.h +++ b/Prism/src/Prism/Renderer/Mesh.h @@ -87,6 +87,7 @@ namespace Prism uint32_t IndexCount; glm::mat4 Transform; + glm::vec3 Min, Max; //TODO: AABB }; class PRISM_API Mesh diff --git a/Prism/src/Prism/Renderer/Renderer.cpp b/Prism/src/Prism/Renderer/Renderer.cpp index e2f3868..b4aa61b 100644 --- a/Prism/src/Prism/Renderer/Renderer.cpp +++ b/Prism/src/Prism/Renderer/Renderer.cpp @@ -4,6 +4,7 @@ #include "Renderer.h" +#include "Renderer2D.h" #include "RendererAPI.h" #include "SceneRenderer.h" #include "glad/glad.h" @@ -35,10 +36,10 @@ namespace Prism // FullScreen Quad static float fullScreenQuadVertex[] = { - -1.0f, -1.0f, 0.0f, 0.0f, 0.0f, - 1.0f, -1.0f, 0.0f, 1.0f, 0.0f, - 1.0f, 1.0f, 0.0f, 1.0f, 1.0f, - -1.0f, 1.0f, 0.0f, 0.0f, 1.0f + -1.0f, -1.0f, 0.1f, 0.0f, 0.0f, + 1.0f, -1.0f, 0.1f, 1.0f, 0.0f, + 1.0f, 1.0f, 0.1f, 1.0f, 1.0f, + -1.0f, 1.0f, 0.1f, 0.0f, 1.0f }; static uint32_t fullScreenQuadIndices[] = { 0, 1, 2, 2, 3, 0 @@ -55,6 +56,7 @@ namespace Prism s_Data.m_FullscreenQuadVertexArray->AddVertexBuffer(quadVB); s_Data.m_FullscreenQuadVertexArray->SetIndexBuffer(quadIB); + Renderer2D::Init(); } void Renderer::Clear() @@ -76,10 +78,10 @@ namespace Prism { } - void Renderer::DrawIndexed(uint32_t count, bool depthTest) + void Renderer::DrawIndexed(const uint32_t count, const PrimitiveType type, const bool depthTest) { Submit([=]() { - RendererAPI::DrawIndexed(count, depthTest); + RendererAPI::DrawIndexed(count, type, depthTest); }); } @@ -90,12 +92,19 @@ namespace Prism return s_Data.m_ShaderLibrary; } + void Renderer::SetLineThickness(const float thickness) + { + Submit([=]() { + RendererAPI::SetLineThickness(thickness); + }); + } + void Renderer::WaitAndRender() { s_Data.m_CommandQueue.Execute(); } - void Renderer::BeginRenderPass(const Ref& renderPass) + void Renderer::BeginRenderPass(const Ref& renderPass, bool clear) { PM_CORE_ASSERT(renderPass, "Render pass cannot be null!"); @@ -103,10 +112,14 @@ namespace Prism s_Data.m_ActiveRenderPass = renderPass; renderPass->GetSpecification().TargetFramebuffer->Bind(); - const glm::vec4& clearColor = renderPass->GetSpecification().TargetFramebuffer->GetSpecification().ClearColor; - Renderer::Submit([=]() { - RendererAPI::Clear(clearColor.r, clearColor.g, clearColor.b, clearColor.a); - }); + + if (clear) + { + const glm::vec4& clearColor = renderPass->GetSpecification().TargetFramebuffer->GetSpecification().ClearColor; + Submit([=]() { + RendererAPI::Clear(clearColor.r, clearColor.g, clearColor.b, clearColor.a); + }); + } } void Renderer::EndRenderPass() @@ -129,7 +142,7 @@ namespace Prism } s_Data.m_FullscreenQuadVertexArray->Bind(); - Renderer::DrawIndexed(6, depthTest); + Renderer::DrawIndexed(6, PrimitiveType::Triangles, depthTest); } void Renderer::SubmitFullscreenQuad(const Ref& material) @@ -142,7 +155,7 @@ namespace Prism } s_Data.m_FullscreenQuadVertexArray->Bind(); - Renderer::DrawIndexed(6, depthTest); + Renderer::DrawIndexed(6, PrimitiveType::Triangles, depthTest); } void Renderer::SubmitMesh(const Ref& mesh, const glm::mat4& transform, const Ref& overrideMaterial) @@ -182,6 +195,36 @@ namespace Prism } } + void Renderer::DrawAABB(const Ref& mesh, const glm::vec4& color) + { + for (Submesh& submesh : mesh->m_Submeshes) + { + const auto& transform = submesh.Transform; + + const glm::vec4 corners[8] = + { + transform * glm::vec4 { submesh.Min.x, submesh.Min.y, submesh.Max.z, 1.0f }, + transform * glm::vec4 { submesh.Min.x, submesh.Max.y, submesh.Max.z, 1.0f }, + transform * glm::vec4 { submesh.Max.x, submesh.Max.y, submesh.Max.z, 1.0f }, + transform * glm::vec4 { submesh.Max.x, submesh.Min.y, submesh.Max.z, 1.0f }, + + transform * glm::vec4 { submesh.Min.x, submesh.Min.y, submesh.Min.z, 1.0f }, + transform * glm::vec4 { submesh.Min.x, submesh.Max.y, submesh.Min.z, 1.0f }, + transform * glm::vec4 { submesh.Max.x, submesh.Max.y, submesh.Min.z, 1.0f }, + transform * glm::vec4 { submesh.Max.x, submesh.Min.y, submesh.Min.z, 1.0f } + }; + + for (uint32_t i = 0; i < 4; i++) + Renderer2D::DrawLine(corners[i], corners[(i + 1) % 4], color); + + for (uint32_t i = 0; i < 4; i++) + Renderer2D::DrawLine(corners[i + 4], corners[((i + 1) % 4) + 4], color); + + for (uint32_t i = 0; i < 4; i++) + Renderer2D::DrawLine(corners[i], corners[i + 4], color); + } + } + RenderCommandQueue& Renderer::GetRenderCommandQueue() { return s_Data.m_CommandQueue; diff --git a/Prism/src/Prism/Renderer/Renderer.h b/Prism/src/Prism/Renderer/Renderer.h index f4f9f0c..7571ba2 100644 --- a/Prism/src/Prism/Renderer/Renderer.h +++ b/Prism/src/Prism/Renderer/Renderer.h @@ -22,11 +22,13 @@ namespace Prism static void Clear(); static void Clear(float r, float g, float b, float a = 1.0f); static void SetClearColor(float r, float g, float b, float a); - static void DrawIndexed(uint32_t count, bool depthTest = true); - static const Scope& GetShaderLibrary(); + static void DrawIndexed(uint32_t count, PrimitiveType type, bool depthTest = true); + // For OpenGL + static void SetLineThickness(float thickness); + template static void Submit(FuncT&& func) { @@ -47,13 +49,14 @@ namespace Prism public: - static void BeginRenderPass(const Ref& renderPass); + static void BeginRenderPass(const Ref& renderPass, bool clear = true); static void EndRenderPass(); static void SubmitQuad(const Ref& material, const glm::mat4& transform = glm::mat4(1.0f)); static void SubmitFullscreenQuad(const Ref& material); static void SubmitMesh(const Ref& mesh, const glm::mat4& transform, const Ref& overrideMaterial = nullptr); + static void DrawAABB(const Ref& mesh, const glm::vec4& color = glm::vec4(1.0f)); private: static RenderCommandQueue& GetRenderCommandQueue(); }; diff --git a/Prism/src/Prism/Renderer/Renderer2D.cpp b/Prism/src/Prism/Renderer/Renderer2D.cpp new file mode 100644 index 0000000..b40d901 --- /dev/null +++ b/Prism/src/Prism/Renderer/Renderer2D.cpp @@ -0,0 +1,418 @@ +// +// Created by sfd on 25-12-1. +// + +#include "Renderer2D.h" + +#include "Renderer.h" +#include "Shader.h" +#include "VertexArray.h" + +namespace Prism +{ + + struct QuadVertex + { + glm::vec3 Position; + glm::vec4 Color; + glm::vec2 TexCoord; + float TexIndex; + float TilingFactor; + }; + + struct LineVertex + { + glm::vec3 Position; + glm::vec4 Color; + }; + + struct Renderer2DData + { + static constexpr uint32_t MaxQuads = 20000; + static constexpr uint32_t MaxVertices = MaxQuads * 4; + static constexpr uint32_t MaxIndices = MaxQuads * 6; + static constexpr uint32_t MaxTextureSlots = 32; // TODO: RenderCaps + + static constexpr uint32_t MaxLines = 10000; + static constexpr uint32_t MaxLineVertices = MaxLines * 2; + static constexpr uint32_t MaxLineIndices = MaxLines * 6; + + // Quad + Ref QuadVertexArray; + Ref QuadVertexBuffer; + Ref TextureShader; + Ref WhiteTexture; + + uint32_t QuadIndexCount = 0; + QuadVertex* QuadVertexBufferBase = nullptr; + QuadVertex* QuadVertexBufferPtr = nullptr; + + std::array, MaxTextureSlots> TextureSlots; + uint32_t TextureSlotIndex = 1; // 0 = white texture + + glm::vec4 QuadVertexPositions[4]; + + + // Lines + Ref LineVertexArray; + Ref LineVertexBuffer; + Ref LineShader; + + uint32_t LineIndexCount = 0; + LineVertex* LineVertexBufferBase = nullptr; + LineVertex* LineVertexBufferPtr = nullptr; + + glm::mat4 CameraViewProj; + bool DepthTest = true; + + Renderer2D::Statistics Stats; + }; + + static Renderer2DData s_Data; + static glm::vec2 defaultTexCoords[] = {{0.0f, 0.0f}, {1.0f, 0.0f}, {1.0f, 1.0f}, {0.0f, 1.0f}}; + + + void Renderer2D::Init() + { + s_Data.QuadVertexArray = VertexArray::Create(); + + s_Data.QuadVertexBuffer = VertexBuffer::Create(s_Data.MaxVertices * sizeof(QuadVertex)); + s_Data.QuadVertexBuffer->SetLayout({ + { ShaderDataType::Float3, "a_Position" }, + { ShaderDataType::Float4, "a_Color" }, + { ShaderDataType::Float2, "a_TexCoord" }, + { ShaderDataType::Float, "a_TexIndex" }, + { ShaderDataType::Float, "a_TilingFactor" } + }); + s_Data.QuadVertexArray->AddVertexBuffer(s_Data.QuadVertexBuffer); + + s_Data.QuadVertexBufferBase = new QuadVertex[s_Data.MaxVertices]; + + uint32_t* quadIndices = new uint32_t[s_Data.MaxIndices]; + + uint32_t offset = 0; + for (uint32_t i = 0; i < s_Data.MaxIndices; i += 6) + { + quadIndices[i + 0] = offset + 0; + quadIndices[i + 1] = offset + 1; + quadIndices[i + 2] = offset + 2; + + quadIndices[i + 3] = offset + 2; + quadIndices[i + 4] = offset + 3; + quadIndices[i + 5] = offset + 0; + + offset += 4; + } + + Ref quadIB = IndexBuffer::Create(quadIndices, s_Data.MaxIndices); + s_Data.QuadVertexArray->SetIndexBuffer(quadIB); + delete[] quadIndices; + + s_Data.WhiteTexture = Texture2D::Create(TextureFormat::RGBA, 1, 1); + uint32_t whiteTextureData = 0xffffffff; + s_Data.WhiteTexture->Lock(); + s_Data.WhiteTexture->GetWriteableBuffer().Write(&whiteTextureData, sizeof(uint32_t)); + s_Data.WhiteTexture->Unlock(); + + s_Data.TextureShader = Shader::Create("assets/shaders/Renderer2D.glsl"); + + // Set all texture slots to 0 + s_Data.TextureSlots[0] = s_Data.WhiteTexture; + + s_Data.QuadVertexPositions[0] = { -0.5f, -0.5f, 0.0f, 1.0f }; + s_Data.QuadVertexPositions[1] = { 0.5f, -0.5f, 0.0f, 1.0f }; + s_Data.QuadVertexPositions[2] = { 0.5f, 0.5f, 0.0f, 1.0f }; + s_Data.QuadVertexPositions[3] = { -0.5f, 0.5f, 0.0f, 1.0f }; + + // Lines + s_Data.LineShader = Shader::Create("assets/shaders/Renderer2D_Line.glsl"); + s_Data.LineVertexArray = VertexArray::Create(); + + s_Data.LineVertexBuffer = VertexBuffer::Create(s_Data.MaxLineVertices * sizeof(LineVertex)); + s_Data.LineVertexBuffer->SetLayout({ + { ShaderDataType::Float3, "a_Position" }, + { ShaderDataType::Float4, "a_Color" } + }); + s_Data.LineVertexArray->AddVertexBuffer(s_Data.LineVertexBuffer); + + s_Data.LineVertexBufferBase = new LineVertex[s_Data.MaxLineVertices]; + + uint32_t* lineIndices = new uint32_t[s_Data.MaxLineIndices]; + for (uint32_t i = 0; i < s_Data.MaxLineIndices; i++) + lineIndices[i] = i; + + Ref lineIB = IndexBuffer::Create(lineIndices, s_Data.MaxLineIndices); + s_Data.LineVertexArray->SetIndexBuffer(lineIB); + delete[] lineIndices; + } + + void Renderer2D::Shutdown() + { + } + + void Renderer2D::BeginScene(const glm::mat4& viewProj, bool depthTest) + { + s_Data.CameraViewProj = viewProj; + s_Data.DepthTest = depthTest; + + s_Data.TextureShader->Bind(); + s_Data.TextureShader->SetMat4("u_ViewProjection", viewProj); + + s_Data.QuadIndexCount = 0; + s_Data.QuadVertexBufferPtr = s_Data.QuadVertexBufferBase; + + s_Data.LineIndexCount = 0; + s_Data.LineVertexBufferPtr = s_Data.LineVertexBufferBase; + + s_Data.TextureSlotIndex = 1; + } + + void Renderer2D::EndScene() + { + uint32_t dataSize = (uint8_t*)s_Data.QuadVertexBufferPtr - (uint8_t*)s_Data.QuadVertexBufferBase; + if (dataSize) + { + s_Data.QuadVertexBuffer->SetData(s_Data.QuadVertexBufferBase, dataSize); + + s_Data.TextureShader->Bind(); + s_Data.TextureShader->SetMat4("u_ViewProjection", s_Data.CameraViewProj); + + for (uint32_t i = 0; i < s_Data.TextureSlotIndex; i++) + s_Data.TextureSlots[i]->Bind(i); + + s_Data.QuadVertexArray->Bind(); + Renderer::DrawIndexed(s_Data.QuadIndexCount, PrimitiveType::Triangles, s_Data.DepthTest); + s_Data.Stats.DrawCalls++; + } + + dataSize = (uint8_t*)s_Data.LineVertexBufferPtr - (uint8_t*)s_Data.LineVertexBufferBase; + if (dataSize) + { + s_Data.LineVertexBuffer->SetData(s_Data.LineVertexBufferBase, dataSize); + + s_Data.LineShader->Bind(); + s_Data.LineShader->SetMat4("u_ViewProjection", s_Data.CameraViewProj); + + s_Data.LineVertexArray->Bind(); + Renderer::SetLineThickness(2.0f); + Renderer::DrawIndexed(s_Data.LineIndexCount, PrimitiveType::Lines, s_Data.DepthTest); + s_Data.Stats.DrawCalls++; + } + +#if OLD + Flush(); +#endif + } + + void Renderer2D::Flush() + { +#if OLD + // Bind textures + for (uint32_t i = 0; i < s_Data.TextureSlotIndex; i++) + s_Data.TextureSlots[i]->Bind(i); + + s_Data.QuadVertexArray->Bind(); + Renderer::DrawIndexed(s_Data.QuadIndexCount, false); + s_Data.Stats.DrawCalls++; +#endif + } + + void Renderer2D::DrawQuad(const glm::vec2& position, const glm::vec2& size, const glm::vec4& color) + { + DrawQuad({ position.x, position.y, 0.0f }, size, color); + } + + void Renderer2D::DrawQuad(const glm::vec3& position, const glm::vec2& size, const glm::vec4& color) + { + if (s_Data.QuadIndexCount >= Renderer2DData::MaxIndices) + FlushAndReset(); + + const float textureIndex = 0.0f; // White Texture + const float tilingFactor = 1.0f; + + glm::mat4 transform = glm::translate(glm::mat4(1.0f), position) + * glm::scale(glm::mat4(1.0f), { size.x, size.y, 1.0f }); + + for (uint32_t i = 0; i < 4; i++) + { + s_Data.QuadVertexBufferPtr->Position = transform * s_Data.QuadVertexPositions[i]; + s_Data.QuadVertexBufferPtr->Color = color; + s_Data.QuadVertexBufferPtr->TexCoord = defaultTexCoords[i]; + s_Data.QuadVertexBufferPtr->TexIndex = textureIndex; + s_Data.QuadVertexBufferPtr->TilingFactor = tilingFactor; + s_Data.QuadVertexBufferPtr++; + } + + s_Data.QuadIndexCount += 6; + + s_Data.Stats.QuadCount++; + } + + void Renderer2D::DrawQuad(const glm::vec2& position, const glm::vec2& size, const Ref& texture, float tilingFactor, const glm::vec4& tintColor) + { + DrawQuad({ position.x, position.y, 0.0f }, size, texture, tilingFactor, tintColor); + } + + void Renderer2D::DrawQuad(const glm::vec3& position, const glm::vec2& size, const Ref& texture, float tilingFactor, const glm::vec4& tintColor) + { + if (s_Data.QuadIndexCount >= Renderer2DData::MaxIndices) + FlushAndReset(); + + constexpr glm::vec4 color = { 1.0f, 1.0f, 1.0f, 1.0f }; + + float textureIndex = 0.0f; + for (uint32_t i = 1; i < s_Data.TextureSlotIndex; i++) + { + if (*s_Data.TextureSlots[i].get() == *texture.get()) + { + textureIndex = (float)i; + break; + } + } + + if (textureIndex == 0.0f) + { + textureIndex = (float)s_Data.TextureSlotIndex; + s_Data.TextureSlots[s_Data.TextureSlotIndex] = texture; + s_Data.TextureSlotIndex++; + } + + glm::mat4 transform = glm::translate(glm::mat4(1.0f), position) + * glm::scale(glm::mat4(1.0f), { size.x, size.y, 1.0f }); + for (uint32_t i = 0; i < 4; i++) + { + s_Data.QuadVertexBufferPtr->Position = transform * s_Data.QuadVertexPositions[i]; + s_Data.QuadVertexBufferPtr->Color = color; + s_Data.QuadVertexBufferPtr->TexCoord = defaultTexCoords[i]; + s_Data.QuadVertexBufferPtr->TexIndex = textureIndex; + s_Data.QuadVertexBufferPtr->TilingFactor = tilingFactor; + s_Data.QuadVertexBufferPtr++; + } + + s_Data.QuadIndexCount += 6; + + s_Data.Stats.QuadCount++; + } + + void Renderer2D::DrawRotatedQuad(const glm::vec2& position, const glm::vec2& size, float rotation, const glm::vec4& color) + { + DrawRotatedQuad({ position.x, position.y, 0.0f }, size, rotation, color); + } + + void Renderer2D::DrawRotatedQuad(const glm::vec3& position, const glm::vec2& size, float rotation, const glm::vec4& color) + { + if (s_Data.QuadIndexCount >= Renderer2DData::MaxIndices) + FlushAndReset(); + + const float textureIndex = 0.0f; // White Texture + const float tilingFactor = 1.0f; + + glm::mat4 transform = glm::translate(glm::mat4(1.0f), position) + * glm::rotate(glm::mat4(1.0f), glm::radians(rotation), { 0.0f, 0.0f, 1.0f }) + * glm::scale(glm::mat4(1.0f), { size.x, size.y, 1.0f }); + + for (uint32_t i = 1; i < 4; i++) + { + s_Data.QuadVertexBufferPtr->Position = transform * s_Data.QuadVertexPositions[i]; + s_Data.QuadVertexBufferPtr->Color = color; + s_Data.QuadVertexBufferPtr->TexCoord = defaultTexCoords[i]; + s_Data.QuadVertexBufferPtr->TexIndex = textureIndex; + s_Data.QuadVertexBufferPtr->TilingFactor = tilingFactor; + s_Data.QuadVertexBufferPtr++; + } + + s_Data.QuadIndexCount += 6; + + s_Data.Stats.QuadCount++; + } + + void Renderer2D::DrawRotatedQuad(const glm::vec2& position, const glm::vec2& size, float rotation, const Ref& texture, float tilingFactor, const glm::vec4& tintColor) + { + DrawRotatedQuad({ position.x, position.y, 0.0f }, size, rotation, texture, tilingFactor, tintColor); + } + + void Renderer2D::DrawRotatedQuad(const glm::vec3& position, const glm::vec2& size, float rotation, const Ref& texture, float tilingFactor, const glm::vec4& tintColor) + { + if (s_Data.QuadIndexCount >= Renderer2DData::MaxIndices) + FlushAndReset(); + + constexpr glm::vec4 color = { 1.0f, 1.0f, 1.0f, 1.0f }; + + float textureIndex = 0.0f; + for (uint32_t i = 1; i < s_Data.TextureSlotIndex; i++) + { + if (*s_Data.TextureSlots[i].get() == *texture.get()) + { + textureIndex = (float)i; + break; + } + } + + if (textureIndex == 0.0f) + { + textureIndex = (float)s_Data.TextureSlotIndex; + s_Data.TextureSlots[s_Data.TextureSlotIndex] = texture; + s_Data.TextureSlotIndex++; + } + + glm::mat4 transform = glm::translate(glm::mat4(1.0f), position) + * glm::rotate(glm::mat4(1.0f), glm::radians(rotation), { 0.0f, 0.0f, 1.0f }) + * glm::scale(glm::mat4(1.0f), { size.x, size.y, 1.0f }); + + for (uint32_t i = 1; i < 4; i++) + { + s_Data.QuadVertexBufferPtr->Position = transform * s_Data.QuadVertexPositions[i]; + s_Data.QuadVertexBufferPtr->Color = color; + s_Data.QuadVertexBufferPtr->TexCoord = defaultTexCoords[i]; + s_Data.QuadVertexBufferPtr->TexIndex = textureIndex; + s_Data.QuadVertexBufferPtr->TilingFactor = tilingFactor; + s_Data.QuadVertexBufferPtr++; + } + + s_Data.QuadIndexCount += 6; + + s_Data.Stats.QuadCount++; + } + + void Renderer2D::DrawLine(const glm::vec3& p0, const glm::vec3& p1, const glm::vec4& color) + { + if (s_Data.LineIndexCount >= Renderer2DData::MaxLineIndices) + FlushAndResetLines(); + + s_Data.LineVertexBufferPtr->Position = p0; + s_Data.LineVertexBufferPtr->Color = color; + s_Data.LineVertexBufferPtr++; + + s_Data.LineVertexBufferPtr->Position = p1; + s_Data.LineVertexBufferPtr->Color = color; + s_Data.LineVertexBufferPtr++; + + s_Data.LineIndexCount += 2; + + s_Data.Stats.LineCount++; + } + + void Renderer2D::ResetStats() + { + memset(&s_Data.Stats, 0, sizeof(Statistics)); + } + + Renderer2D::Statistics Renderer2D::GetStats() + { + return s_Data.Stats; + } + + void Renderer2D::FlushAndReset() + { + EndScene(); + + s_Data.QuadIndexCount = 0; + s_Data.QuadVertexBufferPtr = s_Data.QuadVertexBufferBase; + + s_Data.TextureSlotIndex = 1; + } + + void Renderer2D::FlushAndResetLines() + { + } +} diff --git a/Prism/src/Prism/Renderer/Renderer2D.h b/Prism/src/Prism/Renderer/Renderer2D.h new file mode 100644 index 0000000..6ca6892 --- /dev/null +++ b/Prism/src/Prism/Renderer/Renderer2D.h @@ -0,0 +1,57 @@ +// +// Created by sfd on 25-12-1. +// + +#ifndef RENDERER2D_H +#define RENDERER2D_H + +#include + +#include "Texture.h" + +namespace Prism +{ + class PRISM_API Renderer2D + { + public: + static void Init(); + static void Shutdown(); + + static void BeginScene(const glm::mat4& viewProj, bool depthTest = true); + static void EndScene(); + static void Flush(); + + // Primitives + static void DrawQuad(const glm::vec2& position, const glm::vec2& size, const glm::vec4& color); + static void DrawQuad(const glm::vec3& position, const glm::vec2& size, const glm::vec4& color); + static void DrawQuad(const glm::vec2& position, const glm::vec2& size, const Ref& texture, float tilingFactor = 1.0f, const glm::vec4& tintColor = glm::vec4(1.0f)); + static void DrawQuad(const glm::vec3& position, const glm::vec2& size, const Ref& texture, float tilingFactor = 1.0f, const glm::vec4& tintColor = glm::vec4(1.0f)); + + static void DrawRotatedQuad(const glm::vec2& position, const glm::vec2& size, float rotation, const glm::vec4& color); + static void DrawRotatedQuad(const glm::vec3& position, const glm::vec2& size, float rotation, const glm::vec4& color); + static void DrawRotatedQuad(const glm::vec2& position, const glm::vec2& size, float rotation, const Ref& texture, float tilingFactor = 1.0f, const glm::vec4& tintColor = glm::vec4(1.0f)); + static void DrawRotatedQuad(const glm::vec3& position, const glm::vec2& size, float rotation, const Ref& texture, float tilingFactor = 1.0f, const glm::vec4& tintColor = glm::vec4(1.0f)); + + static void DrawLine(const glm::vec3& p0, const glm::vec3& p1, const glm::vec4& color = glm::vec4(1.0f)); + // Stats + struct Statistics + { + uint32_t DrawCalls = 0; + uint32_t QuadCount = 0; + uint32_t LineCount = 0; + + uint32_t GetTotalVertexCount() { return QuadCount * 4 + LineCount * 2; } + uint32_t GetTotalIndexCount() { return QuadCount * 6 + LineCount * 2; } + }; + static void ResetStats(); + static Statistics GetStats(); + private: + static void FlushAndReset(); + static void FlushAndResetLines(); + }; + +} + + + +#endif //RENDERER2D_H diff --git a/Prism/src/Prism/Renderer/RendererAPI.h b/Prism/src/Prism/Renderer/RendererAPI.h index a6b4092..f962fb5 100644 --- a/Prism/src/Prism/Renderer/RendererAPI.h +++ b/Prism/src/Prism/Renderer/RendererAPI.h @@ -16,14 +16,21 @@ namespace Prism OpenGL }; + // TODO: move into separate header + enum class PrimitiveType + { + None = 0, Triangles, Lines + }; + struct RenderAPICapabilities { std::string Vendor; std::string Renderer; std::string Version; - int MaxSamples; - float MaxAnisotropy; + int MaxSamples = 0; + float MaxAnisotropy = 0.0f; + int MaxTextureUnits = 0; }; class RendererAPI @@ -35,7 +42,8 @@ namespace Prism static void Clear(float r, float g, float b, float a); static void SetClearColor(float r, float g, float b, float a); - static void DrawIndexed(unsigned int count, bool depthTest = true); + static void DrawIndexed(uint32_t count,PrimitiveType type, bool depthTest = true); + static void SetLineThickness(float thickness); static RendererAPIType Current() { return s_CurrentRendererAPI; } static RenderAPICapabilities& GetCapabilities() diff --git a/Prism/src/Prism/Renderer/SceneRenderer.cpp b/Prism/src/Prism/Renderer/SceneRenderer.cpp index 480362a..add52cf 100644 --- a/Prism/src/Prism/Renderer/SceneRenderer.cpp +++ b/Prism/src/Prism/Renderer/SceneRenderer.cpp @@ -9,6 +9,7 @@ #include "Material.h" #include "Mesh.h" #include "Renderer.h" +#include "Renderer2D.h" #include "RenderPass.h" #include "glad/glad.h" @@ -42,6 +43,8 @@ namespace Prism // Grid Ref GridMaterial; + + SceneRendererOptions Options; }; static SceneRendererData s_Data; @@ -52,6 +55,7 @@ namespace Prism geoFramebufferSpec.Width = 1280; geoFramebufferSpec.Height = 720; geoFramebufferSpec.Format = FramebufferFormat::RGBA16F; + geoFramebufferSpec.Samples = 8; geoFramebufferSpec.ClearColor = { 0.1f, 0.1f, 0.1f, 1.0f }; RenderPassSpecification geoRenderPassSpec; @@ -68,7 +72,8 @@ namespace Prism compRenderPassSpec.TargetFramebuffer = FrameBuffer::Create(compFramebufferSpec); s_Data.CompositePass = RenderPass::Create(compRenderPassSpec); - s_Data.CompositeShader = Shader::Create("assets/shaders/hdr.glsl"); + s_Data.CompositeShader = Shader::Create("assets/shaders/SceneComposite.glsl"); + // s_Data.CompositeShader = Shader::Create("assets/shaders/hdr.glsl"); s_Data.BRDFLUT = Texture2D::Create("assets/textures/BRDF_LUT.tga"); @@ -178,11 +183,17 @@ namespace Prism { glBindImageTexture(0, irradianceMap->GetRendererID(), 0, GL_TRUE, 0, GL_WRITE_ONLY, GL_RGBA16F); glDispatchCompute(irradianceMap->GetWidth() / 32, irradianceMap->GetHeight() / 32, 6); + glGenerateTextureMipmap(irradianceMap->GetRendererID()); }); return { envFiltered, irradianceMap }; } + Ref SceneRenderer::GetFinalRenderPass() + { + return s_Data.CompositePass; + } + Ref SceneRenderer::GetFinalColorBuffer() { PM_CORE_ASSERT(false, "Not implemented"); @@ -194,6 +205,11 @@ namespace Prism return s_Data.CompositePass->GetSpecification().TargetFramebuffer->GetColorAttachmentRendererID(); } + SceneRendererOptions& SceneRenderer::GetOptions() + { + return s_Data.Options; + } + void SceneRenderer::FlushDrawList() { PM_CORE_ASSERT(!s_Data.ActiveScene); @@ -209,7 +225,7 @@ namespace Prism { Renderer::BeginRenderPass(s_Data.GeoPass); - auto viewProjection = s_Data.SceneData.SceneCamera.GetProjectionMatrix() * s_Data.SceneData.SceneCamera.GetViewMatrix(); + const auto viewProjection = s_Data.SceneData.SceneCamera.GetViewProjection(); // Skybox auto skyboxShader = s_Data.SceneData.SkyboxMaterial->GetShader(); @@ -234,8 +250,20 @@ namespace Prism } // Grid - s_Data.GridMaterial->Set("u_ViewProjection", viewProjection); - Renderer::SubmitQuad(s_Data.GridMaterial, glm::rotate(glm::mat4(1.0f), glm::radians(90.0f), glm::vec3(1.0f, 0.0f, 0.0f)) * glm::scale(glm::mat4(1.0f), glm::vec3(16.0f))); + const auto option = GetOptions(); + if (option.ShowGrid) + { + s_Data.GridMaterial->Set("u_ViewProjection", viewProjection); + Renderer::SubmitQuad(s_Data.GridMaterial, glm::rotate(glm::mat4(1.0f), glm::radians(90.0f), glm::vec3(1.0f, 0.0f, 0.0f)) * glm::scale(glm::mat4(1.0f), glm::vec3(16.0f))); + } + + if (option.ShowBoundingBoxes) + { + Renderer2D::BeginScene(viewProjection); + for (auto& dc : s_Data.DrawList) + Renderer::DrawAABB(dc.mesh); + Renderer2D::EndScene(); + } Renderer::EndRenderPass(); } @@ -245,6 +273,7 @@ namespace Prism Renderer::BeginRenderPass(s_Data.CompositePass); s_Data.CompositeShader->Bind(); s_Data.CompositeShader->SetFloat("u_Exposure", s_Data.SceneData.SceneCamera.GetExposure()); + s_Data.CompositeShader->SetInt("u_TextureSamples", s_Data.GeoPass->GetSpecification().TargetFramebuffer->GetSpecification().Samples); s_Data.GeoPass->GetSpecification().TargetFramebuffer->BindTexture(); Renderer::SubmitFullscreenQuad(nullptr); Renderer::EndRenderPass(); diff --git a/Prism/src/Prism/Renderer/SceneRenderer.h b/Prism/src/Prism/Renderer/SceneRenderer.h index 861d546..224c2af 100644 --- a/Prism/src/Prism/Renderer/SceneRenderer.h +++ b/Prism/src/Prism/Renderer/SceneRenderer.h @@ -4,12 +4,19 @@ #ifndef SCENERENDERER_H #define SCENERENDERER_H +#include "RenderPass.h" #include "Texture.h" #include "Prism/Scene/Scene.h" namespace Prism { + struct SceneRendererOptions + { + bool ShowGrid = true; + bool ShowBoundingBoxes = false; + }; + class PRISM_API SceneRenderer { public: @@ -24,11 +31,14 @@ namespace Prism static std::pair, Ref> CreateEnvironmentMap(const std::string& filepath); + static Ref GetFinalRenderPass(); static Ref GetFinalColorBuffer(); // TODO: Temp static uint32_t GetFinalColorBufferRendererID(); + static SceneRendererOptions& GetOptions(); + private: static void FlushDrawList(); static void GeometryPass(); diff --git a/Prism/src/Prism/Renderer/Shader.h b/Prism/src/Prism/Renderer/Shader.h index f0620d8..9faa8f6 100644 --- a/Prism/src/Prism/Renderer/Shader.h +++ b/Prism/src/Prism/Renderer/Shader.h @@ -110,9 +110,12 @@ namespace Prism virtual void UploadUniformBuffer(const UniformBufferBase& uniformBuffer) = 0; virtual void SetFloat(const std::string& name, float value) = 0; + virtual void SetInt(const std::string& name, int value) = 0; virtual void SetMat4(const std::string& name, const glm::mat4& value) = 0; virtual void SetMat4FromRenderThread(const std::string& name, const glm::mat4& value, bool bind = true) = 0; + virtual void SetIntArray(const std::string& name, int* values, uint32_t size) = 0; + virtual const std::string& GetName() const = 0; virtual void SetVSMaterialUniformBuffer(Buffer buffer) = 0; diff --git a/Prism/src/Prism/Renderer/Texture.h b/Prism/src/Prism/Renderer/Texture.h index 4d893e5..e618d9f 100644 --- a/Prism/src/Prism/Renderer/Texture.h +++ b/Prism/src/Prism/Renderer/Texture.h @@ -43,6 +43,8 @@ namespace Prism static uint32_t GetBPP(TextureFormat format); static uint32_t CalculateMipMapCount(uint32_t width, uint32_t height); + + virtual bool operator==(const Texture& other) const = 0; }; class PRISM_API Texture2D : public Texture diff --git a/Prism/src/Prism/Renderer/VertexArray.h b/Prism/src/Prism/Renderer/VertexArray.h index 3ba357d..a092d8c 100644 --- a/Prism/src/Prism/Renderer/VertexArray.h +++ b/Prism/src/Prism/Renderer/VertexArray.h @@ -25,6 +25,7 @@ namespace Prism virtual const std::vector>& GetVertexBuffers() const = 0; virtual const Ref& GetIndexBuffer() const = 0; + virtual RendererID GetRendererID() const = 0; }; } diff --git a/Prism/src/Prism/Scene/Entity.cpp b/Prism/src/Prism/Scene/Entity.cpp index 976c50f..3337188 100644 --- a/Prism/src/Prism/Scene/Entity.cpp +++ b/Prism/src/Prism/Scene/Entity.cpp @@ -6,12 +6,12 @@ namespace Prism { - Entity::Entity() - : m_Transform(glm::mat4(1.0f)) - { - } - Entity::~Entity() { } + + Entity::Entity(const std::string& name) + : m_Name(name), m_Transform(glm::mat4(1.0f)) + { + } } diff --git a/Prism/src/Prism/Scene/Entity.h b/Prism/src/Prism/Scene/Entity.h index a357cb6..43fe888 100644 --- a/Prism/src/Prism/Scene/Entity.h +++ b/Prism/src/Prism/Scene/Entity.h @@ -13,7 +13,6 @@ namespace Prism class PRISM_API Entity { public: - Entity(); ~Entity(); // TODO: Move to Component @@ -25,12 +24,21 @@ namespace Prism const glm::mat4& GetTransform() const { return m_Transform; } glm::mat4& Transform() { return m_Transform; } + + + const std::string& GetName() const { return m_Name; } private: + Entity(const std::string& name); + private: + std::string m_Name; glm::mat4 m_Transform; // TODO: Temp Ref m_Mesh; Ref m_Material; + + private: + friend class Scene; }; } diff --git a/Prism/src/Prism/Scene/Scene.cpp b/Prism/src/Prism/Scene/Scene.cpp index bc020aa..886a423 100644 --- a/Prism/src/Prism/Scene/Scene.cpp +++ b/Prism/src/Prism/Scene/Scene.cpp @@ -35,8 +35,6 @@ namespace Prism void Scene::OnUpdate(TimeStep ts) { - m_Camera.Update(ts); - m_SkyboxMaterial->Set("u_TextureLod", m_SkyboxLod); // Update all entities @@ -59,6 +57,11 @@ namespace Prism SceneRenderer::EndScene(); } + void Scene::OnEvent(Event& e) + { + m_Camera.OnEvent(e); + } + void Scene::SetCamera(const Camera& camera) { m_Camera = camera; @@ -81,9 +84,12 @@ namespace Prism m_Entities.push_back(entity); } - Entity* Scene::CreateEntity() + static const std::string DefaultEntityName = "Entity"; + + Entity* Scene::CreateEntity(const std::string& name) { - const auto entity = new Entity(); + const std::string& entityName = name.empty() ? DefaultEntityName : name; + const auto entity = new Entity(entityName); AddEntity(entity); return entity; } diff --git a/Prism/src/Prism/Scene/Scene.h b/Prism/src/Prism/Scene/Scene.h index bfe747b..50a1827 100644 --- a/Prism/src/Prism/Scene/Scene.h +++ b/Prism/src/Prism/Scene/Scene.h @@ -5,6 +5,7 @@ #ifndef SCENE_H #define SCENE_H #include "Entity.h" +#include "Prism/Core/Events/Event.h" #include "Prism/Renderer/Camera.h" #include "Prism/Renderer/Material.h" @@ -28,6 +29,7 @@ namespace Prism void Init(); void OnUpdate(TimeStep ts); + void OnEvent(Event& e); void SetCamera(const Camera& camera); Camera& GetCamera() { return m_Camera; } @@ -38,7 +40,7 @@ namespace Prism float& GetSkyboxLod() { return m_SkyboxLod; } void AddEntity(Entity* entity); - Entity* CreateEntity(); + Entity* CreateEntity(const std::string& name = ""); private: std::string m_DebugName; diff --git a/Sandbox/Sandbox/Layer/TestLayer.cpp b/Sandbox/Sandbox/Layer/TestLayer.cpp index 260b65f..0c74545 100644 --- a/Sandbox/Sandbox/Layer/TestLayer.cpp +++ b/Sandbox/Sandbox/Layer/TestLayer.cpp @@ -142,68 +142,24 @@ static void EnableDockSpace(const bool enable) TestLayer::TestLayer() - :m_Camera(glm::perspectiveFov(glm::radians(45.0f), 1280.0f, 720.0f, 0.1f, 1000.0f)) { } void TestLayer::OnAttach() { - Prism::FramebufferSpecification geoFramebufferspec; - geoFramebufferspec.Width = 1280; - geoFramebufferspec.Height = 720; - geoFramebufferspec.Format = Prism::FramebufferFormat::RGBA16F; - geoFramebufferspec.ClearColor = {0.1f, 0.1f, 0.1f, 1.0f}; + auto environment = Prism::Environment::Load("assets/env/birchwood_4k.hdr"); + { + m_Scene = Prism::CreateRef("test Scene"); + m_Scene->SetCamera(Prism::Camera(glm::perspectiveFov(glm::radians(45.0f), 1280.0f, 720.0f, 0.1f, 10000.0f))); + m_Scene->SetEnvironment(environment); - Prism::RenderPassSpecification geoRenderPass; - geoRenderPass.TargetFramebuffer = Prism::FrameBuffer::Create(geoFramebufferspec); - m_GeoPass = Prism::RenderPass::Create(geoRenderPass); + m_MeshEntity = m_Scene->CreateEntity("test Entity"); - Prism::FramebufferSpecification finalFramebufferspec; - finalFramebufferspec.Width = 1280; - finalFramebufferspec.Height = 720; - finalFramebufferspec.Format = Prism::FramebufferFormat::RGBA8; - finalFramebufferspec.ClearColor = {0.1f, 0.1f, 0.1f, 1.0f}; + m_MeshEntity->SetMesh(Prism::CreateRef("assets/meshes/TestScene.fbx")); + m_MeshMaterial = m_MeshEntity->GetMesh()->GetMaterial(); - Prism::RenderPassSpecification finalRenderPass; - finalRenderPass.TargetFramebuffer = Prism::FrameBuffer::Create(finalFramebufferspec); - m_FinalPass = Prism::RenderPass::Create(finalRenderPass); + } - - static float QuadVertex[] = { - -1.0f, -1.0f, 0.0f, 0.0f, 0.0f, - 1.0f, -1.0f, 0.0f, 1.0f, 0.0f, - 1.0f, 1.0f, 0.0f, 1.0f, 1.0f, - -1.0f, 1.0f, 0.0f, 0.0f, 1.0f - }; - - static uint32_t QuadIndices[] = { - 0, 1, 2, 2, 3, 0 - }; - - m_VertexArray = Prism::VertexArray::Create(); - auto quadVB = Prism::VertexBuffer::Create(QuadVertex, sizeof(QuadVertex) * sizeof(float)); - quadVB->SetLayout({ - { Prism::ShaderDataType::Float3, "a_Position" }, - { Prism::ShaderDataType::Float2, "a_TexCoord" } - }); - m_VertexArray->AddVertexBuffer(quadVB); - - auto ib = Prism::IndexBuffer::Create(QuadIndices, 6 * sizeof(uint32_t)); - m_VertexArray->SetIndexBuffer(ib); - - m_SkyBoxTextureCube.reset(Prism::TextureCube::Create("assets/textures/environments/Arches_E_PineTree_Radiance.tga")); - m_EnvironmentIrradiance.reset(Prism::TextureCube::Create("assets/textures/environments/Arches_E_PineTree_Irradiance.tga")); - - m_SkyBoxShader = Prism::Shader::Create("assets/shaders/quad.glsl"); - m_HDRShader = Prism::Shader::Create("assets/shaders/hdr.glsl"); - - m_Mesh = std::make_unique("assets/models/m1911/m1911.fbx"); - m_MeshMaterial = Prism::CreateRef(m_Mesh->GetMaterial()); - - m_BRDFLUT.reset(Prism::Texture2D::Create("assets/textures/BRDF_LUT.tga")); - - m_Light.Direction = {-0.5f, -0.5f, 1.0f}; - m_Light.Radiance = {1.0f, 1.0f, 1.0f}; } void TestLayer::OnDetach() @@ -213,78 +169,48 @@ void TestLayer::OnDetach() void TestLayer::OnUpdate(Prism::TimeStep deltaTime) { - m_Camera.Update(deltaTime); - auto viewProjection = m_Camera.GetProjectionMatrix() * m_Camera.GetViewMatrix(); - - Prism::Renderer::BeginRenderPass(m_GeoPass); - Prism::Renderer::Clear(m_clearColor[0], m_clearColor[1], m_clearColor[2], m_clearColor[3]); - - // SkyBox - m_SkyBoxShader->Bind(); - m_SkyBoxShader->SetMat4("u_InverseVP", inverse(viewProjection)); - m_SkyBoxTextureCube->Bind(0); - m_VertexArray->Bind(); - Prism::Renderer::DrawIndexed(m_VertexArray->GetIndexBuffer()->GetCount(), false); - - m_MeshMaterial->Set("u_AlbedoColor", m_AlbedoInput.Color); m_MeshMaterial->Set("u_Metalness", m_MetalnessInput.Value); m_MeshMaterial->Set("u_Roughness", m_RoughnessInput.Value); - m_MeshMaterial->Set("u_ViewProjectionMatrix", viewProjection); - m_MeshMaterial->Set("u_ModelMatrix", glm::scale(glm::mat4(1.0f), glm::vec3(m_MeshScale))); m_MeshMaterial->Set("lights", m_Light); - m_MeshMaterial->Set("u_CameraPosition", m_Camera.GetPosition()); - m_MeshMaterial->Set("u_RadiancePrefilter", m_RadiancePrefilter ? 1.0f : 0.0f); m_MeshMaterial->Set("u_AlbedoTexToggle", m_AlbedoInput.UseTexture ? 1.0f : 0.0f); m_MeshMaterial->Set("u_NormalTexToggle", m_NormalInput.UseTexture ? 1.0f : 0.0f); m_MeshMaterial->Set("u_MetalnessTexToggle", m_MetalnessInput.UseTexture ? 1.0f : 0.0f); m_MeshMaterial->Set("u_RoughnessTexToggle", m_RoughnessInput.UseTexture ? 1.0f : 0.0f); m_MeshMaterial->Set("u_EnvMapRotation", m_EnvMapRotation); - m_MeshMaterial->Set("u_EnvRadianceTex", m_SkyBoxTextureCube); - m_MeshMaterial->Set("u_EnvIrradianceTex", m_EnvironmentIrradiance); - m_MeshMaterial->Set("u_BRDFLUTTexture", m_BRDFLUT); - m_Mesh->Render(deltaTime, glm::mat4(1.0f), m_MeshMaterial); + if (m_AllowViewportCameraEvents) + m_Scene->GetCamera().OnUpdate(deltaTime); - Prism::Renderer::EndRenderPass(); - - - // HDR - Prism::Renderer::BeginRenderPass(m_FinalPass); - m_HDRShader->Bind(); - m_HDRShader->SetFloat("u_Exposure", m_Exposure); - m_GeoPass->GetSpecification().TargetFramebuffer->BindTexture(); - m_VertexArray->Bind(); - Prism::Renderer::DrawIndexed(m_VertexArray->GetIndexBuffer()->GetCount(), false); - Prism::Renderer::EndRenderPass(); + m_Scene->OnUpdate(deltaTime); } void TestLayer::OnImGuiRender() { EnableDockSpace(true); - ImGui::Begin("Settings"); - ImGui::ColorEdit4("ClearColor", glm::value_ptr(m_clearColor)); - ImGui::ColorEdit4("TriangleClearColor", glm::value_ptr(m_TriangleColor)); - ImGui::DragFloat("Exposure", &m_Exposure, 0.01f, 0.0f); - const auto& position = m_Camera.GetPosition(); - ImGui::Text("Camera: (%.2f, %.2f, %.2f)", position.x, position.y, position.z); - - - ImGui::End(); ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0.0f, 0.0f)); ImGui::Begin("Viewport"); auto viewportSize = ImGui::GetContentRegionAvail(); - m_GeoPass->GetSpecification().TargetFramebuffer->Resize((uint32_t)viewportSize.x, (uint32_t)viewportSize.y); - m_FinalPass->GetSpecification().TargetFramebuffer->Resize((uint32_t)viewportSize.x, (uint32_t)viewportSize.y); - m_Camera.SetProjectionMatrix(glm::perspectiveFov(glm::radians(45.0f), viewportSize.x, viewportSize.y, 0.1f, 10000.0f)); - ImGui::Image((ImTextureRef)m_FinalPass->GetSpecification().TargetFramebuffer->GetColorAttachmentRendererID(), viewportSize, {0, 1}, {1, 0}); + Prism::SceneRenderer::SetViewportSize((uint32_t)viewportSize.x, (uint32_t)viewportSize.y); + m_Scene->GetCamera().SetProjectionMatrix(glm::perspectiveFov(glm::radians(45.0f), viewportSize.x, viewportSize.y, 0.1f, 10000.0f)); + m_Scene->GetCamera().SetViewportSize((uint32_t)viewportSize.x, (uint32_t)viewportSize.y); + ImGui::Image((ImTextureRef)Prism::SceneRenderer::GetFinalColorBufferRendererID(), viewportSize, { 0, 1 }, { 1, 0 }); + + + auto windowSize = ImGui::GetWindowSize(); + ImVec2 minBound = ImGui::GetWindowPos(); + ImVec2 maxBound = { minBound.x + windowSize.x, minBound.y + windowSize.y }; + m_AllowViewportCameraEvents = ImGui::IsMouseHoveringRect(minBound, maxBound); + ImGui::End(); ImGui::PopStyleVar(); } void TestLayer::OnEvent(Prism::Event& e) { + if (m_AllowViewportCameraEvents) + m_Scene->GetCamera().OnEvent(e); } diff --git a/Sandbox/Sandbox/Layer/TestLayer.h b/Sandbox/Sandbox/Layer/TestLayer.h index 63c16b8..4c961c0 100644 --- a/Sandbox/Sandbox/Layer/TestLayer.h +++ b/Sandbox/Sandbox/Layer/TestLayer.h @@ -13,6 +13,7 @@ #include "Prism/Renderer/RenderPass.h" #include "Prism/Renderer/Shader.h" #include "Prism/Renderer/Texture.h" +#include "Prism/Scene/Scene.h" class TestLayer : public Prism::Layer @@ -29,16 +30,11 @@ private: glm::vec4 m_clearColor = glm::vec4(0.1f, 0.1f, 0.1f, 1.0f); glm::vec4 m_TriangleColor = glm::vec4(1.0f); - Prism::Ref m_GeoPass, m_FinalPass; + Prism::Ref m_Scene; + Prism::Entity* m_MeshEntity; + Prism::Ref m_MeshMaterial; - Prism::Ref m_VertexArray; - Prism::Ref m_SkyBoxTextureCube, m_EnvironmentIrradiance; - Prism::Ref m_HDRShader, m_SkyBoxShader; - Prism::Ref m_Mesh; - Prism::Ref m_MeshMaterial; - Prism::Ref m_BRDFLUT; - - Prism::Camera m_Camera; + bool m_AllowViewportCameraEvents = false; float m_Exposure = 1.0f;