Added Bounding Boxes, And Added CPU-Culling
This commit is contained in:
parent
ecb6c4951f
commit
9b64f2cf50
6
assets/shaders/Line.frag
Normal file
6
assets/shaders/Line.frag
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
#version 330 core
|
||||||
|
out vec4 FragColor;
|
||||||
|
uniform vec4 uColor;
|
||||||
|
void main() {
|
||||||
|
FragColor = uColor;
|
||||||
|
}
|
8
assets/shaders/Line.vert
Normal file
8
assets/shaders/Line.vert
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
#version 330 core
|
||||||
|
layout (location = 0) in vec3 aPos;
|
||||||
|
uniform mat4 uMVP;
|
||||||
|
void main() {
|
||||||
|
gl_Position = uMVP * vec4(aPos, 1.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
10
imgui.ini
10
imgui.ini
@ -80,8 +80,8 @@ Collapsed=0
|
|||||||
DockId=0x0000001F,0
|
DockId=0x0000001F,0
|
||||||
|
|
||||||
[Window][Performance##performance]
|
[Window][Performance##performance]
|
||||||
Pos=8,702
|
Pos=8,581
|
||||||
Size=335,467
|
Size=335,588
|
||||||
Collapsed=0
|
Collapsed=0
|
||||||
DockId=0x0000001C,0
|
DockId=0x0000001C,0
|
||||||
|
|
||||||
@ -105,7 +105,7 @@ DockId=0x0000000F,0
|
|||||||
|
|
||||||
[Window][Scene Window##SceneWindow]
|
[Window][Scene Window##SceneWindow]
|
||||||
Pos=8,28
|
Pos=8,28
|
||||||
Size=335,672
|
Size=335,551
|
||||||
Collapsed=0
|
Collapsed=0
|
||||||
DockId=0x0000001B,0
|
DockId=0x0000001B,0
|
||||||
|
|
||||||
@ -173,8 +173,8 @@ Column 3 Weight=0.6950
|
|||||||
DockSpace ID=0x14621557 Window=0x3DA2F1DE Pos=8,51 Size=1904,1141 Split=X Selected=0xF7365A5A
|
DockSpace ID=0x14621557 Window=0x3DA2F1DE Pos=8,51 Size=1904,1141 Split=X Selected=0xF7365A5A
|
||||||
DockNode ID=0x00000020 Parent=0x14621557 SizeRef=884,684 Split=X
|
DockNode ID=0x00000020 Parent=0x14621557 SizeRef=884,684 Split=X
|
||||||
DockNode ID=0x00000013 Parent=0x00000020 SizeRef=335,1142 Split=Y Selected=0x818D04BB
|
DockNode ID=0x00000013 Parent=0x00000020 SizeRef=335,1142 Split=Y Selected=0x818D04BB
|
||||||
DockNode ID=0x0000001B Parent=0x00000013 SizeRef=264,672 HiddenTabBar=1 Selected=0x1D5D92B6
|
DockNode ID=0x0000001B Parent=0x00000013 SizeRef=264,551 HiddenTabBar=1 Selected=0x1D5D92B6
|
||||||
DockNode ID=0x0000001C Parent=0x00000013 SizeRef=264,467 HiddenTabBar=1 Selected=0x818D04BB
|
DockNode ID=0x0000001C Parent=0x00000013 SizeRef=264,588 HiddenTabBar=1 Selected=0x818D04BB
|
||||||
DockNode ID=0x00000014 Parent=0x00000020 SizeRef=547,1142 Split=X
|
DockNode ID=0x00000014 Parent=0x00000020 SizeRef=547,1142 Split=X
|
||||||
DockNode ID=0x00000015 Parent=0x00000014 SizeRef=1158,1142 Split=X
|
DockNode ID=0x00000015 Parent=0x00000014 SizeRef=1158,1142 Split=X
|
||||||
DockNode ID=0x00000011 Parent=0x00000015 SizeRef=265,1142 Selected=0x1D5D92B6
|
DockNode ID=0x00000011 Parent=0x00000015 SizeRef=265,1142 Selected=0x1D5D92B6
|
||||||
|
@ -36,6 +36,7 @@
|
|||||||
#include "Engine/InputManager.h"
|
#include "Engine/InputManager.h"
|
||||||
#include "Engine/ScopedTimer.h"
|
#include "Engine/ScopedTimer.h"
|
||||||
#include "Engine/Profiler.h"
|
#include "Engine/Profiler.h"
|
||||||
|
#include "Engine/Settings.h"
|
||||||
|
|
||||||
// #define YAML_CPP_STATIC_DEFINE
|
// #define YAML_CPP_STATIC_DEFINE
|
||||||
#include <yaml-cpp/yaml.h>
|
#include <yaml-cpp/yaml.h>
|
||||||
@ -50,6 +51,7 @@ SceneManager g_SceneManager;
|
|||||||
|
|
||||||
InputManager g_InputManager;
|
InputManager g_InputManager;
|
||||||
|
|
||||||
|
Settings g_SettingsManager;
|
||||||
|
|
||||||
std::vector<std::shared_ptr<GameObject>> g_GameObjects;
|
std::vector<std::shared_ptr<GameObject>> g_GameObjects;
|
||||||
|
|
||||||
@ -58,6 +60,8 @@ std::shared_ptr<CameraComponent> g_RuntimeCameraObject;
|
|||||||
int g_GPU_Triangles_drawn_to_screen = 0;
|
int g_GPU_Triangles_drawn_to_screen = 0;
|
||||||
int g_GPU_Draw_Calls = 0;
|
int g_GPU_Draw_Calls = 0;
|
||||||
|
|
||||||
|
bool DrawBBBO;
|
||||||
|
|
||||||
GameObject *g_SelectedObject; // Pointer to the currently selected object
|
GameObject *g_SelectedObject; // Pointer to the currently selected object
|
||||||
|
|
||||||
int m_GameRunning = 0;
|
int m_GameRunning = 0;
|
||||||
@ -65,6 +69,10 @@ int m_GameRunning = 0;
|
|||||||
bool MyEngine::Init(int width, int height, const std::string &title)
|
bool MyEngine::Init(int width, int height, const std::string &title)
|
||||||
{
|
{
|
||||||
DEBUG_PRINT("[START] Engine Init");
|
DEBUG_PRINT("[START] Engine Init");
|
||||||
|
|
||||||
|
g_SettingsManager.S_LineColor = glm::vec4(1.0f, 0.27058823529f, 0.0f, 1.0f);
|
||||||
|
|
||||||
|
|
||||||
// ------------------------------------------
|
// ------------------------------------------
|
||||||
// 1) Initialize GLFW
|
// 1) Initialize GLFW
|
||||||
// ------------------------------------------
|
// ------------------------------------------
|
||||||
@ -170,6 +178,8 @@ bool MyEngine::Init(int width, int height, const std::string &title)
|
|||||||
m_FirstTickGameRunning = true;
|
m_FirstTickGameRunning = true;
|
||||||
m_showProfiler = true;
|
m_showProfiler = true;
|
||||||
|
|
||||||
|
DrawBBBO = false;
|
||||||
|
|
||||||
g_LoggerWindow = m_LoggerWindow.get();
|
g_LoggerWindow = m_LoggerWindow.get();
|
||||||
|
|
||||||
// Optionally, call 'onInit' Lua function
|
// Optionally, call 'onInit' Lua function
|
||||||
@ -206,8 +216,6 @@ void MyEngine::Run()
|
|||||||
glfwPollEvents();
|
glfwPollEvents();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
{
|
{
|
||||||
SCOPE_TIMER("InputManagerUpdate");
|
SCOPE_TIMER("InputManagerUpdate");
|
||||||
g_InputManager.Update(m_Window);
|
g_InputManager.Update(m_Window);
|
||||||
@ -432,6 +440,22 @@ void MyEngine::ShowDockSpace()
|
|||||||
ImGui::Checkbox("Show Profiler", &m_showProfiler); // Add a checkbox to toggle the profiler
|
ImGui::Checkbox("Show Profiler", &m_showProfiler); // Add a checkbox to toggle the profiler
|
||||||
ImGui::EndMenu();
|
ImGui::EndMenu();
|
||||||
}
|
}
|
||||||
|
if (ImGui::BeginMenu("Settings"))
|
||||||
|
{
|
||||||
|
// A checkbox to enable/disable bounding boxes
|
||||||
|
ImGui::Checkbox("Show Box's", &DrawBBBO);
|
||||||
|
|
||||||
|
// On the same line, we place a small color edit widget
|
||||||
|
ImGui::SameLine();
|
||||||
|
ImGui::ColorEdit4("Box Color",
|
||||||
|
reinterpret_cast<float *>(&g_SettingsManager.S_LineColor),
|
||||||
|
ImGuiColorEditFlags_NoInputs | ImGuiColorEditFlags_NoLabel);
|
||||||
|
// Explanation of Flags:
|
||||||
|
// - ImGuiColorEditFlags_NoInputs hides numeric RGBA input fields
|
||||||
|
// - ImGuiColorEditFlags_NoLabel hides the default label, since we already have "Box Color"
|
||||||
|
ImGui::EndMenu();
|
||||||
|
}
|
||||||
|
|
||||||
if (ImGui::BeginMenu("Engine"))
|
if (ImGui::BeginMenu("Engine"))
|
||||||
{
|
{
|
||||||
|
|
||||||
|
@ -520,6 +520,7 @@ Model *LoadModelFromList(const std::string &path)
|
|||||||
|
|
||||||
// Initialize OpenGL buffers for the submesh
|
// Initialize OpenGL buffers for the submesh
|
||||||
submesh.Initialize();
|
submesh.Initialize();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (materialToSubmesh.empty())
|
if (materialToSubmesh.empty())
|
||||||
|
@ -82,10 +82,31 @@ struct Submesh
|
|||||||
std::vector<unsigned int> indices;
|
std::vector<unsigned int> indices;
|
||||||
std::vector<Texture> textures;
|
std::vector<Texture> textures;
|
||||||
GLuint vao = 0, vbo = 0, ebo = 0;
|
GLuint vao = 0, vbo = 0, ebo = 0;
|
||||||
|
unsigned int bboxVAO, bboxVBO;
|
||||||
|
GLsizei bboxVertexCount;
|
||||||
|
|
||||||
|
glm::vec3 minExtents;
|
||||||
|
glm::vec3 maxExtents;
|
||||||
|
|
||||||
// Initialize OpenGL buffers for the submesh
|
// Initialize OpenGL buffers for the submesh
|
||||||
void Initialize()
|
void Initialize()
|
||||||
{
|
{
|
||||||
|
glm::vec3 minExtents(FLT_MAX);
|
||||||
|
glm::vec3 maxExtents(-FLT_MAX);
|
||||||
|
for (auto &v : vertices)
|
||||||
|
{
|
||||||
|
minExtents.x = std::min(minExtents.x, v.position[0]);
|
||||||
|
minExtents.y = std::min(minExtents.y, v.position[1]);
|
||||||
|
minExtents.z = std::min(minExtents.z, v.position[2]);
|
||||||
|
|
||||||
|
maxExtents.x = std::max(maxExtents.x, v.position[0]);
|
||||||
|
maxExtents.y = std::max(maxExtents.y, v.position[1]);
|
||||||
|
maxExtents.z = std::max(maxExtents.z, v.position[2]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Store in the submesh
|
||||||
|
this->minExtents = minExtents;
|
||||||
|
this->maxExtents = maxExtents;
|
||||||
glGenVertexArrays(1, &vao);
|
glGenVertexArrays(1, &vao);
|
||||||
glGenBuffers(1, &vbo);
|
glGenBuffers(1, &vbo);
|
||||||
glGenBuffers(1, &ebo);
|
glGenBuffers(1, &ebo);
|
||||||
@ -109,6 +130,58 @@ struct Submesh
|
|||||||
glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void *)(5 * sizeof(float)));
|
glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void *)(5 * sizeof(float)));
|
||||||
|
|
||||||
glBindVertexArray(0);
|
glBindVertexArray(0);
|
||||||
|
|
||||||
|
std::vector<glm::vec3> bboxLines = {
|
||||||
|
// bottom face
|
||||||
|
{minExtents.x, minExtents.y, minExtents.z},
|
||||||
|
{maxExtents.x, minExtents.y, minExtents.z},
|
||||||
|
{maxExtents.x, minExtents.y, minExtents.z},
|
||||||
|
{maxExtents.x, minExtents.y, maxExtents.z},
|
||||||
|
{maxExtents.x, minExtents.y, maxExtents.z},
|
||||||
|
{minExtents.x, minExtents.y, maxExtents.z},
|
||||||
|
{minExtents.x, minExtents.y, maxExtents.z},
|
||||||
|
{minExtents.x, minExtents.y, minExtents.z},
|
||||||
|
// top face
|
||||||
|
{minExtents.x, maxExtents.y, minExtents.z},
|
||||||
|
{maxExtents.x, maxExtents.y, minExtents.z},
|
||||||
|
{maxExtents.x, maxExtents.y, minExtents.z},
|
||||||
|
{maxExtents.x, maxExtents.y, maxExtents.z},
|
||||||
|
{maxExtents.x, maxExtents.y, maxExtents.z},
|
||||||
|
{minExtents.x, maxExtents.y, maxExtents.z},
|
||||||
|
{minExtents.x, maxExtents.y, maxExtents.z},
|
||||||
|
{minExtents.x, maxExtents.y, minExtents.z},
|
||||||
|
// vertical edges
|
||||||
|
{minExtents.x, minExtents.y, minExtents.z},
|
||||||
|
{minExtents.x, maxExtents.y, minExtents.z},
|
||||||
|
{maxExtents.x, minExtents.y, minExtents.z},
|
||||||
|
{maxExtents.x, maxExtents.y, minExtents.z},
|
||||||
|
{maxExtents.x, minExtents.y, maxExtents.z},
|
||||||
|
{maxExtents.x, maxExtents.y, maxExtents.z},
|
||||||
|
{minExtents.x, minExtents.y, maxExtents.z},
|
||||||
|
{minExtents.x, maxExtents.y, maxExtents.z}};
|
||||||
|
|
||||||
|
glGenVertexArrays(1, &bboxVAO);
|
||||||
|
glGenBuffers(1, &bboxVBO);
|
||||||
|
|
||||||
|
glBindVertexArray(bboxVAO);
|
||||||
|
glBindBuffer(GL_ARRAY_BUFFER, bboxVBO);
|
||||||
|
glBufferData(
|
||||||
|
GL_ARRAY_BUFFER,
|
||||||
|
bboxLines.size() * sizeof(glm::vec3),
|
||||||
|
bboxLines.data(),
|
||||||
|
GL_STATIC_DRAW);
|
||||||
|
|
||||||
|
glEnableVertexAttribArray(0);
|
||||||
|
glVertexAttribPointer(
|
||||||
|
0, 3, GL_FLOAT, GL_FALSE,
|
||||||
|
sizeof(glm::vec3), (void *)0);
|
||||||
|
|
||||||
|
glBindVertexArray(0);
|
||||||
|
|
||||||
|
bboxVAO = bboxVAO;
|
||||||
|
bboxVBO = bboxVBO;
|
||||||
|
bboxVertexCount = (GLsizei)bboxLines.size();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Render the submesh
|
// Render the submesh
|
||||||
@ -200,9 +273,9 @@ public:
|
|||||||
// Debug: Log the variant type
|
// Debug: Log the variant type
|
||||||
if (std::holds_alternative<std::shared_ptr<T>>(it->second))
|
if (std::holds_alternative<std::shared_ptr<T>>(it->second))
|
||||||
{
|
{
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
DebugAssetMap();
|
DebugAssetMap();
|
||||||
#endif
|
#endif
|
||||||
std::cout << "[AssetManager] Retrieved asset from cache: " << key << std::endl;
|
std::cout << "[AssetManager] Retrieved asset from cache: " << key << std::endl;
|
||||||
return std::get<std::shared_ptr<T>>(it->second);
|
return std::get<std::shared_ptr<T>>(it->second);
|
||||||
}
|
}
|
||||||
|
6
src/Engine/Settings.h
Normal file
6
src/Engine/Settings.h
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
#include "imgui.h"
|
||||||
|
#include <glm/gtc/matrix_transform.hpp>
|
||||||
|
|
||||||
|
struct Settings {
|
||||||
|
glm::vec4 S_LineColor;
|
||||||
|
};
|
@ -152,6 +152,12 @@ void Shader::SetVec3(const std::string &name, const glm::vec3 &value) const
|
|||||||
glUniform3fv(glGetUniformLocation(ID, name.c_str()), 1, &value[0]);
|
glUniform3fv(glGetUniformLocation(ID, name.c_str()), 1, &value[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Shader::SetVec4(const std::string &name, const glm::vec4 &value) const
|
||||||
|
{
|
||||||
|
glUseProgram(ID); // Ensure the shader program is active
|
||||||
|
glUniform4fv(glGetUniformLocation(ID, name.c_str()), 1, &value[0]);
|
||||||
|
}
|
||||||
void Shader::SetSampler2D(const std::string &name, int textureUnit) const
|
void Shader::SetSampler2D(const std::string &name, int textureUnit) const
|
||||||
{
|
{
|
||||||
glUseProgram(ID); // Ensure the shader program is active
|
glUseProgram(ID); // Ensure the shader program is active
|
||||||
|
@ -26,6 +26,8 @@ public:
|
|||||||
void SetMat4(const std::string &name, const glm::mat4 &mat) const; // For setting 4x4 matrices
|
void SetMat4(const std::string &name, const glm::mat4 &mat) const; // For setting 4x4 matrices
|
||||||
void SetSampler2D(const std::string &name, int textureUnit) const;
|
void SetSampler2D(const std::string &name, int textureUnit) const;
|
||||||
void SetVec3(const std::string &name, const glm::vec3 &value) const;
|
void SetVec3(const std::string &name, const glm::vec3 &value) const;
|
||||||
|
void SetVec4(const std::string &name, const glm::vec4 &value) const;
|
||||||
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Caching uniform locations for performance
|
// Caching uniform locations for performance
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
#include "PerformanceWindow.h"
|
#include "PerformanceWindow.h"
|
||||||
#include "imgui.h"
|
#include "imgui.h"
|
||||||
#include <algorithm> // for std::max_element, etc.
|
#include <algorithm> // for std::max
|
||||||
|
#include <float.h> // for FLT_MAX
|
||||||
#include "Engine/ThemeManager.h"
|
#include "Engine/ThemeManager.h"
|
||||||
#include "Engine/ScopedTimer.h"
|
#include "Engine/ScopedTimer.h"
|
||||||
|
|
||||||
@ -8,46 +9,44 @@ extern int LoadedAssets;
|
|||||||
extern int g_GPU_Triangles_drawn_to_screen;
|
extern int g_GPU_Triangles_drawn_to_screen;
|
||||||
extern int g_GPU_Draw_Calls;
|
extern int g_GPU_Draw_Calls;
|
||||||
|
|
||||||
|
|
||||||
const char *polygonModeOptions[] = {"Fill", "Wireframe", "Points"};
|
const char *polygonModeOptions[] = {"Fill", "Wireframe", "Points"};
|
||||||
const int numPolygonModes = sizeof(polygonModeOptions) / sizeof(polygonModeOptions[0]);
|
static int polygonMode = 0;
|
||||||
|
|
||||||
int polygonMode = 0;
|
|
||||||
|
|
||||||
// Initialize static members
|
// Initialize static members
|
||||||
int PerformanceWindow::m_OpenGLCallCount = 0;
|
int PerformanceWindow::m_OpenGLCallCount = 0;
|
||||||
int PerformanceWindow::m_TriangleCount = 0;
|
int PerformanceWindow::m_TriangleCount = 0;
|
||||||
|
|
||||||
// We'll store up to 60 data points for each stat.
|
// We'll store up to 60 data points for each stat.
|
||||||
static float s_FpsHistory[60] = {0.0f};
|
static float s_FpsHistory[60] = {0.0f};
|
||||||
static float s_MsHistory[60] = {0.0f};
|
static float s_MsHistory[60] = {0.0f};
|
||||||
static float s_CallsHistory[60] = {0.0f};
|
static float s_CallsHistory[60] = {0.0f};
|
||||||
static float s_TriangleHistory[60] = {0.0f};
|
static float s_TriangleHistory[60] = {0.0f};
|
||||||
|
|
||||||
// Current dynamic max scale for FPS and ms
|
// Current dynamic max scale for FPS and ms
|
||||||
static float s_FpsScale = 120.0f; // default starting scale for FPS
|
static float s_FpsScale = 120.0f; // default starting scale for FPS
|
||||||
static float s_MsScale = 25.0f; // default starting scale for ms
|
static float s_MsScale = 25.0f; // default starting scale for ms
|
||||||
|
|
||||||
// This function shifts the old values left and appends a new value at the end.
|
// Push new value into history, shifting old values left
|
||||||
static void PushValueToHistory(float *historyArray, int historySize, float newValue)
|
static void PushValueToHistory(float* historyArray, int historySize, float newValue)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < historySize - 1; i++)
|
for (int i = 0; i < historySize - 1; i++)
|
||||||
|
{
|
||||||
historyArray[i] = historyArray[i + 1];
|
historyArray[i] = historyArray[i + 1];
|
||||||
|
}
|
||||||
historyArray[historySize - 1] = newValue;
|
historyArray[historySize - 1] = newValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// We'll track when we last pushed data to our history.
|
// We'll track when we last pushed data to our history.
|
||||||
static double s_LastPushTime = 0.0;
|
static double s_LastPushTime = 0.0;
|
||||||
|
|
||||||
// We'll also track when we last updated the scale
|
// We'll also track when we last updated the scale
|
||||||
static double s_LastScaleUpdate = 0.0;
|
static double s_LastScaleUpdate = 0.0;
|
||||||
|
|
||||||
// Update counters from the outside
|
|
||||||
void PerformanceWindow::UpdatePerformanceStats(int newCallCount, int newTriangleCount)
|
void PerformanceWindow::UpdatePerformanceStats(int newCallCount, int newTriangleCount)
|
||||||
{
|
{
|
||||||
m_OpenGLCallCount = newCallCount;
|
m_OpenGLCallCount = newCallCount;
|
||||||
m_TriangleCount = newTriangleCount;
|
m_TriangleCount = newTriangleCount;
|
||||||
|
|
||||||
|
// Reset GPU counters each frame, or each time you show
|
||||||
g_GPU_Triangles_drawn_to_screen = 0;
|
g_GPU_Triangles_drawn_to_screen = 0;
|
||||||
g_GPU_Draw_Calls = 0;
|
g_GPU_Draw_Calls = 0;
|
||||||
}
|
}
|
||||||
@ -59,7 +58,7 @@ void PerformanceWindow::Show(float fps, float ms)
|
|||||||
// 1) Get current time from ImGui's internal clock
|
// 1) Get current time from ImGui's internal clock
|
||||||
double currentTime = ImGui::GetTime();
|
double currentTime = ImGui::GetTime();
|
||||||
|
|
||||||
// 2) If at least 0.05s has passed, push new data (about 20 updates per second)
|
// 2) If at least 0.05s has passed, push new data (~20 times a second)
|
||||||
if ((currentTime - s_LastPushTime) >= 0.05)
|
if ((currentTime - s_LastPushTime) >= 0.05)
|
||||||
{
|
{
|
||||||
s_LastPushTime = currentTime;
|
s_LastPushTime = currentTime;
|
||||||
@ -71,141 +70,234 @@ void PerformanceWindow::Show(float fps, float ms)
|
|||||||
PushValueToHistory(s_TriangleHistory, 60, (float)m_TriangleCount);
|
PushValueToHistory(s_TriangleHistory, 60, (float)m_TriangleCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 3) Every 1 second, recalculate the max scale for FPS and ms
|
// We'll calculate a fallback max for calls
|
||||||
|
static float callsMax = 300.0f;
|
||||||
|
|
||||||
|
// 3) Every 1 second, recalculate the max scale for FPS, ms, and calls
|
||||||
if ((currentTime - s_LastScaleUpdate) >= 1.0)
|
if ((currentTime - s_LastScaleUpdate) >= 1.0)
|
||||||
{
|
{
|
||||||
s_LastScaleUpdate = currentTime;
|
s_LastScaleUpdate = currentTime;
|
||||||
|
|
||||||
// Find the maximum in s_FpsHistory
|
// Recompute s_FpsScale
|
||||||
float maxFps = 0.0f;
|
float maxFps = 0.0f;
|
||||||
for (int i = 0; i < 60; i++)
|
for (int i = 0; i < 60; i++)
|
||||||
{
|
maxFps = std::max(maxFps, s_FpsHistory[i]);
|
||||||
if (s_FpsHistory[i] > maxFps)
|
maxFps = std::max(1.0f, maxFps * 1.15f); // add ~15% headroom
|
||||||
maxFps = s_FpsHistory[i];
|
|
||||||
}
|
|
||||||
// Scale it by +15%, ensure it's not below 1.0
|
|
||||||
maxFps *= 1.15f;
|
|
||||||
if (maxFps < 1.0f)
|
|
||||||
maxFps = 1.0f;
|
|
||||||
s_FpsScale = maxFps;
|
s_FpsScale = maxFps;
|
||||||
|
|
||||||
// Find the maximum in s_MsHistory
|
// Recompute s_MsScale
|
||||||
float maxMs = 0.0f;
|
float maxMs = 0.0f;
|
||||||
for (int i = 0; i < 60; i++)
|
for (int i = 0; i < 60; i++)
|
||||||
{
|
maxMs = std::max(maxMs, s_MsHistory[i]);
|
||||||
if (s_MsHistory[i] > maxMs)
|
maxMs = std::max(1.0f, maxMs * 1.15f);
|
||||||
maxMs = s_MsHistory[i];
|
|
||||||
}
|
|
||||||
// Scale it by +15%, ensure it's not below 1.0
|
|
||||||
maxMs *= 1.15f;
|
|
||||||
if (maxMs < 1.0f)
|
|
||||||
maxMs = 1.0f;
|
|
||||||
s_MsScale = maxMs;
|
s_MsScale = maxMs;
|
||||||
|
|
||||||
|
// Recompute callsMax
|
||||||
|
float localMax = 0.0f;
|
||||||
|
for (int i = 0; i < 60; i++)
|
||||||
|
localMax = std::max(localMax, s_CallsHistory[i]);
|
||||||
|
if (localMax > 0.0f)
|
||||||
|
callsMax = localMax * 1.2f; // 20% headroom
|
||||||
|
else
|
||||||
|
callsMax = 300.0f; // default
|
||||||
}
|
}
|
||||||
|
|
||||||
// Optional style adjustments
|
// Optional style adjustments
|
||||||
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(10, 10));
|
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(10, 10));
|
||||||
|
|
||||||
|
// Optionally make the window auto-resize or set constraints:
|
||||||
|
// ImGui::SetNextWindowSizeConstraints(ImVec2(350, 300), ImVec2(FLT_MAX, FLT_MAX));
|
||||||
|
// ImGui::Begin("Performance##performance", nullptr, ImGuiWindowFlags_AlwaysAutoResize);
|
||||||
|
|
||||||
ImGui::Begin("Performance##performance");
|
ImGui::Begin("Performance##performance");
|
||||||
|
|
||||||
// Colored header
|
// A color-coded main header
|
||||||
ImGui::TextColored(ImVec4(1.0f, 0.8f, 0.2f, 1.0f), "Performance Stats");
|
ImGui::TextColored(ImVec4(1.0f, 0.8f, 0.2f, 1.0f), "Performance Stats");
|
||||||
ImGui::Separator();
|
ImGui::Separator();
|
||||||
|
ImGui::Spacing();
|
||||||
|
|
||||||
// Show current FPS/ms
|
// Show current FPS / ms in color
|
||||||
ImGui::TextColored(ImVec4(0.4f, 1.0f, 0.4f, 1.0f), "FPS: %.1f", fps);
|
|
||||||
ImGui::SameLine();
|
|
||||||
ImGui::TextColored(ImVec4(0.4f, 1.0f, 0.8f, 1.0f), "| ms: %.3f", ms);
|
|
||||||
|
|
||||||
// Graphs for FPS + MS
|
|
||||||
// min = 0, max = s_FpsScale or s_MsScale
|
|
||||||
ImGui::PlotLines("FPS",
|
|
||||||
s_FpsHistory,
|
|
||||||
IM_ARRAYSIZE(s_FpsHistory),
|
|
||||||
0,
|
|
||||||
nullptr,
|
|
||||||
0.0f,
|
|
||||||
s_FpsScale,
|
|
||||||
ImVec2(0, 60));
|
|
||||||
|
|
||||||
ImGui::PlotHistogram("ms/frame",
|
|
||||||
s_MsHistory,
|
|
||||||
IM_ARRAYSIZE(s_MsHistory),
|
|
||||||
0,
|
|
||||||
nullptr,
|
|
||||||
0.0f,
|
|
||||||
s_MsScale,
|
|
||||||
ImVec2(0, 60));
|
|
||||||
|
|
||||||
ImGui::Separator();
|
|
||||||
|
|
||||||
// Show OpenGL calls + Triangles
|
|
||||||
ImGui::Text("OpenGL Calls: %d", m_OpenGLCallCount);
|
|
||||||
ImGui::PlotLines("GL Calls",
|
|
||||||
s_CallsHistory,
|
|
||||||
IM_ARRAYSIZE(s_CallsHistory),
|
|
||||||
0,
|
|
||||||
nullptr,
|
|
||||||
0.0f,
|
|
||||||
300.0f,
|
|
||||||
ImVec2(0, 50));
|
|
||||||
|
|
||||||
ImGui::Text("Indices: %d", m_TriangleCount);
|
|
||||||
ImGui::PlotHistogram("Indices",
|
|
||||||
s_TriangleHistory,
|
|
||||||
IM_ARRAYSIZE(s_TriangleHistory),
|
|
||||||
0,
|
|
||||||
nullptr,
|
|
||||||
0.0f,
|
|
||||||
m_TriangleCount * 2.5,
|
|
||||||
ImVec2(0, 50));
|
|
||||||
|
|
||||||
ImGui::Separator();
|
|
||||||
|
|
||||||
// Show asset count
|
|
||||||
ImGui::TextColored(ImVec4(0.4f, 1.0f, 0.4f, 1.0f), "Assets: %d", LoadedAssets);
|
|
||||||
|
|
||||||
ImGui::Separator();
|
|
||||||
|
|
||||||
const char *options[] = {"Bootsrap", "Duck Red", "Windark", "Deep Dark", "Tesseract Black"};
|
|
||||||
static int current_option = -1; // No selection initially
|
|
||||||
|
|
||||||
const char *preview_value = (current_option >= 0 && current_option < 3) ? options[current_option] : "Select an option";
|
|
||||||
if (ImGui::BeginCombo("Theme", preview_value))
|
|
||||||
{
|
{
|
||||||
for (int n = 0; n < IM_ARRAYSIZE(options); n++)
|
// Line 1: FPS (green) + MS (teal)
|
||||||
|
ImGui::TextColored(ImVec4(0.4f, 1.0f, 0.4f, 1.0f), "FPS: %.1f", fps);
|
||||||
|
ImGui::SameLine();
|
||||||
|
ImGui::TextColored(ImVec4(0.4f, 1.0f, 0.8f, 1.0f), "| ms: %.3f", ms);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Collapsible header for the performance graphs
|
||||||
|
if (ImGui::CollapsingHeader("Performance Graphs", ImGuiTreeNodeFlags_DefaultOpen))
|
||||||
|
{
|
||||||
|
ImGui::Spacing();
|
||||||
|
|
||||||
|
// --------- FPS & MS side by side ----------
|
||||||
|
ImGui::BeginGroup(); // left group
|
||||||
{
|
{
|
||||||
bool is_selected = (current_option == n);
|
ImGui::Text("FPS");
|
||||||
if (ImGui::Selectable(options[n], is_selected))
|
ImGui::PushStyleColor(ImGuiCol_PlotLines, IM_COL32(0, 255, 0, 255)); // green
|
||||||
|
ImGui::PushStyleColor(ImGuiCol_PlotLinesHovered, IM_COL32(255, 0, 0, 255)); // red on hover
|
||||||
|
|
||||||
|
ImGui::PlotLines("##FPS", // hidden label
|
||||||
|
s_FpsHistory, IM_ARRAYSIZE(s_FpsHistory),
|
||||||
|
0, // offset
|
||||||
|
nullptr, // overlay
|
||||||
|
0.0f,
|
||||||
|
s_FpsScale,
|
||||||
|
ImVec2(150, 60));
|
||||||
|
|
||||||
|
if (ImGui::IsItemHovered())
|
||||||
{
|
{
|
||||||
current_option = n; // Update current option
|
ImGui::BeginTooltip();
|
||||||
ThemeManager_ChangeTheme(n); // Call the function with the selected option
|
ImGui::Text("Frames per second over time");
|
||||||
|
ImGui::EndTooltip();
|
||||||
}
|
}
|
||||||
// Set the initial focus when opening the combo (optional)
|
|
||||||
if (is_selected)
|
ImGui::PopStyleColor(2);
|
||||||
ImGui::SetItemDefaultFocus();
|
|
||||||
}
|
}
|
||||||
ImGui::EndCombo();
|
ImGui::EndGroup();
|
||||||
}
|
|
||||||
if (ImGui::Combo("Polygon Mode", &polygonMode, polygonModeOptions, numPolygonModes))
|
ImGui::SameLine();
|
||||||
{
|
|
||||||
switch (polygonMode)
|
ImGui::BeginGroup(); // right group
|
||||||
{
|
{
|
||||||
case 0:
|
ImGui::Text("ms/frame");
|
||||||
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
|
ImGui::PlotHistogram("##ms/frame",
|
||||||
break;
|
s_MsHistory,
|
||||||
case 1:
|
IM_ARRAYSIZE(s_MsHistory),
|
||||||
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
|
0,
|
||||||
break;
|
nullptr,
|
||||||
case 2:
|
0.0f,
|
||||||
glPolygonMode(GL_FRONT_AND_BACK, GL_POINT);
|
s_MsScale,
|
||||||
break;
|
ImVec2(150, 60));
|
||||||
default:
|
|
||||||
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
|
if (ImGui::IsItemHovered())
|
||||||
break;
|
{
|
||||||
|
ImGui::BeginTooltip();
|
||||||
|
ImGui::Text("Frame time in milliseconds");
|
||||||
|
ImGui::EndTooltip();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ImGui::EndGroup();
|
||||||
|
|
||||||
|
ImGui::Spacing();
|
||||||
|
ImGui::Separator();
|
||||||
|
ImGui::Spacing();
|
||||||
|
|
||||||
|
// --------- OpenGL Calls & Indices -----------
|
||||||
|
// 1) GL Calls
|
||||||
|
ImGui::Text("OpenGL Calls: %d", m_OpenGLCallCount);
|
||||||
|
|
||||||
|
ImGui::PlotLines("##GL Calls",
|
||||||
|
s_CallsHistory,
|
||||||
|
IM_ARRAYSIZE(s_CallsHistory),
|
||||||
|
0, // offset
|
||||||
|
nullptr, // overlay text
|
||||||
|
0.0f,
|
||||||
|
callsMax,
|
||||||
|
ImVec2(-1, 50)); // auto-fill width, fixed height=50
|
||||||
|
|
||||||
|
if (ImGui::IsItemHovered())
|
||||||
|
{
|
||||||
|
ImGui::BeginTooltip();
|
||||||
|
ImGui::Text("Number of GL draw calls per frame");
|
||||||
|
ImGui::EndTooltip();
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::Spacing();
|
||||||
|
|
||||||
|
// 2) Indices
|
||||||
|
ImGui::Text("Indices: %d", m_TriangleCount);
|
||||||
|
|
||||||
|
// For Indices, we use a histogram. We could also do dynamic range like callsMax.
|
||||||
|
float indexHistMax = std::max(1.0f, (float)m_TriangleCount * 2.5f);
|
||||||
|
|
||||||
|
ImGui::PlotHistogram("##Indices",
|
||||||
|
s_TriangleHistory,
|
||||||
|
IM_ARRAYSIZE(s_TriangleHistory),
|
||||||
|
0,
|
||||||
|
nullptr,
|
||||||
|
0.0f,
|
||||||
|
indexHistMax,
|
||||||
|
ImVec2(-1, 50)); // auto-size width, height=50
|
||||||
|
|
||||||
|
if (ImGui::IsItemHovered())
|
||||||
|
{
|
||||||
|
ImGui::BeginTooltip();
|
||||||
|
ImGui::Text("Number of indices being rendered per frame");
|
||||||
|
ImGui::EndTooltip();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ImGui::End();
|
ImGui::Spacing();
|
||||||
|
ImGui::Separator();
|
||||||
|
ImGui::Spacing();
|
||||||
|
|
||||||
|
// -------------- Asset Count --------------
|
||||||
|
{
|
||||||
|
ImGui::Text("Loaded Assets: ");
|
||||||
|
ImGui::SameLine();
|
||||||
|
ImGui::TextColored(ImVec4(0.4f, 1.0f, 0.4f, 1.0f), "%d", LoadedAssets);
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::Spacing();
|
||||||
|
ImGui::Separator();
|
||||||
|
ImGui::Spacing();
|
||||||
|
|
||||||
|
// -------------- Theme Combo Box --------------
|
||||||
|
{
|
||||||
|
const char* options[] = {"Bootstrap", "Duck Red", "Windark", "Deep Dark", "Tesseract Black"};
|
||||||
|
static int current_option = -1;
|
||||||
|
const char* preview_value = (current_option >= 0 && current_option < IM_ARRAYSIZE(options))
|
||||||
|
? options[current_option]
|
||||||
|
: "Select an option";
|
||||||
|
|
||||||
|
ImGui::Text("Theme: ");
|
||||||
|
ImGui::SameLine();
|
||||||
|
if (ImGui::BeginCombo("##ThemeCombo", preview_value))
|
||||||
|
{
|
||||||
|
for (int n = 0; n < IM_ARRAYSIZE(options); n++)
|
||||||
|
{
|
||||||
|
bool is_selected = (current_option == n);
|
||||||
|
if (ImGui::Selectable(options[n], is_selected))
|
||||||
|
{
|
||||||
|
current_option = n;
|
||||||
|
// Switch theme
|
||||||
|
ThemeManager_ChangeTheme(n);
|
||||||
|
}
|
||||||
|
if (is_selected)
|
||||||
|
ImGui::SetItemDefaultFocus();
|
||||||
|
}
|
||||||
|
ImGui::EndCombo();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::Spacing();
|
||||||
|
|
||||||
|
// -------------- Polygon Mode Combo Box --------------
|
||||||
|
{
|
||||||
|
ImGui::Text("Polygon Mode: ");
|
||||||
|
ImGui::SameLine();
|
||||||
|
if (ImGui::Combo("##PolygonMode", &polygonMode, polygonModeOptions, IM_ARRAYSIZE(polygonModeOptions)))
|
||||||
|
{
|
||||||
|
switch (polygonMode)
|
||||||
|
{
|
||||||
|
case 0: // Fill
|
||||||
|
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
|
||||||
|
break;
|
||||||
|
case 1: // Wireframe
|
||||||
|
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
|
||||||
|
break;
|
||||||
|
case 2: // Points
|
||||||
|
glPolygonMode(GL_FRONT_AND_BACK, GL_POINT);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::End(); // End of "Performance##performance"
|
||||||
|
|
||||||
|
// Pop the style var
|
||||||
ImGui::PopStyleVar();
|
ImGui::PopStyleVar();
|
||||||
}
|
}
|
||||||
|
@ -8,6 +8,8 @@
|
|||||||
#include <glm/gtc/type_ptr.hpp>
|
#include <glm/gtc/type_ptr.hpp>
|
||||||
#include "imgui.h"
|
#include "imgui.h"
|
||||||
|
|
||||||
|
#include "Engine/Settings.h"
|
||||||
|
|
||||||
#include "gcml.h"
|
#include "gcml.h"
|
||||||
|
|
||||||
#include "Componenets/GameObject.h"
|
#include "Componenets/GameObject.h"
|
||||||
@ -28,12 +30,126 @@ extern std::vector<std::shared_ptr<GameObject>> g_GameObjects;
|
|||||||
|
|
||||||
// Extern reference to our global (or extern) asset manager
|
// Extern reference to our global (or extern) asset manager
|
||||||
extern AssetManager g_AssetManager;
|
extern AssetManager g_AssetManager;
|
||||||
|
extern Settings g_SettingsManager;
|
||||||
|
|
||||||
extern std::shared_ptr<CameraComponent> g_RuntimeCameraObject;
|
extern std::shared_ptr<CameraComponent> g_RuntimeCameraObject;
|
||||||
|
|
||||||
extern int g_GPU_Triangles_drawn_to_screen;
|
extern int g_GPU_Triangles_drawn_to_screen;
|
||||||
extern int g_GPU_Draw_Calls;
|
extern int g_GPU_Draw_Calls;
|
||||||
|
|
||||||
|
extern bool DrawBBBO;
|
||||||
|
|
||||||
|
// Simple container for six planes
|
||||||
|
struct FrustumPlanes
|
||||||
|
{
|
||||||
|
glm::vec4 planes[6]; // Each plane is (A,B,C,D)
|
||||||
|
};
|
||||||
|
|
||||||
|
// Extract 6 planes from the combined view-projection matrix
|
||||||
|
inline FrustumPlanes ExtractFrustumPlanes(const glm::mat4 &vp)
|
||||||
|
{
|
||||||
|
FrustumPlanes frustum;
|
||||||
|
|
||||||
|
// Left
|
||||||
|
frustum.planes[0] = glm::vec4(
|
||||||
|
vp[0][3] + vp[0][0],
|
||||||
|
vp[1][3] + vp[1][0],
|
||||||
|
vp[2][3] + vp[2][0],
|
||||||
|
vp[3][3] + vp[3][0]);
|
||||||
|
|
||||||
|
// Right
|
||||||
|
frustum.planes[1] = glm::vec4(
|
||||||
|
vp[0][3] - vp[0][0],
|
||||||
|
vp[1][3] - vp[1][0],
|
||||||
|
vp[2][3] - vp[2][0],
|
||||||
|
vp[3][3] - vp[3][0]);
|
||||||
|
|
||||||
|
// Bottom
|
||||||
|
frustum.planes[2] = glm::vec4(
|
||||||
|
vp[0][3] + vp[0][1],
|
||||||
|
vp[1][3] + vp[1][1],
|
||||||
|
vp[2][3] + vp[2][1],
|
||||||
|
vp[3][3] + vp[3][1]);
|
||||||
|
|
||||||
|
// Top
|
||||||
|
frustum.planes[3] = glm::vec4(
|
||||||
|
vp[0][3] - vp[0][1],
|
||||||
|
vp[1][3] - vp[1][1],
|
||||||
|
vp[2][3] - vp[2][1],
|
||||||
|
vp[3][3] - vp[3][1]);
|
||||||
|
|
||||||
|
// Near
|
||||||
|
frustum.planes[4] = glm::vec4(
|
||||||
|
vp[0][3] + vp[0][2],
|
||||||
|
vp[1][3] + vp[1][2],
|
||||||
|
vp[2][3] + vp[2][2],
|
||||||
|
vp[3][3] + vp[3][2]);
|
||||||
|
|
||||||
|
// Far
|
||||||
|
frustum.planes[5] = glm::vec4(
|
||||||
|
vp[0][3] - vp[0][2],
|
||||||
|
vp[1][3] - vp[1][2],
|
||||||
|
vp[2][3] - vp[2][2],
|
||||||
|
vp[3][3] - vp[3][2]);
|
||||||
|
|
||||||
|
// Normalize planes (optional but recommended)
|
||||||
|
for (int i = 0; i < 6; i++)
|
||||||
|
{
|
||||||
|
float length = glm::length(glm::vec3(
|
||||||
|
frustum.planes[i].x,
|
||||||
|
frustum.planes[i].y,
|
||||||
|
frustum.planes[i].z));
|
||||||
|
if (length > 0.0f)
|
||||||
|
{
|
||||||
|
frustum.planes[i] /= length;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return frustum;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool IsBoxInFrustum(const glm::vec3 &bmin,
|
||||||
|
const glm::vec3 &bmax,
|
||||||
|
const FrustumPlanes &frustum)
|
||||||
|
{
|
||||||
|
// Build the 8 corners in world space
|
||||||
|
// (We assume bmin/bmax are already in world space.)
|
||||||
|
std::array<glm::vec3, 8> corners = {
|
||||||
|
glm::vec3(bmin.x, bmin.y, bmin.z),
|
||||||
|
glm::vec3(bmin.x, bmin.y, bmax.z),
|
||||||
|
glm::vec3(bmin.x, bmax.y, bmin.z),
|
||||||
|
glm::vec3(bmin.x, bmax.y, bmax.z),
|
||||||
|
glm::vec3(bmax.x, bmin.y, bmin.z),
|
||||||
|
glm::vec3(bmax.x, bmin.y, bmax.z),
|
||||||
|
glm::vec3(bmax.x, bmax.y, bmin.z),
|
||||||
|
glm::vec3(bmax.x, bmax.y, bmax.z)};
|
||||||
|
|
||||||
|
// For each plane, check if all corners are behind it.
|
||||||
|
// If yes => box is completely outside.
|
||||||
|
for (int p = 0; p < 6; p++)
|
||||||
|
{
|
||||||
|
const glm::vec4 &plane = frustum.planes[p];
|
||||||
|
int outCount = 0;
|
||||||
|
|
||||||
|
for (const auto &corner : corners)
|
||||||
|
{
|
||||||
|
// Plane eq: A*x + B*y + C*z + D
|
||||||
|
float distance = plane.x * corner.x +
|
||||||
|
plane.y * corner.y +
|
||||||
|
plane.z * corner.z +
|
||||||
|
plane.w;
|
||||||
|
|
||||||
|
if (distance < 0.0f)
|
||||||
|
outCount++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If all corners are 'behind' the plane, box is outside
|
||||||
|
if (outCount == 8)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// Otherwise, it's at least partially inside
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
bool PlayPauseButton(const char *label, bool *isPlaying, ImVec2 Size)
|
bool PlayPauseButton(const char *label, bool *isPlaying, ImVec2 Size)
|
||||||
{
|
{
|
||||||
@ -167,6 +283,17 @@ void RenderWindow::InitGLResources()
|
|||||||
m_ShaderPtr = shaderAsset.get();
|
m_ShaderPtr = shaderAsset.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
std::shared_ptr<Shader> shaderAsset = g_AssetManager.loadAsset<Shader>(AssetType::SHADER, "assets/shaders/Line");
|
||||||
|
if (!shaderAsset)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "[RenderWindow] Failed to load shader via AssetManager.\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Cast back to your Shader class
|
||||||
|
m_LineShaderPtr = shaderAsset.get();
|
||||||
|
}
|
||||||
|
|
||||||
// ----------------------------------------------------
|
// ----------------------------------------------------
|
||||||
// 3) Load TEXTURE from the asset manager
|
// 3) Load TEXTURE from the asset manager
|
||||||
// ----------------------------------------------------
|
// ----------------------------------------------------
|
||||||
@ -205,12 +332,11 @@ void CheckOpenGLError(const std::string &location)
|
|||||||
|
|
||||||
#include <glm/gtc/type_ptr.hpp> // For glm::value_ptr
|
#include <glm/gtc/type_ptr.hpp> // For glm::value_ptr
|
||||||
#include <algorithm> // Ensure <algorithm> is included
|
#include <algorithm> // Ensure <algorithm> is included
|
||||||
|
|
||||||
void RenderWindow::RenderSceneToFBO(bool *GameRunning)
|
void RenderWindow::RenderSceneToFBO(bool *GameRunning)
|
||||||
{
|
{
|
||||||
m_RotationAngle += 0.001f; // Spin per frame
|
m_RotationAngle += 0.001f; // Spin per frame
|
||||||
|
|
||||||
// Bind the FBO
|
// 1) Bind the FBO and set up viewport
|
||||||
m_FBO.Bind();
|
m_FBO.Bind();
|
||||||
glViewport(0, 0, m_LastWidth, m_LastHeight);
|
glViewport(0, 0, m_LastWidth, m_LastHeight);
|
||||||
|
|
||||||
@ -224,135 +350,188 @@ void RenderWindow::RenderSceneToFBO(bool *GameRunning)
|
|||||||
glClearColor(0.f, 0.f, 0.f, 1.f);
|
glClearColor(0.f, 0.f, 0.f, 1.f);
|
||||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||||
|
|
||||||
// Use our loaded shader
|
// 2) Check our main rendering shader
|
||||||
if (!m_ShaderPtr)
|
if (!m_ShaderPtr)
|
||||||
{
|
{
|
||||||
DEBUG_PRINT("[RenderWindow] Shader pointer is null. Cannot render.");
|
DEBUG_PRINT("[RenderWindow] Shader pointer is null. Cannot render.");
|
||||||
m_FBO.Unbind();
|
m_FBO.Unbind();
|
||||||
return; // Can't render without a shader
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_ShaderPtr->Use();
|
m_ShaderPtr->Use();
|
||||||
|
|
||||||
// Define view and projection matrices once
|
// 3) Obtain view/projection from the active camera (or fallback)
|
||||||
std::shared_ptr<CameraComponent> activeCamera = nullptr;
|
std::shared_ptr<CameraComponent> activeCamera = nullptr;
|
||||||
|
glm::mat4 view, proj;
|
||||||
glm::mat4 view;
|
|
||||||
glm::mat4 proj;
|
|
||||||
|
|
||||||
if (*GameRunning && g_RuntimeCameraObject)
|
if (*GameRunning && g_RuntimeCameraObject)
|
||||||
{
|
{
|
||||||
activeCamera = g_RuntimeCameraObject;
|
activeCamera = g_RuntimeCameraObject;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ensure that an active camera is available
|
|
||||||
if (activeCamera)
|
if (activeCamera)
|
||||||
{
|
{
|
||||||
// Obtain view and projection matrices from the active camera
|
|
||||||
view = activeCamera->GetViewMatrix();
|
view = activeCamera->GetViewMatrix();
|
||||||
proj = activeCamera->GetProjectionMatrix();
|
proj = activeCamera->GetProjectionMatrix();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Fallback to default view and projection if no camera is available
|
// Fallback if no camera
|
||||||
view = glm::translate(glm::mat4(1.f), glm::vec3(0.f, 0.f, -5.f));
|
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;
|
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);
|
proj = glm::perspective(glm::radians(CAM_FOV), aspect, CAM_NEAR_PLAIN, CAM_FAR_PLAIN);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Iterate over each GameObject and render it
|
// 4) Extract frustum planes for culling
|
||||||
|
glm::mat4 vp = proj * view;
|
||||||
|
FrustumPlanes frustum = ExtractFrustumPlanes(vp);
|
||||||
|
|
||||||
|
// 5) Iterate over each GameObject and render
|
||||||
|
glm::vec4 LineColor = g_SettingsManager.S_LineColor;
|
||||||
|
|
||||||
for (auto &obj : g_GameObjects)
|
for (auto &obj : g_GameObjects)
|
||||||
{
|
{
|
||||||
glm::mat4 model = glm::mat4(1.f);
|
glm::mat4 model = glm::mat4(1.f);
|
||||||
|
|
||||||
std::shared_ptr<TransformComponent> transform = obj->GetComponent<TransformComponent>();
|
auto transform = obj->GetComponent<TransformComponent>();
|
||||||
std::shared_ptr<MeshComponent> mesh = obj->GetComponent<MeshComponent>();
|
auto mesh = obj->GetComponent<MeshComponent>();
|
||||||
|
|
||||||
if (transform && mesh && mesh)
|
if (transform && mesh)
|
||||||
{
|
{
|
||||||
// Apply transformations
|
// 5A) Build the Model matrix
|
||||||
model = glm::translate(model, transform->position);
|
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.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.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::rotate(model, glm::radians(transform->rotation.z), glm::vec3(0.f, 0.f, 1.f));
|
||||||
model = glm::scale(model, transform->scale);
|
model = glm::scale(model, transform->scale);
|
||||||
|
|
||||||
// Compute MVP matrix
|
// 5B) For each submesh
|
||||||
glm::mat4 mvp = proj * view * model; // why is this the wrong way?
|
for (auto &submesh : mesh->submeshes)
|
||||||
|
|
||||||
// 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)
|
|
||||||
{
|
{
|
||||||
// Validate VAO
|
// Check if VAO is valid
|
||||||
if (submesh.vao == 0)
|
if (submesh.vao == 0)
|
||||||
{
|
{
|
||||||
DEBUG_PRINT("[RenderWindow] Warning: Submesh VAO is not initialized.");
|
DEBUG_PRINT("[RenderWindow] Warning: Submesh VAO is not initialized.");
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update triangle count
|
// -------------------------
|
||||||
|
// *** FRUSTUM CULLING ***
|
||||||
|
// Transform submesh bounding box from local -> world space
|
||||||
|
glm::vec3 worldMin(FLT_MAX), worldMax(-FLT_MAX);
|
||||||
|
std::array<glm::vec3, 8> corners = {
|
||||||
|
glm::vec3(submesh.minExtents.x, submesh.minExtents.y, submesh.minExtents.z),
|
||||||
|
glm::vec3(submesh.minExtents.x, submesh.minExtents.y, submesh.maxExtents.z),
|
||||||
|
glm::vec3(submesh.minExtents.x, submesh.maxExtents.y, submesh.minExtents.z),
|
||||||
|
glm::vec3(submesh.minExtents.x, submesh.maxExtents.y, submesh.maxExtents.z),
|
||||||
|
glm::vec3(submesh.maxExtents.x, submesh.minExtents.y, submesh.minExtents.z),
|
||||||
|
glm::vec3(submesh.maxExtents.x, submesh.minExtents.y, submesh.maxExtents.z),
|
||||||
|
glm::vec3(submesh.maxExtents.x, submesh.maxExtents.y, submesh.minExtents.z),
|
||||||
|
glm::vec3(submesh.maxExtents.x, submesh.maxExtents.y, submesh.maxExtents.z)};
|
||||||
|
|
||||||
|
for (auto &c : corners)
|
||||||
|
{
|
||||||
|
// Transform corner by the model matrix
|
||||||
|
glm::vec4 worldPos = model * glm::vec4(c, 1.0f);
|
||||||
|
|
||||||
|
// Expand worldMin / worldMax
|
||||||
|
worldMin.x = std::min(worldMin.x, worldPos.x);
|
||||||
|
worldMin.y = std::min(worldMin.y, worldPos.y);
|
||||||
|
worldMin.z = std::min(worldMin.z, worldPos.z);
|
||||||
|
|
||||||
|
worldMax.x = std::max(worldMax.x, worldPos.x);
|
||||||
|
worldMax.y = std::max(worldMax.y, worldPos.y);
|
||||||
|
worldMax.z = std::max(worldMax.z, worldPos.z);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now test that box against frustum
|
||||||
|
if (!IsBoxInFrustum(worldMin, worldMax, frustum))
|
||||||
|
{
|
||||||
|
// The submesh is completely outside the camera's view => skip
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// -------------------------
|
||||||
|
|
||||||
|
// 5C) Compute MVP and pass to shader
|
||||||
|
glm::mat4 mvp = vp * model;
|
||||||
|
m_ShaderPtr->SetMat4("uMVP", mvp);
|
||||||
|
m_ShaderPtr->SetMat4("uModel", model);
|
||||||
|
|
||||||
|
// 5D) Update tri count
|
||||||
g_GPU_Triangles_drawn_to_screen += static_cast<int>(submesh.indices.size() / 3);
|
g_GPU_Triangles_drawn_to_screen += static_cast<int>(submesh.indices.size() / 3);
|
||||||
|
|
||||||
// Bind textures for the submesh
|
// 5E) Bind textures
|
||||||
// Assuming the shader has uniform arrays like uTextures.texture_diffuse[32]
|
const int MAX_DIFFUSE = 32;
|
||||||
const int MAX_DIFFUSE = 32; // Must match the shader's MAX_DIFFUSE
|
|
||||||
int textureUnit = 0;
|
int textureUnit = 0;
|
||||||
|
for (auto &texture : submesh.textures)
|
||||||
// Iterate through all textures and bind those with type "texture_diffuse"
|
|
||||||
for (const auto &texture : submesh.textures)
|
|
||||||
{
|
{
|
||||||
if (texture.type == "texture_diffuse")
|
if (texture.type == "texture_diffuse")
|
||||||
{
|
{
|
||||||
if (textureUnit >= MAX_DIFFUSE)
|
if (textureUnit >= MAX_DIFFUSE)
|
||||||
{
|
{
|
||||||
DEBUG_PRINT("[RenderWindow] Warning: Exceeded maximum number of diffuse textures (%d) for shader.", MAX_DIFFUSE);
|
DEBUG_PRINT("[RenderWindow] Warning: Exceeded maximum diffuse textures.");
|
||||||
break; // Prevent exceeding the array bounds in the shader
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Activate the appropriate texture unit
|
|
||||||
glActiveTexture(GL_TEXTURE0 + textureUnit);
|
glActiveTexture(GL_TEXTURE0 + textureUnit);
|
||||||
glBindTexture(GL_TEXTURE_2D, texture.id);
|
glBindTexture(GL_TEXTURE_2D, texture.id);
|
||||||
|
|
||||||
// Construct the uniform name dynamically (e.g., "uTextures.texture_diffuse[0]")
|
|
||||||
std::string uniformName = "uTextures.texture_diffuse[" + std::to_string(textureUnit) + "]";
|
std::string uniformName = "uTextures.texture_diffuse[" + std::to_string(textureUnit) + "]";
|
||||||
m_ShaderPtr->SetInt(uniformName, textureUnit);
|
m_ShaderPtr->SetInt(uniformName, textureUnit);
|
||||||
|
|
||||||
textureUnit++;
|
textureUnit++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// Assign default texture to unused slots
|
||||||
// Assign default texture to unused texture slots to prevent shader errors
|
|
||||||
for (int i = textureUnit; i < MAX_DIFFUSE; ++i)
|
for (int i = textureUnit; i < MAX_DIFFUSE; ++i)
|
||||||
{
|
{
|
||||||
std::string uniformName = "uTextures.texture_diffuse[" + std::to_string(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);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set the number of active diffuse textures
|
|
||||||
m_ShaderPtr->SetInt("uNumDiffuseTextures", textureUnit);
|
m_ShaderPtr->SetInt("uNumDiffuseTextures", textureUnit);
|
||||||
|
|
||||||
// Draw the submesh
|
// 5F) Draw submesh (filled)
|
||||||
glBindVertexArray(submesh.vao);
|
glBindVertexArray(submesh.vao);
|
||||||
glDrawElements(GL_TRIANGLES, static_cast<GLsizei>(submesh.indices.size()), GL_UNSIGNED_INT, nullptr);
|
glDrawElements(GL_TRIANGLES,
|
||||||
g_GPU_Draw_Calls += 1;
|
static_cast<GLsizei>(submesh.indices.size()),
|
||||||
|
GL_UNSIGNED_INT,
|
||||||
|
nullptr);
|
||||||
|
g_GPU_Draw_Calls++;
|
||||||
glBindVertexArray(0);
|
glBindVertexArray(0);
|
||||||
|
|
||||||
// Reset active texture to default
|
|
||||||
glActiveTexture(GL_TEXTURE0);
|
glActiveTexture(GL_TEXTURE0);
|
||||||
|
|
||||||
|
// ----------------------------------------
|
||||||
|
// 5G) OPTIONAL: Draw a bounding box outline
|
||||||
|
// ----------------------------------------
|
||||||
|
if (DrawBBBO && m_LineShaderPtr && submesh.bboxVAO != 0)
|
||||||
|
{
|
||||||
|
// Use a simpler line shader that doesn't rely on textures
|
||||||
|
m_LineShaderPtr->Use();
|
||||||
|
|
||||||
|
// Recompute the MVP for the bounding box (same model, same vp)
|
||||||
|
glm::mat4 bboxMVP = vp * model;
|
||||||
|
m_LineShaderPtr->SetMat4("uMVP", bboxMVP);
|
||||||
|
m_LineShaderPtr->SetVec4("uColor", LineColor);
|
||||||
|
glLineWidth(2.0f);
|
||||||
|
|
||||||
|
// If your line shader has a uniform color:
|
||||||
|
// m_LineShaderPtr->SetVec4("uColor", glm::vec4(1,1,0,1)); // e.g., yellow
|
||||||
|
|
||||||
|
// Draw the bounding box in wireframe lines
|
||||||
|
glBindVertexArray(submesh.bboxVAO);
|
||||||
|
// We assume submesh.bboxVertexCount is the number of line-vertices
|
||||||
|
glDrawArrays(GL_LINES, 0, submesh.bboxVertexCount);
|
||||||
|
|
||||||
|
glBindVertexArray(0);
|
||||||
|
glUseProgram(0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#if TRANSPERANCY
|
#if TRANSPERANCY
|
||||||
|
|
||||||
glDisable(GL_BLEND);
|
glDisable(GL_BLEND);
|
||||||
#endif
|
#endif
|
||||||
glUseProgram(0);
|
glUseProgram(0);
|
||||||
|
|
||||||
// Unbind the FBO
|
// 6) Unbind the FBO
|
||||||
m_FBO.Unbind();
|
m_FBO.Unbind();
|
||||||
}
|
}
|
||||||
|
@ -35,4 +35,13 @@ private:
|
|||||||
|
|
||||||
// The loaded shader program (via AssetManager)
|
// The loaded shader program (via AssetManager)
|
||||||
Shader* m_ShaderPtr = nullptr;
|
Shader* m_ShaderPtr = nullptr;
|
||||||
|
Shader* m_LineShaderPtr = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
struct Ray
|
||||||
|
{
|
||||||
|
glm::vec3 origin;
|
||||||
|
glm::vec3 direction; // Should be normalized
|
||||||
|
};
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user