diff --git a/$tmpPly.polys b/$tmpPly.polys index 1da24d5..3b259bc 100644 --- a/$tmpPly.polys +++ b/$tmpPly.polys @@ -2,10 +2,6 @@ Entities: - ID: 0 Name: Light Components: - Transform: - Position: [-1.6726234, -0.228918433, 0.638042808] - Rotation: [1.5, 2.70000005, 342.5] - Scale: [1, 1, 1] Light: Type: 0 Intensity: 1 @@ -16,29 +12,37 @@ Entities: cutOff: 0 outerCutOff: 39.7900009 Direction: [-0.200000003, -1, -0.300000012] + Transform: + Position: [-1.6726234, -0.228918433, 0.638042808] + Rotation: [1.5, 2.70000005, 342.5] + Scale: [1, 1, 1] - ID: 1 Name: Cube Components: + Render: + MeshName: model + Color: [1, 1, 1] Transform: Position: [0, 0, 0] Rotation: [0, -166.600006, 0] Scale: [0.100000001, 0.100000001, 0.100000001] - Render: - MeshName: model - Color: [1, 1, 1] - ID: 2 Name: Environment Components: - Render: - MeshName: WhiteCube - Color: [1, 1, 1] Transform: Position: [0, 0, 0] Rotation: [0, 0, 0] Scale: [18.7000008, 7.4000001, 10] + Render: + MeshName: WhiteCube + Color: [1, 1, 1] - ID: 3 Name: LightBlue Components: + Transform: + Position: [0, 1.8090117, 3.07234383] + Rotation: [0, 0, 0] + Scale: [1, 1, 1] Light: Type: 0 Intensity: 2 @@ -49,13 +53,13 @@ Entities: cutOff: 12.5 outerCutOff: 17.5 Direction: [-0.200000003, -1, -0.300000012] - Transform: - Position: [0, 1.8090117, 3.07234383] - Rotation: [0, 0, 0] - Scale: [1, 1, 1] - ID: 4 Name: LightRed Components: + Transform: + Position: [-2.94120026, 1.60229158, -1.5770874] + Rotation: [0, 0, 0] + Scale: [1, 1, 1] Light: Type: 0 Intensity: 1 @@ -66,20 +70,16 @@ Entities: cutOff: 12.5 outerCutOff: 17.5 Direction: [-0.200000003, -1, -0.300000012] - Transform: - Position: [-2.94120026, 1.60229158, -1.5770874] - Rotation: [0, 0, 0] - Scale: [1, 1, 1] - ID: 5 Name: Camera Components: + Transform: + Position: [-4.12095118, 0.57130301, -1.16569459] + Rotation: [0, 106.199997, 0] + Scale: [1, 1, 1] Camera: Zoom: 10 FOV: 45 Orthographic: false NearPlane: 0.100000001 - FarPlane: 1000 - Transform: - Position: [0, 0, 0] - Rotation: [0, 26.2000008, 0] - Scale: [0.100000001, 0.100000001, -0.100000001] \ No newline at end of file + FarPlane: 1000 \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json index e9ff01b..3833b35 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -72,6 +72,10 @@ "mutex": "cpp", "semaphore": "cpp", "stop_token": "cpp", - "thread": "cpp" + "thread": "cpp", + "bitset": "cpp", + "unordered_set": "cpp", + "shared_mutex": "cpp", + "typeindex": "cpp" } } \ No newline at end of file diff --git a/assets/Example_House.polys b/assets/Example_House.polys new file mode 100644 index 0000000..3b259bc --- /dev/null +++ b/assets/Example_House.polys @@ -0,0 +1,85 @@ +Entities: + - ID: 0 + Name: Light + Components: + Light: + Type: 0 + Intensity: 1 + Color: [0, 1, 0] + Constant: 1 + Linear: 0.0900000036 + Quadratic: 0.0320000015 + cutOff: 0 + outerCutOff: 39.7900009 + Direction: [-0.200000003, -1, -0.300000012] + Transform: + Position: [-1.6726234, -0.228918433, 0.638042808] + Rotation: [1.5, 2.70000005, 342.5] + Scale: [1, 1, 1] + - ID: 1 + Name: Cube + Components: + Render: + MeshName: model + Color: [1, 1, 1] + Transform: + Position: [0, 0, 0] + Rotation: [0, -166.600006, 0] + Scale: [0.100000001, 0.100000001, 0.100000001] + - ID: 2 + Name: Environment + Components: + Transform: + Position: [0, 0, 0] + Rotation: [0, 0, 0] + Scale: [18.7000008, 7.4000001, 10] + Render: + MeshName: WhiteCube + Color: [1, 1, 1] + - ID: 3 + Name: LightBlue + Components: + Transform: + Position: [0, 1.8090117, 3.07234383] + Rotation: [0, 0, 0] + Scale: [1, 1, 1] + Light: + Type: 0 + Intensity: 2 + Color: [0, 0, 1] + Constant: 1 + Linear: 0 + Quadratic: 0.200000003 + cutOff: 12.5 + outerCutOff: 17.5 + Direction: [-0.200000003, -1, -0.300000012] + - ID: 4 + Name: LightRed + Components: + Transform: + Position: [-2.94120026, 1.60229158, -1.5770874] + Rotation: [0, 0, 0] + Scale: [1, 1, 1] + Light: + Type: 0 + Intensity: 1 + Color: [1, 0, 0] + Constant: 1 + Linear: 0.0900000036 + Quadratic: 0.0320000015 + cutOff: 12.5 + outerCutOff: 17.5 + Direction: [-0.200000003, -1, -0.300000012] + - ID: 5 + Name: Camera + Components: + Transform: + Position: [-4.12095118, 0.57130301, -1.16569459] + Rotation: [0, 106.199997, 0] + Scale: [1, 1, 1] + Camera: + Zoom: 10 + FOV: 45 + Orthographic: false + NearPlane: 0.100000001 + FarPlane: 1000 \ No newline at end of file diff --git a/assets/White_bookshelf.polys b/assets/White_bookshelf.polys new file mode 100644 index 0000000..836205b --- /dev/null +++ b/assets/White_bookshelf.polys @@ -0,0 +1,62 @@ +Entities: + - ID: 0 + Name: Light + Components: + Light: + Type: 0 + Intensity: 1 + Color: [1, 1, 1] + Constant: 1 + Linear: 0.0900000036 + Quadratic: 0.0320000015 + cutOff: 0 + outerCutOff: 39.7900009 + Direction: [-0.200000003, -1, -0.300000012] + Transform: + Position: [-8.23400021, -0.379575908, 0.520573974] + Rotation: [1.5, 2.70000005, 342.5] + Scale: [1, 1, 1] + - ID: 1 + Name: Cube + Components: + Render: + MeshName: shelf + Color: [1, 1, 1] + Transform: + Position: [-1.21370173, 1.20000005, 0] + Rotation: [1.34287302e-05, -41.9440002, 1.62548586e-05] + Scale: [1, 1, 1] + - ID: 2 + Name: Light + Components: + Transform: + Position: [0, -2.21429968, 4.51696587] + Rotation: [0, 0, 0] + Scale: [1, 1, 1] + Light: + Type: 0 + Intensity: 1 + Color: [1, 1, 1] + Constant: 1 + Linear: 0.0900000036 + Quadratic: 0.0320000015 + cutOff: 12.5 + outerCutOff: 17.5 + Direction: [-0.200000003, -1, -0.300000012] + - ID: 3 + Name: Light + Components: + Transform: + Position: [-4.97912979, 7.21913528, 4.91323614] + Rotation: [0, 0, 0] + Scale: [1, 1, 1] + Light: + Type: 0 + Intensity: 1 + Color: [1, 1, 1] + Constant: 1 + Linear: 0.0900000036 + Quadratic: 0.0320000015 + cutOff: 12.5 + outerCutOff: 17.5 + Direction: [-0.200000003, -1, -0.300000012] \ No newline at end of file diff --git a/assets/wood.png b/assets/wood.png new file mode 100644 index 0000000..143b8a8 Binary files /dev/null and b/assets/wood.png differ diff --git a/build/Entity.o b/build/Entity.o index 83e83c5..e034607 100644 Binary files a/build/Entity.o and b/build/Entity.o differ diff --git a/build/game_engine.exe b/build/game_engine.exe index feb6036..192df87 100644 Binary files a/build/game_engine.exe and b/build/game_engine.exe differ diff --git a/build/main.o b/build/main.o index d017fe1..d4ad90f 100644 Binary files a/build/main.o and b/build/main.o differ diff --git a/images/fileicon.png b/images/fileicon.png new file mode 100644 index 0000000..3d2dda9 Binary files /dev/null and b/images/fileicon.png differ diff --git a/images/objecticon.png b/images/objecticon.png new file mode 100644 index 0000000..a831fcc Binary files /dev/null and b/images/objecticon.png differ diff --git a/images/sceneicon.png b/images/sceneicon.png new file mode 100644 index 0000000..d171d54 Binary files /dev/null and b/images/sceneicon.png differ diff --git a/imgui.ini b/imgui.ini index a450542..9a14dc6 100644 --- a/imgui.ini +++ b/imgui.ini @@ -16,13 +16,13 @@ DockId=0x00000005,0 [Window][Game View] Pos=312,28 -Size=1213,779 +Size=1213,680 Collapsed=0 DockId=0x00000009,0 [Window][Asset Panel] -Pos=8,607 -Size=302,582 +Pos=8,519 +Size=302,670 Collapsed=0 DockId=0x00000008,0 @@ -34,13 +34,13 @@ DockId=0x0000000B,0 [Window][Scene] Pos=8,28 -Size=302,577 +Size=302,489 Collapsed=0 DockId=0x00000007,0 [Window][Info] -Pos=312,809 -Size=1213,380 +Pos=312,710 +Size=1213,479 Collapsed=0 DockId=0x0000000A,0 @@ -59,14 +59,14 @@ DockId=0x00000009,1 [Docking][Data] DockSpace ID=0xC746EC7D Window=0x9DF47A72 Pos=8,28 Size=1904,1161 Split=X Selected=0x642CEEBB DockNode ID=0x00000003 Parent=0xC746EC7D SizeRef=1517,1161 Split=X - DockNode ID=0x00000001 Parent=0x00000003 SizeRef=302,1161 Split=Y Selected=0x9D571615 - DockNode ID=0x00000007 Parent=0x00000001 SizeRef=580,577 Selected=0xE192E354 - DockNode ID=0x00000008 Parent=0x00000001 SizeRef=580,582 Selected=0x9D571615 + DockNode ID=0x00000001 Parent=0x00000003 SizeRef=302,1161 Split=Y Selected=0xE192E354 + DockNode ID=0x00000007 Parent=0x00000001 SizeRef=302,489 Selected=0xE192E354 + DockNode ID=0x00000008 Parent=0x00000001 SizeRef=302,670 Selected=0x9D571615 DockNode ID=0x00000002 Parent=0x00000003 SizeRef=1213,1161 Split=X DockNode ID=0x00000005 Parent=0x00000002 SizeRef=197,1161 Selected=0x4E0EE8E4 DockNode ID=0x00000006 Parent=0x00000002 SizeRef=1035,1161 Split=Y Selected=0x642CEEBB - DockNode ID=0x00000009 Parent=0x00000006 SizeRef=1266,779 CentralNode=1 Selected=0x642CEEBB - DockNode ID=0x0000000A Parent=0x00000006 SizeRef=1266,380 Selected=0xE534E588 + DockNode ID=0x00000009 Parent=0x00000006 SizeRef=1266,680 CentralNode=1 Selected=0x642CEEBB + DockNode ID=0x0000000A Parent=0x00000006 SizeRef=1266,479 Selected=0xE534E588 DockNode ID=0x00000004 Parent=0xC746EC7D SizeRef=385,1161 Split=Y Selected=0xE7039252 DockNode ID=0x0000000B Parent=0x00000004 SizeRef=385,779 Selected=0xE7039252 DockNode ID=0x0000000C Parent=0x00000004 SizeRef=385,380 Selected=0x54723243 diff --git a/scene.polys b/scene.polys index 519187f..d297cf4 100644 --- a/scene.polys +++ b/scene.polys @@ -1,15 +1,59 @@ Entities: - ID: 0 - Name: Entity 0 + Name: Light + Components: + Light: + Type: 0 + Intensity: 1 + Color: [1, 0, 0] + Constant: 1 + Linear: 0.0900000036 + Quadratic: 0.0320000015 + cutOff: 0 + outerCutOff: 39.7900009 + Direction: [-0.200000003, -1, -0.300000012] + Transform: + Position: [-8.23400021, -0.379575908, 0.520573974] + Rotation: [1.5, 2.70000005, 342.5] + Scale: [1, 1, 1] + - ID: 1 + Name: Cube + Components: + Render: + MeshName: shelf + Color: [1, 1, 1] + Transform: + Position: [-1.21370173, 1.20000005, 0] + Rotation: [1.34287302e-05, -41.9440002, 1.62548586e-05] + Scale: [1, 1, 1] + - ID: 2 + Name: Light Components: Transform: - Position: [0, 0, 0] + Position: [0, -2.21429968, 4.51696587] Rotation: [0, 0, 0] Scale: [1, 1, 1] Light: Type: 0 Intensity: 1 - Color: [1, 1, 1] + Color: [0.186046124, 0, 1] + Constant: 1 + Linear: 0.0900000036 + Quadratic: 0.0320000015 + cutOff: 12.5 + outerCutOff: 17.5 + Direction: [-0.200000003, -1, -0.300000012] + - ID: 3 + Name: Light + Components: + Transform: + Position: [-4.97912979, 7.21913528, 4.91323614] + Rotation: [0, 0, 0] + Scale: [1, 1, 1] + Light: + Type: 0 + Intensity: 1 + Color: [0, 1, 0] Constant: 1 Linear: 0.0900000036 Quadratic: 0.0320000015 diff --git a/src/Entity.cpp b/src/Entity.cpp index ff660ee..9e845db 100644 --- a/src/Entity.cpp +++ b/src/Entity.cpp @@ -19,6 +19,19 @@ void Entity::AddComponent(const std::shared_ptr& component) components[component->GetName()] = component; } + + +std::shared_ptr Entity::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 Entity::Serialize() { YAML::Node node; diff --git a/src/Entity.h b/src/Entity.h index bd68036..36300eb 100644 --- a/src/Entity.h +++ b/src/Entity.h @@ -19,6 +19,8 @@ public: Entity(int id, const std::string& name); void AddComponent(const std::shared_ptr& component); + std::shared_ptr GetComponentByName(const std::string& name) const; + template std::shared_ptr GetComponent() diff --git a/src/main.cpp b/src/main.cpp index 4702362..a0958c3 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -44,6 +44,8 @@ const int MAX_SPOT_LIGHTS = 64; #include "imgui.h" +#include "stb/stb_image.h" + // Include ImGui headers #include "imgui_impl_glfw.h" #include "imgui_impl_opengl3.h" @@ -66,6 +68,8 @@ const int MAX_SPOT_LIGHTS = 64; #include #include // For yawPitchRoll in light calculations +#define LOGPOINT(msg) std::cout << "[POLYDBG] [" << __func__ << ":" << __LINE__ << "] " << (msg) << std::endl; + #define MAX_LIGHTS 256 Settings settings; @@ -99,7 +103,7 @@ GLuint framebuffer = 0; GLuint renderedTexture = 0; GLuint depthRenderbuffer = 0; -std::vector> entities; + std::shared_ptr selectedEntity = nullptr; std::shared_ptr selectedAsset = nullptr; @@ -113,6 +117,10 @@ Model ImportedModel; Model ImportedModel_shelf; +ImTextureID fileIconTexture; +ImTextureID sceneIconTexture; +ImTextureID objectIconTexture; + // Function prototypes void RenderCube(glm::mat4 model, glm::mat4 view, glm::mat4 projection, glm::vec3 viewPos, glm::vec3 lightPos); @@ -120,40 +128,105 @@ void ShowEntityComponentTree(std::vector> &entities, std void ShowInspector(std::shared_ptr &selectedEntity); void ShowGameView(std::vector> &entities); -void ShowAssetPanel(const std::filesystem::path &assetsDirectory, std::shared_ptr &selectedAsset); +void ShowAssetPanel(const std::filesystem::path &assetsDirectory, std::shared_ptr &selectedAsset, std::vector>& entities); void ShowCameraComponent(std::shared_ptr entity); void ManipulateEditorCamera(EditorCamera &editorCamera, float aspectRatio); -void ShowCameraPreview(std::vector> &entities); +// Function declarations +GLFWwindow* InitializeGLFW(int width, int height, const std::string& title); +bool InitializeOpenGL(); +bool InitializeShaders(); +bool LoadModels(); +bool SetupCube(); +bool SetupFramebuffer(int width, int height); +bool InitializeImGui(GLFWwindow* window, const char* glsl_version); +void Cleanup(GLFWwindow* window); +void MainLoop(GLFWwindow* window, std::vector>& entities, std::shared_ptr& selectedEntity, std::shared_ptr& selectedAsset, const std::filesystem::path& assetsDir, Settings& settings); + + + + +void Cleanup(GLFWwindow* window) { + LOGPOINT("Remember to add this"); + +//void Cleanup(GLFWwindow* window) +//{ +// // Cleanup ImGui +// ImGui_ImplOpenGL3_Shutdown(); +// ImGui_ImplGlfw_Shutdown(); +// ImGui::DestroyContext(); +// +// // Cleanup OpenGL resources +// if (cubeShader) { delete cubeShader; cubeShader = nullptr; } +// if (gizmoShader) { delete gizmoShader; gizmoShader = nullptr; } +// if (previewShader) { delete previewShader; previewShader = nullptr; } +// if (FrustumShader) { delete FrustumShader; FrustumShader = nullptr; } +// +// if (cubeVAO) { glDeleteVertexArrays(1, &cubeVAO); cubeVAO = 0; } +// if (cubeVBO) { glDeleteBuffers(1, &cubeVBO); cubeVBO = 0; } +// +// if (framebuffer) { glDeleteFramebuffers(1, &framebuffer); framebuffer = 0; } +// if (renderedTexture) { glDeleteTextures(1, &renderedTexture); renderedTexture = 0; } +// if (depthRenderbuffer) { glDeleteRenderbuffers(1, &depthRenderbuffer); depthRenderbuffer = 0; } +// +// // Delete textures +// if (fileIconTexture) { glDeleteTextures(1, &fileIconTexture); fileIconTexture = 0; } +// if (sceneIconTexture) { glDeleteTextures(1, &sceneIconTexture); sceneIconTexture = 0; } +// if (objectIconTexture) { glDeleteTextures(1, &objectIconTexture); objectIconTexture = 0; } +// +// // Destroy window and terminate GLFW +// glfwDestroyWindow(window); +// glfwTerminate(); +//} -// Function to retrieve the active game camera (first CameraComponent found) -std::shared_ptr GetActiveGameCamera(const std::vector> &entities) -{ - for (const auto &entity : entities) - { - auto camera = entity->GetComponent(); - if (camera) - { - return camera; - } - } - return nullptr; // No camera found } -// Helper function to find the entity owning a specific CameraComponent -std::shared_ptr FindEntityWithCamera(const std::vector> &entities, std::shared_ptr camera) + + + + + + +// Function to retrieve the active game camera (first CameraComponent found) +std::shared_ptr GetActiveGameCamera(const std::vector>& entities) { - for (const auto &entity : entities) + auto it = std::find_if(entities.begin(), entities.end(), + [](const std::shared_ptr& entity) { + return entity->GetComponent() != nullptr; + }); + + if (it != entities.end()) { - auto entityCamera = entity->GetComponent(); - if (entityCamera && entityCamera == camera) - { - return entity; - } + return (*it)->GetComponent(); } - return nullptr; // No matching entity found + + // Log a warning if no camera is found + std::cerr << "[Poly] Warning: No active game camera found in the scene." << std::endl; + return nullptr; +} + + + + +// Helper function to find the entity owning a specific CameraComponent +std::shared_ptr FindEntityWithCamera(const std::vector>& entities, const std::shared_ptr& camera) +{ + auto it = std::find_if(entities.begin(), entities.end(), + [&camera](const std::shared_ptr& entity) { + auto entityCamera = entity->GetComponent(); + return entityCamera && entityCamera == camera; + }); + + if (it != entities.end()) + { + return *it; + } + + // Log a warning if no matching entity is found + std::cerr << "[Poly] Warning: No entity found with the specified CameraComponent." << std::endl; + return nullptr; } // Function to open a file dialog and return the selected file path as std::wstring @@ -208,25 +281,76 @@ std::wstring SaveFileDialog(HWND owner = NULL, const std::wstring &defaultFilena return std::wstring(); } -void RenderLightGizmo(glm::vec3 position, glm::mat4 view, glm::mat4 projection) +// Function to load a texture and return it as ImTextureID +ImTextureID LoadTexture(const std::string& filename) { + int width, height, channels; + unsigned char* data = stbi_load(filename.c_str(), &width, &height, &channels, STBI_rgb_alpha); + if (!data) + { + std::cerr << "[Poly] Failed to load texture: " << filename << std::endl; + return 1; + } + + GLuint textureID; + glGenTextures(1, &textureID); + glBindTexture(GL_TEXTURE_2D, textureID); + + // Upload texture data + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data); + + // Generate mipmaps + glGenerateMipmap(GL_TEXTURE_2D); + + // Set texture parameters for wrapping and filtering + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + + // Unbind texture and free image data + glBindTexture(GL_TEXTURE_2D, 0); + stbi_image_free(data); + + // Convert GLuint to ImTextureID safely + return textureID; +} + +// Function to render a light gizmo (small cube) at a specified position +void RenderLightGizmo(const glm::vec3& position, const glm::mat4& view, const glm::mat4& projection) +{ + if (!gizmoShader) + { + std::cerr << "[Poly] Error: Gizmo shader not initialized." << std::endl; + return; + } gizmoShader->Use(); - // Model matrix for the gizmo (small cube at the light's position) - glm::mat4 model = glm::mat4(1.0f); - model = glm::translate(model, position); - model = glm::scale(model, glm::vec3(0.05f)); // Make the gizmo small + // Construct model matrix: translate and scale + glm::mat4 model = glm::translate(glm::mat4(1.0f), position) * + glm::scale(glm::mat4(1.0f), glm::vec3(0.05f)); - // Set uniforms - glUniformMatrix4fv(glGetUniformLocation(gizmoShader->Program, "model"), 1, GL_FALSE, glm::value_ptr(model)); - glUniformMatrix4fv(glGetUniformLocation(gizmoShader->Program, "view"), 1, GL_FALSE, glm::value_ptr(view)); - glUniformMatrix4fv(glGetUniformLocation(gizmoShader->Program, "projection"), 1, GL_FALSE, glm::value_ptr(projection)); + // Set shader uniforms + GLint modelLoc = glGetUniformLocation(gizmoShader->Program, "model"); + GLint viewLoc = glGetUniformLocation(gizmoShader->Program, "view"); + GLint projLoc = glGetUniformLocation(gizmoShader->Program, "projection"); + GLint colorLoc = glGetUniformLocation(gizmoShader->Program, "gizmoColor"); - // Set gizmo color (e.g., yellow) - glUniform3f(glGetUniformLocation(gizmoShader->Program, "gizmoColor"), 1.0f, 1.0f, 0.0f); + if (modelLoc == -1 || viewLoc == -1 || projLoc == -1 || colorLoc == -1) + { + std::cerr << "[Poly] Error: Failed to get uniform locations for RenderLightGizmo." << std::endl; + return; + } - // Draw cube (using the same cube VAO) + glUniformMatrix4fv(modelLoc, 1, GL_FALSE, glm::value_ptr(model)); + glUniformMatrix4fv(viewLoc, 1, GL_FALSE, glm::value_ptr(view)); + glUniformMatrix4fv(projLoc, 1, GL_FALSE, glm::value_ptr(projection)); + + // Set gizmo color to yellow + glUniform3f(colorLoc, 1.0f, 1.0f, 0.0f); + + // Bind the cube VAO and render glBindVertexArray(cubeVAO); glDrawArrays(GL_TRIANGLES, 0, 36); glBindVertexArray(0); @@ -370,6 +494,7 @@ void MouseCallback(GLFWwindow *window, double xpos, double ypos) // Callback for scroll input void ScrollCallback(GLFWwindow *window, double xoffset, double yoffset) { + ImGui_ImplGlfw_ScrollCallback(window, xoffset, yoffset); if (gameWindowFocused) { editorCamera.ProcessMouseScroll(static_cast(yoffset)); @@ -444,218 +569,369 @@ void setupCube(GLfloat *vertices, size_t vertexArraySize, GLuint &cubeVAO, GLuin glBindFramebuffer(GL_FRAMEBUFFER, 0); } + + + + +// Entry point int main() { + // Display Engine Version std::cout << "Poly Engine 3D version " << POLY_VERSION_MAJOR << "." << POLY_VERSION_MINOR << std::endl; std::cout << "[Poly] Initializing..." << std::endl; - std::cout << "[Poly] GLFW " << GLFW_VERSION_MAJOR << "." << GLFW_VERSION_MINOR << std::endl; - // Initialize GLFW - if (!glfwInit()) - return -1; - - // Create GLFW window - glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); - glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); - glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); - GLFWwindow *window = glfwCreateWindow(1280, 720, "Poly Engine", NULL, NULL); - if (window == NULL) + // Initialize GLFW and create window + GLFWwindow* window = InitializeGLFW(1280, 720, "Poly Engine"); + if (!window) { + std::cerr << "[Poly] Failed to initialize GLFW window." << std::endl; + return -1; + } + + // Initialize OpenGL + if (!InitializeOpenGL()) + { + std::cerr << "[Poly] Failed to initialize OpenGL." << std::endl; glfwTerminate(); return -1; } - glfwMakeContextCurrent(window); - glfwSwapInterval(settings.vsyncEnabled); // vsync - - // Initialize GLEW (or any other OpenGL loader) - glewExperimental = GL_TRUE; - if (glewInit() != GLEW_OK) + // Initialize Shaders + if (!InitializeShaders()) { - std::cerr << "Failed to initialize OpenGL loader!" << std::endl; + std::cerr << "[Poly] Failed to initialize shaders." << std::endl; + Cleanup(window); return -1; } - std::cout << "[Poly] Initializing ShaderCore" << std::endl; - - // Load shaders - cubeShader = new Shader("./shaders/vertex_shader.glsl", "./shaders/fragment_shader.glsl"); - gizmoShader = new Shader("./shaders/gizmo_vertex_shader.glsl", "./shaders/gizmo_fragment_shader.glsl"); - // Initialization code (once during setup) - previewShader = new Shader("shaders/preview_vertex.glsl", "shaders/preview_fragment.glsl"); - - - FrustumShader = new Shader("./shaders/cam_vertex.glsl", "./shaders/cam_frag.glsl"); - - std::cout << "[Poly] Initializing ImportedCore" << std::endl; - - if (!ImportedModel.loadFromOBJ("./cottage_obj.obj")) + // Load Models + if (!LoadModels()) { - std::cerr << "Failed to load model!" << std::endl; + std::cerr << "[Poly] Failed to load models." << std::endl; + Cleanup(window); return -1; } - ImportedModel.textureID = ImportedModel.loadTexture("./assets/texture.png"); + // Setup Cube VAO and VBO + if (!SetupCube()) + { + std::cerr << "[Poly] Failed to setup Cube VAO/VBO." << std::endl; + Cleanup(window); + return -1; + } + + // Setup Framebuffer + if (!SetupFramebuffer(680, 700)) + { + std::cerr << "[Poly] Failed to setup framebuffer." << std::endl; + Cleanup(window); + return -1; + } + + // Initialize ImGui + if (!InitializeImGui(window, "#version 330")) + { + std::cerr << "[Poly] Failed to initialize ImGui." << std::endl; + Cleanup(window); + return -1; + } - if (!ImportedModel_shelf.loadFromOBJ("./bookshelf.obj")) - { - std::cerr << "Failed to load model!" << std::endl; - return -1; - } - - //ImportedModel.textureID = ImportedModel.loadTexture("./assets/texture.png"); - - // Cube vertex data - // Cube vertex data (positions and normals) - GLfloat vertices[] = { - // Positions // Normals - -0.5f, -0.5f, -0.5f, 0.0f, 0.0f, -1.0f, // Back face - 0.5f, -0.5f, -0.5f, 0.0f, 0.0f, -1.0f, - 0.5f, 0.5f, -0.5f, 0.0f, 0.0f, -1.0f, - 0.5f, 0.5f, -0.5f, 0.0f, 0.0f, -1.0f, - -0.5f, 0.5f, -0.5f, 0.0f, 0.0f, -1.0f, - -0.5f, -0.5f, -0.5f, 0.0f, 0.0f, -1.0f, - - -0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 1.0f, // Front face - 0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 1.0f, - 0.5f, 0.5f, 0.5f, 0.0f, 0.0f, 1.0f, - 0.5f, 0.5f, 0.5f, 0.0f, 0.0f, 1.0f, - -0.5f, 0.5f, 0.5f, 0.0f, 0.0f, 1.0f, - -0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 1.0f, - - -0.5f, 0.5f, 0.5f, -1.0f, 0.0f, 0.0f, // Left face - -0.5f, 0.5f, -0.5f, -1.0f, 0.0f, 0.0f, - -0.5f, -0.5f, -0.5f, -1.0f, 0.0f, 0.0f, - -0.5f, -0.5f, -0.5f, -1.0f, 0.0f, 0.0f, - -0.5f, -0.5f, 0.5f, -1.0f, 0.0f, 0.0f, - -0.5f, 0.5f, 0.5f, -1.0f, 0.0f, 0.0f, - - 0.5f, 0.5f, 0.5f, 1.0f, 0.0f, 0.0f, // Right face - 0.5f, 0.5f, -0.5f, 1.0f, 0.0f, 0.0f, - 0.5f, -0.5f, -0.5f, 1.0f, 0.0f, 0.0f, - 0.5f, -0.5f, -0.5f, 1.0f, 0.0f, 0.0f, - 0.5f, -0.5f, 0.5f, 1.0f, 0.0f, 0.0f, - 0.5f, 0.5f, 0.5f, 1.0f, 0.0f, 0.0f, - - -0.5f, -0.5f, -0.5f, 0.0f, -1.0f, 0.0f, // Bottom face - 0.5f, -0.5f, -0.5f, 0.0f, -1.0f, 0.0f, - 0.5f, -0.5f, 0.5f, 0.0f, -1.0f, 0.0f, - 0.5f, -0.5f, 0.5f, 0.0f, -1.0f, 0.0f, - -0.5f, -0.5f, 0.5f, 0.0f, -1.0f, 0.0f, - -0.5f, -0.5f, -0.5f, 0.0f, -1.0f, 0.0f, - - -0.5f, 0.5f, -0.5f, 0.0f, 1.0f, 0.0f, // Top face - 0.5f, 0.5f, -0.5f, 0.0f, 1.0f, 0.0f, - 0.5f, 0.5f, 0.5f, 0.0f, 1.0f, 0.0f, - 0.5f, 0.5f, 0.5f, 0.0f, 1.0f, 0.0f, - -0.5f, 0.5f, 0.5f, 0.0f, 1.0f, 0.0f, - -0.5f, 0.5f, -0.5f, 0.0f, 1.0f, 0.0f}; - - // Setup cube VAO - glGenVertexArrays(1, &cubeVAO); - glGenBuffers(1, &cubeVBO); - - // Fill buffer - glBindBuffer(GL_ARRAY_BUFFER, cubeVBO); - glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); - - // Link vertex attributes - // Link vertex attributes - glBindVertexArray(cubeVAO); - // Position attribute - glEnableVertexAttribArray(0); - glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(GLfloat), (GLvoid *)0); - // Normal attribute - glEnableVertexAttribArray(1); - glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(GLfloat), (GLvoid *)(3 * sizeof(GLfloat))); - - glBindBuffer(GL_ARRAY_BUFFER, 0); - glBindVertexArray(0); - - // Create the framebuffer - glGenFramebuffers(1, &framebuffer); - glBindFramebuffer(GL_FRAMEBUFFER, framebuffer); - - // Create the texture to render to - glGenTextures(1, &renderedTexture); - glBindTexture(GL_TEXTURE_2D, renderedTexture); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 680, 700, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - - // Attach the texture to the framebuffer - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, renderedTexture, 0); - - // Create a renderbuffer object for depth and stencil attachment - glGenRenderbuffers(1, &depthRenderbuffer); - glBindRenderbuffer(GL_RENDERBUFFER, depthRenderbuffer); - glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, 680, 700); - glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, depthRenderbuffer); - - // Check if framebuffer is complete - if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) - std::cerr << "Framebuffer not complete!" << std::endl; - - glBindFramebuffer(GL_FRAMEBUFFER, 0); // Unbind framebuffer - - // Setup Dear ImGui context - IMGUI_CHECKVERSION(); - ImGui::CreateContext(); - ImGuiIO &io = ImGui::GetIO(); - io.ConfigFlags |= ImGuiConfigFlags_DockingEnable; // Enable docking - - // Setup Platform/Renderer bindings - ImGui_ImplGlfw_InitForOpenGL(window, true); - ImGui_ImplOpenGL3_Init("#version 330"); - - SetupImGuiStyle(); - - // Set input callbacks + + // Have to initialize after imgui glfwSetCursorPosCallback(window, MouseCallback); glfwSetScrollCallback(window, ScrollCallback); glfwSetMouseButtonCallback(window, CustomMouseButtonCallback); - std::cout << "[Poly] Initializing FontCore" << std::endl; + // Load Textures + fileIconTexture = LoadTexture("./images/fileicon.png"); + sceneIconTexture = LoadTexture("./images/sceneicon.png"); + objectIconTexture = LoadTexture("./images/objecticon.png"); + // Log Engine Start + std::cout << "[Poly] Starting" << std::endl; + AddLogMessage("PolyEngine3D Version " + std::to_string(POLY_VERSION_MAJOR) + "." + std::to_string(POLY_VERSION_MINOR)); + + // Initialize entities and assets + std::vector> entities; + std::shared_ptr selectedEntity = nullptr; + std::shared_ptr selectedAsset = nullptr; + std::filesystem::path assetsDir = "./assets"; // Define your assets directory path + Settings settings; // Assumed to be a struct holding engine settings + settings.vsyncEnabled = true; // Example initialization + settings.maxLights = MAX_LIGHTS; + + // Enter the main loop + MainLoop(window, entities, selectedEntity, selectedAsset, assetsDir, settings); + + // Cleanup and exit + Cleanup(window); + std::cout << "[Poly] Done!" << std::endl; + return 0; +} + +// Function definitions + +GLFWwindow* InitializeGLFW(int width, int height, const std::string& title) +{ + if (!glfwInit()) + { + std::cerr << "[Poly] GLFW initialization failed." << std::endl; + return nullptr; + } + + // Set GLFW window hints for OpenGL version and profile + glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); + glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); + glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); + + // Create GLFW window + GLFWwindow* window = glfwCreateWindow(width, height, title.c_str(), NULL, NULL); + if (!window) + { + std::cerr << "[Poly] GLFW window creation failed." << std::endl; + glfwTerminate(); + return nullptr; + } + + // Make the OpenGL context current + glfwMakeContextCurrent(window); + + // Enable VSync based on settings + glfwSwapInterval(0); // Enable vsync by default + + + + return window; +} + +bool InitializeOpenGL() +{ + // Initialize GLEW + glewExperimental = GL_TRUE; + GLenum glewStatus = glewInit(); + if (glewStatus != GLEW_OK) + { + std::cerr << "[Poly] GLEW initialization failed: " << glewGetErrorString(glewStatus) << std::endl; + return false; + } + + // Enable depth testing + glEnable(GL_DEPTH_TEST); + + return true; +} + +bool InitializeShaders() +{ + try + { + cubeShader = new Shader("./shaders/vertex_shader.glsl", "./shaders/fragment_shader.glsl"); + gizmoShader = new Shader("./shaders/gizmo_vertex_shader.glsl", "./shaders/gizmo_fragment_shader.glsl"); + previewShader = new Shader("shaders/preview_vertex.glsl", "shaders/preview_fragment.glsl"); + FrustumShader = new Shader("./shaders/cam_vertex.glsl", "./shaders/cam_frag.glsl"); + } + catch (const std::exception& e) + { + std::cerr << "[Poly] Shader compilation/linking failed: " << e.what() << std::endl; + return false; + } + + return true; +} + +bool LoadModels() +{ + // Load the cottage model + if (!ImportedModel.loadFromOBJ("./cottage_obj.obj")) + { + std::cerr << "[Poly] Failed to load cottage_obj.obj!" << std::endl; + return false; + } + ImportedModel.textureID = ImportedModel.loadTexture("./assets/texture.png"); + + // Load the bookshelf model + if (!ImportedModel_shelf.loadFromOBJ("./bookshelf.obj")) + { + std::cerr << "[Poly] Failed to load bookshelf.obj!" << std::endl; + return false; + } + ImportedModel_shelf.textureID = ImportedModel_shelf.loadTexture("./assets/wood.png"); + + return true; +} + +bool SetupCube() +{ + // Define cube vertices (positions and normals) + GLfloat vertices[] = { + // Positions // Normals + // Back face + -0.5f, -0.5f, -0.5f, 0.0f, 0.0f, -1.0f, + 0.5f, -0.5f, -0.5f, 0.0f, 0.0f, -1.0f, + 0.5f, 0.5f, -0.5f, 0.0f, 0.0f, -1.0f, + 0.5f, 0.5f, -0.5f, 0.0f, 0.0f, -1.0f, + -0.5f, 0.5f, -0.5f, 0.0f, 0.0f, -1.0f, + -0.5f, -0.5f, -0.5f, 0.0f, 0.0f, -1.0f, + + // Front face + -0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 1.0f, + 0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 1.0f, + 0.5f, 0.5f, 0.5f, 0.0f, 0.0f, 1.0f, + 0.5f, 0.5f, 0.5f, 0.0f, 0.0f, 1.0f, + -0.5f, 0.5f, 0.5f, 0.0f, 0.0f, 1.0f, + -0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 1.0f, + + // Left face + -0.5f, 0.5f, 0.5f,-1.0f, 0.0f, 0.0f, + -0.5f, 0.5f, -0.5f,-1.0f, 0.0f, 0.0f, + -0.5f, -0.5f, -0.5f,-1.0f, 0.0f, 0.0f, + -0.5f, -0.5f, -0.5f,-1.0f, 0.0f, 0.0f, + -0.5f, -0.5f, 0.5f,-1.0f, 0.0f, 0.0f, + -0.5f, 0.5f, 0.5f,-1.0f, 0.0f, 0.0f, + + // Right face + 0.5f, 0.5f, 0.5f,1.0f, 0.0f, 0.0f, + 0.5f, 0.5f, -0.5f,1.0f, 0.0f, 0.0f, + 0.5f, -0.5f, -0.5f,1.0f, 0.0f, 0.0f, + 0.5f, -0.5f, -0.5f,1.0f, 0.0f, 0.0f, + 0.5f, -0.5f, 0.5f,1.0f, 0.0f, 0.0f, + 0.5f, 0.5f, 0.5f,1.0f, 0.0f, 0.0f, + + // Bottom face + -0.5f, -0.5f, -0.5f,0.0f,-1.0f, 0.0f, + 0.5f, -0.5f, -0.5f,0.0f,-1.0f, 0.0f, + 0.5f, -0.5f, 0.5f,0.0f,-1.0f, 0.0f, + 0.5f, -0.5f, 0.5f,0.0f,-1.0f, 0.0f, + -0.5f, -0.5f, 0.5f,0.0f,-1.0f, 0.0f, + -0.5f, -0.5f, -0.5f,0.0f,-1.0f, 0.0f, + + // Top face + -0.5f, 0.5f, -0.5f,0.0f, 1.0f, 0.0f, + 0.5f, 0.5f, -0.5f,0.0f, 1.0f, 0.0f, + 0.5f, 0.5f, 0.5f,0.0f, 1.0f, 0.0f, + 0.5f, 0.5f, 0.5f,0.0f, 1.0f, 0.0f, + -0.5f, 0.5f, 0.5f,0.0f, 1.0f, 0.0f, + -0.5f, 0.5f, -0.5f,0.0f, 1.0f, 0.0f + }; + + // Generate and bind VAO and VBO + glGenVertexArrays(1, &cubeVAO); + glGenBuffers(1, &cubeVBO); + + glBindBuffer(GL_ARRAY_BUFFER, cubeVBO); + glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); + + glBindVertexArray(cubeVAO); + // Position attribute + glEnableVertexAttribArray(0); + glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(GLfloat), (GLvoid*)0); + // Normal attribute + glEnableVertexAttribArray(1); + glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(GLfloat), (GLvoid*)(3 * sizeof(GLfloat))); + + glBindBuffer(GL_ARRAY_BUFFER, 0); + glBindVertexArray(0); + + return true; +} + +bool SetupFramebuffer(int width, int height) +{ + // Generate and bind framebuffer + glGenFramebuffers(1, &framebuffer); + glBindFramebuffer(GL_FRAMEBUFFER, framebuffer); + + // Create texture to render to + glGenTextures(1, &renderedTexture); + glBindTexture(GL_TEXTURE_2D, renderedTexture); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + + // Attach texture to framebuffer + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, renderedTexture, 0); + + // Create renderbuffer for depth and stencil + glGenRenderbuffers(1, &depthRenderbuffer); + glBindRenderbuffer(GL_RENDERBUFFER, depthRenderbuffer); + glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, width, height); + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, depthRenderbuffer); + + // Check framebuffer completeness + if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) + { + std::cerr << "[Poly] Framebuffer not complete!" << std::endl; + return false; + } + + // Unbind framebuffer + glBindFramebuffer(GL_FRAMEBUFFER, 0); + return true; +} + +bool InitializeImGui(GLFWwindow* window, const char* glsl_version) +{ + // Setup Dear ImGui context + IMGUI_CHECKVERSION(); + ImGui::CreateContext(); + ImGuiIO& io = ImGui::GetIO(); (void)io; + io.ConfigFlags |= ImGuiConfigFlags_DockingEnable; // Enable docking + + // Setup Dear ImGui style + SetupImGuiStyle(); // Assumed to be defined elsewhere + + // Setup Platform/Renderer bindings + if (!ImGui_ImplGlfw_InitForOpenGL(window, true)) + { + std::cerr << "[Poly] Failed to initialize ImGui GLFW." << std::endl; + return false; + } + if (!ImGui_ImplOpenGL3_Init(glsl_version)) + { + std::cerr << "[Poly] Failed to initialize ImGui OpenGL3." << std::endl; + return false; + } + + // Load Fonts io.Fonts->AddFontFromFileTTF("./fonts/primary.ttf", 14.0f); + if (io.Fonts->Fonts.empty()) + { + std::cerr << "[Poly] Failed to load fonts." << std::endl; + return false; + } + + - // Remove window borders and title bars - ImGuiStyle &style = ImGui::GetStyle(); + // Configure ImGui style + ImGuiStyle& style = ImGui::GetStyle(); style.WindowBorderSize = 0.0f; style.WindowRounding = 0.0f; + return true; +} + +void MainLoop(GLFWwindow* window, std::vector>& entities, std::shared_ptr& selectedEntity, std::shared_ptr& selectedAsset, const std::filesystem::path& assetsDir, Settings& settings) +{ + // Initialize timing variables double previousTime = glfwGetTime(); int frameCount = 0; - settings.maxLights = MAX_LIGHTS; - - // Our state - - - std::cout << "[Poly] Starting" << std::endl; - - AddLogMessage("PolyEngine3D Version " + std::to_string(POLY_VERSION_MAJOR) + "." + std::to_string(POLY_VERSION_MINOR)); - - // Main loop while (!glfwWindowShouldClose(window)) { // Poll and handle events glfwPollEvents(); - settings.lightCount = totalLights; + // Update settings (e.g., light count) + settings.lightCount = totalLights; // Assumed to be defined elsewhere - // Measure speed + // Frame rate calculation double currentTime = glfwGetTime(); frameCount++; - // If a second has passed. if (currentTime - previousTime >= 1.0) { - // Display the frame count here any way you want. fps = frameCount; - //AddLogMessage("FPS: " + std::to_string(fps)); - frameCount = 0; previousTime = currentTime; } @@ -665,6 +941,7 @@ int main() ImGui_ImplGlfw_NewFrame(); ImGui::NewFrame(); + // Setup DockSpace ImGui::SetNextWindowPos(ImVec2(0, 20)); ImGui::SetNextWindowSize(ImGui::GetIO().DisplaySize); ImGui::SetNextWindowViewport(ImGui::GetMainViewport()->ID); @@ -678,34 +955,38 @@ int main() ImGui::DockSpace(dockspaceID, ImVec2(0.0f, 0.0f), ImGuiDockNodeFlags_None); ImGui::End(); + // Setup Main Menu Bar if (ImGui::BeginMainMenuBar()) { if (ImGui::BeginMenu("File")) { if (ImGui::MenuItem("Save Scene")) { - SaveScene(entities, "./scene.polys"); + SaveScene(entities, "./scene.polys"); // Assumed to be defined elsewhere + AddLogMessage("Scene saved to ./scene.polys"); } - if (ImGui::MenuItem("Save Scene as")) + if (ImGui::MenuItem("Save Scene As")) { - - std::wstring selectedFile = SaveFileDialog(); + std::wstring selectedFile = SaveFileDialog(); // Assumed to be defined elsewhere if (!selectedFile.empty()) { - std::filesystem::path sourcePath(selectedFile); - std::filesystem::path destinationPath = assetsDir / sourcePath.filename(); - + std::filesystem::path destinationPath(selectedFile); SaveScene(entities, destinationPath.string()); + AddLogMessage("Scene saved to " + destinationPath.string()); } } + if (ImGui::MenuItem("Load Scene")) { - LoadScene(entities, "./scene.polys"); + LoadScene(entities, "./scene.polys"); // Assumed to be defined elsewhere selectedEntity = nullptr; // Reset selected entity + AddLogMessage("Scene loaded from ./scene.polys"); } + ImGui::EndMenu(); } + if (ImGui::BeginMenu("Engine")) { if (ImGui::MenuItem(GameRunning ? "Stop" : "Run")) @@ -713,42 +994,47 @@ int main() if (!GameRunning) { SaveScene(entities, "./$tmpPly.polys"); - selectedEntity = nullptr; // Reset selected entity + selectedEntity = nullptr; GameRunning = true; + AddLogMessage("Game started."); } else { LoadScene(entities, "./$tmpPly.polys"); selectedEntity = nullptr; - GameRunning = false; + AddLogMessage("Game stopped."); } } ImGui::EndMenu(); } + ImGui::EndMainMenuBar(); } - // Get the window size + // Get the framebuffer size int display_w, display_h; glfwGetFramebufferSize(window, &display_w, &display_h); - // Show windows - DrawSettingsWindow(settings, fps, window); - + // Show various ImGui windows + DrawSettingsWindow(settings, fps, window); // Assumed to be defined elsewhere ShowEntityComponentTree(entities, selectedEntity); ShowInspector(selectedEntity); - ShowGameView(entities); - ShowCameraPreview(entities); - - ShowAssetPanel(assetsDir, selectedAsset); - DrawLogTerminal("Info"); + ShowGameView(entities); // Assumed to be defined elsewhere + ShowAssetPanel(assetsDir, selectedAsset, entities); // Refactored earlier + DrawLogTerminal("Info"); // Assumed to be defined elsewhere // Rendering ImGui::Render(); glViewport(0, 0, display_w, display_h); glClearColor(0.45f, 0.55f, 0.60f, 1.00f); - glClear(GL_COLOR_BUFFER_BIT); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Clear depth buffer as well + + // Bind the framebuffer for off-screen rendering if needed + // glBindFramebuffer(GL_FRAMEBUFFER, framebuffer); + // glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + // ... Render your scene here ... + // glBindFramebuffer(GL_FRAMEBUFFER, 0); // Render ImGui draw data ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData()); @@ -756,30 +1042,9 @@ int main() // Swap buffers glfwSwapBuffers(window); } - - std::cout << "[Poly] Closing..." << std::endl; - - // Cleanup ImGui and GLFW - ImGui_ImplOpenGL3_Shutdown(); - ImGui_ImplGlfw_Shutdown(); - ImGui::DestroyContext(); - - glfwDestroyWindow(window); - glfwTerminate(); - - // Cleanup OpenGL resources - delete cubeShader; - glDeleteVertexArrays(1, &cubeVAO); - glDeleteBuffers(1, &cubeVBO); - glDeleteFramebuffers(1, &framebuffer); - glDeleteTextures(1, &renderedTexture); - glDeleteRenderbuffers(1, &depthRenderbuffer); - - std::cout << "[Poly] Done!" << std::endl; - - return 0; } + void RenderCube(glm::mat4 model, glm::mat4 view, glm::mat4 projection, glm::vec3 viewPos, glm::vec3 lightPos, glm::vec3 objectColor) { cubeShader->Use(); @@ -799,76 +1064,104 @@ void RenderCube(glm::mat4 model, glm::mat4 view, glm::mat4 projection, glm::vec3 glBindVertexArray(0); } +// Function to display the Entity Tree without component viewing void ShowEntityComponentTree(std::vector> &entities, std::shared_ptr &selectedEntity) { ImGui::Begin("Scene"); - // Button to add a new entity - if (ImGui::Button("Add Entity")) + // ----------------------------- + // Add Entity Button Section + // ----------------------------- { - int newId = entities.size(); - auto newEntity = std::make_shared(newId, "Entity " + std::to_string(newId)); - newEntity->AddComponent((std::make_shared())); - entities.push_back(newEntity); - } - int __id = 0; + // Adjust button size based on available width + float buttonWidth = ImGui::GetContentRegionAvail().x / 2.0f - ImGui::GetStyle().ItemSpacing.x; - // Loop through entities - for (auto it = entities.begin(); it != entities.end();) - { - auto &entity = *it; - ImGui::PushID(__id); - __id++; - - ImGuiTreeNodeFlags nodeFlags = ImGuiTreeNodeFlags_OpenOnArrow; - if (selectedEntity == entity) - nodeFlags |= ImGuiTreeNodeFlags_Selected; - - bool nodeOpen = ImGui::TreeNodeEx((void *)(intptr_t)entity->id, nodeFlags, entity->name.c_str()); - if (ImGui::IsItemClicked()) + // Add Entity Button + if (ImGui::Button("Add Entity", ImVec2(buttonWidth, 0))) { - selectedEntity = entity; + int newId = entities.size(); + auto newEntity = std::make_shared(newId, "Entity " + std::to_string(newId)); + newEntity->AddComponent(std::make_shared()); // Ensure each entity has a TransformComponent by default + entities.push_back(newEntity); } - // Right-click context menu for entities - if (ImGui::BeginPopupContextItem()) + ImGui::SameLine(); + + + } + + ImGui::Separator(); + + // ----------------------------- + // Entity List Section + // ----------------------------- + { + // Define TreeNode flags for better visuals and interaction + ImGuiTreeNodeFlags nodeFlags = ImGuiTreeNodeFlags_OpenOnArrow | ImGuiTreeNodeFlags_SpanAvailWidth; + + // Iterate through entities using index for unique identification + for (size_t i = 0; i < entities.size(); ++i) { - if (ImGui::MenuItem("Delete Entity")) + auto &entity = entities[i]; + + // Determine flags based on selection + ImGuiTreeNodeFlags flags = nodeFlags; + if (selectedEntity == entity) + flags |= ImGuiTreeNodeFlags_Selected; + + // Unique identifier for each entity node + std::string nodeLabel = entity->name; + bool nodeOpen = ImGui::TreeNodeEx((void*)(intptr_t)i, flags, nodeLabel.c_str()); + + // Handle selection + if (ImGui::IsItemClicked(ImGuiMouseButton_Left)) { - if (selectedEntity == entity) + selectedEntity = entity; + } + + // Right-click context menu for entity actions + if (ImGui::BeginPopupContextItem()) + { + // Delete Entity Option + if (ImGui::MenuItem("Delete Entity")) { - selectedEntity = nullptr; + // Confirm deletion if necessary (optional) + // Example: Show a confirmation dialog before deletion + + // Remove the entity from the list + entities.erase(entities.begin() + i); + + // Clear selection if the deleted entity was selected + if (selectedEntity == entity) + selectedEntity = nullptr; + + ImGui::EndPopup(); + + // Since we've erased the current entity, skip incrementing the index + --i; + continue; } - it = entities.erase(it); + ImGui::EndPopup(); - if (nodeOpen) - ImGui::TreePop(); - ImGui::PopID(); - continue; } - ImGui::EndPopup(); - } - if (nodeOpen) - { - // Display components - for (const auto &compPair : entity->components) + // Optionally, you can implement double-click to rename or perform other actions + + // Close the tree node + if (nodeOpen) { - auto &component = compPair.second; - ImGuiTreeNodeFlags compFlags = ImGuiTreeNodeFlags_Leaf | ImGuiTreeNodeFlags_NoTreePushOnOpen; - ImGui::TreeNodeEx((void *)(intptr_t)(entity->id * 100 + (int)(intptr_t)component.get()), compFlags, component->GetName().c_str()); + // If you decide to add child nodes in the future, handle them here + // Since components are removed, no additional handling is required + + ImGui::TreePop(); } - - ImGui::TreePop(); } - - ImGui::PopID(); - ++it; } - ImGui::End(); // End of Entity Component Tree window + ImGui::End(); // End of Scene window } + // Function to display error messages within the UI void DisplayError(const std::string &message) { @@ -884,189 +1177,216 @@ void DisplayError(const std::string &message) } } -// Function to display the Asset Panel as a Tree with enhanced visuals -void ShowAssetPanel(const std::filesystem::path &assetsDirectory, std::shared_ptr &selectedAsset) +// Function to display the Asset Panel as a Grid without recursion and folders +void ShowAssetPanel(const std::filesystem::path &assetsDirectory, std::shared_ptr &selectedAsset, std::vector>& entities) { ImGui::Begin("Asset Panel"); - // Search Bar + // Static variable to track the current directory path + static std::filesystem::path currentPath = assetsDirectory; + + // ----------------------------- + // Search Bar Section + // ----------------------------- + static char searchBuffer[256] = ""; - ImGui::InputTextWithHint("##Search", "Search assets...", searchBuffer, IM_ARRAYSIZE(searchBuffer)); + if (ImGui::InputTextWithHint("##Search", "Search assets...", searchBuffer, IM_ARRAYSIZE(searchBuffer))) + { + // Implement search filtering if needed + } + ImGui::Separator(); - // Top Buttons: Refresh and Import - if (ImGui::Button("➕ Import Asset")) + // ----------------------------- + // Top Buttons: Import Asset and Up + // ----------------------------- { - std::wstring selectedFile = OpenFileDialog(); - if (!selectedFile.empty()) - { - // Convert std::wstring to std::filesystem::path - std::filesystem::path sourcePath(selectedFile); - std::filesystem::path destinationPath = assetsDirectory / sourcePath.filename(); + // Adjust button size for better aesthetics + float buttonWidth = ImGui::GetContentRegionAvail().x / 2.0f - ImGui::GetStyle().ItemSpacing.x; - try + // Import Asset Button + if (ImGui::Button("Import Asset", ImVec2(buttonWidth, 0))) + { + std::wstring selectedFile = OpenFileDialog(); + if (!selectedFile.empty()) { - // Copy the selected file to the assets directory - std::filesystem::copy_file(sourcePath, destinationPath, std::filesystem::copy_options::overwrite_existing); - // Optionally, add a success notification - } - catch (const std::exception &e) - { - DisplayError("Error importing asset: " + std::string(e.what())); + // Convert std::wstring to std::filesystem::path + std::filesystem::path sourcePath(selectedFile); + std::filesystem::path destinationPath = currentPath / sourcePath.filename(); + + try + { + // Copy the selected file to the assets directory + std::filesystem::copy_file(sourcePath, destinationPath, std::filesystem::copy_options::overwrite_existing); + // Optionally, add a success notification + } + catch (const std::exception &e) + { + DisplayError("Error importing asset: " + std::string(e.what())); + } } } } ImGui::Separator(); - // Recursive lambda to display directories and files - std::function DisplayTree; - DisplayTree = [&](const std::filesystem::path &directory) + // ----------------------------- + // Current Path Display + // ----------------------------- { - for (const auto &entry : std::filesystem::directory_iterator(directory)) + ImGui::Text("Current Path: %s", currentPath.string().c_str()); + } + + ImGui::Separator(); + + // ----------------------------- + // Validate currentPath + // ----------------------------- + { + if (!std::filesystem::exists(currentPath)) { - // Skip hidden files and directories - if (entry.path().filename().string().front() == '.') - continue; + DisplayError("Current directory does not exist."); + ImGui::End(); + return; + } - // Apply search filter - if (strlen(searchBuffer) > 0) + if (!std::filesystem::is_directory(currentPath)) + { + DisplayError("Current path is not a directory."); + ImGui::End(); + return; + } + } + + // ----------------------------- + // Asset Grid Display + // ----------------------------- + { + // Define thumbnail size and padding + const float thumbnailSize = 80.0f; + const float padding = 20.0f; + + // Begin child region for scrolling with automatic width and height + ImGui::BeginChild("AssetGrid", ImVec2(0, 0), false, ImGuiWindowFlags_HorizontalScrollbar); + + // Calculate the number of columns based on window width + float windowWidth = ImGui::GetContentRegionAvail().x; + int columns = static_cast((windowWidth + padding) / (thumbnailSize + padding)); + columns = std::max(1, columns); // Ensure at least one column + + // Set up the table with calculated columns + if (ImGui::BeginTable("AssetGridTable", columns, ImGuiTableFlags_NoBordersInBody | ImGuiTableFlags_SizingFixedFit)) + { + ImGui::TableSetupScrollFreeze(0, 1); // Keep header row frozen + ImGui::TableHeadersRow(); // Optional: Add headers if needed + + for (const auto &entry : std::filesystem::directory_iterator(currentPath, std::filesystem::directory_options::skip_permission_denied)) { - std::string filename = entry.path().filename().string(); - std::string searchStr(searchBuffer); - // Simple case-insensitive substring search - std::transform(filename.begin(), filename.end(), filename.begin(), ::tolower); - std::transform(searchStr.begin(), searchStr.end(), searchStr.begin(), ::tolower); - if (filename.find(searchStr) == std::string::npos) + // Skip hidden files and directories + if (!entry.path().filename().empty() && entry.path().filename().string().front() == '.') continue; - } - bool isDir = entry.is_directory(); - std::string label = entry.path().filename().string(); - - // Push unique ID - ImGui::PushID(entry.path().string().c_str()); - - if (isDir) - { - // Folder Icon and Label - std::string folderLabel = "\uF07B " + label; - ImGuiTreeNodeFlags nodeFlags = ImGuiTreeNodeFlags_OpenOnArrow | ImGuiTreeNodeFlags_OpenOnDoubleClick; - if (selectedAsset && selectedAsset->path == entry.path()) - nodeFlags |= ImGuiTreeNodeFlags_Selected; - - bool nodeOpen = ImGui::TreeNodeEx(folderLabel.c_str(), nodeFlags); - - // Tooltip on hover - if (ImGui::IsItemHovered()) + // Apply search filter + if (strlen(searchBuffer) > 0) { - ImGui::SetTooltip("Folder: %s", label.c_str()); + std::string filename = entry.path().filename().string(); + std::string searchStr(searchBuffer); + // Simple case-insensitive substring search + std::transform(filename.begin(), filename.end(), filename.begin(), ::tolower); + std::transform(searchStr.begin(), searchStr.end(), searchStr.begin(), ::tolower); + if (filename.find(searchStr) == std::string::npos) + continue; } - // Context Menu for Folder - if (ImGui::BeginPopupContextItem()) + bool isDir = entry.is_directory(); + std::string label = entry.path().filename().string(); + + // Since folders are removed, skip directories + if (isDir) + continue; + + // Determine which icon to use based on file extension + ImTextureID icon; + if (entry.path().extension() == ".polys") { - if (ImGui::MenuItem("Rename")) - { - // Implement rename logic - } - if (ImGui::MenuItem("Delete")) - { - // Implement delete logic - } - ImGui::EndPopup(); + icon = sceneIconTexture; + } + else if (entry.path().extension() == ".obj") + { + icon = objectIconTexture; + } + else + { + icon = fileIconTexture; } - if (nodeOpen) + // Begin table cell + ImGui::TableNextColumn(); + + // Begin a group to keep the image button and label together + ImGui::BeginGroup(); + + // Image Button for the asset + if (ImGui::ImageButton(("##" + entry.path().string()).c_str(), icon, ImVec2(thumbnailSize, thumbnailSize))) { - // Optionally, handle folder click (e.g., navigate into folder) - DisplayTree(entry.path()); - ImGui::TreePop(); - } + + // Handle asset selection + selectedAsset = std::make_shared(); + selectedAsset->path = entry.path(); - // Handle folder selection - if (ImGui::IsItemClicked() && !ImGui::IsItemToggledOpen()) - { - // Optionally, set as selected asset or perform other actions - } - } - else - { - // File Icon and Label - std::string fileLabel = "\uF15B " + label; - ImGuiTreeNodeFlags leafFlags = ImGuiTreeNodeFlags_Leaf | ImGuiTreeNodeFlags_NoTreePushOnOpen; - if (selectedAsset && selectedAsset->path == entry.path()) - leafFlags |= ImGuiTreeNodeFlags_Selected; - - ImGui::TreeNodeEx(fileLabel.c_str(), leafFlags); - - // Tooltip on hover - if (ImGui::IsItemHovered()) - { - std::string tooltip = "File: " + label + "\nSize: " + std::to_string(std::filesystem::file_size(entry.path())) + " bytes"; - ImGui::SetTooltip("%s", tooltip.c_str()); - } - - // Context Menu for File - if (ImGui::BeginPopupContextItem()) - { - if (ImGui::MenuItem("Open")) - { - if (entry.path().extension() == ".polys") - { - // Save current scene - SaveScene(entities, "./scene.polys"); - - // Load selected scene - LoadScene(entities, entry.path().string()); - - // Update selected asset - selectedAsset = std::make_shared(); - selectedAsset->path = entry.path(); - } - // Handle other file types if needed - } - if (ImGui::MenuItem("Rename")) - { - // Implement rename logic - } - if (ImGui::MenuItem("Delete")) - { - // Implement delete logic - } - ImGui::EndPopup(); - } - - // Handle file selection - if (ImGui::IsItemClicked() && !ImGui::IsItemToggledOpen()) - { + // Additional handling for specific file types if (entry.path().extension() == ".polys") { - // Save current scene - SaveScene(entities, "./scene.polys"); + try + { + // Save the current scene to a temporary file + SaveScene(entities, "./scene.polys"); - // Load selected scene - LoadScene(entities, entry.path().string()); + // Load the selected .polys scene + LoadScene(entities, entry.path().string()); - // Update selected asset - selectedAsset = std::make_shared(); - selectedAsset->path = entry.path(); + // Update the selected asset with the new path + selectedAsset->path = entry.path(); + + } + catch (const std::exception &e) + { + // Display an error message if loading fails + DisplayError("Error loading scene: " + std::string(e.what())); + LOGPOINT("Error Loading Scene"); + + } } - // Handle other file types if needed + // Handle other file types here if necessary } + + // Optional: Add tooltip for better UX + if (ImGui::IsItemHovered()) + { + ImGui::SetTooltip("%s", label.c_str()); + } + + // Center the label below the thumbnail + float textWidth = ImGui::CalcTextSize(label.c_str()).x; + float cursorX = (thumbnailSize - textWidth) * 0.5f; + ImGui::SetCursorPosX(ImGui::GetCursorPosX() + cursorX); + + // Render the asset label + ImGui::TextWrapped("%s", label.c_str()); + + ImGui::EndGroup(); } - // Pop ID - ImGui::PopID(); + ImGui::EndTable(); } - }; - // Start displaying the tree from the assets directory - DisplayTree(assetsDirectory); + ImGui::EndChild(); // End of scrolling region + } ImGui::End(); // End of Asset Panel window } + void ShowInspector(std::shared_ptr &selectedEntity) { ImGui::Begin("Inspector"); @@ -1074,224 +1394,259 @@ void ShowInspector(std::shared_ptr &selectedEntity) // Display selected entity properties if (selectedEntity) { - // Editable entity name - char buffer[128]; - strncpy(buffer, selectedEntity->name.c_str(), sizeof(buffer)); - buffer[sizeof(buffer) - 1] = 0; - if (ImGui::InputText("Name", buffer, sizeof(buffer))) + // ----------------------------- + // Editable Entity Name Section + // ----------------------------- { - selectedEntity->name = buffer; + char buffer[128]; + strncpy(buffer, selectedEntity->name.c_str(), sizeof(buffer)); + buffer[sizeof(buffer) - 1] = 0; + if (ImGui::InputText("Name", buffer, sizeof(buffer))) + { + selectedEntity->name = buffer; + } } ImGui::Separator(); - // Add Component Button - if (ImGui::Button("Add Component")) + // ----------------------------- + // Add Component Button Section + // ----------------------------- { - ImGui::OpenPopup("AddComponentPopup"); - } - - if (ImGui::BeginPopup("AddComponentPopup")) - { - if (!selectedEntity->GetComponent()) + if (ImGui::Button("Add Component")) { - if (ImGui::MenuItem("Transform Component")) - { + ImGui::OpenPopup("AddComponentPopup"); + } + + if (ImGui::BeginPopup("AddComponentPopup")) + { + // List of available components with their corresponding add actions + struct ComponentInfo { + std::string name; + std::function addFunc; + }; + + std::vector availableComponents; + + // Populate available components based on absence in the selected entity + auto addAvailableComponent = [&](const std::string &compName, std::function addFunc) { + if (!selectedEntity->GetComponentByName(compName)) + { + availableComponents.push_back({ compName, addFunc }); + } + }; + + addAvailableComponent("Transform Component", [&]() { selectedEntity->AddComponent(std::make_shared()); - } - } - if (!selectedEntity->GetComponent()) - { - if (ImGui::MenuItem("Render Component")) - { + }); + addAvailableComponent("Render Component", [&]() { selectedEntity->AddComponent(std::make_shared()); - } - } - if (!selectedEntity->GetComponent()) - { - if (ImGui::MenuItem("Light Component")) - { + }); + addAvailableComponent("Light Component", [&]() { selectedEntity->AddComponent(std::make_shared()); - } - } - // Corrected check for RigidBody3DComponent - if (!selectedEntity->GetComponent()) - { - if (ImGui::MenuItem("RigidBody3D Component")) - { + }); + addAvailableComponent("RigidBody3D Component", [&]() { selectedEntity->AddComponent(std::make_shared()); - } - } - // Add CollisionShape3DComponent - if (!selectedEntity->GetComponent()) - { - if (ImGui::MenuItem("CollisionShape3D Component")) - { + }); + addAvailableComponent("CollisionShape3D Component", [&]() { selectedEntity->AddComponent(std::make_shared()); - } - } - // Add CameraComponent - if (!selectedEntity->GetComponent()) - { - if (ImGui::MenuItem("Camera Component")) - { + }); + addAvailableComponent("Camera Component", [&]() { selectedEntity->AddComponent(std::make_shared()); + }); + + // Render menu items for available components + for (const auto &comp : availableComponents) + { + if (ImGui::MenuItem(comp.name.c_str())) + { + comp.addFunc(); + } } + + ImGui::EndPopup(); } - ImGui::EndPopup(); } ImGui::Separator(); - // Loop through all components of the selected entity - for (auto it = selectedEntity->components.begin(); it != selectedEntity->components.end();) + // ----------------------------- + // Component Properties Section + // ----------------------------- { - auto &compPair = *it; - auto &component = compPair.second; - ImGui::PushID(component->GetName().c_str()); + // Lambda to handle removal of components + auto removeComponent = [&](auto it) -> decltype(it) { + return selectedEntity->components.erase(it); + }; - if (ImGui::CollapsingHeader(component->GetName().c_str(), ImGuiTreeNodeFlags_DefaultOpen)) + // Iterate through all components of the selected entity + for (auto it = selectedEntity->components.begin(); it != selectedEntity->components.end();) { - // Display component properties - if (auto transform = std::dynamic_pointer_cast(component)) + auto &compPair = *it; + auto &component = compPair.second; + ImGui::PushID(component->GetName().c_str()); + + if (ImGui::CollapsingHeader(component->GetName().c_str(), ImGuiTreeNodeFlags_DefaultOpen)) { - ImGui::DragFloat3("Position", glm::value_ptr(transform->position), 0.1f); - ImGui::DragFloat3("Rotation", glm::value_ptr(transform->rotation), 0.1f); - ImGui::DragFloat3("Scale", glm::value_ptr(transform->scale), 0.1f); - } - else if (auto render = std::dynamic_pointer_cast(component)) - { - char meshBuffer[128]; - strncpy(meshBuffer, render->meshName.c_str(), sizeof(meshBuffer)); - meshBuffer[sizeof(meshBuffer) - 1] = 0; - if (ImGui::InputText("Mesh Name", meshBuffer, sizeof(meshBuffer))) + // Lambda to simplify setting component properties + auto handleTransformComponent = [&](std::shared_ptr transform) { + ImGui::DragFloat3("Position", glm::value_ptr(transform->position), 0.1f); + ImGui::DragFloat3("Rotation", glm::value_ptr(transform->rotation), 0.1f); + ImGui::DragFloat3("Scale", glm::value_ptr(transform->scale), 0.1f); + }; + + auto handleRenderComponent = [&](std::shared_ptr render) { + char meshBuffer[128]; + strncpy(meshBuffer, render->meshName.c_str(), sizeof(meshBuffer)); + meshBuffer[sizeof(meshBuffer) - 1] = 0; + if (ImGui::InputText("Mesh Name", meshBuffer, sizeof(meshBuffer))) + { + render->meshName = meshBuffer; + } + + // Color picker for object color + ImGui::ColorEdit3("Color", glm::value_ptr(render->color)); + }; + + auto handleLightComponent = [&](std::shared_ptr light) { + // Light Type Combo Box + const char *lightTypes[] = { "Point", "Directional", "Spot" }; + int typeIndex = static_cast(light->type); + if (ImGui::Combo("Type", &typeIndex, lightTypes, IM_ARRAYSIZE(lightTypes))) + { + light->type = static_cast(typeIndex); + } + + // Color and Intensity + ImGui::ColorEdit3("Color", glm::value_ptr(light->color)); + ImGui::DragFloat("Intensity", &light->intensity, 0.1f, 0.0f, 10.0f); + + // Attenuation Factors for Point Lights + if (light->type == LightType::Point) + { + ImGui::DragFloat("Constant", &light->constant, 0.01f, 0.0f, 1.0f); + ImGui::DragFloat("Linear", &light->linear, 0.01f, 0.0f, 1.0f); + ImGui::DragFloat("Quadratic", &light->quadratic, 0.01f, 0.0f, 1.0f); + } + + // Direction for Directional Lights + if (light->type == LightType::Directional) + { + ImGui::DragFloat3("Direction", glm::value_ptr(light->direction), 0.1f); + } + + // Spot Light Specific Properties + if (light->type == LightType::Spot) + { + ImGui::DragFloat("CutOff", &light->cutOff, 0.1f, 0.0f, 90.0f, "%.1f degrees"); + ImGui::DragFloat("Outer CutOff", &light->outerCutOff, 0.1f, 0.0f, 90.0f, "%.1f degrees"); + } + }; + + auto handleRigidBody3DComponent = [&](std::shared_ptr rigidBody) { + ImGui::DragFloat3("Velocity", glm::value_ptr(rigidBody->velocity), 0.1f); + ImGui::DragFloat3("Acceleration", glm::value_ptr(rigidBody->acceleration), 0.1f); + ImGui::DragFloat("Mass", &rigidBody->mass, 0.1f, 0.1f, 100.0f); + + // RigidBody Type Combo Box + const char *rbTypes[] = { "Static", "Dynamic", "Kinematic" }; + int typeIndex = static_cast(rigidBody->type); + if (ImGui::Combo("Type", &typeIndex, rbTypes, IM_ARRAYSIZE(rbTypes))) + { + rigidBody->type = static_cast(typeIndex); + } + }; + + auto handleCollisionShape3DComponent = [&](std::shared_ptr collisionShape) { + // Shape Type Combo Box + const char *shapeTypes[] = { "Box", "Sphere", "Capsule" }; + int shapeIndex = static_cast(collisionShape->shapeType); + if (ImGui::Combo("Shape Type", &shapeIndex, shapeTypes, IM_ARRAYSIZE(shapeTypes))) + { + collisionShape->shapeType = static_cast(shapeIndex); + } + + // Display properties based on shape type + switch (collisionShape->shapeType) + { + case CollisionShapeType::Box: + ImGui::DragFloat3("Size", glm::value_ptr(collisionShape->size), 0.1f, 0.1f, 100.0f); + break; + case CollisionShapeType::Sphere: + ImGui::DragFloat("Radius", &collisionShape->radius, 0.1f, 0.1f, 100.0f); + break; + case CollisionShapeType::Capsule: + ImGui::DragFloat3("Direction", glm::value_ptr(collisionShape->direction), 0.1f); + ImGui::DragFloat("Height", &collisionShape->height, 0.1f, 0.1f, 100.0f); + break; + // Add UI elements for additional shapes here + default: + break; + } + }; + + auto handleCameraComponent = [&](std::shared_ptr camera) { + // Field of View (FOV) slider + ImGui::DragFloat("Field of View", &camera->fov, 1.0f, 1.0f, 120.0f, "%.1f degrees"); + + // Toggle between Orthographic and Perspective projection + ImGui::Checkbox("Orthographic", &camera->orthographic); + + // Near Plane slider + ImGui::DragFloat("Near Plane", &camera->nearPlane, 0.1f, 0.1f, camera->farPlane - 0.1f, "%.1f"); + + // Far Plane slider + ImGui::DragFloat("Far Plane", &camera->farPlane, 1.0f, camera->nearPlane + 0.1f, 1000.0f, "%.1f"); + + // Additional Camera Utilities (Optional) + ImGui::DragFloat("Zoom", &camera->zoom, 0.1f, 1.0f, 100.0f, "%.1f"); + }; + + // Determine the type of the component and handle accordingly + if (auto transform = std::dynamic_pointer_cast(component)) { - render->meshName = meshBuffer; + handleTransformComponent(transform); + } + else if (auto render = std::dynamic_pointer_cast(component)) + { + handleRenderComponent(render); + } + else if (auto light = std::dynamic_pointer_cast(component)) + { + handleLightComponent(light); + } + else if (auto rigidBody = std::dynamic_pointer_cast(component)) + { + handleRigidBody3DComponent(rigidBody); + } + else if (auto collisionShape = std::dynamic_pointer_cast(component)) + { + handleCollisionShape3DComponent(collisionShape); + } + else if (auto camera = std::dynamic_pointer_cast(component)) + { + handleCameraComponent(camera); } - // Color picker for object color - ImGui::ColorEdit3("Color", glm::value_ptr(render->color)); - } - else if (auto light = std::dynamic_pointer_cast(component)) - { - // Light Type - const char *lightTypes[] = {"Point", "Directional", "Spot"}; - int typeIndex = static_cast(light->type); - if (ImGui::Combo("Type", &typeIndex, lightTypes, IM_ARRAYSIZE(lightTypes))) + // ----------------------------- + // Remove Component Button + // ----------------------------- + // Prevent removal of essential components like TransformComponent + if (component->GetName() != "Transform") { - light->type = static_cast(typeIndex); - } - - // Color and Intensity - ImGui::ColorEdit3("Color", glm::value_ptr(light->color)); - ImGui::DragFloat("Intensity", &light->intensity, 0.1f, 0.0f, 10.0f); - - // Attenuation Factors for Point Lights - if (light->type == LightType::Point) - { - ImGui::DragFloat("Constant", &light->constant, 0.01f, 0.0f, 1.0f); - ImGui::DragFloat("Linear", &light->linear, 0.01f, 0.0f, 1.0f); - ImGui::DragFloat("Quadratic", &light->quadratic, 0.01f, 0.0f, 1.0f); - } - - // Direction for Directional Lights - if (light->type == LightType::Directional) - { - ImGui::DragFloat3("Direction", glm::value_ptr(light->direction), 0.1f); - } - - if (light->type == LightType::Spot) - { - ImGui::DragFloat("cutOff", &light->cutOff, 0.01f, 0.0f, 10.0f); - ImGui::DragFloat("outerCutOff", &light->outerCutOff, 0.01f, 0.0f, 50.0f); + if (ImGui::Button(("Remove " + component->GetName()).c_str())) + { + it = removeComponent(it); + ImGui::Separator(); + ImGui::PopID(); + continue; // Skip iterator increment as it is already updated + } } } - else if (auto rigidBody = std::dynamic_pointer_cast(component)) - { - ImGui::DragFloat3("Velocity", glm::value_ptr(rigidBody->velocity), 0.1f); - ImGui::DragFloat3("Acceleration", glm::value_ptr(rigidBody->acceleration), 0.1f); - ImGui::DragFloat("Mass", &rigidBody->mass, 0.1f, 0.1f, 100.0f); - // RigidBody Type - const char *rbTypes[] = {"Static", "Dynamic", "Kinematic"}; - int typeIndex = static_cast(rigidBody->type); - if (ImGui::Combo("Type", &typeIndex, rbTypes, IM_ARRAYSIZE(rbTypes))) - { - rigidBody->type = static_cast(typeIndex); - } - } - else if (auto collisionShape = std::dynamic_pointer_cast(component)) - { - // Shape Type - const char *shapeTypes[] = {"Box", "Sphere", "Capsule"}; - int shapeIndex = static_cast(collisionShape->shapeType); - if (ImGui::Combo("Shape Type", &shapeIndex, shapeTypes, IM_ARRAYSIZE(shapeTypes))) - { - collisionShape->shapeType = static_cast(shapeIndex); - } - - // Display properties based on shape type - switch (collisionShape->shapeType) - { - case CollisionShapeType::Box: - ImGui::DragFloat3("Size", glm::value_ptr(collisionShape->size), 0.1f, 0.1f, 100.0f); - break; - case CollisionShapeType::Sphere: - ImGui::DragFloat("Radius", &collisionShape->radius, 0.1f, 0.1f, 100.0f); - break; - case CollisionShapeType::Capsule: - ImGui::DragFloat3("Direction", glm::value_ptr(collisionShape->direction), 0.1f); - ImGui::DragFloat("Height", &collisionShape->height, 0.1f, 0.1f, 100.0f); - break; - // Add UI elements for additional shapes here - default: - break; - } - } - else if (auto camera = std::dynamic_pointer_cast(component)) - { - // Field of View (FOV) slider - ImGui::DragFloat("Field of View", &camera->fov, 1.0f, 1.0f, 120.0f, "%.1f degrees"); - - // Toggle between Orthographic and Perspective projection - ImGui::Checkbox("Orthographic", &camera->orthographic); - - // Near Plane slider - ImGui::DragFloat("Near Plane", &camera->nearPlane, 0.1f, 0.1f, camera->farPlane - 0.1f, "%.1f"); - - // Far Plane slider - ImGui::DragFloat("Far Plane", &camera->farPlane, 1.0f, camera->nearPlane + 0.1f, 1000.0f, "%.1f"); - - // Additional Camera Utilities (Optional) - // Example: Zoom control if applicable - ImGui::DragFloat("Zoom", &camera->zoom, 0.1f, 1.0f, 100.0f, "%.1f"); - - // Example: Projection Type Dropdown (if more projection types are supported) - /* - const char* projectionTypes[] = { "Perspective", "Orthographic" }; - int currentProjection = camera->orthographic ? 1 : 0; - if (ImGui::Combo("Projection Type", ¤tProjection, projectionTypes, IM_ARRAYSIZE(projectionTypes))) - { - camera->orthographic = (currentProjection == 1); - } - */ - } - - // Button to remove the component - if (strcmp(component->GetName().c_str(), "Transform") != 0) - { - if (ImGui::Button(("Remove " + component->GetName()).c_str())) - { - it = selectedEntity->components.erase(it); - ImGui::Separator(); - ImGui::PopID(); - - continue; // Continue as the iterator is updated - } - } + ImGui::PopID(); + ++it; } - ImGui::PopID(); - ++it; } } else @@ -1302,6 +1657,7 @@ void ShowInspector(std::shared_ptr &selectedEntity) ImGui::End(); // End of Inspector window } + // Function to manipulate the Editor Camera using ImGuizmo void ManipulateEditorCamera(EditorCamera &editorCamera, float aspectRatio) { @@ -1349,7 +1705,10 @@ void ManipulateEditorCamera(EditorCamera &editorCamera, float aspectRatio) void DrawImGuizmo(TransformComponent &transform, glm::mat4 &view, glm::mat4 &projection) { - if (GameRunning) {return;} + if (GameRunning) + { + return; + } // Ensure ImGuizmo context is initialized ImGuizmo::BeginFrame(); @@ -1440,113 +1799,111 @@ glm::mat4 GetRotationMatrix(const TransformComponent *transform) return rotation; } -void ShowCameraPreview(std::vector> &entities) -{ - ImGui::Begin("Camera Preview"); +//void ShowCameraPreview(std::vector> &entities) +//{ +// ImGui::Begin("Camera Preview"); +// +// // Get the window size for rendering +// ImVec2 windowSize = ImGui::GetContentRegionAvail(); +// int texWidth = static_cast(windowSize.x); +// int texHeight = static_cast(windowSize.y); +// +// // Initialize framebuffer if not done +// static Framebuffer fb = {0, 0, 0}; +// static bool framebufferInitialized = false; +// +// if (!framebufferInitialized || texWidth != 0 || texHeight != 0) +// { +// if (framebufferInitialized) +// { +// // Delete previous framebuffer resources +// glDeleteFramebuffers(1, &fb.FBO); +// glDeleteTextures(1, &fb.texture); +// glDeleteRenderbuffers(1, &fb.RBO); +// } +// fb = InitFramebuffer(texWidth, texHeight); +// framebufferInitialized = true; +// } +// +// // Bind the framebuffer +// glBindFramebuffer(GL_FRAMEBUFFER, fb.FBO); +// +// // Set viewport to match the framebuffer size +// glViewport(0, 0, texWidth, texHeight); +// +// // Clear the framebuffer +// glEnable(GL_DEPTH_TEST); +// glClearColor(0.2f, 0.2f, 0.2f, 1.0f); // Slightly lighter background for visibility +// glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); +// +// // Find the camera entity +// std::shared_ptr activeGameCamera = GetActiveGameCamera(entities); +// std::shared_ptr cameraEntity = FindEntityWithCamera(entities, activeGameCamera); +// if (cameraEntity) +// { +// auto camera = cameraEntity->GetComponent(); +// auto transform = cameraEntity->GetComponent(); +// +// if (camera && transform) +// { +// // Compute view and projection matrices +// glm::mat4 viewMatrix = camera->GetViewMatrix(transform->position, transform->rotation); +// glm::mat4 projectionMatrix = camera->GetProjectionMatrix(static_cast(texWidth) / static_cast(texHeight)); +// +// // Use the minimal shader +// previewShader->Use(); +// +// // Set uniforms +// glUniformMatrix4fv(glGetUniformLocation(previewShader->Program, "view"), 1, GL_FALSE, glm::value_ptr(viewMatrix)); +// glUniformMatrix4fv(glGetUniformLocation(previewShader->Program, "projection"), 1, GL_FALSE, glm::value_ptr(projectionMatrix)); +// +// // Render all entities except the camera itself +// for (const auto &entity : entities) +// { +// if (entity == cameraEntity) +// continue; // Skip the camera entity +// +// auto render = entity->GetComponent(); +// auto entityTransform = entity->GetComponent(); +// +// if (render && entityTransform) +// { +// // Compute model matrix +// glm::mat4 model = glm::mat4(1.0f); +// model = glm::translate(model, entityTransform->position); +// model = glm::rotate(model, glm::radians(entityTransform->rotation.x), glm::vec3(1, 0, 0)); +// model = glm::rotate(model, glm::radians(entityTransform->rotation.y), glm::vec3(0, 1, 0)); +// model = glm::rotate(model, glm::radians(entityTransform->rotation.z), glm::vec3(0, 0, 1)); +// model = glm::scale(model, entityTransform->scale); +// +// // Set model and object color +// glUniformMatrix4fv(glGetUniformLocation(previewShader->Program, "model"), 1, GL_FALSE, glm::value_ptr(model)); +// glUniform3fv(glGetUniformLocation(previewShader->Program, "objectColor"), 1, glm::value_ptr(render->color)); +// +// // Bind VAO and draw +// glBindVertexArray(cubeVAO); +// glDrawArrays(GL_TRIANGLES, 0, 36); // Assuming a cube with 36 vertices +// glBindVertexArray(0); +// } +// } +// } +// } +// else +// { +// // No camera found, display a message +// ImGui::Text("No camera entity found."); +// } +// +// // Unbind framebuffer +// glBindFramebuffer(GL_FRAMEBUFFER, 0); +// glDisable(GL_DEPTH_TEST); +// +// // Display the rendered texture in ImGui +// ImGui::Image((intptr_t)fb.texture, windowSize, ImVec2(0, 1), ImVec2(1, 0)); +// +// ImGui::End(); // End of Camera Preview window +//} - // Get the window size for rendering - ImVec2 windowSize = ImGui::GetContentRegionAvail(); - int texWidth = static_cast(windowSize.x); - int texHeight = static_cast(windowSize.y); - - // Initialize framebuffer if not done - static Framebuffer fb = {0, 0, 0}; - static bool framebufferInitialized = false; - - if (!framebufferInitialized || texWidth != 0 || texHeight != 0) { - if (framebufferInitialized) { - // Delete previous framebuffer resources - glDeleteFramebuffers(1, &fb.FBO); - glDeleteTextures(1, &fb.texture); - glDeleteRenderbuffers(1, &fb.RBO); - } - fb = InitFramebuffer(texWidth, texHeight); - framebufferInitialized = true; - } - - // Bind the framebuffer - glBindFramebuffer(GL_FRAMEBUFFER, fb.FBO); - - // Set viewport to match the framebuffer size - glViewport(0, 0, texWidth, texHeight); - - // Clear the framebuffer - glEnable(GL_DEPTH_TEST); - glClearColor(0.2f, 0.2f, 0.2f, 1.0f); // Slightly lighter background for visibility - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - - // Find the camera entity - std::shared_ptr activeGameCamera = GetActiveGameCamera(entities); - std::shared_ptr cameraEntity = FindEntityWithCamera(entities, activeGameCamera); - if (cameraEntity) - { - auto camera = cameraEntity->GetComponent(); - auto transform = cameraEntity->GetComponent(); - - if (camera && transform) - { - // Compute view and projection matrices - glm::mat4 viewMatrix = camera->GetViewMatrix(transform->position, transform->rotation); - glm::mat4 projectionMatrix = camera->GetProjectionMatrix(static_cast(texWidth) / static_cast(texHeight)); - - // Use the minimal shader - previewShader->Use(); - - // Set uniforms - glUniformMatrix4fv(glGetUniformLocation(previewShader->Program, "view"), 1, GL_FALSE, glm::value_ptr(viewMatrix)); - glUniformMatrix4fv(glGetUniformLocation(previewShader->Program, "projection"), 1, GL_FALSE, glm::value_ptr(projectionMatrix)); - - - - // Render all entities except the camera itself - for (const auto &entity : entities) - { - if (entity == cameraEntity) - continue; // Skip the camera entity - - auto render = entity->GetComponent(); - auto entityTransform = entity->GetComponent(); - - if (render && entityTransform) - { - // Compute model matrix - glm::mat4 model = glm::mat4(1.0f); - model = glm::translate(model, entityTransform->position); - model = glm::rotate(model, glm::radians(entityTransform->rotation.x), glm::vec3(1, 0, 0)); - model = glm::rotate(model, glm::radians(entityTransform->rotation.y), glm::vec3(0, 1, 0)); - model = glm::rotate(model, glm::radians(entityTransform->rotation.z), glm::vec3(0, 0, 1)); - model = glm::scale(model, entityTransform->scale); - - // Set model and object color - glUniformMatrix4fv(glGetUniformLocation(previewShader->Program, "model"), 1, GL_FALSE, glm::value_ptr(model)); - glUniform3fv(glGetUniformLocation(previewShader->Program, "objectColor"), 1, glm::value_ptr(render->color)); - - - // Bind VAO and draw - glBindVertexArray(cubeVAO); - glDrawArrays(GL_TRIANGLES, 0, 36); // Assuming a cube with 36 vertices - glBindVertexArray(0); - } - } - } - } - else - { - // No camera found, display a message - ImGui::Text("No camera entity found."); - } - - // Unbind framebuffer - glBindFramebuffer(GL_FRAMEBUFFER, 0); - glDisable(GL_DEPTH_TEST); - - // Display the rendered texture in ImGui - ImGui::Image((intptr_t)fb.texture, windowSize, ImVec2(0,1), ImVec2(1,0)); - - ImGui::End(); // End of Camera Preview window -} - -// Updated ShowGameView function void ShowGameView(std::vector> &entities) { ImGui::Begin("Game View"); @@ -1554,13 +1911,20 @@ void ShowGameView(std::vector> &entities) // Get the window size for rendering ImVec2 windowSize = ImGui::GetContentRegionAvail(); - - // Update the framebuffer and texture size if the window size changes - static int prevWidth = 0; - static int prevHeight = 0; int texWidth = static_cast(windowSize.x); int texHeight = static_cast(windowSize.y); + // Static variables to track previous size + static int prevWidth = 0; + static int prevHeight = 0; + + // Fallback camera parameters + glm::mat4 fallbackView = glm::translate(glm::mat4(1.0f), glm::vec3(0, 0, -5)); + glm::mat4 fallbackProjection = glm::perspective(glm::radians(45.0f), + static_cast(texWidth) / static_cast(texHeight), 0.1f, 100.0f); + glm::vec3 fallbackPosition = glm::vec3(0, 0, 5); + + // Handle framebuffer and texture resizing if (texWidth != prevWidth || texHeight != prevHeight) { prevWidth = texWidth; @@ -1575,18 +1939,38 @@ void ShowGameView(std::vector> &entities) glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, texWidth, texHeight); } - // Bind the framebuffer + // Bind the framebuffer and set viewport glBindFramebuffer(GL_FRAMEBUFFER, framebuffer); - - // Set viewport to match the framebuffer size glViewport(0, 0, texWidth, texHeight); - // Clear the framebuffer + // Enable depth testing and clear buffers glEnable(GL_DEPTH_TEST); glClearColor(0.1f, 0.1f, 0.1f, 1.0f); // Dark background glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - // Determine which camera to use based on GameRunning + // Cache uniform locations + cubeShader->Use(); + GLuint viewLoc = glGetUniformLocation(cubeShader->Program, "view"); + GLuint projLoc = glGetUniformLocation(cubeShader->Program, "projection"); + GLuint viewPosLoc = glGetUniformLocation(cubeShader->Program, "viewPos"); + GLuint useTextureLoc = glGetUniformLocation(cubeShader->Program, "useTexture"); + GLuint modelLoc = glGetUniformLocation(cubeShader->Program, "model"); + GLuint objectColorLoc = glGetUniformLocation(cubeShader->Program, "objectColor"); + + // Helper lambdas + auto setUniform = [&](const std::string& name, const glm::vec3& value) { + glUniform3fv(glGetUniformLocation(cubeShader->Program, name.c_str()), 1, glm::value_ptr(value)); + }; + + auto setUniformFloat = [&](const std::string& name, float value) { + glUniform1f(glGetUniformLocation(cubeShader->Program, name.c_str()), value); + }; + + auto getRotationMatrix = [&](TransformComponent* transform) -> glm::mat4 { + return glm::mat4_cast(glm::quat(glm::radians(transform->rotation))); + }; + + // Determine and set up the active camera glm::mat4 viewMatrix; glm::mat4 projectionMatrix; glm::vec3 cameraPosition; @@ -1596,60 +1980,57 @@ void ShowGameView(std::vector> &entities) // Editor Mode: Use editor camera viewMatrix = editorCamera.GetViewMatrix(); projectionMatrix = editorCamera.GetProjectionMatrix(static_cast(texWidth) / static_cast(texHeight)); - // Use the getter method to access the position cameraPosition = editorCamera.GetPosition(); } - else { - // **Game Mode** + // Game Mode: Use active game camera auto activeGameCamera = GetActiveGameCamera(entities); if (activeGameCamera) { - // Find the entity that owns this CameraComponent - std::shared_ptr cameraEntity = FindEntityWithCamera(entities, activeGameCamera); + auto cameraEntity = FindEntityWithCamera(entities, activeGameCamera); if (cameraEntity) { - // Retrieve the TransformComponent from the camera's entity auto transform = cameraEntity->GetComponent(); if (transform) { - // Get position and rotation from TransformComponent - glm::vec3 position = transform->position; - glm::vec3 rotation = transform->rotation; // Assuming rotation.x = Pitch, rotation.y = Yaw, rotation.z = Roll - - // Compute view and projection matrices using CameraComponent and TransformComponent data - viewMatrix = activeGameCamera->GetViewMatrix(position, rotation); + cameraPosition = transform->position; + viewMatrix = activeGameCamera->GetViewMatrix(cameraPosition, transform->rotation); projectionMatrix = activeGameCamera->GetProjectionMatrix(static_cast(texWidth) / static_cast(texHeight)); - cameraPosition = position; } else { - // Fallback if TransformComponent is missing - viewMatrix = glm::translate(glm::mat4(1.0f), glm::vec3(0, 0, -5)); - projectionMatrix = glm::perspective(glm::radians(45.0f), static_cast(texWidth) / static_cast(texHeight), 0.1f, 100.0f); - cameraPosition = glm::vec3(0, 0, 5); + // Use fallback if TransformComponent is missing + viewMatrix = fallbackView; + projectionMatrix = fallbackProjection; + cameraPosition = fallbackPosition; } } else { - // Fallback if no entity is found with activeGameCamera - viewMatrix = glm::translate(glm::mat4(1.0f), glm::vec3(0, 0, -5)); - projectionMatrix = glm::perspective(glm::radians(45.0f), static_cast(texWidth) / static_cast(texHeight), 0.1f, 100.0f); - cameraPosition = glm::vec3(0, 0, 5); + // Use fallback if no entity found + viewMatrix = fallbackView; + projectionMatrix = fallbackProjection; + cameraPosition = fallbackPosition; } } else { - // Fallback to default view if no CameraComponent is active - viewMatrix = glm::translate(glm::mat4(1.0f), glm::vec3(0, 0, -5)); - projectionMatrix = glm::perspective(glm::radians(45.0f), static_cast(texWidth) / static_cast(texHeight), 0.1f, 100.0f); - cameraPosition = glm::vec3(0, 0, 5); + // Use fallback if no active camera + viewMatrix = fallbackView; + projectionMatrix = fallbackProjection; + cameraPosition = fallbackPosition; } } + // Set camera uniforms + glUniformMatrix4fv(viewLoc, 1, GL_FALSE, glm::value_ptr(viewMatrix)); + glUniformMatrix4fv(projLoc, 1, GL_FALSE, glm::value_ptr(projectionMatrix)); + glUniform3fv(viewPosLoc, 1, glm::value_ptr(cameraPosition)); + glUniform1i(useTextureLoc, false); + // Collect lights from entities - std::vector> lights; + std::vector> lights; for (const auto &entity : entities) { auto light = entity->GetComponent(); @@ -1660,121 +2041,57 @@ void ShowGameView(std::vector> &entities) } } - // Set up shader for rendering - cubeShader->Use(); - - // Set camera position - glUniform3fv(glGetUniformLocation(cubeShader->Program, "viewPos"), 1, glm::value_ptr(cameraPosition)); - glUniform1i(glGetUniformLocation(cubeShader->Program, "useTexture"), false); - - // Set view and projection matrices - glUniformMatrix4fv(glGetUniformLocation(cubeShader->Program, "view"), 1, GL_FALSE, glm::value_ptr(viewMatrix)); - glUniformMatrix4fv(glGetUniformLocation(cubeShader->Program, "projection"), 1, GL_FALSE, glm::value_ptr(projectionMatrix)); - // Initialize light counts - int pointLightCount = 0; - int dirLightCount = 0; - int spotLightCount = 0; + int pointLightCount = 0, dirLightCount = 0, spotLightCount = 0; // Iterate over all lights and categorize them - for (size_t i = 0; i < lights.size(); ++i) + for (const auto &[light, transform] : lights) { - LightComponent *light = lights[i].first; - TransformComponent *lightTransform = lights[i].second; - - // Determine light type and process accordingly switch (light->type) { - case LightType::Point: - { - if (pointLightCount >= MAX_POINT_LIGHTS) + case LightType::Point: + if (pointLightCount < MAX_POINT_LIGHTS) + { + std::string base = "pointLights[" + std::to_string(pointLightCount) + "]."; + setUniform(base + "position", transform->position); + setUniform(base + "color", light->color * light->intensity); + setUniformFloat(base + "constant", light->constant); + setUniformFloat(base + "linear", light->linear); + setUniformFloat(base + "quadratic", light->quadratic); + pointLightCount++; + } break; - std::string baseName = "pointLights[" + std::to_string(pointLightCount) + "]"; - - // Set Point Light properties - glUniform3fv(glGetUniformLocation(cubeShader->Program, (baseName + ".position").c_str()), 1, glm::value_ptr(lightTransform->position)); - glUniform3fv(glGetUniformLocation(cubeShader->Program, (baseName + ".color").c_str()), 1, glm::value_ptr(light->color * light->intensity)); - - glUniform1f(glGetUniformLocation(cubeShader->Program, (baseName + ".constant").c_str()), light->constant); - glUniform1f(glGetUniformLocation(cubeShader->Program, (baseName + ".linear").c_str()), light->linear); - glUniform1f(glGetUniformLocation(cubeShader->Program, (baseName + ".quadratic").c_str()), light->quadratic); - - pointLightCount++; - break; - } - case LightType::Directional: - { - if (dirLightCount >= MAX_DIR_LIGHTS) + case LightType::Directional: + if (dirLightCount < MAX_DIR_LIGHTS) + { + std::string base = "dirLights[" + std::to_string(dirLightCount) + "]."; + glm::vec3 worldDir = glm::normalize(glm::vec3(getRotationMatrix(transform) * glm::vec4(light->direction, 0.0f))); + setUniform(base + "direction", worldDir); + setUniform(base + "color", light->color * light->intensity); + dirLightCount++; + } break; - std::string baseName = "dirLights[" + std::to_string(dirLightCount) + "]"; - - // Obtain the rotation matrix from the TransformComponent - glm::mat4 rotationMatrix = GetRotationMatrix(lightTransform); - - // Transform the light's direction vector to world space - glm::vec3 worldDirection = glm::normalize(glm::vec3(rotationMatrix * glm::vec4(light->direction, 0.0))); - - // Set Directional Light properties with transformed direction - glUniform3fv(glGetUniformLocation(cubeShader->Program, (baseName + ".direction").c_str()), 1, glm::value_ptr(worldDirection)); - glUniform3fv(glGetUniformLocation(cubeShader->Program, (baseName + ".color").c_str()), 1, glm::value_ptr(light->color * light->intensity)); - - dirLightCount++; - break; - } - case LightType::Spot: - { - if (spotLightCount >= MAX_SPOT_LIGHTS) + case LightType::Spot: + if (spotLightCount < MAX_SPOT_LIGHTS) + { + std::string base = "spotLights[" + std::to_string(spotLightCount) + "]."; + setUniform(base + "position", transform->position); + glm::vec3 worldDir = glm::normalize(glm::vec3(getRotationMatrix(transform) * glm::vec4(light->direction, 0.0f))); + setUniform(base + "direction", worldDir); + setUniform(base + "color", light->color * light->intensity); + setUniformFloat(base + "cutOff", glm::cos(glm::radians(light->cutOff))); + setUniformFloat(base + "outerCutOff", glm::cos(glm::radians(light->outerCutOff))); + setUniformFloat(base + "constant", light->constant); + setUniformFloat(base + "linear", light->linear); + setUniformFloat(base + "quadratic", light->quadratic); + spotLightCount++; + } break; - std::string baseName = "spotLights[" + std::to_string(spotLightCount) + "]"; - - // Set Spotlight position - GLint posLoc = glGetUniformLocation(cubeShader->Program, (baseName + ".position").c_str()); - glUniform3fv(posLoc, 1, glm::value_ptr(lightTransform->position)); - - // Create rotation matrix from TransformComponent - glm::mat4 rotationMatrix = GetRotationMatrix(lightTransform); - - // Transform the spotlight's direction vector to world space - glm::vec3 worldDirection = glm::normalize(glm::vec3(rotationMatrix * glm::vec4(light->direction, 0.0f))); - - // Set Spotlight direction - GLint dirLoc = glGetUniformLocation(cubeShader->Program, (baseName + ".direction").c_str()); - glUniform3fv(dirLoc, 1, glm::value_ptr(worldDirection)); - - // Set Spotlight color and intensity - GLint colorLoc = glGetUniformLocation(cubeShader->Program, (baseName + ".color").c_str()); - glUniform3fv(colorLoc, 1, glm::value_ptr(light->color * light->intensity)); - - // Set cutoff angles (ensure they are the cosine of the angles in radians) - float cutOff = glm::cos(glm::radians(light->cutOff)); - float outerCutOff = glm::cos(glm::radians(light->outerCutOff)); - - GLint cutOffLoc = glGetUniformLocation(cubeShader->Program, (baseName + ".cutOff").c_str()); - glUniform1f(cutOffLoc, cutOff); - - GLint outerCutOffLoc = glGetUniformLocation(cubeShader->Program, (baseName + ".outerCutOff").c_str()); - glUniform1f(outerCutOffLoc, outerCutOff); - - // Set attenuation factors - GLint constLoc = glGetUniformLocation(cubeShader->Program, (baseName + ".constant").c_str()); - glUniform1f(constLoc, light->constant); - - GLint linearLoc = glGetUniformLocation(cubeShader->Program, (baseName + ".linear").c_str()); - glUniform1f(linearLoc, light->linear); - - GLint quadraticLoc = glGetUniformLocation(cubeShader->Program, (baseName + ".quadratic").c_str()); - glUniform1f(quadraticLoc, light->quadratic); - - spotLightCount++; - break; - } - - default: - // Handle unknown light types if necessary - break; + default: + break; } } @@ -1798,11 +2115,8 @@ void ShowGameView(std::vector> &entities) model = glm::rotate(model, glm::radians(transform->rotation.z), glm::vec3(0, 0, 1)); model = glm::scale(model, transform->scale); - // Set model matrix - glUniformMatrix4fv(glGetUniformLocation(cubeShader->Program, "model"), 1, GL_FALSE, glm::value_ptr(model)); - - // Set object color - glUniform3fv(glGetUniformLocation(cubeShader->Program, "objectColor"), 1, glm::value_ptr(render->color)); + glUniformMatrix4fv(modelLoc, 1, GL_FALSE, glm::value_ptr(model)); + glUniform3fv(objectColorLoc, 1, glm::value_ptr(render->color)); if (render->meshName == "model") { @@ -1814,7 +2128,6 @@ void ShowGameView(std::vector> &entities) } else { - // Draw cube glBindVertexArray(cubeVAO); glDrawArrays(GL_TRIANGLES, 0, 36); glBindVertexArray(0); @@ -1822,51 +2135,45 @@ void ShowGameView(std::vector> &entities) } } + // Render gizmos if not in Game mode if (!GameRunning) { - - // auto camera = GetActiveGameCamera(entities); - // auto entity = FindEntityWithCamera(entities, camera); - // if (entity) - //{ - // auto transform = entity->GetComponent(); - // // Get position and rotation from TransformComponent - // glm::vec3 position = transform->position; - // RenderCameraGizmo(position, glm::vec3(0.1f,0.1f,0.1f), viewMatrix, projectionMatrix); - // } totalLights = 0; - // Render light gizmos (if any) - for (const auto &lightPair : lights) + for (const auto &[light, transform] : lights) { - // LightComponent *light = lightPair.first; - TransformComponent *lightTransform = lightPair.second; totalLights++; - RenderLightGizmo(lightTransform->position, viewMatrix, projectionMatrix); + RenderLightGizmo(transform->position, viewMatrix, projectionMatrix); + } + + if (selectedEntity) + { + auto transform = selectedEntity->GetComponent(); + if (transform) + { + gizmoShader->Use(); + DrawImGuizmo(*transform, viewMatrix, projectionMatrix); + } } } - glBindFramebuffer(GL_FRAMEBUFFER, 0); // Unbind framebuffer - + // Unbind framebuffer and disable depth testing + glBindFramebuffer(GL_FRAMEBUFFER, 0); glDisable(GL_DEPTH_TEST); // Display the rendered texture in ImGui ImGui::Image((intptr_t)renderedTexture, windowSize, ImVec2(0, 1), ImVec2(1, 0)); - glm::mat4 view = editorCamera.GetViewMatrix(); - glm::mat4 projection = glm::perspective(glm::radians(45.0f), (static_cast(texWidth) / static_cast(texHeight)), 0.1f, 100.0f); - // Assume `selectedEntity` is the entity being manipulated + // Handle Gizmo Manipulation if (selectedEntity) { auto transform = selectedEntity->GetComponent(); if (transform) { gizmoShader->Use(); - DrawImGuizmo(*transform, view, projection); - // std::cout << "1" << std::endl; + DrawImGuizmo(*transform, viewMatrix, projectionMatrix); } } ImGui::End(); // End of Game View window } -