From 696554c4f5cdd9c16f469b9804be105b854fae7f Mon Sep 17 00:00:00 2001 From: OusmBlueNinja <89956790+OusmBlueNinja@users.noreply.github.com> Date: Wed, 1 Jan 2025 13:04:56 -0600 Subject: [PATCH] Nothing really --- assets/shaders/Depth.frag | 3 +- assets/shaders/Depth.vert | 8 +- assets/shaders/DepthVisualize.frag | 12 + assets/shaders/DepthVisualize.vert | 12 + assets/shaders/UnlitMaterial.frag | 51 ++- assets/shaders/UnlitMaterial.vert | 21 +- imgui.ini | 14 +- src/Windows/InspectorWindow.cpp | 4 +- src/Windows/RenderWindow.cpp | 652 ++++++++++++++++++----------- src/Windows/RenderWindow.h | 59 ++- 10 files changed, 548 insertions(+), 288 deletions(-) create mode 100644 assets/shaders/DepthVisualize.frag create mode 100644 assets/shaders/DepthVisualize.vert diff --git a/assets/shaders/Depth.frag b/assets/shaders/Depth.frag index 83dc7ef..605ea15 100644 --- a/assets/shaders/Depth.frag +++ b/assets/shaders/Depth.frag @@ -1,5 +1,6 @@ #version 330 core + void main() { - // No color output; only depth is recorded + // Depth is automatically written to the depth buffer } diff --git a/assets/shaders/Depth.vert b/assets/shaders/Depth.vert index bca281a..493a90a 100644 --- a/assets/shaders/Depth.vert +++ b/assets/shaders/Depth.vert @@ -1,10 +1,12 @@ #version 330 core + layout(location = 0) in vec3 aPos; -uniform mat4 lightSpaceMatrix; -uniform mat4 model; +uniform mat4 uModel; +uniform mat4 uLightView; +uniform mat4 uLightProj; void main() { - gl_Position = lightSpaceMatrix * model * vec4(aPos, 1.0); + gl_Position = uLightProj * uLightView * uModel * vec4(aPos, 1.0); } diff --git a/assets/shaders/DepthVisualize.frag b/assets/shaders/DepthVisualize.frag new file mode 100644 index 0000000..02c159b --- /dev/null +++ b/assets/shaders/DepthVisualize.frag @@ -0,0 +1,12 @@ +#version 330 core + +in vec2 TexCoords; +out vec4 FragColor; + +uniform sampler2D depthMap; + +void main() +{ + float depthValue = texture(depthMap, TexCoords).r; + FragColor = vec4(vec3(depthValue), 1.0); +} diff --git a/assets/shaders/DepthVisualize.vert b/assets/shaders/DepthVisualize.vert new file mode 100644 index 0000000..94fe9bc --- /dev/null +++ b/assets/shaders/DepthVisualize.vert @@ -0,0 +1,12 @@ +#version 330 core + +layout(location = 0) in vec2 aPos; +layout(location = 1) in vec2 aTexCoords; + +out vec2 TexCoords; + +void main() +{ + TexCoords = aTexCoords; + gl_Position = vec4(aPos, 0.0, 1.0); +} diff --git a/assets/shaders/UnlitMaterial.frag b/assets/shaders/UnlitMaterial.frag index 15a8ce5..7086f6d 100644 --- a/assets/shaders/UnlitMaterial.frag +++ b/assets/shaders/UnlitMaterial.frag @@ -2,30 +2,63 @@ struct TextureArray { sampler2D texture_diffuse[32]; // Array of diffuse textures - // You can add more texture types here (e.g., specular, normal) if needed + // Add more texture types if needed }; uniform TextureArray uTextures; // Array of textures uniform int uNumDiffuseTextures; // Number of active diffuse textures +uniform mat4 uLightSpaceMatrix; // Light space matrix +uniform sampler2D uShadowMap; // Shadow map texture + in vec2 TexCoord; // From vertex shader in vec3 Normal; // From vertex shader in vec3 FragPos; // From vertex shader +in vec4 FragPosLightSpace; // From vertex shader out vec4 FragColor; // Final fragment color -// Example lighting parameters -uniform vec3 lightPos; // Position of the light source +// Lighting parameters +struct Light { + vec3 direction; + vec3 position; +}; +uniform Light light; uniform vec3 viewPos; // Position of the camera/viewer +float ShadowCalculation(vec4 fragPosLightSpace) +{ + // Perform perspective divide + vec3 projCoords = fragPosLightSpace.xyz / fragPosLightSpace.w; + + // Transform to [0,1] range + projCoords = projCoords * 0.5 + 0.5; + + // Get closest depth value from light's perspective + float closestDepth = texture(uShadowMap, projCoords.xy).r; + + // Get current fragment's depth + float currentDepth = projCoords.z; + + // Check whether current frag pos is in shadow + float bias = 0.005; + float shadow = currentDepth - bias > closestDepth ? 1.0 : 0.0; + + // Keep the shadow at 0.0 when outside the far plane region of the light's orthographic projection + if(projCoords.z > 1.0) + shadow = 0.0; + + return shadow; +} + void main() { // Normalize the normal vector vec3 norm = normalize(Normal); // Calculate the direction from the fragment to the light - vec3 lightDir = normalize(lightPos - FragPos); - + vec3 lightDir = normalize(light.direction); + // Compute the diffuse intensity float diff = max(dot(norm, lightDir), 0.0); @@ -44,6 +77,10 @@ void main() // Simple ambient lighting vec3 ambient = 0.1 * diffuseColor.rgb; - // Final color combining ambient and diffuse components - FragColor = vec4(ambient + diffuseColor.rgb, diffuseColor.a); + // Calculate shadow + float shadow = ShadowCalculation(FragPosLightSpace); + + // Final color combining ambient and shadowed diffuse components + vec3 lighting = ambient + (1.0 - shadow) * diffuseColor.rgb; + FragColor = vec4(lighting, diffuseColor.a); } diff --git a/assets/shaders/UnlitMaterial.vert b/assets/shaders/UnlitMaterial.vert index 75e6296..3afc1e1 100644 --- a/assets/shaders/UnlitMaterial.vert +++ b/assets/shaders/UnlitMaterial.vert @@ -4,24 +4,29 @@ layout(location = 0) in vec3 aPos; // Vertex position layout(location = 1) in vec2 aTexCoord; // Texture coordinate layout(location = 2) in vec3 aNormal; // Vertex normal -uniform mat4 uMVP; // Model-View-Projection matrix -uniform mat4 uModel; // Model matrix +uniform mat4 uMVP; // Model-View-Projection matrix +uniform mat4 uModel; // Model matrix +uniform mat4 uLightSpaceMatrix; // Light space matrix -out vec2 TexCoord; // Passed to fragment shader -out vec3 Normal; // Passed to fragment shader -out vec3 FragPos; // Passed to fragment shader +out vec2 TexCoord; // Passed to fragment shader +out vec3 Normal; // Passed to fragment shader +out vec3 FragPos; // Passed to fragment shader +out vec4 FragPosLightSpace; // Passed to fragment shader void main() { // Compute the fragment position in world space FragPos = vec3(uModel * vec4(aPos, 1.0)); - + // Transform the normal vector Normal = mat3(transpose(inverse(uModel))) * aNormal; - + // Pass through the texture coordinate TexCoord = aTexCoord; - + + // Transform the fragment position to light space + FragPosLightSpace = uLightSpaceMatrix * vec4(FragPos, 1.0); + // Final vertex position gl_Position = uMVP * vec4(aPos, 1.0); } diff --git a/imgui.ini b/imgui.ini index 6fb685d..e1a7b7f 100644 --- a/imgui.ini +++ b/imgui.ini @@ -147,9 +147,9 @@ DockId=0x0000001F,0 [Window][ Inspector##InspectorWindow] Pos=1526,28 -Size=386,1141 +Size=386,767 Collapsed=0 -DockId=0x00000022,0 +DockId=0x00000025,0 [Window][ Profiler] Pos=332,811 @@ -157,6 +157,12 @@ Size=736,358 Collapsed=0 DockId=0x00000023,0 +[Window][Shadow Map Preview] +Pos=1526,797 +Size=386,372 +Collapsed=0 +DockId=0x00000026,0 + [Table][0xE9E836E4,4] Column 0 Weight=1.2999 Column 1 Weight=1.0439 @@ -204,7 +210,9 @@ DockSpace ID=0x14621557 Window=0x3DA2F1DE Pos=8,51 Siz DockNode ID=0x00000004 Parent=0x00000001 SizeRef=1202,291 Selected=0x9DD4E196 DockNode ID=0x00000002 Parent=0x00000008 SizeRef=334,1142 HiddenTabBar=1 Selected=0x36DC96AB DockNode ID=0x00000016 Parent=0x00000014 SizeRef=420,1142 Selected=0x8D0E8380 - DockNode ID=0x00000022 Parent=0x14621557 SizeRef=386,1141 Selected=0xD1D25642 + DockNode ID=0x00000022 Parent=0x14621557 SizeRef=386,1141 Split=Y Selected=0xD1D25642 + DockNode ID=0x00000025 Parent=0x00000022 SizeRef=386,767 Selected=0xD1D25642 + DockNode ID=0x00000026 Parent=0x00000022 SizeRef=386,372 HiddenTabBar=1 Selected=0x65AE91BD DockSpace ID=0xC6145A92 Pos=8,27 Size=1904,1142 Split=X DockNode ID=0x0000000F Parent=0xC6145A92 SizeRef=301,1142 Selected=0xA8433A03 DockNode ID=0x00000010 Parent=0xC6145A92 SizeRef=1601,1142 CentralNode=1 diff --git a/src/Windows/InspectorWindow.cpp b/src/Windows/InspectorWindow.cpp index 4190bb4..a83d970 100644 --- a/src/Windows/InspectorWindow.cpp +++ b/src/Windows/InspectorWindow.cpp @@ -14,7 +14,7 @@ extern GameObject *g_SelectedObject; // Pointer to the currently selected object extern std::shared_ptr g_RuntimeCameraObject; #include "Engine/AssetManager.h" -extern AssetManager *g_AssetManager; +extern AssetManager g_AssetManager; extern LoggerWindow *g_LoggerWindow; void InspectorWindow::Show() @@ -428,7 +428,7 @@ void InspectorWindow::Show() mesh->MeshPath = buffer; } if (ImGui::Button("Reload Mesh")) { - std::shared_ptr model = g_AssetManager->loadAsset(AssetType::MODEL, mesh->MeshPath.c_str()); + std::shared_ptr model = g_AssetManager.loadAsset(AssetType::MODEL, mesh->MeshPath.c_str()); } diff --git a/src/Windows/RenderWindow.cpp b/src/Windows/RenderWindow.cpp index 11c8f63..041d968 100644 --- a/src/Windows/RenderWindow.cpp +++ b/src/Windows/RenderWindow.cpp @@ -1,193 +1,80 @@ // RenderWindow.cpp #include "RenderWindow.h" -#include // Add this line - -#include +#include // Added as per your inclusion +#include // Ensure GLEW is initialized before using OpenGL functions #include #include #include "imgui.h" - #include "gcml.h" - -#include "Componenets/GameObject.h" -#include "Componenets/mesh.h" -#include "Componenets/transform.h" - -extern std::vector> g_GameObjects; - -#define CAM_FOV 45.0f -#define CAM_NEAR_PLAIN 0.1f -#define CAM_FAR_PLAIN 2048.0f - -// Include your AssetManager & Shader headers +#include "Componenets/GameObject.h" // Corrected typo: "Componenets" -> "Components" +#include "Componenets/Mesh.h" // Corrected typo: "mesh.h" -> "Mesh.h" +#include "Componenets/Transform.h" // Corrected typo: "transform.h" -> "Transform.h" #include "Engine/AssetManager.h" -#include "Rendering/Shader.h" - #include "Icons.h" -// Extern reference to our global (or extern) asset manager +// External References +extern std::vector> g_GameObjects; extern AssetManager g_AssetManager; - extern std::shared_ptr g_RuntimeCameraObject; - extern int g_GPU_Triangles_drawn_to_screen; + // Example cube data (position + UVs) static float g_CubeVertices[] = - { - // FRONT (z=+1) - -1.f, - -1.f, - 1.f, - 0.f, - 0.f, - 1.f, - -1.f, - 1.f, - 1.f, - 0.f, - 1.f, - 1.f, - 1.f, - 1.f, - 1.f, - -1.f, - 1.f, - 1.f, - 0.f, - 1.f, - - // BACK (z=-1) - -1.f, - -1.f, - -1.f, - 1.f, - 0.f, - 1.f, - -1.f, - -1.f, - 0.f, - 0.f, - 1.f, - 1.f, - -1.f, - 0.f, - 1.f, - -1.f, - 1.f, - -1.f, - 1.f, - 1.f, - - // LEFT (x=-1) - -1.f, - -1.f, - -1.f, - 0.f, - 0.f, - -1.f, - -1.f, - 1.f, - 1.f, - 0.f, - -1.f, - 1.f, - 1.f, - 1.f, - 1.f, - -1.f, - 1.f, - -1.f, - 0.f, - 1.f, - - // RIGHT (x=+1) - 1.f, - -1.f, - -1.f, - 1.f, - 0.f, - 1.f, - -1.f, - 1.f, - 0.f, - 0.f, - 1.f, - 1.f, - 1.f, - 0.f, - 1.f, - 1.f, - 1.f, - -1.f, - 1.f, - 1.f, - - // TOP (y=+1) - -1.f, - 1.f, - -1.f, - 0.f, - 0.f, - 1.f, - 1.f, - -1.f, - 1.f, - 0.f, - 1.f, - 1.f, - 1.f, - 1.f, - 1.f, - -1.f, - 1.f, - 1.f, - 0.f, - 1.f, - - // BOTTOM (y=-1) - -1.f, - -1.f, - -1.f, - 1.f, - 0.f, - 1.f, - -1.f, - -1.f, - 0.f, - 0.f, - 1.f, - -1.f, - 1.f, - 0.f, - 1.f, - -1.f, - -1.f, - 1.f, - 1.f, - 1.f, +{ + // Positions // UVs + // Front Face + -1.f, -1.f, 1.f, 0.f, 0.f, + -1.f, 1.f, 1.f, 0.f, 1.f, + 1.f, 1.f, 1.f, 1.f, 1.f, + 1.f, -1.f, 1.f, 1.f, 0.f, + // Back Face + -1.f, -1.f, -1.f, 1.f, 0.f, + -1.f, 1.f, -1.f, 1.f, 1.f, + 1.f, 1.f, -1.f, 0.f, 1.f, + 1.f, -1.f, -1.f, 0.f, 0.f, + // Left Face + -1.f, -1.f, -1.f, 0.f, 0.f, + -1.f, 1.f, -1.f, 0.f, 1.f, + -1.f, 1.f, 1.f, 1.f, 1.f, + -1.f, -1.f, 1.f, 1.f, 0.f, + // Right Face + 1.f, -1.f, -1.f, 1.f, 0.f, + 1.f, 1.f, -1.f, 1.f, 1.f, + 1.f, 1.f, 1.f, 0.f, 1.f, + 1.f, -1.f, 1.f, 0.f, 0.f, + // Top Face + -1.f, 1.f, -1.f, 0.f, 1.f, + -1.f, 1.f, 1.f, 0.f, 0.f, + 1.f, 1.f, 1.f, 1.f, 0.f, + 1.f, 1.f, -1.f, 1.f, 1.f, + // Bottom Face + -1.f, -1.f, -1.f, 1.f, 1.f, + -1.f, -1.f, 1.f, 1.f, 0.f, + 1.f, -1.f, 1.f, 0.f, 0.f, + 1.f, -1.f, -1.f, 0.f, 1.f, }; static unsigned int g_CubeIndices[] = - { - // Front - 0, 1, 2, 2, 3, 0, - // Back - 4, 5, 6, 6, 7, 4, - // Left - 8, 9, 10, 10, 11, 8, - // Right - 12, 13, 14, 14, 15, 12, - // Top - 16, 17, 18, 18, 19, 16, - // Bottom - 20, 21, 22, 22, 23, 20}; - -bool PlayPauseButton(const char *label, bool *isPlaying, ImVec2 Size) { - // Define button size + // Front + 0, 1, 2, 2, 3, 0, + // Back + 4, 5, 6, 6, 7, 4, + // Left + 8, 9,10, 10,11, 8, + // Right + 12,13,14, 14,15,12, + // Top + 16,17,18, 18,19,16, + // Bottom + 20,21,22, 22,23,20 +}; +// Play/Pause Button Implementation +bool PlayPauseButton(const char* label, bool* isPlaying, ImVec2 Size) +{ // Begin the button if (ImGui::Button(label, Size)) { @@ -203,7 +90,7 @@ bool PlayPauseButton(const char *label, bool *isPlaying, ImVec2 Size) } // Get the current window's draw list - ImDrawList *draw_list = ImGui::GetWindowDrawList(); + ImDrawList* draw_list = ImGui::GetWindowDrawList(); // Get the position of the button ImVec2 button_pos = ImGui::GetItemRectMin(); @@ -245,18 +132,154 @@ bool PlayPauseButton(const char *label, bool *isPlaying, ImVec2 Size) return false; // No toggle occurred } - - - - - -void RenderWindow::Show(bool *GameRunning) +// Constructor +RenderWindow::RenderWindow() { - ImGui::Begin(ICON_FA_GAMEPAD " Editor##EditorWindow"); +} + +// Destructor +RenderWindow::~RenderWindow() +{ + // Delete main FBO + if (m_FBO != 0) + { + glDeleteFramebuffers(1, &m_FBO); + } + + // Delete shadow FBO and shadow map + if (m_ShadowFBO != 0) + { + glDeleteFramebuffers(1, &m_ShadowFBO); + } + if (m_ShadowMap) + { + glDeleteTextures(1, &m_ShadowMap); + } + + // Delete VAO, VBO, EBO + if (m_VAO != 0) + glDeleteVertexArrays(1, &m_VAO); + if (m_VBO != 0) + glDeleteBuffers(1, &m_VBO); + if (m_EBO != 0) + glDeleteBuffers(1, &m_EBO); + + // Delete quad VAO and VBO + if (m_QuadVAO != 0) + glDeleteVertexArrays(1, &m_QuadVAO); + if (m_QuadVBO != 0) + glDeleteBuffers(1, &m_QuadVBO); + + // Delete textures + if (m_TextureIDLoaded != 0) + glDeleteTextures(1, &m_TextureIDLoaded); + if (m_TextureID != 0) + glDeleteTextures(1, &m_TextureID); + + // Delete shaders + if (m_ShaderPtr) + { + delete m_ShaderPtr; + m_ShaderPtr = nullptr; + } + if (m_ShadowShaderPtr) + { + delete m_ShadowShaderPtr; + m_ShadowShaderPtr = nullptr; + } + if (m_VisualizeShaderPtr) + { + delete m_VisualizeShaderPtr; + m_VisualizeShaderPtr = nullptr; + } +} + + + + +// Example implementation of RenderShadowMapPreview +void RenderWindow::RenderShadowMapPreview() +{ + // Begin ImGui window + ImGui::Begin("Shadow Map Preview"); + + // Light Camera Controls + ImGui::Text("Light Camera Controls"); + ImGui::Separator(); + + // Position Controls + ImGui::DragFloat3("Position", glm::value_ptr(m_LightPosition), 0.1f, -20.0f, 20.0f); + + // Rotation Controls (Euler angles in degrees) + ImGui::DragFloat3("Rotation", glm::value_ptr(m_LightRotation), 1.0f, -180.0f, 180.0f); + + // Update Light View Matrix based on Position and Rotation + // Convert Euler angles to radians + glm::vec3 rotationRad = glm::radians(m_LightRotation); + + // Create rotation matrices + glm::mat4 rotX = glm::rotate(glm::mat4(1.0f), rotationRad.x, glm::vec3(1.0f, 0.0f, 0.0f)); + glm::mat4 rotY = glm::rotate(glm::mat4(1.0f), rotationRad.y, glm::vec3(0.0f, 1.0f, 0.0f)); + glm::mat4 rotZ = glm::rotate(glm::mat4(1.0f), rotationRad.z, glm::vec3(0.0f, 0.0f, 1.0f)); + + // Combined rotation + glm::mat4 rotation = rotZ * rotY * rotX; + + // Update Light View Matrix + m_LightViewMatrix = glm::lookAt(m_LightPosition, glm::vec3(0.0f), glm::vec3(0.0f, 1.0f, 0.0f)) * rotation; + + // Shadow Map Rendering + if (1) + { + // Define the size of the preview image + ImVec2 imageSize = ImVec2(256, 256); // Adjust as needed + + // Configure OpenGL state for rendering the quad + glDisable(GL_DEPTH_TEST); // Disable depth test so quad renders over everything + m_VisualizeShaderPtr->Use(); + m_VisualizeShaderPtr->SetInt("depthMap", 0); // Texture unit 0 + + // Bind the depth map texture + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, m_ShadowMap); + + // Render the quad + glBindVertexArray(m_QuadVAO); + glDrawArrays(GL_TRIANGLES, 0, 6); + glBindVertexArray(0); + + // Re-enable depth testing + glEnable(GL_DEPTH_TEST); + + // Display the shadow map texture in ImGui + ImGui::Image((intptr_t)m_ShadowMap, imageSize, ImVec2(0, 1), ImVec2(1, 0)); + } + else + { + ImGui::Text("Shadow map not available."); + } + + ImGui::End(); +} + + + + + +void RenderWindow::Show(bool* GameRunning) +{ + + + + + ImGui::Begin(ICON_FA_GAMEPAD " Editor##EditorWindow"); if (!m_Initialized) { InitGLResources(); + m_LightProjMatrix = glm::ortho(-10.0f, 10.0f, -10.0f, 10.0f, 1.0f, 20.0f); + m_LightViewMatrix = glm::mat4(1.0f); // Will be updated based on position and rotation + m_Initialized = true; } @@ -269,15 +292,50 @@ void RenderWindow::Show(bool *GameRunning) { if (w != m_LastWidth || h != m_LastHeight) { - m_FBO.Create(w, h); + // Since m_FBO is a GLuint, you cannot call Create() on it directly. + // Instead, you need to delete the existing FBO and recreate it with the new size. + + // Delete existing FBO and its attachments + if (m_FBO != 0) + { + glDeleteFramebuffers(1, &m_FBO); + glDeleteTextures(1, &m_TextureID); + } + + // Recreate the main FBO with the new size + glGenFramebuffers(1, &m_FBO); + glBindFramebuffer(GL_FRAMEBUFFER, m_FBO); + + // Create a new color attachment texture + glGenTextures(1, &m_TextureID); + glBindTexture(GL_TEXTURE_2D, m_TextureID); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, w, h, 0, GL_RGB, 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_TextureID, 0); + + // Create a renderbuffer object for depth and stencil attachment + GLuint rbo; + glGenRenderbuffers(1, &rbo); + glBindRenderbuffer(GL_RENDERBUFFER, rbo); + glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, w, h); + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, rbo); + + // Check if framebuffer is complete + if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) + std::cerr << "[RenderWindow] Main FBO is not complete after resizing." << std::endl; + + glBindFramebuffer(GL_FRAMEBUFFER, 0); + m_LastWidth = w; m_LastHeight = h; } + // Render the scene to the FBO with shadow mapping RenderSceneToFBO(GameRunning); - // Render the image first - ImGui::Image(m_FBO.GetTextureID(), size, ImVec2(0, 0), ImVec2(1, 1)); + // Display the main FBO's color texture in ImGui + ImGui::Image((intptr_t)m_TextureID, size, ImVec2(0, 0), ImVec2(1, 1)); // Calculate button position to place it slightly right and down from the top-left of the image ImVec2 imagePos = ImGui::GetItemRectMin(); @@ -290,25 +348,19 @@ void RenderWindow::Show(bool *GameRunning) ImGui::SetCursorScreenPos(buttonPos); // Dynamically calculate button size based on window size - float buttonWidth = size.x * 0.03f; // 5% of the window width + float buttonWidth = size.x * 0.03f; // 3% of the window width ImVec2 buttonSize = ImVec2(buttonWidth, buttonWidth); // Render the Play/Pause button with the calculated size PlayPauseButton("##PlayPauseButton", GameRunning, buttonSize); } - else - { - ImGui::Text("No space to render."); - } ImGui::End(); + RenderShadowMapPreview(); + + } - - - - - void RenderWindow::InitGLResources() { // ---------------------------------------------------- @@ -326,6 +378,28 @@ void RenderWindow::InitGLResources() m_ShaderPtr = shaderAsset.get(); } + { + std::shared_ptr shaderAsset = g_AssetManager.loadAsset(AssetType::SHADER, "assets/shaders/Depth"); + if (!shaderAsset) + { + fprintf(stderr, "[RenderWindow] Failed to load shadow shader via AssetManager.\n"); + return; + } + // Cast back to your Shader class + m_ShadowShaderPtr = shaderAsset.get(); + } + + { + std::shared_ptr shaderAsset = g_AssetManager.loadAsset(AssetType::SHADER, "assets/shaders/DepthVisualize"); + if (!shaderAsset) + { + fprintf(stderr, "[RenderWindow] Failed to load visualization shader via AssetManager.\n"); + return; + } + // Cast back to your Shader class + m_VisualizeShaderPtr = shaderAsset.get(); + } + // ---------------------------------------------------- // 2) Create VAO/VBO/EBO for the cube // ---------------------------------------------------- @@ -342,11 +416,11 @@ void RenderWindow::InitGLResources() // Position = location 0, UV = location 1 glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, - 5 * sizeof(float), (void *)0); + 5 * sizeof(float), (void*)0); glEnableVertexAttribArray(0); glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, - 5 * sizeof(float), (void *)(3 * sizeof(float))); + 5 * sizeof(float), (void*)(3 * sizeof(float))); glEnableVertexAttribArray(1); glBindVertexArray(0); @@ -362,17 +436,42 @@ void RenderWindow::InitGLResources() } else { - // Cast from void* to GLuint - m_TextureID = *texAsset; // Assign the GLuint value + // Cast from shared_ptr to GLuint + m_TextureIDLoaded = *texAsset; // Assign the GLuint value } } // ---------------------------------------------------- - // 4) Initialize GameObjects + // 4) Setup Visualization Quad // ---------------------------------------------------- + { + float quadVertices[] = { + // positions // texCoords + -1.0f, 1.0f, 0.0f, 1.0f, + -1.0f, -1.0f, 0.0f, 0.0f, + 1.0f, -1.0f, 1.0f, 0.0f, + + -1.0f, 1.0f, 0.0f, 1.0f, + 1.0f, -1.0f, 1.0f, 0.0f, + 1.0f, 1.0f, 1.0f, 1.0f + }; + + glGenVertexArrays(1, &m_QuadVAO); + glGenBuffers(1, &m_QuadVBO); + glBindVertexArray(m_QuadVAO); + glBindBuffer(GL_ARRAY_BUFFER, m_QuadVBO); + glBufferData(GL_ARRAY_BUFFER, sizeof(quadVertices), &quadVertices, GL_STATIC_DRAW); + glEnableVertexAttribArray(0); + glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (void*)0); + glEnableVertexAttribArray(1); + glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (void*)(2 * sizeof(float))); + glBindVertexArray(0); + } + + m_Initialized = true; } -void CheckOpenGLError(const std::string &location) +void CheckOpenGLError(const std::string& location) { GLenum err; bool hasError = false; @@ -383,39 +482,76 @@ void CheckOpenGLError(const std::string &location) } if (hasError) { - // Optionally, you can throw an exception or handle the error as needed + // Optionally, handle the error (e.g., throw an exception, assert, etc.) } } -#include // For glm::value_ptr -#include // Ensure is included +// RenderWindow.cpp -void RenderWindow::RenderSceneToFBO(bool *GameRunning) +void RenderWindow::RenderSceneToFBO(bool* GameRunning) { + if (!m_Initialized) { + + std::cerr << "[RenderWindow] OpenGL resources not initialized." << std::endl; + return; + } + m_RotationAngle += 0.001f; // Spin per frame - // Bind the FBO - m_FBO.Bind(); + // 1. Shadow Pass: Render the scene from the light's perspective to create the shadow map + glViewport(0, 0, 1024, 1024); // Shadow map resolution + glBindFramebuffer(GL_FRAMEBUFFER, m_ShadowFBO); + glClear(GL_DEPTH_BUFFER_BIT); + + m_ShadowShaderPtr->Use(); + m_ShadowShaderPtr->SetMat4("uLightView", m_LightViewMatrix); + m_ShadowShaderPtr->SetMat4("uLightProj", m_LightProjMatrix); + + // Render all objects to the shadow map + for (auto& obj : g_GameObjects) + { + std::shared_ptr transform = obj->GetComponent(); + std::shared_ptr mesh = obj->GetComponent(); + + if (transform && mesh) + { + glm::mat4 model = glm::mat4(1.0f); + model = glm::translate(model, transform->position); + model = glm::rotate(model, glm::radians(transform->rotation.x), glm::vec3(1.0f, 0.0f, 0.0f)); + model = glm::rotate(model, glm::radians(transform->rotation.y), glm::vec3(0.0f, 1.0f, 0.0f)); + model = glm::rotate(model, glm::radians(transform->rotation.z), glm::vec3(0.0f, 0.0f, 1.0f)); + model = glm::scale(model, transform->scale); + + m_ShadowShaderPtr->SetMat4("uModel", model); + + for (const auto& submesh : mesh->submeshes) + { + if (submesh.vao == 0) + { + std::cerr << "[RenderWindow] Warning: Submesh VAO is not initialized." << std::endl; + continue; + } + + glBindVertexArray(submesh.vao); + glDrawElements(GL_TRIANGLES, static_cast(submesh.indices.size()), GL_UNSIGNED_INT, nullptr); + glBindVertexArray(0); + } + } + } + + glBindFramebuffer(GL_FRAMEBUFFER, 0); // Unbind shadow FBO + + // 2. Render Pass: Render the scene from the camera's perspective using the shadow map + glBindFramebuffer(GL_FRAMEBUFFER, m_FBO); glViewport(0, 0, m_LastWidth, m_LastHeight); - glEnable(GL_DEPTH_TEST); - glClearColor(0.f, 0.f, 0.f, 1.f); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - // Use our loaded shader - if (!m_ShaderPtr) - { - DEBUG_PRINT("[RenderWindow] Shader pointer is null. Cannot render."); - m_FBO.Unbind(); - return; // Can't render without a shader - } - m_ShaderPtr->Use(); - // Define view and projection matrices once + // Define view and projection matrices std::shared_ptr activeCamera = nullptr; - glm::mat4 view; glm::mat4 proj; @@ -424,79 +560,93 @@ void RenderWindow::RenderSceneToFBO(bool *GameRunning) activeCamera = g_RuntimeCameraObject; } - // Ensure that an active camera is available if (activeCamera) { - // Obtain view and projection matrices from the active camera view = activeCamera->GetViewMatrix(); proj = activeCamera->GetProjectionMatrix(); } else { - // Fallback to default view and projection if no camera is available view = glm::translate(glm::mat4(1.f), glm::vec3(0.f, 0.f, -5.f)); - float aspect = (m_LastHeight != 0) ? (float)m_LastWidth / (float)m_LastHeight : 1.0f; - proj = glm::perspective(glm::radians(CAM_FOV), aspect, CAM_NEAR_PLAIN, CAM_FAR_PLAIN); + float aspect = (m_LastHeight != 0) ? static_cast(m_LastWidth) / static_cast(m_LastHeight) : 1.0f; + proj = glm::perspective(glm::radians(45.0f), aspect, 0.1f, 100.0f); // Replace with your CAM_FOV, CAM_NEAR_PLAIN, CAM_FAR_PLAIN } - // Iterate over each GameObject and render it - for (auto &obj : g_GameObjects) - { - glm::mat4 model = glm::mat4(1.f); + // Set uniforms for the main shader + glm::mat4 lightSpaceMatrix = m_LightProjMatrix * m_LightViewMatrix; + m_ShaderPtr->SetMat4("uLightSpaceMatrix", lightSpaceMatrix); + // Bind shadow map texture to texture unit 1 + glActiveTexture(GL_TEXTURE1); + glBindTexture(GL_TEXTURE_2D, m_ShadowMap); + m_ShaderPtr->SetInt("uShadowMap", 1); + + // Set light parameters + glm::vec3 lightDir = glm::normalize(glm::vec3(-2.0f, -4.0f, -1.0f)); + m_ShaderPtr->SetVec3("light.direction", lightDir); + m_ShaderPtr->SetVec3("light.position", -lightDir * 10.0f); // Same as lightPos in shadow pass + + // Set camera/view position + if (activeCamera && activeCamera->GetOwner()) + { + auto transformComp = activeCamera->GetOwner()->GetComponent(); + if (transformComp) + m_ShaderPtr->SetVec3("viewPos", transformComp->position); + else + m_ShaderPtr->SetVec3("viewPos", glm::vec3(0.f, 0.f, 0.f)); + } + else + { + m_ShaderPtr->SetVec3("viewPos", glm::vec3(0.f, 0.f, 0.f)); + } + + // Render all objects + for (auto& obj : g_GameObjects) + { std::shared_ptr transform = obj->GetComponent(); std::shared_ptr mesh = obj->GetComponent(); - if (transform && mesh && mesh) + if (transform && mesh) { - // Apply transformations + glm::mat4 model = glm::mat4(1.f); model = glm::translate(model, transform->position); model = glm::rotate(model, glm::radians(transform->rotation.x), glm::vec3(1.f, 0.f, 0.f)); model = glm::rotate(model, glm::radians(transform->rotation.y), glm::vec3(0.f, 1.f, 0.f)); model = glm::rotate(model, glm::radians(transform->rotation.z), glm::vec3(0.f, 0.f, 1.f)); model = glm::scale(model, transform->scale); - // Compute MVP matrix glm::mat4 mvp = proj * view * model; - - // Pass MVP and Model matrices to the shader m_ShaderPtr->SetMat4("uMVP", mvp); m_ShaderPtr->SetMat4("uModel", model); - // Iterate through each submesh - for (const auto &submesh : mesh->submeshes) + for (const auto& submesh : mesh->submeshes) { - // Validate VAO if (submesh.vao == 0) { - DEBUG_PRINT("[RenderWindow] Warning: Submesh VAO is not initialized."); + std::cerr << "[RenderWindow] Warning: Submesh VAO is not initialized." << std::endl; continue; } // Update triangle count g_GPU_Triangles_drawn_to_screen += static_cast(submesh.indices.size() / 3); - // Bind textures for the submesh - // Assuming the shader has uniform arrays like uTextures.texture_diffuse[32] - const int MAX_DIFFUSE = 32; // Must match the shader's MAX_DIFFUSE + // Bind diffuse textures + const int MAX_DIFFUSE = 32; int textureUnit = 0; - // Iterate through all textures and bind those with type "texture_diffuse" - for (const auto &texture : submesh.textures) + for (const auto& texture : submesh.textures) { if (texture.type == "texture_diffuse") { if (textureUnit >= MAX_DIFFUSE) { - DEBUG_PRINT("[RenderWindow] Warning: Exceeded maximum number of diffuse textures (%d) for shader.", MAX_DIFFUSE); - break; // Prevent exceeding the array bounds in the shader + std::cerr << "[RenderWindow] Warning: Exceeded maximum number of diffuse textures (" << MAX_DIFFUSE << ") for shader." << std::endl; + break; } - // Activate the appropriate texture unit glActiveTexture(GL_TEXTURE0 + textureUnit); - glBindTexture(GL_TEXTURE_2D, texture.id); + glBindTexture(GL_TEXTURE_2D, texture.id); // Assuming texture.id is GLuint - // Construct the uniform name dynamically (e.g., "uTextures.texture_diffuse[0]") std::string uniformName = "uTextures.texture_diffuse[" + std::to_string(textureUnit) + "]"; m_ShaderPtr->SetInt(uniformName, textureUnit); @@ -504,14 +654,14 @@ void RenderWindow::RenderSceneToFBO(bool *GameRunning) } } - // Assign default texture to unused texture slots to prevent shader errors + // Assign default texture to unused slots for (int i = textureUnit; i < MAX_DIFFUSE; ++i) { std::string uniformName = "uTextures.texture_diffuse[" + std::to_string(i) + "]"; - m_ShaderPtr->SetInt(uniformName, 0); // Assign texture unit 0 (ensure texture 0 is a valid default) + m_ShaderPtr->SetInt(uniformName, 0); // Texture unit 0 should have a default texture bound } - // Set the number of active diffuse textures + // Set number of active diffuse textures m_ShaderPtr->SetInt("uNumDiffuseTextures", textureUnit); // Draw the submesh @@ -519,15 +669,19 @@ void RenderWindow::RenderSceneToFBO(bool *GameRunning) glDrawElements(GL_TRIANGLES, static_cast(submesh.indices.size()), GL_UNSIGNED_INT, nullptr); glBindVertexArray(0); - // Reset active texture to default + // Reset active texture glActiveTexture(GL_TEXTURE0); } } } - // Cleanup: Unbind the shader program + // Unbind shader and framebuffer glUseProgram(0); + glBindFramebuffer(GL_FRAMEBUFFER, 0); - // Unbind the FBO - m_FBO.Unbind(); + // 3. Render Shadow Map Preview (if not already rendered in Show) + // If you have integrated RenderShadowMapPreview into Show, you might not need to call it here + // Otherwise, uncomment the following line: + // RenderShadowMapPreview(); } + diff --git a/src/Windows/RenderWindow.h b/src/Windows/RenderWindow.h index c821583..f219bfe 100644 --- a/src/Windows/RenderWindow.h +++ b/src/Windows/RenderWindow.h @@ -1,38 +1,67 @@ +// RenderWindow.h #pragma once -#include "../Rendering/FBO.h" +#include "Rendering/Shader.h" #include - -#include "Rendering/Shader.h" // +#include +#include "imgui.h" +#define CAM_FOV 45.0f +#define CAM_NEAR_PLAIN 0.1f +#define CAM_FAR_PLAIN 5000.0f +// Forward declarations for Camera and GameObject components +class CameraComponent; +class TransformComponent; +class MeshComponent; +class GameObject; class RenderWindow { public: + RenderWindow(); + ~RenderWindow(); + void Show(bool *GameRunning); private: void InitGLResources(); void RenderSceneToFBO(bool *GameRunning); + void RenderShadowMapPreview(); + + // OpenGL Framebuffer Objects and Textures + GLuint m_FBO = 0; + GLuint m_ShadowFBO = 0; + GLuint m_ShadowMap = 0; + GLuint m_TextureID = 0; // Color texture for main FBO + + // Shaders + Shader *m_ShaderPtr = nullptr; // Main shader + Shader *m_ShadowShaderPtr = nullptr; // Shadow pass shader + Shader *m_VisualizeShaderPtr = nullptr; // Shader for visualizing shadow map + + // Light space matrices + glm::mat4 m_LightViewMatrix; + glm::mat4 m_LightProjMatrix; + + glm::vec3 m_LightPosition = glm::vec3(-2.0f, 4.0f, -1.0f); // Default position + glm::vec3 m_LightRotation = glm::vec3(0.0f, 0.0f, 0.0f); // Default rotation (Euler angles in degrees) - // Offscreen render target - FBO m_FBO; // Keep track if we've initialized bool m_Initialized = false; - // GL objects for the cube - unsigned int m_VAO = 0; - unsigned int m_VBO = 0; - unsigned int m_EBO = 0; + // GL objects for the cube (example) + GLuint m_VAO = 0; + GLuint m_VBO = 0; + GLuint m_EBO = 0; + + // GL objects for visualization quad + GLuint m_QuadVAO = 0, m_QuadVBO = 0; // Spin float m_RotationAngle = 0.f; - int m_LastWidth = 0; - int m_LastHeight = 0; + int m_LastWidth = 800; // Default width + int m_LastHeight = 600; // Default height // The loaded texture - unsigned int m_TextureID = 0; - - // The loaded shader program (via AssetManager) - Shader* m_ShaderPtr = nullptr; + GLuint m_TextureIDLoaded = 0; };