diff --git a/.vscode/settings.json b/.vscode/settings.json index c89ef97..5e5476a 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -2,11 +2,11 @@ "cmake.configureArgs": [ "-DVCPKG_APPLOCAL_DEPS=ON", "-DX_VCPKG_APPLOCAL_DEPS_INSTALL=ON", - "-DVCPKG_MANIFEST_MODE=ON", - "-DVCPKG_TARGET_TRIPLET=x64-linux" + "-DVCPKG_TARGET_TRIPLET=x64-linux", + "-DVCPKG_MANIFEST_MODE=ON" ], "vcpkg.general.enable": true, - "vcpkg.target.hostTriplet": "", + "vcpkg.target.hostTriplet": "x64-linux", // use x64-linx / arm64-osx "vcpkg.target.defaultTriplet": "x64-linux", "vcpkg.target.useStaticLib": false, diff --git a/README.md b/README.md index f4ae221..679683d 100644 --- a/README.md +++ b/README.md @@ -51,3 +51,5 @@ brew install pkg-config - [ ] Remove VCPKG extension and use directly in CMake - [ ] Figure out how to add new cpp files correctly without needing to delete the build folder. - [ ] Lift mouse settings on app level instead of per-scene level +- [ ] Scene Graph +- [ ] Find optimised way of doing transforms diff --git a/src/engine/app/base_scene.cpp b/src/engine/app/base_scene.cpp index 136e2b2..a3e0e09 100644 --- a/src/engine/app/base_scene.cpp +++ b/src/engine/app/base_scene.cpp @@ -1,7 +1,76 @@ #include "base_scene.h" -BaseScene::BaseScene(RenderContext &renderContext) - : m_renderContext(renderContext) { +BaseScene::BaseScene(RenderContext &renderContext, std::string sceneTitle) + : m_renderContext(renderContext), m_sceneTitle(sceneTitle) { + m_objectPropertiesEditorPtr = + std::make_shared(ObjectPropertiesEditor([&]() { + ImGui::Text(m_sceneTitle.c_str()); + + if (ImGui::BeginCombo( + "Selected Object", + fmt::format("Object {}", m_activeModelIndex).c_str())) { + for (int itemIdx = 0; itemIdx < m_models.size(); itemIdx++) { + const bool is_selected = (m_activeModelIndex == itemIdx); + if (ImGui::Selectable( + fmt::format("Object {}", itemIdx).c_str(), + is_selected)) + m_activeModelIndex = itemIdx; + + // TODO: When object is selected, disable animation + if (is_selected) { + // disable animation + } else { + // enable animation + } + } + ImGui::EndCombo(); + } + })); + + m_cameraPropertiesEditorPtr = + std::make_shared(CameraPropertiesEditor([&]() { + if (ImGui::BeginCombo( + "Active Camera", + fmt::format("Camera {}", m_activeCameraIndex).c_str())) { + for (int itemIdx = 0; itemIdx < m_cameras.size(); itemIdx++) { + const bool is_selected = (m_activeCameraIndex == itemIdx); + if (ImGui::Selectable( + fmt::format("Camera {}", itemIdx).c_str(), + is_selected)) + m_activeCameraIndex = itemIdx; + + // Set the initial focus when opening the combo + // (scrolling + keyboard navigation focus) + if (is_selected) + ImGui::SetItemDefaultFocus(); + } + ImGui::EndCombo(); + } + + ImGui::SeparatorText("Camera Properties"); + })); + + m_inputPropertiesEditorPtr = + std::make_shared(InputPropertiesEditor([&]() { + ImGui::SeparatorText("Mouse"); + ImGui::SliderFloat("X Sensitivity", &m_xSensitivity, 0.01f, 30.0f); + ImGui::SliderFloat("Y Sensitivity", &m_ySensitivity, 0.01f, 30.0f); + ImGui::SliderFloat("Movement Sensitivity", &m_moveSpeed, 0.01f, + 30.0f); + ImGui::Checkbox("Inverted", &isInverted); + })); +} + +void BaseScene::OnGUIRender() { + if (ImGui::BeginTabBar("Editor")) { + m_objectPropertiesEditorPtr->Render(); + if (m_cameras.size() > 0) { + m_cameraPropertiesEditorPtr->Render(); + } + m_inputPropertiesEditorPtr->Render(); + + ImGui::EndTabBar(); + } } void BaseScene::OnUpdate() { @@ -77,46 +146,4 @@ void BaseScene::OnUpdate() { activeCamera.UpdatePosition(positionDelta); } } -} - -void BaseScene::OnGUIRender( - std::shared_ptr objectPropertiesEditorPtr) { - if (ImGui::BeginTabBar("Editor")) { - objectPropertiesEditorPtr->Render(); - - if (m_cameras.size() > 0 && ImGui::BeginTabItem("Camera")) { - if (ImGui::BeginCombo( - "Active Camera", - fmt::format("Camera {}", m_activeCameraIndex).c_str())) { - for (int itemIdx = 0; itemIdx < m_cameras.size(); itemIdx++) { - const bool is_selected = (m_activeCameraIndex == itemIdx); - if (ImGui::Selectable( - fmt::format("Camera {}", itemIdx).c_str(), - is_selected)) - m_activeCameraIndex = itemIdx; - - // Set the initial focus when opening the combo - // (scrolling + keyboard navigation focus) - if (is_selected) - ImGui::SetItemDefaultFocus(); - } - ImGui::EndCombo(); - } - - ImGui::SeparatorText("Camera Properties"); - ImGui::EndTabItem(); - } - - if (ImGui::BeginTabItem("Input")) { - ImGui::SeparatorText("Mouse"); - ImGui::SliderFloat("X Sensitivity", &m_xSensitivity, 0.01f, 30.0f); - ImGui::SliderFloat("Y Sensitivity", &m_ySensitivity, 0.01f, 30.0f); - ImGui::SliderFloat("Movement Sensitivity", &m_moveSpeed, 0.01f, - 30.0f); - ImGui::Checkbox("Inverted", &isInverted); - ImGui::EndTabItem(); - } - - ImGui::EndTabBar(); - } } \ No newline at end of file diff --git a/src/engine/app/base_scene.h b/src/engine/app/base_scene.h index 6fb1878..0a861ba 100644 --- a/src/engine/app/base_scene.h +++ b/src/engine/app/base_scene.h @@ -36,35 +36,43 @@ struct RenderContext { class BaseScene { protected: RenderContext &m_renderContext; + std::vector m_models; private: std::vector m_cameras; int m_activeCameraIndex = 0; + + int m_activeModelIndex = 0; float m_xSensitivity = 8.0f; float m_ySensitivity = 8.0f; float m_moveSpeed = 8.0f; bool isInverted = true; + std::string m_sceneTitle; + + std::shared_ptr m_objectPropertiesEditorPtr; + std::shared_ptr m_cameraPropertiesEditorPtr; + std::shared_ptr m_inputPropertiesEditorPtr; + public: - BaseScene(RenderContext &renderContext); + BaseScene(RenderContext &renderContext, std::string sceneTitle); // * Keep in mind that even if these functions are overriden, the base // * functions can still be called from children virtual void OnUpdate(); virtual void OnRender(){}; - virtual void OnGUIRender(){}; + virtual void OnGUIRender(); protected: - // this has intentionally been made non overrideable with a change in - // signature - void OnGUIRender( - std::shared_ptr objectPropertiesEditorPtr); - void AddCamera(Camera camera) { m_cameras.push_back(std::move(camera)); } Camera &GetActiveCamera() { + if (m_cameras.size() == 0) { + throw std::runtime_error("No camera has been added to the scene"); + } + return m_cameras[m_activeCameraIndex]; } @@ -73,4 +81,22 @@ class BaseScene { m_activeCameraIndex = index; } } + + void AddModel(Model model) { + m_models.push_back(std::move(model)); + } + + void SetActiveModelIndex(int index) { + if (index < m_models.size()) { + m_activeModelIndex = index; + } + } + + Model &GetActiveModel() { + if (m_models.size() == 0) { + throw std::runtime_error("No model has been added to the scene"); + } + + return m_models[m_activeModelIndex]; + } }; diff --git a/src/engine/app/widgets/properties_editor.cpp b/src/engine/app/widgets/properties_editor.cpp index 18fb90e..4fc242a 100644 --- a/src/engine/app/widgets/properties_editor.cpp +++ b/src/engine/app/widgets/properties_editor.cpp @@ -1,15 +1,40 @@ #include "properties_editor.h" ObjectPropertiesEditor::ObjectPropertiesEditor(std::function renderCb) - : m_renderCb(renderCb) -{ -} - -void ObjectPropertiesEditor::Render() -{ - if (ImGui::BeginTabItem("Object Properties")) - { - m_renderCb(); - ImGui::EndTabItem(); - } -} \ No newline at end of file + : m_renderCb(renderCb) { +} + +void ObjectPropertiesEditor::SetAdditionalRenderCallback( + std::function renderCb) { + m_additionalRenderCb = renderCb; +} + +void ObjectPropertiesEditor::Render() { + if (ImGui::BeginTabItem("Object Properties")) { + m_renderCb(); + m_additionalRenderCb(); + ImGui::EndTabItem(); + } +} + +CameraPropertiesEditor::CameraPropertiesEditor(std::function renderCb) + : m_renderCb(renderCb) { +} + +void CameraPropertiesEditor::Render() { + if (ImGui::BeginTabItem("Camera")) { + m_renderCb(); + ImGui::EndTabItem(); + } +} + +InputPropertiesEditor::InputPropertiesEditor(std::function renderCb) + : m_renderCb(renderCb) { +} + +void InputPropertiesEditor::Render() { + if (ImGui::BeginTabItem("Input")) { + m_renderCb(); + ImGui::EndTabItem(); + } +} diff --git a/src/engine/app/widgets/properties_editor.h b/src/engine/app/widgets/properties_editor.h index 945b6ac..cb69b68 100644 --- a/src/engine/app/widgets/properties_editor.h +++ b/src/engine/app/widgets/properties_editor.h @@ -1,29 +1,41 @@ #pragma once -#include #include -class BasePropertiesEditor -{ - virtual void Render(){}; +#include + +class BasePropertiesEditor { + virtual void Render(){}; }; -class CameraPropertiesEditor : public BasePropertiesEditor -{ - CameraPropertiesEditor(); +class CameraPropertiesEditor : public BasePropertiesEditor { +private: + std::function m_renderCb; + +public: + CameraPropertiesEditor(std::function renderCb); + void Render(); }; -class LightPropertiesEditor : public BasePropertiesEditor -{ +class LightPropertiesEditor : public BasePropertiesEditor {}; + +class ObjectPropertiesEditor : public BasePropertiesEditor { +private: + // TODO: Having issues with reference here + std::function m_renderCb; + std::function m_additionalRenderCb = []() {}; + +public: + ObjectPropertiesEditor(std::function renderCb); + void SetAdditionalRenderCallback(std::function renderCb); + void Render(); }; -class ObjectPropertiesEditor : public BasePropertiesEditor -{ +class InputPropertiesEditor : public BasePropertiesEditor { private: - // TODO: Having issues with reference here - std::function m_renderCb; + std::function m_renderCb; public: - ObjectPropertiesEditor(std::function renderCb); - void Render(); + InputPropertiesEditor(std::function renderCb); + void Render(); }; \ No newline at end of file diff --git a/src/engine/core/gl/model.h b/src/engine/core/gl/model.h index 45a9d69..f97559a 100644 --- a/src/engine/core/gl/model.h +++ b/src/engine/core/gl/model.h @@ -30,6 +30,9 @@ class Model { glm::vec3 scale = glm::vec3(1.0f)); ~Model(); + /// @brief Applies delta translation to the model + /// @param translation + /// @return the model itself inline Model &Translate(glm::vec3 translation) { m_position += translation; @@ -40,13 +43,14 @@ class Model { return *this; } + /// @brief Sets the position of the model inline Model &SetPosition(glm::vec3 position) { InitializeModelMatrix(position, m_rotation, m_scale, true); return *this; } - /// @brief Rotates the model along x, y, z axis. Rotation is applied in xyz - /// order + /// @brief Rotates the model by delta along x, y, z axis. Rotation is + /// applied in xyz order /// @param rotation A vec3 containing angles in degree for each axis inline Model &Rotate(glm::vec3 rotation) { m_rotation += rotation; @@ -64,6 +68,7 @@ class Model { return *this; } + /// @brief Sets the rotation of the model inline Model &SetOrientation(glm::vec3 rotation) { InitializeModelMatrix(m_position, rotation, m_scale, true); return *this; diff --git a/src/scenes/hello_3D_world/scene.cpp b/src/scenes/hello_3D_world/scene.cpp index 2d1006f..32f99e4 100644 --- a/src/scenes/hello_3D_world/scene.cpp +++ b/src/scenes/hello_3D_world/scene.cpp @@ -1,10 +1,10 @@ #include "scene.h" Hello3DWorldScene::Hello3DWorldScene(RenderContext &renderContext) - : BaseScene(renderContext), + : BaseScene(renderContext, "Hello 3D World"), m_shader("assets/shaders/vertex/simple_3d.vert", "assets/shaders/fragment/simple_3d.frag") { - m_modelPtr = std::make_unique(Plane(2, {0, -1.5f, 5}, {-45, 0, 0})); + AddModel(Plane(2, {0, -1.5f, 5}, {-45, 0, 0})); // set up camera AddCamera(Camera( @@ -14,10 +14,6 @@ Hello3DWorldScene::Hello3DWorldScene(RenderContext &renderContext) 100.0f))); AddCamera(Camera(glm::vec3(0, 0, 10), 0, -90, glm::ortho(-20.0f, 20.0f, -20.0f, 20.0f, 0.1f, 100.0f))); - - // set up editor callback - m_objectPropertiesEditorPtr = std::make_shared( - ObjectPropertiesEditor([&]() { ImGui::Text("Hello 3D World!"); })); } void Hello3DWorldScene::OnUpdate() { @@ -28,7 +24,7 @@ void Hello3DWorldScene::OnUpdate() { // m_modelPtr->Rotate({0.5f, 0, 0}).Translate({0, 0, 0.01f}); // } - m_modelPtr->SetPosition({0, 0, -10}).SetOrientation({45, 0, 0}); + m_models[0].SetPosition({0, 0, -10}).SetOrientation({45, 0, 0}); } void Hello3DWorldScene::OnRender() { @@ -36,17 +32,18 @@ void Hello3DWorldScene::OnRender() { Camera &activeCamera = GetActiveCamera(); - glm::mat4 mvpMatrix = Renderer::ComputeMVPMatrix( - m_modelPtr->GetModelMatrix(), activeCamera.GetViewMatrix(), - activeCamera.GetProjectionMatrix()); - - m_shader.SetUniformMatrix4f("u_mvp", mvpMatrix); - m_shader.SetUniformBool("u_shouldUseTexture", false); + for (auto &model : m_models) { + glm::mat4 mvpMatrix = Renderer::ComputeMVPMatrix( + model.GetModelMatrix(), activeCamera.GetViewMatrix(), + activeCamera.GetProjectionMatrix()); - m_modelPtr->Draw(*m_renderContext.rendererPtr); + m_shader.SetUniformMatrix4f("u_mvp", mvpMatrix); + m_shader.SetUniformBool("u_shouldUseTexture", false); + model.Draw(*m_renderContext.rendererPtr); + } m_shader.Unbind(); } void Hello3DWorldScene::OnGUIRender() { - BaseScene::OnGUIRender(m_objectPropertiesEditorPtr); + BaseScene::OnGUIRender(); } diff --git a/src/scenes/hello_3D_world/scene.h b/src/scenes/hello_3D_world/scene.h index 973fd1f..7783291 100644 --- a/src/scenes/hello_3D_world/scene.h +++ b/src/scenes/hello_3D_world/scene.h @@ -7,9 +7,6 @@ class Hello3DWorldScene : public BaseScene { private: Shader m_shader; - std::unique_ptr m_modelPtr; - - std::shared_ptr m_objectPropertiesEditorPtr; public: Hello3DWorldScene(RenderContext &renderContext); diff --git a/src/scenes/hello_texture/scene.cpp b/src/scenes/hello_texture/scene.cpp index a63614b..b0c3e1d 100644 --- a/src/scenes/hello_texture/scene.cpp +++ b/src/scenes/hello_texture/scene.cpp @@ -1,7 +1,7 @@ #include "scene.h" HelloTextureScene::HelloTextureScene(RenderContext &renderContext) - : BaseScene(renderContext), + : BaseScene(renderContext, "Hello Texture"), m_shader("assets/shaders/vertex/simple_uv.vert", "assets/shaders/fragment/simple_texture.frag"), m_texture("assets/textures/default.png", false) { @@ -19,7 +19,7 @@ HelloTextureScene::HelloTextureScene(RenderContext &renderContext) layout.Push(2); // uv std::vector meshes = {Mesh(vertices, indices, layout)}; - m_modelPtr = std::make_unique(Model(meshes)); + m_models.push_back(std::move(Model(meshes))); m_texture.Bind(); @@ -29,6 +29,6 @@ HelloTextureScene::HelloTextureScene(RenderContext &renderContext) void HelloTextureScene::OnRender() { m_shader.Bind(); - m_modelPtr->Draw(*m_renderContext.rendererPtr); + m_models[0].Draw(*m_renderContext.rendererPtr); m_shader.Unbind(); } \ No newline at end of file diff --git a/src/scenes/hello_texture/scene.h b/src/scenes/hello_texture/scene.h index 68b2f6e..898257e 100644 --- a/src/scenes/hello_texture/scene.h +++ b/src/scenes/hello_texture/scene.h @@ -5,7 +5,6 @@ class HelloTextureScene : public BaseScene { private: Shader m_shader; - std::unique_ptr m_modelPtr; Texture m_texture; public: diff --git a/src/scenes/hello_triangle/scene.cpp b/src/scenes/hello_triangle/scene.cpp index 97219cc..65f8da2 100644 --- a/src/scenes/hello_triangle/scene.cpp +++ b/src/scenes/hello_triangle/scene.cpp @@ -1,7 +1,7 @@ #include "scene.h" HelloTriangleScene::HelloTriangleScene(RenderContext &renderContext) - : BaseScene(renderContext), + : BaseScene(renderContext, "Hello Triangle"), m_shader("assets/shaders/vertex/clip_space.vert", "assets/shaders/fragment/simple_interpolated_color.frag") { std::vector vertices = { @@ -14,11 +14,11 @@ HelloTriangleScene::HelloTriangleScene(RenderContext &renderContext) layout.Push(3); std::vector meshes = {Mesh(vertices, indices, layout)}; - m_modelPtr = std::make_unique(Model(meshes)); + m_models.push_back(std::move(Model(meshes))); } void HelloTriangleScene::OnRender() { m_shader.Bind(); - m_modelPtr->Draw(*m_renderContext.rendererPtr); + m_models[0].Draw(*m_renderContext.rendererPtr); m_shader.Unbind(); } \ No newline at end of file diff --git a/src/scenes/hello_triangle/scene.h b/src/scenes/hello_triangle/scene.h index 13cf3ff..c6d3dee 100644 --- a/src/scenes/hello_triangle/scene.h +++ b/src/scenes/hello_triangle/scene.h @@ -5,7 +5,6 @@ class HelloTriangleScene : public BaseScene { private: Shader m_shader; - std::unique_ptr m_modelPtr; public: HelloTriangleScene(RenderContext &renderContext);