Compare commits

...

1 Commits

Author SHA1 Message Date
OusmBlueNinja
696554c4f5 Nothing really 2025-01-01 13:04:56 -06:00
10 changed files with 548 additions and 288 deletions

View File

@ -1,5 +1,6 @@
#version 330 core
void main()
{
// No color output; only depth is recorded
// Depth is automatically written to the depth buffer
}

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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);
}

View File

@ -2,29 +2,62 @@
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);
}

View File

@ -4,12 +4,14 @@ 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()
{
@ -22,6 +24,9 @@ void main()
// 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);
}

View File

@ -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

View File

@ -14,7 +14,7 @@ extern GameObject *g_SelectedObject; // Pointer to the currently selected object
extern std::shared_ptr<CameraComponent> 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> model = g_AssetManager->loadAsset<Model>(AssetType::MODEL, mesh->MeshPath.c_str());
std::shared_ptr<Model> model = g_AssetManager.loadAsset<Model>(AssetType::MODEL, mesh->MeshPath.c_str());
}

View File

@ -1,193 +1,80 @@
// RenderWindow.cpp
#include "RenderWindow.h"
#include <vector> // Add this line
#include <GL/glew.h>
#include <vector> // Added as per your inclusion
#include <GL/glew.h> // Ensure GLEW is initialized before using OpenGL functions
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>
#include "imgui.h"
#include "gcml.h"
#include "Componenets/GameObject.h"
#include "Componenets/mesh.h"
#include "Componenets/transform.h"
extern std::vector<std::shared_ptr<GameObject>> 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<std::shared_ptr<GameObject>> g_GameObjects;
extern AssetManager g_AssetManager;
extern std::shared_ptr<CameraComponent> 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<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();
}
// ----------------------------------------------------
// 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<GLuint> 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 <glm/gtc/type_ptr.hpp> // For glm::value_ptr
#include <algorithm> // Ensure <algorithm> 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<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);
}
}
}
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<CameraComponent> 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<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
}
// 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<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));
}
// Render all objects
for (auto& obj : g_GameObjects)
{
std::shared_ptr<TransformComponent> transform = obj->GetComponent<TransformComponent>();
std::shared_ptr<MeshComponent> mesh = obj->GetComponent<MeshComponent>();
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<int>(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<GLsizei>(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();
}

View File

@ -1,38 +1,67 @@
// RenderWindow.h
#pragma once
#include "../Rendering/FBO.h"
#include "Rendering/Shader.h"
#include <glm/glm.hpp>
#include "Rendering/Shader.h" //
#include <vector>
#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;
};