Converted Gameobjects and componenets to Classes, added texture and mesh inspectors

This commit is contained in:
OusmBlueNinja 2024-12-26 19:34:34 -06:00
parent d71876544a
commit 9ad51f97b7
17 changed files with 1010 additions and 460 deletions

View File

@ -2,7 +2,7 @@
# Compiler and Flags
CXX := g++
CXXFLAGS := -Wall -Wextra -std=c++17 -g
CXXFLAGS := -Wall -Wextra -std=c++17 -g -DDEBUG
# Directories
SRC_DIR := src
@ -11,7 +11,7 @@ BUILD_DIR := build
# Include Directories
GLFW_INCLUDE := C:/libraries/glfw/include
INCLUDE_DIRS := $(SRC_DIR) $(VENDOR_DIRS) $(GLFW_INCLUDE) vendor/stb/include
INCLUDE_DIRS := $(SRC_DIR) $(VENDOR_DIRS) $(GLFW_INCLUDE) vendor/stb/include C:\msys64\mingw64\include
INCLUDE_DIRS := $(SRC_DIR) $(VENDOR_DIRS) $(GLFW_INCLUDE) vendor/gcml
INCLUDES := $(addprefix -I, $(INCLUDE_DIRS))
@ -43,7 +43,7 @@ OBJ_FILES := $(patsubst %.cpp, $(BUILD_DIR)/%.o, $(ALL_SRC))
TARGET := TesseractEngine.exe
# Libraries
LIBS := -LC:/libraries/glfw/lib -lglfw3 -lopengl32 -lgdi32 -limm32 -lole32 -loleaut32 -luuid -lwinmm -lglew32 -lglu32
LIBS := -LC:/libraries/glfw/lib -lglfw3 -lopengl32 -lgdi32 -limm32 -lole32 -loleaut32 -luuid -lwinmm -lglew32 -lglu32 -lyaml-cpp
# Phony Targets
.PHONY: all clean copy_assets

View File

@ -10,7 +10,7 @@ Collapsed=0
[Window][Inspector]
Pos=1588,27
Size=324,772
Size=324,587
Collapsed=0
DockId=0x00000005,0
@ -21,8 +21,8 @@ Collapsed=0
DockId=0x00000003,0
[Window][Performance]
Pos=1588,801
Size=324,368
Pos=1588,616
Size=324,553
Collapsed=0
DockId=0x00000006,0
@ -54,6 +54,6 @@ DockSpace ID=0x14621557 Window=0x3DA2F1DE Pos=8,27 Size=1904,1142 Split=
DockNode ID=0x00000003 Parent=0x00000001 SizeRef=1578,770 CentralNode=1 HiddenTabBar=1 Selected=0xF7365A5A
DockNode ID=0x00000004 Parent=0x00000001 SizeRef=1578,370 HiddenTabBar=1 Selected=0x9DD4E196
DockNode ID=0x00000002 Parent=0x00000008 SizeRef=324,1142 Split=Y Selected=0x36DC96AB
DockNode ID=0x00000005 Parent=0x00000002 SizeRef=324,772 HiddenTabBar=1 Selected=0x36DC96AB
DockNode ID=0x00000006 Parent=0x00000002 SizeRef=324,368 HiddenTabBar=1 Selected=0x726D8899
DockNode ID=0x00000005 Parent=0x00000002 SizeRef=324,587 HiddenTabBar=1 Selected=0x36DC96AB
DockNode ID=0x00000006 Parent=0x00000002 SizeRef=324,553 HiddenTabBar=1 Selected=0x726D8899

View File

@ -1,7 +1,7 @@
#pragma once
#include <string>
//#include <yaml-cpp/yaml.h>
#include <yaml-cpp/yaml.h>
class Component
{
@ -11,6 +11,6 @@ public:
// Serialization methods
//virtual YAML::Node Serialize() = 0;
//virtual void Deserialize(const YAML::Node& node) = 0;
virtual YAML::Node Serialize() = 0;
virtual void Deserialize(const YAML::Node& node) = 0;
};

View File

@ -0,0 +1,99 @@
#include "GameObject.h"
#include "Transform.h"
#include <iostream>
GameObject::GameObject(int id, const std::string &name)
: id(id), name(name)
{
}
int GameObject::GetComponentCount() const
{
return static_cast<int>(components.size());
}
void GameObject::AddComponent(const std::shared_ptr<Component> &component)
{
components[component->GetName()] = component;
//std::cout << "Added " << component->GetName() << std::endl;
}
std::shared_ptr<Component> GameObject::GetComponentByName(const std::string &name) const
{
auto it = components.find(name);
if (it != components.end())
{
return it->second;
}
return nullptr; // Component not found
}
YAML::Node GameObject::Serialize()
{
YAML::Node node;
node["ID"] = id;
node["Name"] = name;
YAML::Node componentsNode;
for (const auto &compPair : components)
{
const std::string &compName = compPair.first;
std::shared_ptr<Component> component = compPair.second;
componentsNode[compName] = component->Serialize();
}
node["Components"] = componentsNode;
return node;
}
void GameObject::Deserialize(const YAML::Node &node)
{
if (node["ID"])
{
id = node["ID"].as<int>();
}
if (node["Name"])
{
name = node["Name"].as<std::string>();
}
if (node["Components"])
{
YAML::Node componentsNode = node["Components"];
for (auto it = componentsNode.begin(); it != componentsNode.end(); ++it)
{
std::string compName = it->first.as<std::string>();
YAML::Node compNode = it->second;
if (compName == TransformComponent::GetStaticName())
{
auto transform = std::make_shared<TransformComponent>();
transform->Deserialize(compNode);
AddComponent(transform);
}
else
{
std::cout << "[Poly] [De/Serialize] [ERROR] Invalid Component Type '" << compName << "' Skipping" << std::endl;
}
// Add deserialization for other components as needed
}
}
}
//}
//else if (compName == MeshComponent::GetStaticName())
//{
// auto render = std::make_shared<MeshComponent>();
// render->Deserialize(compNode);
// AddComponent(render);
//}
//else if (compName == MeshComponent::GetStaticName())
//{
// auto render = std::make_shared<MeshComponent>();
// render->Deserialize(compNode);
// AddComponent(render);

View File

@ -2,14 +2,43 @@
#pragma once
#include <string>
#include <unordered_map>
#include <memory>
#include "Component.h"
#include "Transform.h"
#include "Mesh.h"
#include <yaml-cpp/yaml.h>
struct GameObject
// GetComponent<CameraComponent>()
class GameObject
{
std::string name; // Unique name for the GameObject
Transform transform; // Position, Rotation, Scale
Mesh mesh; // Rendering Mesh
// Add other components as needed
public:
int id;
std::string name;
std::unordered_map<std::string, std::shared_ptr<Component>> components;
int GetComponentCount() const;
GameObject(int id, const std::string &name);
void AddComponent(const std::shared_ptr<Component> &component);
std::shared_ptr<Component> GetComponentByName(const std::string &name) const;
template <typename T>
std::shared_ptr<T> GetComponent()
{
auto it = components.find(T::GetStaticName());
if (it != components.end())
{
return std::dynamic_pointer_cast<T>(it->second);
}
return nullptr;
}
// Serialization methods
YAML::Node Serialize();
void Deserialize(const YAML::Node &node);
};

48
src/Componenets/Mesh.cpp Normal file
View File

@ -0,0 +1,48 @@
#include "Mesh.h"
const std::string MeshComponent::name = "Mesh";
MeshComponent::MeshComponent()
: vao(0), indexCount(0), textureID(0)
{
}
const std::string& MeshComponent::GetName() const
{
return name;
}
const std::string& MeshComponent::GetStaticName()
{
return name;
}
YAML::Node MeshComponent::Serialize()
{
YAML::Node node;
node["vao"] = static_cast<int>(vao);
node["indexCount"] = static_cast<int>(indexCount);
node["textureID"] = static_cast<int>(textureID);
return node;
}
void MeshComponent::Deserialize(const YAML::Node& node)
{
if (node["vao"])
{
vao = static_cast<int>(node["vao"].as<int>());
}
if (node["indexCount"])
{
indexCount = static_cast<int>(node["indexCount"].as<int>());
}
if (node["textureID"])
{
textureID = static_cast<int>(node["textureID"].as<int>());
}
}

View File

@ -1,12 +1,28 @@
// Mesh.h
#pragma once
#include <GL/glew.h>
// A simple mesh storing a VAO, index count, and texture ID
struct Mesh
#include "Component.h"
#include <GL/glew.h>
#include <glm/glm.hpp>
#include <yaml-cpp/yaml.h>
class MeshComponent : public Component
{
public:
GLuint vao = 0; // Vertex Array Object
GLuint indexCount = 0; // Number of indices to draw
GLuint textureID = 0; // The texture handle
};
MeshComponent();
virtual const std::string& GetName() const override;
static const std::string& GetStaticName();
// Serialization methods
virtual YAML::Node Serialize() override;
virtual void Deserialize(const YAML::Node& node) override;
private:
static const std::string name;
};

View File

@ -0,0 +1,82 @@
// TransformComponent.cpp
#include "Transform.h"
const std::string TransformComponent::name = "Transform";
TransformComponent::TransformComponent()
: position(0.0f), rotation(0.0f), scale(1.0f)
{
position = glm::vec3(0.0f, 0.0f, 0.0f);
rotation = glm::vec3(0.0f, 0.0f, 0.0f);
scale = glm::vec3(1.0f, 1.0f, 1.0f);
}
const std::string& TransformComponent::GetName() const
{
return name;
}
const std::string& TransformComponent::GetStaticName()
{
return name;
}
YAML::Node TransformComponent::Serialize()
{
YAML::Node node;
// Position
{
YAML::Node posNode;
posNode.SetStyle(YAML::EmitterStyle::Flow);
posNode.push_back(position.x);
posNode.push_back(position.y);
posNode.push_back(position.z);
node["Position"] = posNode;
}
// Rotation
{
YAML::Node rotNode;
rotNode.SetStyle(YAML::EmitterStyle::Flow);
rotNode.push_back(rotation.x);
rotNode.push_back(rotation.y);
rotNode.push_back(rotation.z);
node["Rotation"] = rotNode;
}
// Scale
{
YAML::Node scaleNode;
scaleNode.SetStyle(YAML::EmitterStyle::Flow);
scaleNode.push_back(scale.x);
scaleNode.push_back(scale.y);
scaleNode.push_back(scale.z);
node["Scale"] = scaleNode;
}
return node;
}
void TransformComponent::Deserialize(const YAML::Node& node)
{
if (node["Position"])
{
auto pos = node["Position"].as<std::vector<float>>();
if (pos.size() == 3)
position = glm::vec3(pos[0], pos[1], pos[2]);
}
if (node["Rotation"])
{
auto rot = node["Rotation"].as<std::vector<float>>();
if (rot.size() == 3)
rotation = glm::vec3(rot[0], rot[1], rot[2]);
}
if (node["Scale"])
{
auto scl = node["Scale"].as<std::vector<float>>();
if (scl.size() == 3)
scale = glm::vec3(scl[0], scl[1], scl[2]);
}
}

View File

@ -1,14 +1,25 @@
// Transform.h
#pragma once
#include "Component.h"
#include <glm/glm.hpp>
#include <yaml-cpp/yaml.h>
// A simple transform with position, rotation, scale
struct Transform
class TransformComponent : public Component
{
glm::vec3 position {0.f, 0.f, 0.f};
glm::vec3 rotation {0.f, 0.f, 0.f}; // Euler angles, in degrees or radians
glm::vec3 scale {1.f, 1.f, 1.f};
public:
glm::vec3 position;
glm::vec3 rotation;
glm::vec3 scale;
TransformComponent();
virtual const std::string& GetName() const override;
static const std::string& GetStaticName();
// Serialization methods
virtual YAML::Node Serialize() override;
virtual void Deserialize(const YAML::Node& node) override;
private:
static const std::string name;
};

View File

@ -1,7 +1,5 @@
// src/Engine.cpp
// Settings
#define VSync 1
@ -11,6 +9,7 @@
#include <chrono>
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include <string>
// Dear ImGui
#include "imgui.h"
@ -23,36 +22,25 @@
#include "Windows/InspectorWindow.h"
#include "Windows/SceneWindow.h"
#include "Engine/ThemeManager.h"
#define YAML_CPP_STATIC_DEFINE
// #define YAML_CPP_STATIC_DEFINE
#include <yaml-cpp/yaml.h>
#include "TestModel.h"
AssetManager g_AssetManager;
LoggerWindow *g_LoggerWindow;
std::vector<GameObject> g_GameObjects;
std::vector<std::shared_ptr<GameObject>> g_GameObjects;
GameObject* g_SelectedObject; // Pointer to the currently selected object
int g_GPU_Triangles_drawn_to_screen = 0;
GameObject *g_SelectedObject; // Pointer to the currently selected object
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");
// ------------------------------------------
@ -94,7 +82,7 @@ bool MyEngine::Init(int width, int height, const std::string& title)
// ------------------------------------------
IMGUI_CHECKVERSION();
ImGui::CreateContext();
ImGuiIO& io = ImGui::GetIO();
ImGuiIO &io = ImGui::GetIO();
(void)io;
// Enable docking
io.ConfigFlags |= ImGuiConfigFlags_DockingEnable;
@ -104,18 +92,16 @@ bool MyEngine::Init(int width, int height, const std::string& title)
// Style
ImGui::StyleColorsDark();
// Platform/Renderer bindings
ImGui_ImplGlfw_InitForOpenGL(m_Window, true);
ImGui_ImplOpenGL3_Init("#version 330");
// Initialize windows
m_RenderWindow = std::make_unique<RenderWindow>();
m_RenderWindow = std::make_unique<RenderWindow>();
m_PerformanceWindow = std::make_unique<PerformanceWindow>();
m_LoggerWindow = std::make_unique<LoggerWindow>();
m_InspectorWindow = std::make_unique<InspectorWindow>();
m_SceneWindow = std::make_unique<SceneWindow>();
m_LoggerWindow = std::make_unique<LoggerWindow>();
m_InspectorWindow = std::make_unique<InspectorWindow>();
m_SceneWindow = std::make_unique<SceneWindow>();
// Some initial logs
m_LoggerWindow->AddLog("Engine initialized.");
@ -130,36 +116,70 @@ bool MyEngine::Init(int width, int height, const std::string& title)
return true;
}
void MyEngine::Run()
{
DEBUG_PRINT("[START] Engine Run ");
DEBUG_PRINT("Transition to Editor");
// Pseudocode:
GameObject cube;
int newId = g_GameObjects.size();
auto newGameObject = std::make_shared<GameObject>(newId, ("Default"));
cube.name = std::string("Default");
cube.transform.position = glm::vec3(0.f, 0.f, 0.f);
cube.transform.rotation = glm::vec3(0.f, 0.5f, 0.f);
cube.transform.scale = glm::vec3(1.f, 1.f, 1.f);
DEBUG_PRINT("Created Default GameObject");
// Suppose we loaded a VAO, an EBO with 36 indices for the cube,
newGameObject->AddComponent(std::make_shared<TransformComponent>());
newGameObject->AddComponent(std::make_shared<MeshComponent>());
DEBUG_PRINT("Added Componenets");
// Suppose we loaded a VAO, an EBO with 36 indices for the cube,
// and a texture ID from the asset manager
cube.mesh.vao = CreateCubeVAO();
cube.mesh.indexCount = 36;
cube.mesh.textureID = static_cast<GLuint>(reinterpret_cast<uintptr_t>(g_AssetManager.loadAsset(AssetType::TEXTURE, "assets/textures/wood.png")));
auto mesh = newGameObject->GetComponent<MeshComponent>();
auto transform = newGameObject->GetComponent<TransformComponent>();
g_GameObjects.push_back(cube);
DEBUG_PRINT("Got pointers to Componenets");
//printf("%p\n", &g_GameObjects);
if (mesh)
{
// printf("Got Valid Mesh Component\n");
mesh->vao = CreateCubeVAO();
mesh->indexCount = 36;
mesh->textureID = static_cast<GLuint>(reinterpret_cast<uintptr_t>(g_AssetManager.loadAsset(AssetType::TEXTURE, "assets/textures/wood.png")));
}
else
{
DEBUG_PRINT("Could not find Mesh Component\n");
}
if (transform)
{
// printf("Got Valid Transform Component\n");
transform->position = glm::vec3(0.f, 0.f, 0.f);
transform->rotation = glm::vec3(0.f, 0.5f, 0.f);
transform->scale = glm::vec3(1.f, 1.f, 1.f);
}
else
{
DEBUG_PRINT("Could not find Transform Component");
}
g_AssetManager.loadAsset(AssetType::TEXTURE, "assets/textures/bricks.png");
g_AssetManager.loadAsset(AssetType::TEXTURE, "assets/textures/default.png");
g_AssetManager.loadAsset(AssetType::TEXTURE, "assets/textures/lush_grass.png");
g_GameObjects.push_back(newGameObject);
DEBUG_PRINT("Put componenent into Global Componenets Subsystem");
// printf("%p\n", &g_GameObjects);
// Possibly create more GameObjects with different positions or textures
ThemeManager_ChangeTheme(2);
DEBUG_PRINT("Changed Theme to default");
while (!glfwWindowShouldClose(m_Window) && m_Running)
{
// Poll
@ -172,7 +192,7 @@ void MyEngine::Run()
if (delta >= 0.1)
{
m_Fps = (float)(m_FrameCount / delta);
m_Ms = 100.0f / m_Fps;
m_Ms = 100.0f / m_Fps;
m_FrameCount = 0;
m_LastTime = current_time;
}
@ -183,31 +203,31 @@ void MyEngine::Run()
// Show main DockSpace
ShowDockSpace();
m_InspectorWindow->Show();
// Show our windows
m_RenderWindow->Show(); // The spinning triangle as ImGui::Image
m_PerformanceWindow->Show(m_Fps, m_Ms); // FPS & ms
m_LoggerWindow->Show(); // Logs
m_RenderWindow->Show(); // The spinning triangle as ImGui::Image
m_PerformanceWindow->Show(m_Fps, m_Ms); // FPS & ms
m_LoggerWindow->Show(); // Logs
m_SceneWindow->Show();
// After rendering
m_PerformanceWindow->UpdatePerformanceStats(-1, -1);
m_PerformanceWindow->UpdatePerformanceStats(-1, g_GPU_Triangles_drawn_to_screen);
// End frame
EndFrame();
}
DEBUG_PRINT("[OK] Engine Run ");
}
void MyEngine::Cleanup()
{
DEBUG_PRINT("[START] Engine Cleanup ");
// ImGui cleanup
ImGui_ImplOpenGL3_Shutdown();
ImGui_ImplGlfw_Shutdown();
@ -223,7 +243,6 @@ void MyEngine::Cleanup()
m_Running = false;
DEBUG_PRINT("[OK] Engine Cleanup ");
}
void MyEngine::BeginFrame()
@ -250,10 +269,10 @@ void MyEngine::EndFrame()
ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
// (Optional) handle multi-viewport
ImGuiIO& io = ImGui::GetIO();
ImGuiIO &io = ImGui::GetIO();
if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
{
GLFWwindow* backup_current_context = glfwGetCurrentContext();
GLFWwindow *backup_current_context = glfwGetCurrentContext();
ImGui::UpdatePlatformWindows();
ImGui::RenderPlatformWindowsDefault();
glfwMakeContextCurrent(backup_current_context);
@ -267,31 +286,28 @@ void MyEngine::ShowDockSpace()
{
static bool dockspaceOpen = true;
static bool opt_fullscreen = true;
static ImGuiDockNodeFlags dockspace_flags = ImGuiDockNodeFlags_None;
// Initialize dockspace_flags without ImGuiDockNodeFlags_DockSpace
static ImGuiDockNodeFlags dockspace_flags = ImGuiDockNodeFlags_PassthruCentralNode;
ImGuiWindowFlags window_flags = ImGuiWindowFlags_MenuBar | ImGuiWindowFlags_NoDocking;
if (opt_fullscreen)
{
ImGuiViewport* viewport = ImGui::GetMainViewport();
ImGuiViewport *viewport = ImGui::GetMainViewport();
ImGui::SetNextWindowPos(viewport->WorkPos);
ImGui::SetNextWindowSize(viewport->WorkSize);
ImGui::SetNextWindowViewport(viewport->ID);
window_flags |= ImGuiWindowFlags_NoTitleBar
| ImGuiWindowFlags_NoCollapse
| ImGuiWindowFlags_NoResize
| ImGuiWindowFlags_NoMove;
window_flags |= ImGuiWindowFlags_NoBringToFrontOnFocus
| ImGuiWindowFlags_NoNavFocus;
window_flags |= ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove;
window_flags |= ImGuiWindowFlags_NoBringToFrontOnFocus | ImGuiWindowFlags_NoNavFocus;
}
// Style
// Style adjustments
ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 0.0f);
ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, 0.0f);
ImGui::Begin("DockSpace", &dockspaceOpen, window_flags);
ImGui::PopStyleVar(2);
// Menu bar example
// Menu bar
if (ImGui::BeginMenuBar())
{
if (ImGui::BeginMenu("File"))
@ -304,9 +320,12 @@ void MyEngine::ShowDockSpace()
}
// DockSpace
ImGuiIO& io = ImGui::GetIO();
ImGuiIO &io = ImGui::GetIO();
if (io.ConfigFlags & ImGuiConfigFlags_DockingEnable)
{
// Optional: Log the flags for debugging
// DEBUG_PRINT("DockSpace Flags: %d", dockspace_flags);
ImGuiID dockspace_id = ImGui::GetID("MyDockSpace");
ImGui::DockSpace(dockspace_id, ImVec2(0.0f, 0.0f), dockspace_flags);
}

View File

@ -18,7 +18,7 @@
#include "TestModel.h"
//#define DEBUG
#include "gcml.h"
// Forward declaration to avoid including GLFW in the header if you prefer

View File

@ -7,10 +7,7 @@
#include <vector>
extern std::vector<GameObject> g_GameObjects;
extern GameObject* g_SelectedObject; // Pointer to the currently selected object
extern GameObject *g_SelectedObject; // Pointer to the currently selected object
void InspectorWindow::Show()
{
@ -22,261 +19,310 @@ void InspectorWindow::Show()
if (ImGui::Begin("Inspector"))
{
// Title label (white text)
ImGui::TextUnformatted("Selected Object Inspector");
ImGui::Separator();
ImGui::Spacing();
// ===========================
// 1) TRANSFORM
// ===========================
// Color the Transform header
ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(1.0f, 1.0f, 0.4f, 1.0f));
bool transformOpen = ImGui::CollapsingHeader("Transform##Main", ImGuiTreeNodeFlags_DefaultOpen);
ImGui::PopStyleColor();
if (transformOpen && g_SelectedObject) //! Funny: I did not put a null check here and it broke everything.
const char *objectName = "No Object Selected";
if (g_SelectedObject)
{
objectName = g_SelectedObject->name.c_str();
ImGui::Text("Editing Object: %s", objectName);
ImGui::Text("Components: %d", g_SelectedObject->GetComponentCount());
Transform* transform = &g_SelectedObject->transform;
if (ImGui::IsItemHovered())
{
ImGui::BeginTooltip();
ImGui::TextUnformatted("Controls the object's Position, Rotation, and Scale.");
ImGui::EndTooltip();
}
// -----------------------------------
// Position
// -----------------------------------
ImGui::TextUnformatted("Position");
ImGui::Spacing();
{
// We'll assign colors for X, Y, Z buttons
// (normal, hovered, active)
static const ImVec4 colX = ImVec4(1.0f, 0.4f, 0.4f, 1.0f);
static const ImVec4 colXHover = ImVec4(1.0f, 0.6f, 0.6f, 1.0f);
static const ImVec4 colXActive = ImVec4(1.0f, 0.2f, 0.2f, 1.0f);
static const ImVec4 colY = ImVec4(0.4f, 1.0f, 0.4f, 1.0f);
static const ImVec4 colYHover = ImVec4(0.6f, 1.0f, 0.6f, 1.0f);
static const ImVec4 colYActive = ImVec4(0.2f, 1.0f, 0.2f, 1.0f);
static const ImVec4 colZ = ImVec4(0.4f, 0.4f, 1.0f, 1.0f);
static const ImVec4 colZHover = ImVec4(0.6f, 0.6f, 1.0f, 1.0f);
static const ImVec4 colZActive = ImVec4(0.2f, 0.2f, 1.0f, 1.0f);
const char *axisNames[3] = {"X", "Y", "Z"};
// We'll reference transform.position here
float *pos = glm::value_ptr(transform->position);
ImGui::PushID("PositionRow");
for (int i = 0; i < 3; i++)
{
// Determine color set
ImVec4 col, colH, colA;
if (i == 0)
{
col = colX;
colH = colXHover;
colA = colXActive;
}
else if (i == 1)
{
col = colY;
colH = colYHover;
colA = colYActive;
}
else
{
col = colZ;
colH = colZHover;
colA = colZActive;
}
// Push color style for button
ImGui::PushStyleColor(ImGuiCol_Button, col);
ImGui::PushStyleColor(ImGuiCol_ButtonHovered, colH);
ImGui::PushStyleColor(ImGuiCol_ButtonActive, colA);
// Small button with the axis name
if (ImGui::Button(axisNames[i], ImVec2(20, 0)))
{
// No action on click, but we have a box with color
}
ImGui::PopStyleColor(3);
ImGui::SameLine();
ImGui::SetNextItemWidth(60.0f);
ImGui::DragFloat((std::string("##Pos") + axisNames[i]).c_str(), &pos[i], 0.1f);
if (i < 2)
ImGui::SameLine(0, 15);
}
ImGui::PopID();
}
ImGui::Spacing();
ImGui::Separator();
// -----------------------------------
// Rotation
// -----------------------------------
ImGui::TextUnformatted("Rotation");
ImGui::Spacing();
// ===========================
// 1) TRANSFORM
// ===========================
// Color the Transform header
ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(1.0f, 1.0f, 0.4f, 1.0f));
bool transformOpen = ImGui::CollapsingHeader("Transform##Main", ImGuiTreeNodeFlags_DefaultOpen);
ImGui::PopStyleColor();
if (transformOpen && g_SelectedObject) //! Funny: I did not put a null check here and it broke everything.
{
// Same approach, but referencing transform.rotation
const char *axisNames[3] = {"X", "Y", "Z"};
float *rot = glm::value_ptr(transform->rotation);
// We can reuse the same color sets
ImGui::PushID("RotationRow");
for (int i = 0; i < 3; i++)
// Transform* transform = &g_SelectedObject->transform;
std::shared_ptr<TransformComponent> transform = g_SelectedObject->GetComponent<TransformComponent>();
// printf("%p\n", &transform);
if (transform)
{
// Decide color sets for X, Y, Z
ImVec4 col, colH, colA;
if (i == 0)
if (ImGui::IsItemHovered())
{
col = ImVec4(1.0f, 0.4f, 0.4f, 1.0f);
colH = ImVec4(1.0f, 0.6f, 0.6f, 1.0f);
colA = ImVec4(1.0f, 0.2f, 0.2f, 1.0f);
}
else if (i == 1)
{
col = ImVec4(0.4f, 1.0f, 0.4f, 1.0f);
colH = ImVec4(0.6f, 1.0f, 0.6f, 1.0f);
colA = ImVec4(0.2f, 1.0f, 0.2f, 1.0f);
}
else
{
col = ImVec4(0.4f, 0.4f, 1.0f, 1.0f);
colH = ImVec4(0.6f, 0.6f, 1.0f, 1.0f);
colA = ImVec4(0.2f, 0.2f, 1.0f, 1.0f);
ImGui::BeginTooltip();
ImGui::TextUnformatted("Controls the object's Position, Rotation, and Scale.");
ImGui::EndTooltip();
}
ImGui::PushStyleColor(ImGuiCol_Button, col);
ImGui::PushStyleColor(ImGuiCol_ButtonHovered, colH);
ImGui::PushStyleColor(ImGuiCol_ButtonActive, colA);
// -----------------------------------
// Position
// -----------------------------------
ImGui::TextUnformatted("Position");
ImGui::Spacing();
if (ImGui::Button(axisNames[i], ImVec2(20, 0)))
{
// No action
// We'll assign colors for X, Y, Z buttons
// (normal, hovered, active)
static const ImVec4 colX = ImVec4(1.0f, 0.4f, 0.4f, 1.0f);
static const ImVec4 colXHover = ImVec4(1.0f, 0.6f, 0.6f, 1.0f);
static const ImVec4 colXActive = ImVec4(1.0f, 0.2f, 0.2f, 1.0f);
static const ImVec4 colY = ImVec4(0.4f, 1.0f, 0.4f, 1.0f);
static const ImVec4 colYHover = ImVec4(0.6f, 1.0f, 0.6f, 1.0f);
static const ImVec4 colYActive = ImVec4(0.2f, 1.0f, 0.2f, 1.0f);
static const ImVec4 colZ = ImVec4(0.4f, 0.4f, 1.0f, 1.0f);
static const ImVec4 colZHover = ImVec4(0.6f, 0.6f, 1.0f, 1.0f);
static const ImVec4 colZActive = ImVec4(0.2f, 0.2f, 1.0f, 1.0f);
const char *axisNames[3] = {"X", "Y", "Z"};
// We'll reference transform.position here
float *pos = glm::value_ptr(transform->position);
ImGui::PushID("PositionRow");
for (int i = 0; i < 3; i++)
{
// Determine color set
ImVec4 col, colH, colA;
if (i == 0)
{
col = colX;
colH = colXHover;
colA = colXActive;
}
else if (i == 1)
{
col = colY;
colH = colYHover;
colA = colYActive;
}
else
{
col = colZ;
colH = colZHover;
colA = colZActive;
}
// Push color style for button
ImGui::PushStyleColor(ImGuiCol_Button, col);
ImGui::PushStyleColor(ImGuiCol_ButtonHovered, colH);
ImGui::PushStyleColor(ImGuiCol_ButtonActive, colA);
// Small button with the axis name
if (ImGui::Button(axisNames[i], ImVec2(20, 0)))
{
// No action on click, but we have a box with color
}
ImGui::PopStyleColor(3);
ImGui::SameLine();
ImGui::SetNextItemWidth(60.0f);
ImGui::DragFloat((std::string("##Pos") + axisNames[i]).c_str(), &pos[i], 0.1f);
if (i < 2)
ImGui::SameLine(0, 15);
}
ImGui::PopID();
}
ImGui::PopStyleColor(3);
ImGui::SameLine();
ImGui::SetNextItemWidth(60.0f);
ImGui::DragFloat((std::string("##Rot") + axisNames[i]).c_str(), &rot[i], 0.1f);
ImGui::Spacing();
ImGui::Separator();
if (i < 2)
ImGui::SameLine(0, 15);
// -----------------------------------
// Rotation
// -----------------------------------
ImGui::TextUnformatted("Rotation");
ImGui::Spacing();
{
// Same approach, but referencing transform.rotation
const char *axisNames[3] = {"X", "Y", "Z"};
float *rot = glm::value_ptr(transform->rotation);
// We can reuse the same color sets
ImGui::PushID("RotationRow");
for (int i = 0; i < 3; i++)
{
// Decide color sets for X, Y, Z
ImVec4 col, colH, colA;
if (i == 0)
{
col = ImVec4(1.0f, 0.4f, 0.4f, 1.0f);
colH = ImVec4(1.0f, 0.6f, 0.6f, 1.0f);
colA = ImVec4(1.0f, 0.2f, 0.2f, 1.0f);
}
else if (i == 1)
{
col = ImVec4(0.4f, 1.0f, 0.4f, 1.0f);
colH = ImVec4(0.6f, 1.0f, 0.6f, 1.0f);
colA = ImVec4(0.2f, 1.0f, 0.2f, 1.0f);
}
else
{
col = ImVec4(0.4f, 0.4f, 1.0f, 1.0f);
colH = ImVec4(0.6f, 0.6f, 1.0f, 1.0f);
colA = ImVec4(0.2f, 0.2f, 1.0f, 1.0f);
}
ImGui::PushStyleColor(ImGuiCol_Button, col);
ImGui::PushStyleColor(ImGuiCol_ButtonHovered, colH);
ImGui::PushStyleColor(ImGuiCol_ButtonActive, colA);
if (ImGui::Button(axisNames[i], ImVec2(20, 0)))
{
// No action
}
ImGui::PopStyleColor(3);
ImGui::SameLine();
ImGui::SetNextItemWidth(60.0f);
ImGui::DragFloat((std::string("##Rot") + axisNames[i]).c_str(), &rot[i], 0.1f);
if (i < 2)
ImGui::SameLine(0, 15);
}
ImGui::PopID();
}
ImGui::Spacing();
ImGui::Separator();
// -----------------------------------
// Scale
// -----------------------------------
ImGui::TextUnformatted("Scale");
ImGui::Spacing();
{
const char *axisNames[3] = {"X", "Y", "Z"};
float *scl = glm::value_ptr(transform->scale);
ImGui::PushID("ScaleRow");
for (int i = 0; i < 3; i++)
{
// same color approach
ImVec4 col, colH, colA;
if (i == 0)
{
col = ImVec4(1.0f, 0.4f, 0.4f, 1.0f);
colH = ImVec4(1.0f, 0.6f, 0.6f, 1.0f);
colA = ImVec4(1.0f, 0.2f, 0.2f, 1.0f);
}
else if (i == 1)
{
col = ImVec4(0.4f, 1.0f, 0.4f, 1.0f);
colH = ImVec4(0.6f, 1.0f, 0.6f, 1.0f);
colA = ImVec4(0.2f, 1.0f, 0.2f, 1.0f);
}
else
{
col = ImVec4(0.4f, 0.4f, 1.0f, 1.0f);
colH = ImVec4(0.6f, 0.6f, 1.0f, 1.0f);
colA = ImVec4(0.2f, 0.2f, 1.0f, 1.0f);
}
ImGui::PushStyleColor(ImGuiCol_Button, col);
ImGui::PushStyleColor(ImGuiCol_ButtonHovered, colH);
ImGui::PushStyleColor(ImGuiCol_ButtonActive, colA);
if (ImGui::Button(axisNames[i], ImVec2(20, 0)))
{
// No action
}
ImGui::PopStyleColor(3);
ImGui::SameLine();
ImGui::SetNextItemWidth(60.0f);
ImGui::DragFloat((std::string("##Scl") + axisNames[i]).c_str(), &scl[i], 0.1f);
if (i < 2)
ImGui::SameLine(0, 15);
}
ImGui::PopID();
}
ImGui::Spacing();
ImGui::Separator();
}
else
{
ImGui::Text("Error, Null Component");
}
ImGui::PopID();
}
ImGui::Spacing();
ImGui::Separator();
// -----------------------------------
// Scale
// -----------------------------------
ImGui::TextUnformatted("Scale");
ImGui::Spacing();
ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(1.0f, 1.0f, 0.4f, 1.0f));
bool meshOpen = ImGui::CollapsingHeader("Mesh##Main", ImGuiTreeNodeFlags_DefaultOpen);
ImGui::PopStyleColor();
if (meshOpen && g_SelectedObject) //! Funny: I did not put a null check here and it broke everything.
{
const char *axisNames[3] = {"X", "Y", "Z"};
float *scl = glm::value_ptr(transform->scale);
ImGui::PushID("ScaleRow");
for (int i = 0; i < 3; i++)
// Transform* transform = &g_SelectedObject->transform;
std::shared_ptr<MeshComponent> mesh = g_SelectedObject->GetComponent<MeshComponent>();
// printf("%p\n", &transform);
if (mesh)
{
// same color approach
ImVec4 col, colH, colA;
if (i == 0)
int vao = static_cast<int>(mesh->vao);
if (ImGui::DragInt("vao", &vao, 1, 0, 1024))
{
col = ImVec4(1.0f, 0.4f, 0.4f, 1.0f);
colH = ImVec4(1.0f, 0.6f, 0.6f, 1.0f);
colA = ImVec4(1.0f, 0.2f, 0.2f, 1.0f);
}
else if (i == 1)
{
col = ImVec4(0.4f, 1.0f, 0.4f, 1.0f);
colH = ImVec4(0.6f, 1.0f, 0.6f, 1.0f);
colA = ImVec4(0.2f, 1.0f, 0.2f, 1.0f);
}
else
{
col = ImVec4(0.4f, 0.4f, 1.0f, 1.0f);
colH = ImVec4(0.6f, 0.6f, 1.0f, 1.0f);
colA = ImVec4(0.2f, 0.2f, 1.0f, 1.0f);
mesh->vao = static_cast<GLuint>(vao);
}
ImGui::PushStyleColor(ImGuiCol_Button, col);
ImGui::PushStyleColor(ImGuiCol_ButtonHovered, colH);
ImGui::PushStyleColor(ImGuiCol_ButtonActive, colA);
if (ImGui::Button(axisNames[i], ImVec2(20, 0)))
int indexCount = static_cast<int>(mesh->indexCount);
if (ImGui::DragInt("indexCount", &indexCount, 1, 0, 1024))
{
// No action
mesh->indexCount = static_cast<GLuint>(indexCount);
}
ImGui::PopStyleColor(3);
ImGui::SameLine();
ImGui::SetNextItemWidth(60.0f);
ImGui::DragFloat((std::string("##Scl") + axisNames[i]).c_str(), &scl[i], 0.1f);
if (i < 2)
ImGui::SameLine(0, 15);
int textureID = static_cast<int>(mesh->textureID);
if (ImGui::DragInt("textureID", &textureID, 1, 0, 1024))
{
mesh->textureID = static_cast<GLuint>(textureID);
}
}
ImGui::PopID();
}
ImGui::Spacing();
ImGui::Separator();
// ===========================
// 2) SCRIPT
// ===========================
// We keep script text in white
// if (ImGui::CollapsingHeader("Script##Main", ImGuiTreeNodeFlags_DefaultOpen))
//{
// if (ImGui::IsItemHovered())
// {
// ImGui::BeginTooltip();
// ImGui::TextUnformatted("Attach a script or logic component here.");
// ImGui::EndTooltip();
// }
// ImGui::TextUnformatted("Script Name:");
// ImGui::SameLine();
// {
// char buffer[128];
// std::snprintf(buffer, sizeof(buffer), "%s", script.scriptName.c_str());
// ImGui::SetNextItemWidth(-1);
// if (ImGui::InputText("##ScriptName", buffer, sizeof(buffer)))
// {
// script.scriptName = buffer;
// }
// }
// ImGui::Spacing();
// ImGui::TextUnformatted("Script Enabled:");
// ImGui::SameLine();
// ImGui::Checkbox("##ScriptEnabled", &script.enabled);
// ImGui::Spacing();
// ImGui::Separator();
//}
}
ImGui::End();
ImGui::Spacing();
// ===========================
// 2) SCRIPT
// ===========================
// We keep script text in white
// if (ImGui::CollapsingHeader("Script##Main", ImGuiTreeNodeFlags_DefaultOpen))
//{
// if (ImGui::IsItemHovered())
// {
// ImGui::BeginTooltip();
// ImGui::TextUnformatted("Attach a script or logic component here.");
// ImGui::EndTooltip();
// }
// ImGui::TextUnformatted("Script Name:");
// ImGui::SameLine();
// {
// char buffer[128];
// std::snprintf(buffer, sizeof(buffer), "%s", script.scriptName.c_str());
// ImGui::SetNextItemWidth(-1);
// if (ImGui::InputText("##ScriptName", buffer, sizeof(buffer)))
// {
// script.scriptName = buffer;
// }
// }
// ImGui::Spacing();
// ImGui::TextUnformatted("Script Enabled:");
// ImGui::SameLine();
// ImGui::Checkbox("##ScriptEnabled", &script.enabled);
// ImGui::Spacing();
// ImGui::Separator();
//}
ImGui::End();
} //
} //
// Restore style
ImGui::PopStyleVar(3);

View File

@ -7,6 +7,7 @@
extern int LoaddedAssets;
extern int g_GPU_Triangles_drawn_to_screen;
// Initialize static members
int PerformanceWindow::m_OpenGLCallCount = 0;
@ -41,6 +42,9 @@ void PerformanceWindow::UpdatePerformanceStats(int newCallCount, int newTriangle
{
m_OpenGLCallCount = newCallCount;
m_TriangleCount = newTriangleCount;
g_GPU_Triangles_drawn_to_screen = 0;
}
void PerformanceWindow::Show(float fps, float ms)
@ -138,14 +142,14 @@ void PerformanceWindow::Show(float fps, float ms)
300.0f,
ImVec2(0, 50));
ImGui::Text("Triangles: %d", m_TriangleCount);
ImGui::PlotHistogram("Triangles",
ImGui::Text("Indices: %d", m_TriangleCount);
ImGui::PlotHistogram("Indices",
s_TriangleHistory,
IM_ARRAYSIZE(s_TriangleHistory),
0,
nullptr,
0.0f,
5000.0f,
m_TriangleCount*2.5,
ImVec2(0, 50));
ImGui::Separator();

View File

@ -8,18 +8,18 @@
#include <glm/gtc/type_ptr.hpp>
#include "imgui.h"
#include "gcml.h"
#include "Componenets/GameObject.h"
#include "Componenets/Mesh.h"
#include "Componenets/Transform.h"
#include "Componenets/mesh.h"
#include "Componenets/transform.h"
extern std::vector<GameObject> g_GameObjects;
#define CAM_FOV 45.0f
#define CAM_NEAR_PLAIN 0.1f
#define CAM_FAR_PLAIN 1000.0f
extern std::vector<std::shared_ptr<GameObject>> g_GameObjects;
#define CAM_FOV 45.0f
#define CAM_NEAR_PLAIN 0.1f
#define CAM_FAR_PLAIN 1000.0f
// Include your AssetManager & Shader headers
#include "Engine/AssetManager.h"
@ -28,64 +28,163 @@ extern std::vector<GameObject> g_GameObjects;
// Extern reference to our global (or extern) asset manager
extern AssetManager g_AssetManager;
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,
{
// 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,
// 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,
// 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,
// 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,
// 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,
// 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,
};
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
};
{
// 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};
void RenderWindow::Show()
{
ImGui::Begin("OpenGL Output");
ImVec2 size = ImGui::GetContentRegionAvail();
@ -98,18 +197,23 @@ void RenderWindow::Show()
m_Initialized = true;
}
// If there's space, render to the FBO, then show it as an ImGui image
if (w > 0 && h > 0)
{
if (w != m_LastWidth || h != m_LastHeight)
{
m_FBO.Create(w, h);
m_LastWidth = w;
m_LastWidth = w;
m_LastHeight = h;
}
RenderSceneToFBO();
ImGui::Image(m_FBO.GetTextureID(), size, ImVec2(0,0), ImVec2(1,1));
ImGui::Image(m_FBO.GetTextureID(), size, ImVec2(0, 0), ImVec2(1, 1));
}
else
{
@ -117,6 +221,7 @@ void RenderWindow::Show()
}
ImGui::End();
}
void RenderWindow::InitGLResources()
@ -124,15 +229,16 @@ void RenderWindow::InitGLResources()
// ----------------------------------------------------
// 1) Load SHADER from the asset manager
// ----------------------------------------------------
{
void* shaderAsset = g_AssetManager.loadAsset(AssetType::SHADER, "assets/shaders/UnlitMaterial");
void *shaderAsset = g_AssetManager.loadAsset(AssetType::SHADER, "assets/shaders/UnlitMaterial");
if (!shaderAsset)
{
fprintf(stderr, "[RenderWindow] Failed to load shader via AssetManager.\n");
return;
}
// Cast back to your Shader class
m_ShaderPtr = static_cast<Shader*>(shaderAsset);
m_ShaderPtr = static_cast<Shader *>(shaderAsset);
}
// ----------------------------------------------------
@ -151,11 +257,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);
@ -164,7 +270,7 @@ void RenderWindow::InitGLResources()
// 3) Load TEXTURE from the asset manager
// ----------------------------------------------------
{
void* texAsset = g_AssetManager.loadAsset(AssetType::TEXTURE, "assets/textures/wood.png");
void *texAsset = g_AssetManager.loadAsset(AssetType::TEXTURE, "assets/textures/wood.png");
if (!texAsset)
{
fprintf(stderr, "[RenderWindow] Failed to load texture.\n");
@ -179,13 +285,15 @@ void RenderWindow::InitGLResources()
// ----------------------------------------------------
// 4) Initialize GameObjects
// ----------------------------------------------------
}
}
void RenderWindow::RenderSceneToFBO()
{
m_RotationAngle += 0.1f; // spin per frame
m_RotationAngle += 0.001f; // spin per frame
// Bind the FBO
m_FBO.Bind();
@ -193,10 +301,11 @@ void RenderWindow::RenderSceneToFBO()
glEnable(GL_DEPTH_TEST);
glClearColor(0.1f, 0.15f, 0.2f, 1.f);
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)
return; // Can't render without a shader
@ -209,50 +318,76 @@ void RenderWindow::RenderSceneToFBO()
glm::mat4 proj = glm::perspective(glm::radians(CAM_FOV), aspect, CAM_NEAR_PLAIN, CAM_FAR_PLAIN);
// Iterate over each GameObject and render it
for (auto& obj : g_GameObjects)
{
for (auto &obj : g_GameObjects)
{
// -----------------------------------
// 1) Build MVP from obj.transform
// 1) Build MVP from transform
// -----------------------------------
glm::mat4 model = glm::mat4(1.f);
// Translate
model = glm::translate(model, obj.transform.position);
// Rotate around X, Y, Z
model = glm::rotate(model, glm::radians(obj.transform.rotation.x), glm::vec3(1.f, 0.f, 0.f));
model = glm::rotate(model, glm::radians(obj.transform.rotation.y), glm::vec3(0.f, 1.f, 0.f));
model = glm::rotate(model, glm::radians(obj.transform.rotation.z), glm::vec3(0.f, 0.f, 1.f));
std::shared_ptr<TransformComponent> transform = obj->GetComponent<TransformComponent>();
// Scale
model = glm::scale(model, obj.transform.scale);
// Compute MVP
glm::mat4 mvp = proj * view * model;
// Pass MVP to the shader
GLint mvpLoc = glGetUniformLocation(programID, "uMVP");
glUniformMatrix4fv(mvpLoc, 1, GL_FALSE, glm::value_ptr(mvp));
std::shared_ptr<MeshComponent> mesh = obj->GetComponent<MeshComponent>();
// -----------------------------------
// 2) Bind the object's texture
// -----------------------------------
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, obj.mesh.textureID);
if (!transform) {
DEBUG_PRINT("Could not find Transform Component");
}
// Set the sampler uniform to texture unit 0
GLint texLoc = glGetUniformLocation(programID, "uTexture");
glUniform1i(texLoc, 0);
// -----------------------------------
// 3) Draw the object's mesh
// -----------------------------------
glBindVertexArray(obj.mesh.vao);
glDrawElements(GL_TRIANGLES, obj.mesh.indexCount, GL_UNSIGNED_INT, nullptr);
if (transform && mesh)
{
// Translate
// Unbind for cleanliness
glBindVertexArray(0);
glBindTexture(GL_TEXTURE_2D, 0);
g_GPU_Triangles_drawn_to_screen = static_cast<int>(mesh->indexCount);
model = glm::translate(model, transform->position);
// Rotate around X, Y, Z
//transform->rotation.x += m_RotationAngle;
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));
// Scale
model = glm::scale(model, transform->scale);
// Compute MVP
glm::mat4 mvp = proj * view * model;
// Pass MVP to the shader
GLint mvpLoc = glGetUniformLocation(programID, "uMVP");
glUniformMatrix4fv(mvpLoc, 1, GL_FALSE, glm::value_ptr(mvp));
// -----------------------------------
// 2) Bind the object's texture
// -----------------------------------
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, mesh->textureID);
// Set the sampler uniform to texture unit 0
GLint texLoc = glGetUniformLocation(programID, "uTexture");
glUniform1i(texLoc, 0);
// -----------------------------------
// 3) Draw the object's mesh
// -----------------------------------
glBindVertexArray(mesh->vao);
glDrawElements(GL_TRIANGLES, mesh->indexCount, GL_UNSIGNED_INT, nullptr);
// Unbind for cleanliness
glBindVertexArray(0);
glBindTexture(GL_TEXTURE_2D, 0);
}
}
// Cleanup

View File

@ -5,35 +5,46 @@
// Include your asset manager and any other necessary headers
#include "Engine/AssetManager.h"
#include "TestModel.h"
#include "gcml.h"
#include <iostream>
// Globals
extern std::vector<GameObject> g_GameObjects;
extern GameObject* g_SelectedObject;
extern std::vector<std::shared_ptr<GameObject>> g_GameObjects;
extern std::shared_ptr<GameObject> g_SelectedObject;
extern AssetManager g_AssetManager;
// Constructor
// Helper: Create a default cube GameObject
GameObject CreateDefaultCube() {
GameObject cube;
cube.name = "Cube";
cube.transform.position = glm::vec3(0.f, 0.f, 0.f);
cube.transform.rotation = glm::vec3(0.f, 0.5f, 0.f);
cube.transform.scale = glm::vec3(1.f, 1.f, 1.f);
cube.mesh.vao = CreateCubeVAO(); // Implement your VAO creation logic
cube.mesh.indexCount = 36;
cube.mesh.textureID = static_cast<unsigned int>(reinterpret_cast<uintptr_t>(g_AssetManager.loadAsset(AssetType::TEXTURE, "assets/textures/wood.png")));
return cube;
std::shared_ptr<GameObject> CreateDefaultCube()
{
// Pseudocode:
int newId = g_GameObjects.size();
auto newGameObject = std::make_shared<GameObject>(newId, ("New GameObject"));
newGameObject->AddComponent(std::make_shared<TransformComponent>()); // Ensure each entity has a TransformComponent by default
newGameObject->AddComponent(std::make_shared<MeshComponent>()); // Ensure each entity has a TransformComponent by default
// Suppose we loaded a VAO, an EBO with 36 indices for the cube,
// and a texture ID from the asset manager
std::shared_ptr<MeshComponent> mesh = newGameObject->GetComponent<MeshComponent>();
mesh->vao = CreateCubeVAO();
mesh->indexCount = 36;
mesh->textureID = static_cast<GLuint>(reinterpret_cast<uintptr_t>(g_AssetManager.loadAsset(AssetType::TEXTURE, "assets/textures/wood.png")));
return newGameObject;
}
// Show function implementation
void SceneWindow::Show() {
if (ImGui::Begin("Scene Window")) {
void SceneWindow::Show()
{
if (ImGui::Begin("Scene Window"))
{
// Add Button
if (ImGui::Button("Add Object")) {
if (ImGui::Button("Add Object"))
{
AddGameObject();
std::cout << "Added a new GameObject. Total objects: " << g_GameObjects.size() << std::endl;
}
ImGui::Separator();
@ -41,25 +52,62 @@ void SceneWindow::Show() {
// Begin child region for the list to make it scrollable
ImGui::BeginChild("GameObjectList", ImVec2(0, -ImGui::GetFrameHeightWithSpacing()), false, ImGuiWindowFlags_HorizontalScrollbar);
// List GameObjects
for (int index = 0; index < static_cast<int>(g_GameObjects.size()); ++index) {
GameObject& obj = g_GameObjects[index];
bool isSelected = (g_SelectedObject == &obj);
// Define TreeNode flags for better visuals and interaction
ImGuiTreeNodeFlags nodeFlags = ImGuiTreeNodeFlags_OpenOnArrow | ImGuiTreeNodeFlags_SpanAvailWidth;
// Create a selectable item for each GameObject
if (ImGui::Selectable(obj.name.c_str(), isSelected)) {
g_SelectedObject = &obj;
// Iterate through GameObjects using index for unique identification
for (size_t i = 0; i < g_GameObjects.size(); ++i)
{
auto &obj = g_GameObjects[i];
// Determine flags based on selection
ImGuiTreeNodeFlags flags = nodeFlags;
if (g_SelectedObject == obj)
flags |= ImGuiTreeNodeFlags_Selected;
// Unique identifier for each GameObject node using pointer to ensure uniqueness
// Alternatively, you can use the object's ID or address
std::string nodeLabel = obj->name;
bool nodeOpen = ImGui::TreeNodeEx((void *)(intptr_t)i, flags, nodeLabel.c_str());
// Handle selection
if (ImGui::IsItemClicked(ImGuiMouseButton_Left))
{
g_SelectedObject = obj;
std::cout << "Selected GameObject: " << obj->name << " with ID: " << obj->id << std::endl;
}
// Right-click context menu to remove GameObject
if (ImGui::BeginPopupContextItem()) {
if (ImGui::MenuItem("Remove")) {
RemoveGameObject(index);
// Right-click context menu for GameObject actions
if (ImGui::BeginPopupContextItem())
{
// Delete GameObject Option
if (ImGui::MenuItem("Remove"))
{
std::cout << "Attempting to remove GameObject: " << obj->name << " with ID: " << obj->id << std::endl;
RemoveGameObject(static_cast<int>(i));
std::cout << "Removed GameObject: " << obj->name << std::endl;
ImGui::EndPopup();
break; // Exit the loop as the list has been modified
// Since we've erased the current entity, adjust the loop accordingly
// Decrement i to account for the removed element
--i;
continue; // Skip the rest of the loop iteration
}
ImGui::EndPopup();
}
// Optionally, implement double-click to rename or perform other actions
// Close the tree node
if (nodeOpen)
{
// If you decide to add child nodes in the future, handle them here
// Currently, no additional handling is required
ImGui::TreePop();
}
}
ImGui::EndChild();
@ -67,14 +115,13 @@ void SceneWindow::Show() {
ImGui::Separator();
// Show currently selected object details at the bottom
if (g_SelectedObject) {
if (g_SelectedObject)
{
ImGui::Text("Selected Object: %s", g_SelectedObject->name.c_str());
// Optionally add details or editable fields here
// Example:
// ImGui::DragFloat3("Position", &g_SelectedObject->transform.position.x, 0.1f);
// ImGui::DragFloat3("Rotation", &g_SelectedObject->transform.rotation.x, 0.1f);
// ImGui::DragFloat3("Scale", &g_SelectedObject->transform.scale.x, 0.1f);
} else {
// Optionally, display more details or provide editing capabilities
}
else
{
ImGui::Text("No Object Selected");
}
}
@ -82,25 +129,38 @@ void SceneWindow::Show() {
}
// AddGameObject: Adds a new GameObject
void SceneWindow::AddGameObject() {
GameObject newObj = CreateDefaultCube();
// Optionally, modify the name to ensure uniqueness
newObj.name += " " + std::to_string(g_GameObjects.size() + 1);
void SceneWindow::AddGameObject()
{
std::shared_ptr<GameObject> newObj = CreateDefaultCube();
// Modify the name to ensure uniqueness
newObj->name += " " + std::to_string(g_GameObjects.size());
g_GameObjects.push_back(newObj);
std::cout << "Added GameObject: " << newObj->name << " with ID: " << newObj->id << std::endl;
}
// RemoveGameObject: Removes a GameObject by index
void SceneWindow::RemoveGameObject(int index) {
if (index >= 0 && index < static_cast<int>(g_GameObjects.size())) {
void SceneWindow::RemoveGameObject(int index)
{
if (index >= 0 && index < static_cast<int>(g_GameObjects.size()))
{
// If the object to be removed is selected, clear the selection
if (g_SelectedObject == &g_GameObjects[index]) {
if (g_SelectedObject == g_GameObjects[index])
{
g_SelectedObject = nullptr;
std::cout << "Cleared selection as the selected GameObject was removed." << std::endl;
}
std::cout << "Removing GameObject: " << g_GameObjects[index]->name << " with ID: " << g_GameObjects[index]->id << std::endl;
g_GameObjects.erase(g_GameObjects.begin() + index);
}
else
{
std::cerr << "Attempted to remove GameObject with invalid index: " << index << std::endl;
}
}
// GetSelectedObject function implementation
GameObject* SceneWindow::GetSelectedObject() const {
std::shared_ptr<GameObject> SceneWindow::GetSelectedObject() const
{
return g_SelectedObject;
}

View File

@ -10,7 +10,7 @@
class SceneWindow {
public:
void Show();
GameObject* GetSelectedObject() const;
std::shared_ptr<GameObject> GetSelectedObject() const;
private:
void AddGameObject(); // Adds a new game object

View File

@ -5,6 +5,7 @@
int main()
{
DEBUG_PRINT("[START] Creating Global Engine ");