2024-12-25 23:35:38 +00:00
|
|
|
// RenderWindow.cpp
|
|
|
|
|
2024-12-25 21:44:33 +00:00
|
|
|
#include "RenderWindow.h"
|
2025-01-01 19:04:56 +00:00
|
|
|
#include <vector> // Added as per your inclusion
|
|
|
|
#include <GL/glew.h> // Ensure GLEW is initialized before using OpenGL functions
|
2024-12-25 23:01:05 +00:00
|
|
|
#include <glm/gtc/matrix_transform.hpp>
|
|
|
|
#include <glm/gtc/type_ptr.hpp>
|
2024-12-25 21:44:33 +00:00
|
|
|
#include "imgui.h"
|
2024-12-27 01:34:34 +00:00
|
|
|
#include "gcml.h"
|
2025-01-01 19:04:56 +00:00
|
|
|
#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"
|
2024-12-25 23:35:38 +00:00
|
|
|
#include "Engine/AssetManager.h"
|
2025-01-01 04:31:58 +00:00
|
|
|
#include "Icons.h"
|
|
|
|
|
2025-01-01 19:04:56 +00:00
|
|
|
// External References
|
|
|
|
extern std::vector<std::shared_ptr<GameObject>> g_GameObjects;
|
2024-12-25 23:01:05 +00:00
|
|
|
extern AssetManager g_AssetManager;
|
2024-12-30 04:25:16 +00:00
|
|
|
extern std::shared_ptr<CameraComponent> g_RuntimeCameraObject;
|
2024-12-29 02:50:39 +00:00
|
|
|
extern int g_GPU_Triangles_drawn_to_screen;
|
2024-12-27 01:34:34 +00:00
|
|
|
|
2025-01-01 19:04:56 +00:00
|
|
|
|
2024-12-25 23:35:38 +00:00
|
|
|
// Example cube data (position + UVs)
|
2024-12-25 23:01:05 +00:00
|
|
|
static float g_CubeVertices[] =
|
2025-01-01 19:04:56 +00:00
|
|
|
{
|
|
|
|
// 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,
|
2024-12-25 23:01:05 +00:00
|
|
|
};
|
2024-12-25 21:44:33 +00:00
|
|
|
|
2024-12-25 23:01:05 +00:00
|
|
|
static unsigned int g_CubeIndices[] =
|
2024-12-25 21:44:33 +00:00
|
|
|
{
|
2025-01-01 19:04:56 +00:00
|
|
|
// 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
|
|
|
|
};
|
2024-12-29 02:50:39 +00:00
|
|
|
|
2025-01-01 19:04:56 +00:00
|
|
|
// Play/Pause Button Implementation
|
|
|
|
bool PlayPauseButton(const char* label, bool* isPlaying, ImVec2 Size)
|
|
|
|
{
|
2024-12-29 02:50:39 +00:00
|
|
|
// Begin the button
|
2024-12-31 22:35:06 +00:00
|
|
|
if (ImGui::Button(label, Size))
|
2024-12-29 02:50:39 +00:00
|
|
|
{
|
|
|
|
// Toggle the state
|
|
|
|
*isPlaying = !(*isPlaying);
|
|
|
|
return true; // Indicate that the state was toggled
|
|
|
|
}
|
|
|
|
|
|
|
|
// Add tooltip
|
|
|
|
if (ImGui::IsItemHovered())
|
|
|
|
{
|
|
|
|
ImGui::SetTooltip(*isPlaying ? "Pause (Space)" : "Play (Space)");
|
|
|
|
}
|
|
|
|
|
|
|
|
// Get the current window's draw list
|
2025-01-01 19:04:56 +00:00
|
|
|
ImDrawList* draw_list = ImGui::GetWindowDrawList();
|
2024-12-29 02:50:39 +00:00
|
|
|
|
|
|
|
// Get the position of the button
|
|
|
|
ImVec2 button_pos = ImGui::GetItemRectMin();
|
|
|
|
ImVec2 button_size = ImGui::GetItemRectSize();
|
|
|
|
ImVec2 center = ImVec2(button_pos.x + button_size.x * 0.5f, button_pos.y + button_size.y * 0.5f);
|
|
|
|
|
|
|
|
// Define icon size
|
2024-12-31 22:35:06 +00:00
|
|
|
float icon_size = 0.4f * Size.x;
|
2024-12-29 02:50:39 +00:00
|
|
|
float half_icon_size = icon_size / 2.0f;
|
|
|
|
|
|
|
|
// Define colors
|
|
|
|
ImU32 icon_color = ImGui::GetColorU32(ImGuiCol_Text);
|
|
|
|
|
|
|
|
if (*isPlaying)
|
|
|
|
{
|
|
|
|
// Draw Pause Icon (two vertical bars)
|
|
|
|
float bar_width = 4.0f;
|
2024-12-31 22:35:06 +00:00
|
|
|
float spacing = 0.1f * Size.x;
|
2024-12-29 02:50:39 +00:00
|
|
|
|
|
|
|
// Left bar
|
|
|
|
ImVec2 left_bar_p1 = ImVec2(center.x - spacing - bar_width, center.y - half_icon_size);
|
|
|
|
ImVec2 left_bar_p2 = ImVec2(center.x - spacing, center.y + half_icon_size);
|
|
|
|
draw_list->AddRectFilled(left_bar_p1, left_bar_p2, icon_color, 2.0f);
|
|
|
|
|
|
|
|
// Right bar
|
|
|
|
ImVec2 right_bar_p1 = ImVec2(center.x + spacing, center.y - half_icon_size);
|
|
|
|
ImVec2 right_bar_p2 = ImVec2(center.x + spacing + bar_width, center.y + half_icon_size);
|
|
|
|
draw_list->AddRectFilled(right_bar_p1, right_bar_p2, icon_color, 2.0f);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// Draw Play Icon (triangle)
|
|
|
|
ImVec2 p1 = ImVec2(center.x - half_icon_size, center.y - half_icon_size);
|
|
|
|
ImVec2 p2 = ImVec2(center.x - half_icon_size, center.y + half_icon_size);
|
|
|
|
ImVec2 p3 = ImVec2(center.x + half_icon_size, center.y);
|
|
|
|
draw_list->AddTriangleFilled(p1, p2, p3, icon_color);
|
|
|
|
}
|
|
|
|
|
|
|
|
return false; // No toggle occurred
|
|
|
|
}
|
|
|
|
|
2025-01-01 19:04:56 +00:00
|
|
|
// Constructor
|
|
|
|
RenderWindow::RenderWindow()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
// 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);
|
2024-12-29 02:50:39 +00:00
|
|
|
|
2025-01-01 19:04:56 +00:00
|
|
|
// 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();
|
|
|
|
}
|
2024-12-29 02:50:39 +00:00
|
|
|
|
2024-12-31 22:35:06 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
2025-01-01 19:04:56 +00:00
|
|
|
|
|
|
|
void RenderWindow::Show(bool* GameRunning)
|
2024-12-29 02:50:39 +00:00
|
|
|
{
|
2025-01-01 19:04:56 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
ImGui::Begin(ICON_FA_GAMEPAD " Editor##EditorWindow");
|
2024-12-25 21:44:33 +00:00
|
|
|
|
|
|
|
if (!m_Initialized)
|
|
|
|
{
|
|
|
|
InitGLResources();
|
2025-01-01 19:04:56 +00:00
|
|
|
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
|
|
|
|
|
2024-12-25 21:44:33 +00:00
|
|
|
m_Initialized = true;
|
|
|
|
}
|
|
|
|
|
2024-12-31 22:35:06 +00:00
|
|
|
ImVec2 size = ImGui::GetContentRegionAvail();
|
|
|
|
int w = static_cast<int>(size.x);
|
|
|
|
int h = static_cast<int>(size.y);
|
2024-12-27 01:34:34 +00:00
|
|
|
|
2024-12-25 23:35:38 +00:00
|
|
|
// If there's space, render to the FBO, then show it as an ImGui image
|
2024-12-25 21:44:33 +00:00
|
|
|
if (w > 0 && h > 0)
|
|
|
|
{
|
|
|
|
if (w != m_LastWidth || h != m_LastHeight)
|
|
|
|
{
|
2025-01-01 19:04:56 +00:00
|
|
|
// 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);
|
|
|
|
|
2024-12-27 01:34:34 +00:00
|
|
|
m_LastWidth = w;
|
2024-12-25 21:44:33 +00:00
|
|
|
m_LastHeight = h;
|
|
|
|
}
|
|
|
|
|
2025-01-01 19:04:56 +00:00
|
|
|
// Render the scene to the FBO with shadow mapping
|
2024-12-30 04:25:16 +00:00
|
|
|
RenderSceneToFBO(GameRunning);
|
2024-12-27 01:34:34 +00:00
|
|
|
|
2025-01-01 19:04:56 +00:00
|
|
|
// Display the main FBO's color texture in ImGui
|
|
|
|
ImGui::Image((intptr_t)m_TextureID, size, ImVec2(0, 0), ImVec2(1, 1));
|
2024-12-31 22:35:06 +00:00
|
|
|
|
|
|
|
// Calculate button position to place it slightly right and down from the top-left of the image
|
|
|
|
ImVec2 imagePos = ImGui::GetItemRectMin();
|
|
|
|
|
|
|
|
// Add an offset to position the button
|
|
|
|
ImVec2 buttonOffset(10.0f, 10.0f); // Adjust these values as needed for the desired offset
|
|
|
|
ImVec2 buttonPos = ImVec2(imagePos.x + buttonOffset.x, imagePos.y + buttonOffset.y);
|
|
|
|
|
|
|
|
// Set cursor position for the button
|
|
|
|
ImGui::SetCursorScreenPos(buttonPos);
|
|
|
|
|
|
|
|
// Dynamically calculate button size based on window size
|
2025-01-01 19:04:56 +00:00
|
|
|
float buttonWidth = size.x * 0.03f; // 3% of the window width
|
2024-12-31 22:35:06 +00:00
|
|
|
ImVec2 buttonSize = ImVec2(buttonWidth, buttonWidth);
|
|
|
|
|
|
|
|
// Render the Play/Pause button with the calculated size
|
|
|
|
PlayPauseButton("##PlayPauseButton", GameRunning, buttonSize);
|
2024-12-25 21:44:33 +00:00
|
|
|
}
|
|
|
|
|
2024-12-29 02:50:39 +00:00
|
|
|
ImGui::End();
|
2025-01-01 19:04:56 +00:00
|
|
|
RenderShadowMapPreview();
|
2024-12-31 22:35:06 +00:00
|
|
|
|
|
|
|
|
2025-01-01 19:04:56 +00:00
|
|
|
}
|
2024-12-31 22:35:06 +00:00
|
|
|
|
2024-12-25 21:44:33 +00:00
|
|
|
void RenderWindow::InitGLResources()
|
|
|
|
{
|
2024-12-25 23:35:38 +00:00
|
|
|
// ----------------------------------------------------
|
|
|
|
// 1) Load SHADER from the asset manager
|
|
|
|
// ----------------------------------------------------
|
2024-12-27 01:34:34 +00:00
|
|
|
|
2024-12-25 21:44:33 +00:00
|
|
|
{
|
2024-12-31 08:40:23 +00:00
|
|
|
std::shared_ptr<Shader> shaderAsset = g_AssetManager.loadAsset<Shader>(AssetType::SHADER, "assets/shaders/UnlitMaterial");
|
2024-12-25 23:35:38 +00:00
|
|
|
if (!shaderAsset)
|
|
|
|
{
|
|
|
|
fprintf(stderr, "[RenderWindow] Failed to load shader via AssetManager.\n");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
// Cast back to your Shader class
|
2024-12-31 08:40:23 +00:00
|
|
|
m_ShaderPtr = shaderAsset.get();
|
2024-12-25 21:44:33 +00:00
|
|
|
}
|
|
|
|
|
2025-01-01 19:04:56 +00:00
|
|
|
{
|
|
|
|
std::shared_ptr<Shader> shaderAsset = g_AssetManager.loadAsset<Shader>(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<Shader> shaderAsset = g_AssetManager.loadAsset<Shader>(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();
|
|
|
|
}
|
|
|
|
|
2024-12-25 23:35:38 +00:00
|
|
|
// ----------------------------------------------------
|
|
|
|
// 2) Create VAO/VBO/EBO for the cube
|
|
|
|
// ----------------------------------------------------
|
2024-12-25 21:44:33 +00:00
|
|
|
glGenVertexArrays(1, &m_VAO);
|
|
|
|
glBindVertexArray(m_VAO);
|
|
|
|
|
|
|
|
glGenBuffers(1, &m_VBO);
|
|
|
|
glBindBuffer(GL_ARRAY_BUFFER, m_VBO);
|
|
|
|
glBufferData(GL_ARRAY_BUFFER, sizeof(g_CubeVertices), g_CubeVertices, GL_STATIC_DRAW);
|
|
|
|
|
|
|
|
glGenBuffers(1, &m_EBO);
|
|
|
|
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_EBO);
|
|
|
|
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(g_CubeIndices), g_CubeIndices, GL_STATIC_DRAW);
|
|
|
|
|
2024-12-25 23:35:38 +00:00
|
|
|
// Position = location 0, UV = location 1
|
|
|
|
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE,
|
2025-01-01 19:04:56 +00:00
|
|
|
5 * sizeof(float), (void*)0);
|
2024-12-25 21:44:33 +00:00
|
|
|
glEnableVertexAttribArray(0);
|
|
|
|
|
2024-12-25 23:01:05 +00:00
|
|
|
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE,
|
2025-01-01 19:04:56 +00:00
|
|
|
5 * sizeof(float), (void*)(3 * sizeof(float)));
|
2024-12-25 21:44:33 +00:00
|
|
|
glEnableVertexAttribArray(1);
|
|
|
|
|
|
|
|
glBindVertexArray(0);
|
2024-12-25 23:01:05 +00:00
|
|
|
|
2024-12-25 23:35:38 +00:00
|
|
|
// ----------------------------------------------------
|
|
|
|
// 3) Load TEXTURE from the asset manager
|
|
|
|
// ----------------------------------------------------
|
2024-12-25 23:01:05 +00:00
|
|
|
{
|
2024-12-31 08:40:23 +00:00
|
|
|
std::shared_ptr<GLuint> texAsset = g_AssetManager.loadAsset<GLuint>(AssetType::TEXTURE, "assets/textures/wood.png");
|
2024-12-25 23:35:38 +00:00
|
|
|
if (!texAsset)
|
2024-12-25 23:01:05 +00:00
|
|
|
{
|
2024-12-25 23:35:38 +00:00
|
|
|
fprintf(stderr, "[RenderWindow] Failed to load texture.\n");
|
2024-12-25 23:01:05 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2025-01-01 19:04:56 +00:00
|
|
|
// Cast from shared_ptr<GLuint> to GLuint
|
|
|
|
m_TextureIDLoaded = *texAsset; // Assign the GLuint value
|
2024-12-25 23:01:05 +00:00
|
|
|
}
|
|
|
|
}
|
2024-12-26 00:15:18 +00:00
|
|
|
|
|
|
|
// ----------------------------------------------------
|
2025-01-01 19:04:56 +00:00
|
|
|
// 4) Setup Visualization Quad
|
2024-12-26 00:15:18 +00:00
|
|
|
// ----------------------------------------------------
|
2025-01-01 19:04:56 +00:00
|
|
|
{
|
|
|
|
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;
|
2024-12-27 01:34:34 +00:00
|
|
|
}
|
2024-12-26 00:15:18 +00:00
|
|
|
|
2025-01-01 19:04:56 +00:00
|
|
|
void CheckOpenGLError(const std::string& location)
|
2024-12-25 21:44:33 +00:00
|
|
|
{
|
2024-12-30 04:25:16 +00:00
|
|
|
GLenum err;
|
|
|
|
bool hasError = false;
|
|
|
|
while ((err = glGetError()) != GL_NO_ERROR)
|
|
|
|
{
|
|
|
|
std::cerr << "[OpenGL Error] (" << err << ") at " << location << std::endl;
|
|
|
|
hasError = true;
|
|
|
|
}
|
|
|
|
if (hasError)
|
|
|
|
{
|
2025-01-01 19:04:56 +00:00
|
|
|
// Optionally, handle the error (e.g., throw an exception, assert, etc.)
|
2024-12-30 04:25:16 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2025-01-01 19:04:56 +00:00
|
|
|
// RenderWindow.cpp
|
2024-12-31 08:40:23 +00:00
|
|
|
|
2025-01-01 19:04:56 +00:00
|
|
|
void RenderWindow::RenderSceneToFBO(bool* GameRunning)
|
2024-12-30 04:25:16 +00:00
|
|
|
{
|
2025-01-01 19:04:56 +00:00
|
|
|
if (!m_Initialized) {
|
|
|
|
|
|
|
|
std::cerr << "[RenderWindow] OpenGL resources not initialized." << std::endl;
|
|
|
|
return;
|
|
|
|
}
|
2024-12-25 21:44:33 +00:00
|
|
|
|
2025-01-01 19:04:56 +00:00
|
|
|
m_RotationAngle += 0.001f; // Spin per frame
|
2024-12-25 21:44:33 +00:00
|
|
|
|
2025-01-01 19:04:56 +00:00
|
|
|
// 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);
|
2024-12-25 23:01:05 +00:00
|
|
|
|
2025-01-01 19:04:56 +00:00
|
|
|
m_ShadowShaderPtr->Use();
|
|
|
|
m_ShadowShaderPtr->SetMat4("uLightView", m_LightViewMatrix);
|
|
|
|
m_ShadowShaderPtr->SetMat4("uLightProj", m_LightProjMatrix);
|
2024-12-25 21:44:33 +00:00
|
|
|
|
2025-01-01 19:04:56 +00:00
|
|
|
// Render all objects to the shadow map
|
|
|
|
for (auto& obj : g_GameObjects)
|
2024-12-30 04:25:16 +00:00
|
|
|
{
|
2025-01-01 19:04:56 +00:00
|
|
|
std::shared_ptr<TransformComponent> transform = obj->GetComponent<TransformComponent>();
|
|
|
|
std::shared_ptr<MeshComponent> mesh = obj->GetComponent<MeshComponent>();
|
|
|
|
|
|
|
|
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<GLsizei>(submesh.indices.size()), GL_UNSIGNED_INT, nullptr);
|
|
|
|
glBindVertexArray(0);
|
|
|
|
}
|
|
|
|
}
|
2024-12-30 04:25:16 +00:00
|
|
|
}
|
2024-12-25 21:44:33 +00:00
|
|
|
|
2025-01-01 19:04:56 +00:00
|
|
|
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);
|
|
|
|
|
2024-12-26 00:15:18 +00:00
|
|
|
m_ShaderPtr->Use();
|
2024-12-25 21:44:33 +00:00
|
|
|
|
2025-01-01 19:04:56 +00:00
|
|
|
// Define view and projection matrices
|
2024-12-30 04:25:16 +00:00
|
|
|
std::shared_ptr<CameraComponent> activeCamera = nullptr;
|
|
|
|
glm::mat4 view;
|
|
|
|
glm::mat4 proj;
|
2024-12-27 01:34:34 +00:00
|
|
|
|
2024-12-30 04:25:16 +00:00
|
|
|
if (*GameRunning && g_RuntimeCameraObject)
|
|
|
|
{
|
|
|
|
activeCamera = g_RuntimeCameraObject;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (activeCamera)
|
2024-12-29 02:50:39 +00:00
|
|
|
{
|
2024-12-30 04:25:16 +00:00
|
|
|
view = activeCamera->GetViewMatrix();
|
|
|
|
proj = activeCamera->GetProjectionMatrix();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
view = glm::translate(glm::mat4(1.f), glm::vec3(0.f, 0.f, -5.f));
|
2025-01-01 19:04:56 +00:00
|
|
|
float aspect = (m_LastHeight != 0) ? static_cast<float>(m_LastWidth) / static_cast<float>(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
|
2024-12-30 04:25:16 +00:00
|
|
|
}
|
2024-12-27 01:34:34 +00:00
|
|
|
|
2025-01-01 19:04:56 +00:00
|
|
|
// 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())
|
2024-12-30 04:25:16 +00:00
|
|
|
{
|
2025-01-01 19:04:56 +00:00
|
|
|
auto transformComp = activeCamera->GetOwner()->GetComponent<TransformComponent>();
|
|
|
|
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));
|
|
|
|
}
|
2024-12-26 00:15:18 +00:00
|
|
|
|
2025-01-01 19:04:56 +00:00
|
|
|
// Render all objects
|
|
|
|
for (auto& obj : g_GameObjects)
|
|
|
|
{
|
2024-12-27 01:34:34 +00:00
|
|
|
std::shared_ptr<TransformComponent> transform = obj->GetComponent<TransformComponent>();
|
|
|
|
std::shared_ptr<MeshComponent> mesh = obj->GetComponent<MeshComponent>();
|
2024-12-26 00:15:18 +00:00
|
|
|
|
2025-01-01 19:04:56 +00:00
|
|
|
if (transform && mesh)
|
2024-12-27 01:34:34 +00:00
|
|
|
{
|
2025-01-01 19:04:56 +00:00
|
|
|
glm::mat4 model = glm::mat4(1.f);
|
2024-12-27 01:34:34 +00:00
|
|
|
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);
|
|
|
|
|
|
|
|
glm::mat4 mvp = proj * view * model;
|
2024-12-31 08:40:23 +00:00
|
|
|
m_ShaderPtr->SetMat4("uMVP", mvp);
|
|
|
|
m_ShaderPtr->SetMat4("uModel", model);
|
2024-12-30 04:25:16 +00:00
|
|
|
|
2025-01-01 19:04:56 +00:00
|
|
|
for (const auto& submesh : mesh->submeshes)
|
2024-12-30 04:25:16 +00:00
|
|
|
{
|
2024-12-31 08:40:23 +00:00
|
|
|
if (submesh.vao == 0)
|
|
|
|
{
|
2025-01-01 19:04:56 +00:00
|
|
|
std::cerr << "[RenderWindow] Warning: Submesh VAO is not initialized." << std::endl;
|
2024-12-31 08:40:23 +00:00
|
|
|
continue;
|
|
|
|
}
|
2024-12-27 01:34:34 +00:00
|
|
|
|
2024-12-31 08:40:23 +00:00
|
|
|
// Update triangle count
|
|
|
|
g_GPU_Triangles_drawn_to_screen += static_cast<int>(submesh.indices.size() / 3);
|
2024-12-30 04:25:16 +00:00
|
|
|
|
2025-01-01 19:04:56 +00:00
|
|
|
// Bind diffuse textures
|
|
|
|
const int MAX_DIFFUSE = 32;
|
2024-12-31 08:40:23 +00:00
|
|
|
int textureUnit = 0;
|
|
|
|
|
2025-01-01 19:04:56 +00:00
|
|
|
for (const auto& texture : submesh.textures)
|
2024-12-30 04:25:16 +00:00
|
|
|
{
|
2024-12-31 08:40:23 +00:00
|
|
|
if (texture.type == "texture_diffuse")
|
2024-12-30 04:25:16 +00:00
|
|
|
{
|
2024-12-31 08:40:23 +00:00
|
|
|
if (textureUnit >= MAX_DIFFUSE)
|
|
|
|
{
|
2025-01-01 19:04:56 +00:00
|
|
|
std::cerr << "[RenderWindow] Warning: Exceeded maximum number of diffuse textures (" << MAX_DIFFUSE << ") for shader." << std::endl;
|
|
|
|
break;
|
2024-12-31 08:40:23 +00:00
|
|
|
}
|
2024-12-30 04:25:16 +00:00
|
|
|
|
2024-12-31 08:40:23 +00:00
|
|
|
glActiveTexture(GL_TEXTURE0 + textureUnit);
|
2025-01-01 19:04:56 +00:00
|
|
|
glBindTexture(GL_TEXTURE_2D, texture.id); // Assuming texture.id is GLuint
|
2024-12-30 04:25:16 +00:00
|
|
|
|
2024-12-31 08:40:23 +00:00
|
|
|
std::string uniformName = "uTextures.texture_diffuse[" + std::to_string(textureUnit) + "]";
|
|
|
|
m_ShaderPtr->SetInt(uniformName, textureUnit);
|
2024-12-30 04:25:16 +00:00
|
|
|
|
2024-12-31 08:40:23 +00:00
|
|
|
textureUnit++;
|
2024-12-30 04:25:16 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2025-01-01 19:04:56 +00:00
|
|
|
// Assign default texture to unused slots
|
2024-12-31 22:35:06 +00:00
|
|
|
for (int i = textureUnit; i < MAX_DIFFUSE; ++i)
|
2024-12-30 04:25:16 +00:00
|
|
|
{
|
2024-12-31 08:40:23 +00:00
|
|
|
std::string uniformName = "uTextures.texture_diffuse[" + std::to_string(i) + "]";
|
2025-01-01 19:04:56 +00:00
|
|
|
m_ShaderPtr->SetInt(uniformName, 0); // Texture unit 0 should have a default texture bound
|
2024-12-30 04:25:16 +00:00
|
|
|
}
|
|
|
|
|
2025-01-01 19:04:56 +00:00
|
|
|
// Set number of active diffuse textures
|
2024-12-31 08:40:23 +00:00
|
|
|
m_ShaderPtr->SetInt("uNumDiffuseTextures", textureUnit);
|
|
|
|
|
|
|
|
// Draw the submesh
|
|
|
|
glBindVertexArray(submesh.vao);
|
|
|
|
glDrawElements(GL_TRIANGLES, static_cast<GLsizei>(submesh.indices.size()), GL_UNSIGNED_INT, nullptr);
|
|
|
|
glBindVertexArray(0);
|
2024-12-27 01:34:34 +00:00
|
|
|
|
2025-01-01 19:04:56 +00:00
|
|
|
// Reset active texture
|
2024-12-31 08:40:23 +00:00
|
|
|
glActiveTexture(GL_TEXTURE0);
|
|
|
|
}
|
2024-12-27 01:34:34 +00:00
|
|
|
}
|
2024-12-26 00:15:18 +00:00
|
|
|
}
|
2024-12-25 21:44:33 +00:00
|
|
|
|
2025-01-01 19:04:56 +00:00
|
|
|
// Unbind shader and framebuffer
|
2024-12-26 00:15:18 +00:00
|
|
|
glUseProgram(0);
|
2025-01-01 19:04:56 +00:00
|
|
|
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
2024-12-30 04:25:16 +00:00
|
|
|
|
2025-01-01 19:04:56 +00:00
|
|
|
// 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();
|
2024-12-25 21:44:33 +00:00
|
|
|
}
|
2025-01-01 19:04:56 +00:00
|
|
|
|