add serialization (use yaml-cpp), add stencil to render outline for selected entity, add play mode, UUIDS, add orthographic and perspective camera, add editor camera
This commit is contained in:
3
.gitmodules
vendored
3
.gitmodules
vendored
@ -20,3 +20,6 @@
|
|||||||
[submodule "Prism/vendor/EnTT"]
|
[submodule "Prism/vendor/EnTT"]
|
||||||
path = Prism/vendor/EnTT
|
path = Prism/vendor/EnTT
|
||||||
url = https://github.com/skypjack/entt.git
|
url = https://github.com/skypjack/entt.git
|
||||||
|
[submodule "Prism/vendor/yaml-cpp"]
|
||||||
|
path = Prism/vendor/yaml-cpp
|
||||||
|
url = https://github.com/jbeder/yaml-cpp
|
||||||
|
|||||||
@ -6,6 +6,7 @@
|
|||||||
#include "ImGuizmo.h"
|
#include "ImGuizmo.h"
|
||||||
#include "Prism/Core/Input.h"
|
#include "Prism/Core/Input.h"
|
||||||
#include "Prism/Renderer/Renderer2D.h"
|
#include "Prism/Renderer/Renderer2D.h"
|
||||||
|
#include "Prism/Script/ScriptEngine.h"
|
||||||
|
|
||||||
namespace Prism
|
namespace Prism
|
||||||
{
|
{
|
||||||
@ -119,7 +120,7 @@ namespace Prism
|
|||||||
}
|
}
|
||||||
|
|
||||||
EditorLayer::EditorLayer()
|
EditorLayer::EditorLayer()
|
||||||
: m_SceneType(SceneType::Model)
|
: m_SceneType(SceneType::Model), m_EditorCamera(glm::perspectiveFov(glm::radians(45.0f), 1280.0f, 720.0f, 0.1f, 10000.0f))
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -129,103 +130,16 @@ namespace Prism
|
|||||||
|
|
||||||
void EditorLayer::OnAttach()
|
void EditorLayer::OnAttach()
|
||||||
{
|
{
|
||||||
const auto environment = Environment::Load("assets/env/birchwood_4k.hdr");
|
|
||||||
|
|
||||||
// Model Scene
|
|
||||||
{
|
|
||||||
m_Scene = Ref<Scene>::Create("Model Scene");
|
|
||||||
m_CameraEntity = m_Scene->CreateEntity("Camera Entity");
|
|
||||||
m_CameraEntity.AddComponent<CameraComponent>(Camera(glm::perspectiveFov(glm::radians(45.0f), 1280.0f, 720.0f, 0.1f, 10000.0f)));
|
|
||||||
|
|
||||||
m_Scene->SetEnvironment(environment);
|
|
||||||
|
|
||||||
m_MeshEntity = m_Scene->CreateEntity("test Entity");
|
|
||||||
auto mesh = Ref<Mesh>::Create("assets/meshes/TestScene.fbx");
|
|
||||||
// auto mesh = Ref<Mesh>::Create("assets/models/Apollo AE/Apollo AE.fbx");
|
|
||||||
// auto mesh = Ref<Mesh>::Create("assets/models/tafi/塔菲.pmx");
|
|
||||||
m_MeshEntity.AddComponent<MeshComponent>(mesh);
|
|
||||||
|
|
||||||
m_MeshMaterial = mesh->GetMaterial();
|
|
||||||
|
|
||||||
m_MeshEntity.AddComponent<ScriptComponent>("Example.Script");
|
|
||||||
|
|
||||||
// Test Sandbox
|
|
||||||
auto mapGenerator = m_Scene->CreateEntity("Map Generator");
|
|
||||||
mapGenerator.AddComponent<ScriptComponent>("Example.MapGenerator");
|
|
||||||
|
|
||||||
/*
|
|
||||||
auto secondEntity = m_Scene->CreateEntity("Gun Entity");
|
|
||||||
secondEntity->Transform() = glm::translate(glm::mat4(1.0f), { 5, 5, 5 }) * glm::scale(glm::mat4(1.0f), {10, 10, 10});
|
|
||||||
mesh = Ref<Mesh>::Create("assets/models/m1911/M1911Materials.fbx");
|
|
||||||
secondEntity->SetMesh(mesh);
|
|
||||||
*/
|
|
||||||
}
|
|
||||||
|
|
||||||
// Sphere Scene
|
|
||||||
{
|
|
||||||
m_SphereScene = Ref<Scene>::Create("PBR Sphere Scene");
|
|
||||||
auto cameraEntity = m_SphereScene->CreateEntity("camera");
|
|
||||||
cameraEntity.AddComponent<CameraComponent>(Camera(glm::perspectiveFov(glm::radians(45.0f), 1280.0f, 720.0f, 0.1f, 10000.0f)));
|
|
||||||
|
|
||||||
m_SphereScene->SetEnvironment(environment);
|
|
||||||
|
|
||||||
auto sphereMesh = Ref<Mesh>::Create("assets/models/Sphere1m.fbx");
|
|
||||||
m_SphereBaseMaterial = sphereMesh->GetMaterial();
|
|
||||||
|
|
||||||
float x = -4.0f;
|
|
||||||
float roughness = 0.0f;
|
|
||||||
for (int i = 0; i < 8; i++)
|
|
||||||
{
|
|
||||||
auto sphereEntity = m_SphereScene->CreateEntity();
|
|
||||||
|
|
||||||
Ref<MaterialInstance> mi = Ref<MaterialInstance>::Create(m_SphereBaseMaterial);
|
|
||||||
mi->Set("u_Metalness", 1.0f);
|
|
||||||
mi->Set("u_Roughness", roughness);
|
|
||||||
x += 1.1f;
|
|
||||||
roughness += 0.15f;
|
|
||||||
m_MetalSphereMaterialInstances.push_back(mi);
|
|
||||||
|
|
||||||
/*
|
|
||||||
sphereEntity->SetMesh(sphereMesh);
|
|
||||||
sphereEntity->SetMaterial(mi);
|
|
||||||
sphereEntity->Transform() = glm::translate(glm::mat4(1.0f), glm::vec3(x, 0.0f, 0.0f));
|
|
||||||
*/
|
|
||||||
}
|
|
||||||
|
|
||||||
x = -4.0f;
|
|
||||||
roughness = 0.0f;
|
|
||||||
for (int i = 0; i < 8; i++)
|
|
||||||
{
|
|
||||||
auto sphereEntity = m_SphereScene->CreateEntity();
|
|
||||||
|
|
||||||
Ref<MaterialInstance> mi(new MaterialInstance(m_SphereBaseMaterial));
|
|
||||||
mi->Set("u_Metalness", 0.0f);
|
|
||||||
mi->Set("u_Roughness", roughness);
|
|
||||||
x += 1.1f;
|
|
||||||
roughness += 0.15f;
|
|
||||||
m_DielectricSphereMaterialInstances.push_back(mi);
|
|
||||||
|
|
||||||
/*
|
|
||||||
sphereEntity->SetMesh(sphereMesh);
|
|
||||||
sphereEntity->SetMaterial(mi);
|
|
||||||
sphereEntity->Transform() = glm::translate(glm::mat4(1.0f), glm::vec3(x, 1.2f, 0.0f));
|
|
||||||
*/
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
m_ActiveScene = m_Scene;
|
|
||||||
m_SceneHierarchyPanel = CreateScope<SceneHierarchyPanel>(m_ActiveScene);
|
|
||||||
|
|
||||||
|
|
||||||
// Editor
|
// Editor
|
||||||
m_CheckerboardTex = Texture2D::Create("assets/editor/Checkerboard.tga");
|
m_CheckerboardTex = Texture2D::Create("assets/editor/Checkerboard.tga");
|
||||||
|
m_PlayButtonTex = Texture2D::Create("assets/editor/PlayButton.png");
|
||||||
|
|
||||||
// set lights
|
m_EditorScene = Ref<Scene>::Create();
|
||||||
auto& light = m_Scene->GetLight();
|
ScriptEngine::SetSceneContext(m_EditorScene);
|
||||||
light.Direction = { -0.5f, -0.5f, 1.0f };
|
m_SceneHierarchyPanel = CreateScope<SceneHierarchyPanel>(m_EditorScene);
|
||||||
light.Radiance = { 1.0f, 1.0f, 1.0f };
|
m_SceneHierarchyPanel->SetSelectionChangedCallback(std::bind(&EditorLayer::SelectEntity, this, std::placeholders::_1));
|
||||||
|
m_SceneHierarchyPanel->SetEntityDeletedCallback(std::bind(&EditorLayer::OnEntityDeleted, this, std::placeholders::_1));
|
||||||
|
|
||||||
m_CurrentlySelectedTransform = &m_MeshEntity.Transform();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void EditorLayer::OnDetach()
|
void EditorLayer::OnDetach()
|
||||||
@ -234,72 +148,61 @@ namespace Prism
|
|||||||
|
|
||||||
void EditorLayer::OnUpdate(const TimeStep deltaTime)
|
void EditorLayer::OnUpdate(const TimeStep deltaTime)
|
||||||
{
|
{
|
||||||
// THINGS TO LOOK AT:
|
switch (m_SceneState)
|
||||||
// - BRDF LUT
|
|
||||||
// - Tonemapping and proper HDR pipeline
|
|
||||||
using namespace Prism;
|
|
||||||
using namespace glm;
|
|
||||||
|
|
||||||
m_MeshMaterial->Set("u_AlbedoColor", m_AlbedoInput.Color);
|
|
||||||
m_MeshMaterial->Set("u_Metalness", m_MetalnessInput.Value);
|
|
||||||
m_MeshMaterial->Set("u_Roughness", m_RoughnessInput.Value);
|
|
||||||
m_MeshMaterial->Set("u_AlbedoTexToggle", m_AlbedoInput.UseTexture ? 1.0f : 0.0f);
|
|
||||||
m_MeshMaterial->Set("u_NormalTexToggle", m_NormalInput.UseTexture ? 1.0f : 0.0f);
|
|
||||||
m_MeshMaterial->Set("u_MetalnessTexToggle", m_MetalnessInput.UseTexture ? 1.0f : 0.0f);
|
|
||||||
m_MeshMaterial->Set("u_RoughnessTexToggle", m_RoughnessInput.UseTexture ? 1.0f : 0.0f);
|
|
||||||
m_MeshMaterial->Set("u_EnvMapRotation", m_EnvMapRotation);
|
|
||||||
|
|
||||||
m_SphereBaseMaterial->Set("u_AlbedoColor", m_AlbedoInput.Color);
|
|
||||||
// m_SphereBaseMaterial->Set("lights", m_Light);
|
|
||||||
m_SphereBaseMaterial->Set("lights", m_Scene->GetLight());
|
|
||||||
m_SphereBaseMaterial->Set("u_RadiancePrefilter", m_RadiancePrefilter ? 1.0f : 0.0f);
|
|
||||||
m_SphereBaseMaterial->Set("u_AlbedoTexToggle", m_AlbedoInput.UseTexture ? 1.0f : 0.0f);
|
|
||||||
m_SphereBaseMaterial->Set("u_NormalTexToggle", m_NormalInput.UseTexture ? 1.0f : 0.0f);
|
|
||||||
m_SphereBaseMaterial->Set("u_MetalnessTexToggle", m_MetalnessInput.UseTexture ? 1.0f : 0.0f);
|
|
||||||
m_SphereBaseMaterial->Set("u_RoughnessTexToggle", m_RoughnessInput.UseTexture ? 1.0f : 0.0f);
|
|
||||||
m_SphereBaseMaterial->Set("u_EnvMapRotation", m_EnvMapRotation);
|
|
||||||
|
|
||||||
|
|
||||||
if (m_AlbedoInput.TextureMap)
|
|
||||||
m_MeshMaterial->Set("u_AlbedoTexture", m_AlbedoInput.TextureMap);
|
|
||||||
if (m_NormalInput.TextureMap)
|
|
||||||
m_MeshMaterial->Set("u_NormalTexture", m_NormalInput.TextureMap);
|
|
||||||
if (m_MetalnessInput.TextureMap)
|
|
||||||
m_MeshMaterial->Set("u_MetalnessTexture", m_MetalnessInput.TextureMap);
|
|
||||||
if (m_RoughnessInput.TextureMap)
|
|
||||||
m_MeshMaterial->Set("u_RoughnessTexture", m_RoughnessInput.TextureMap);
|
|
||||||
|
|
||||||
/*
|
|
||||||
if (m_AllowViewportCameraEvents)
|
|
||||||
m_Scene->GetCamera().OnUpdate(deltaTime);
|
|
||||||
*/
|
|
||||||
|
|
||||||
m_ActiveScene->OnUpdate(deltaTime);
|
|
||||||
|
|
||||||
if (m_DrawOnTopBoundingBoxes)
|
|
||||||
{
|
{
|
||||||
Renderer::BeginRenderPass(SceneRenderer::GetFinalRenderPass(), false);
|
case SceneState::Edit:
|
||||||
auto viewProj = m_CameraEntity.GetComponent<CameraComponent>().Camera.GetViewProjection();
|
{
|
||||||
Renderer2D::BeginScene(viewProj, false);
|
if (m_ViewportPanelFocused)
|
||||||
Renderer::DrawAABB(m_MeshEntity.GetComponent<MeshComponent>(), m_MeshEntity.GetComponent<TransformComponent>());
|
m_EditorCamera.OnUpdate(deltaTime);
|
||||||
|
|
||||||
Renderer2D::EndScene();
|
m_EditorScene->OnRenderEditor(deltaTime, m_EditorCamera);
|
||||||
Renderer::EndRenderPass();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!m_SelectionContext.empty())
|
if (m_DrawOnTopBoundingBoxes)
|
||||||
{
|
{
|
||||||
auto& selection = m_SelectionContext[0];
|
Renderer::BeginRenderPass(SceneRenderer::GetFinalRenderPass(), false);
|
||||||
|
auto viewProj = m_EditorCamera.GetViewProjection();
|
||||||
|
Renderer2D::BeginScene(viewProj, false);
|
||||||
|
// TODO: Renderer::DrawAABB(m_MeshEntity.GetComponent<MeshComponent>(), m_MeshEntity.GetComponent<TransformComponent>());
|
||||||
|
Renderer2D::EndScene();
|
||||||
|
Renderer::EndRenderPass();
|
||||||
|
}
|
||||||
|
|
||||||
Renderer::BeginRenderPass(SceneRenderer::GetFinalRenderPass(), false);
|
if (m_SelectionContext.size() && false)
|
||||||
const auto viewProj = m_CameraEntity.GetComponent<CameraComponent>().Camera.GetViewProjection();
|
{
|
||||||
Renderer2D::BeginScene(viewProj, false);
|
auto& selection = m_SelectionContext[0];
|
||||||
|
|
||||||
const glm::vec4 color = (m_SelectionMode == SelectionMode::Entity) ? glm::vec4{ 1.0f, 1.0f, 1.0f, 1.0f } : glm::vec4{ 0.2f, 0.9f, 0.2f, 1.0f };
|
if (selection.Mesh && selection.Entity.HasComponent<MeshComponent>())
|
||||||
Renderer::DrawAABB(selection.Mesh->BoundingBox, selection.Entity.GetComponent<TransformComponent>().Transform * selection.Mesh->Transform, color);
|
{
|
||||||
|
Renderer::BeginRenderPass(SceneRenderer::GetFinalRenderPass(), false);
|
||||||
|
auto viewProj = m_EditorCamera.GetViewProjection();
|
||||||
|
Renderer2D::BeginScene(viewProj, false);
|
||||||
|
glm::vec4 color = (m_SelectionMode == SelectionMode::Entity) ? glm::vec4{ 1.0f, 1.0f, 1.0f, 1.0f } : glm::vec4{ 0.2f, 0.9f, 0.2f, 1.0f };
|
||||||
|
Renderer::DrawAABB(selection.Mesh->BoundingBox, selection.Entity.GetComponent<TransformComponent>().Transform * selection.Mesh->Transform, color);
|
||||||
|
Renderer2D::EndScene();
|
||||||
|
Renderer::EndRenderPass();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case SceneState::Play:
|
||||||
|
{
|
||||||
|
if (m_ViewportPanelFocused)
|
||||||
|
m_EditorCamera.OnUpdate(deltaTime);
|
||||||
|
|
||||||
|
m_RuntimeScene->OnUpdate(deltaTime);
|
||||||
|
m_RuntimeScene->OnRenderRuntime(deltaTime);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case SceneState::Pause:
|
||||||
|
{
|
||||||
|
if (m_ViewportPanelFocused)
|
||||||
|
m_EditorCamera.OnUpdate(deltaTime);
|
||||||
|
|
||||||
|
m_RuntimeScene->OnRenderRuntime(deltaTime);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
Renderer2D::EndScene();
|
|
||||||
Renderer::EndRenderPass();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -365,119 +268,80 @@ namespace Prism
|
|||||||
// Show demo options and help
|
// Show demo options and help
|
||||||
if (ImGui::BeginMenuBar())
|
if (ImGui::BeginMenuBar())
|
||||||
{
|
{
|
||||||
if (ImGui::BeginMenu("Options"))
|
if (ImGui::BeginMenu("file"))
|
||||||
{
|
{
|
||||||
// Disabling fullscreen would allow the window to be moved to the front of other windows,
|
if (ImGui::MenuItem("New Scene"))
|
||||||
// which we can't undo at the moment without finer window depth/z control.
|
{
|
||||||
ImGui::MenuItem("Fullscreen", NULL, &opt_fullscreen);
|
|
||||||
ImGui::MenuItem("Padding", NULL, &opt_padding);
|
}
|
||||||
|
if (ImGui::MenuItem("Open Scene..."))
|
||||||
|
{
|
||||||
|
auto& app = Application::Get();
|
||||||
|
std::string filepath = app.OpenFile(R"(Scene file (*.hsc)*.hsc)");
|
||||||
|
if (!filepath.empty())
|
||||||
|
{
|
||||||
|
Ref<Scene> newScene = Ref<Scene>::Create();
|
||||||
|
SceneSerializer serializer(newScene);
|
||||||
|
serializer.Deserialize(filepath);
|
||||||
|
m_EditorScene = newScene;
|
||||||
|
m_SceneHierarchyPanel->SetContext(m_EditorScene);
|
||||||
|
ScriptEngine::SetSceneContext(m_EditorScene);
|
||||||
|
|
||||||
|
m_EditorScene->SetSelectedEntity({});
|
||||||
|
m_SelectionContext.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (ImGui::MenuItem("Save Scene..."))
|
||||||
|
{
|
||||||
|
auto& app = Application::Get();
|
||||||
|
std::string filepath = app.SaveFile(R"(Scene file (*.hsc)*.hsc)");
|
||||||
|
SceneSerializer serializer(m_EditorScene);
|
||||||
|
serializer.Serialize(filepath);
|
||||||
|
}
|
||||||
|
|
||||||
ImGui::Separator();
|
ImGui::Separator();
|
||||||
|
|
||||||
if (ImGui::MenuItem("Flag: NoDockingOverCentralNode", "",
|
if (ImGui::MenuItem("Reload C# Assembly"))
|
||||||
(dockspace_flags & ImGuiDockNodeFlags_NoDockingOverCentralNode) != 0))
|
ScriptEngine::ReloadAssembly("assets/scripts/ExampleApp.dll");
|
||||||
{
|
|
||||||
dockspace_flags ^= ImGuiDockNodeFlags_NoDockingOverCentralNode;
|
|
||||||
}
|
|
||||||
if (ImGui::MenuItem("Flag: NoDockingSplit", "",
|
|
||||||
(dockspace_flags & ImGuiDockNodeFlags_NoDockingSplit) != 0))
|
|
||||||
{
|
|
||||||
dockspace_flags ^= ImGuiDockNodeFlags_NoDockingSplit;
|
|
||||||
}
|
|
||||||
if (ImGui::MenuItem("Flag: NoUndocking", "", (dockspace_flags & ImGuiDockNodeFlags_NoUndocking) != 0))
|
|
||||||
{
|
|
||||||
dockspace_flags ^= ImGuiDockNodeFlags_NoUndocking;
|
|
||||||
}
|
|
||||||
if (ImGui::MenuItem("Flag: NoResize", "", (dockspace_flags & ImGuiDockNodeFlags_NoResize) != 0))
|
|
||||||
{
|
|
||||||
dockspace_flags ^= ImGuiDockNodeFlags_NoResize;
|
|
||||||
}
|
|
||||||
if (ImGui::MenuItem("Flag: AutoHideTabBar", "",
|
|
||||||
(dockspace_flags & ImGuiDockNodeFlags_AutoHideTabBar) != 0))
|
|
||||||
{
|
|
||||||
dockspace_flags ^= ImGuiDockNodeFlags_AutoHideTabBar;
|
|
||||||
}
|
|
||||||
if (ImGui::MenuItem("Flag: PassthruCentralNode", "",
|
|
||||||
(dockspace_flags & ImGuiDockNodeFlags_PassthruCentralNode) != 0, opt_fullscreen))
|
|
||||||
{
|
|
||||||
dockspace_flags ^= ImGuiDockNodeFlags_PassthruCentralNode;
|
|
||||||
}
|
|
||||||
ImGui::Separator();
|
ImGui::Separator();
|
||||||
|
if (ImGui::MenuItem("Exit"))
|
||||||
if (ImGui::MenuItem("Close", NULL, false, p_open != false))
|
|
||||||
p_open = false;
|
p_open = false;
|
||||||
ImGui::EndMenu();
|
ImGui::EndMenu();
|
||||||
}
|
}
|
||||||
if (ImGui::BeginMenu("Help"))
|
|
||||||
{
|
|
||||||
ImGui::TextUnformatted(
|
|
||||||
"This demo has nothing to do with enabling docking!" "\n"
|
|
||||||
"This demo only demonstrate the use of ImGui::DockSpace() which allows you to manually\ncreate a docking node _within_ another window."
|
|
||||||
"\n"
|
|
||||||
"Most application can simply call ImGui::DockSpaceOverViewport() and be done with it.");
|
|
||||||
ImGui::Separator();
|
|
||||||
ImGui::TextUnformatted(
|
|
||||||
"When docking is enabled, you can ALWAYS dock MOST window into another! Try it now!" "\n"
|
|
||||||
"- Drag from window title bar or their tab to dock/undock." "\n"
|
|
||||||
"- Drag from window menu button (upper-left button) to undock an entire node (all windows)." "\n"
|
|
||||||
"- Hold SHIFT to disable docking (if io.ConfigDockingWithShift == false, default)" "\n"
|
|
||||||
"- Hold SHIFT to enable docking (if io.ConfigDockingWithShift == true)");
|
|
||||||
ImGui::Separator();
|
|
||||||
ImGui::TextUnformatted("More details:");
|
|
||||||
ImGui::Bullet();
|
|
||||||
ImGui::SameLine();
|
|
||||||
ImGui::TextLinkOpenURL("Docking Wiki page", "https://github.com/ocornut/imgui/wiki/Docking");
|
|
||||||
ImGui::BulletText("Read comments in ShowExampleAppDockSpace()");
|
|
||||||
ImGui::EndMenu();
|
|
||||||
}
|
|
||||||
|
|
||||||
ImGuiShowHelpMarker(
|
|
||||||
"You can _always_ dock _any_ window into another by holding the SHIFT key while moving a window. Try it now!"
|
|
||||||
"\n"
|
|
||||||
"This demo app has nothing to do with it!" "\n\n"
|
|
||||||
"This demo app only demonstrate the use of ImGui::DockSpace() which allows you to manually create a docking node _within_ another window. This is useful so you can decorate your main application window (e.g. with a menu bar)."
|
|
||||||
"\n\n"
|
|
||||||
"ImGui::DockSpace() comes with one hard constraint: it needs to be submitted _before_ any window which may be docked into it. Therefore, if you use a dock spot as the central point of your application, you'll probably want it to be part of the very first window you are submitting to imgui every frame."
|
|
||||||
"\n\n"
|
|
||||||
"(NB: because of this constraint, the implicit \"Debug\" window can not be docked into an explicit DockSpace() node, because that window is submitted as part of the NewFrame() call. An easy workaround is that you can create your own implicit \"Debug##2\" window after calling DockSpace() and leave it in the window stack for anyone to use.)"
|
|
||||||
);
|
|
||||||
|
|
||||||
ImGui::EndMenuBar();
|
ImGui::EndMenuBar();
|
||||||
}
|
}
|
||||||
|
|
||||||
m_SceneHierarchyPanel->OnImGuiRender();
|
m_SceneHierarchyPanel->OnImGuiRender();
|
||||||
|
|
||||||
|
ScriptEngine::OnImGuiRender();
|
||||||
|
|
||||||
ImGui::End();
|
ImGui::End();
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Editor Panel ------------------------------------------------------------------------------
|
// Editor Panel ------------------------------------------------------------------------------
|
||||||
ImGui::Begin("Model");
|
ImGui::Begin("Model");
|
||||||
|
|
||||||
if (ImGui::RadioButton("Spheres", (int*)&m_SceneType, (int)SceneType::Spheres))
|
|
||||||
m_ActiveScene = m_SphereScene;
|
|
||||||
ImGui::SameLine();
|
|
||||||
if (ImGui::RadioButton("Model", (int*)&m_SceneType, (int)SceneType::Model))
|
|
||||||
m_ActiveScene = m_Scene;
|
|
||||||
|
|
||||||
ImGui::Begin("Environment");
|
ImGui::Begin("Environment");
|
||||||
|
|
||||||
if (ImGui::Button("Load Environment Map"))
|
if (ImGui::Button("Load Environment Map"))
|
||||||
{
|
{
|
||||||
std::string filename = Application::Get().OpenFile("*.hdr");
|
std::string filename = Application::Get().OpenFile("*.hdr");
|
||||||
if (!filename.empty())
|
if (!filename.empty())
|
||||||
m_ActiveScene->SetEnvironment(Environment::Load(filename));
|
m_EditorScene->SetEnvironment(Environment::Load(filename));
|
||||||
}
|
}
|
||||||
|
|
||||||
ImGui::SliderFloat("Skybox LOD", &m_Scene->GetSkyboxLod(), 0.0f, 11.0f);
|
ImGui::SliderFloat("Skybox LOD", &m_EditorScene->GetSkyboxLod(), 0.0f, 11.0f);
|
||||||
|
|
||||||
|
|
||||||
ImGui::Columns(2);
|
ImGui::Columns(2);
|
||||||
ImGui::AlignTextToFramePadding();
|
ImGui::AlignTextToFramePadding();
|
||||||
|
|
||||||
auto& light = m_Scene->GetLight();
|
auto& light = m_EditorScene->GetLight();
|
||||||
Property("Light Direction", light.Direction);
|
Property("Light Direction", light.Direction);
|
||||||
Property("Light Radiance", light.Radiance, PropertyFlag::ColorProperty);
|
Property("Light Radiance", light.Radiance, PropertyFlag::ColorProperty);
|
||||||
Property("Light Multiplier", light.Multiplier, 0.0f, 5.0f);
|
Property("Light Multiplier", light.Multiplier, 0.0f, 5.0f);
|
||||||
Property("Exposure", m_CameraEntity.GetComponent<CameraComponent>().Camera.GetExposure(), 0.0f, 5.0f);
|
Property("Exposure", m_EditorCamera.GetExposure(), 0.0f, 5.0f);
|
||||||
|
|
||||||
Property("Radiance Prefiltering", m_RadiancePrefilter);
|
Property("Radiance Prefiltering", m_RadiancePrefilter);
|
||||||
Property("Env Map Rotation", m_EnvMapRotation, -360.0f, 360.0f);
|
Property("Env Map Rotation", m_EnvMapRotation, -360.0f, 360.0f);
|
||||||
@ -500,6 +364,7 @@ namespace Prism
|
|||||||
ImGui::Separator();
|
ImGui::Separator();
|
||||||
{
|
{
|
||||||
ImGui::Text("Mesh");
|
ImGui::Text("Mesh");
|
||||||
|
/*
|
||||||
auto meshComponent = m_MeshEntity.GetComponent<MeshComponent>();
|
auto meshComponent = m_MeshEntity.GetComponent<MeshComponent>();
|
||||||
std::string fullpath = meshComponent.Mesh ? meshComponent.Mesh->GetFilePath() : "None";
|
std::string fullpath = meshComponent.Mesh ? meshComponent.Mesh->GetFilePath() : "None";
|
||||||
size_t found = fullpath.find_last_of("/\\");
|
size_t found = fullpath.find_last_of("/\\");
|
||||||
@ -517,6 +382,7 @@ namespace Prism
|
|||||||
meshComponent.Mesh = newMesh;
|
meshComponent.Mesh = newMesh;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
ImGui::Separator();
|
ImGui::Separator();
|
||||||
|
|
||||||
@ -679,14 +545,57 @@ namespace Prism
|
|||||||
|
|
||||||
ImGui::End();
|
ImGui::End();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(12, 0));
|
||||||
|
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(12, 4));
|
||||||
|
ImGui::PushStyleVar(ImGuiStyleVar_ItemInnerSpacing, ImVec2(0, 0));
|
||||||
|
ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0, 0, 0, 0));
|
||||||
|
ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(0.8f, 0.8f, 0.8f, 0.0f));
|
||||||
|
ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImVec4(0, 0, 0, 0));
|
||||||
|
ImGui::Begin("Toolbar");
|
||||||
|
if (m_SceneState == SceneState::Edit)
|
||||||
|
{
|
||||||
|
if (ImGui::ImageButton("editbutton", (ImTextureID)(m_PlayButtonTex->GetRendererID()), ImVec2(32, 32), ImVec2(0, 0), ImVec2(1, 1), ImVec4(0,0,0,0), ImVec4(0.9f, 0.9f, 0.9f, 1.0f)))
|
||||||
|
{
|
||||||
|
OnScenePlay();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (m_SceneState == SceneState::Play)
|
||||||
|
{
|
||||||
|
if (ImGui::ImageButton("playbutton", (ImTextureID)(m_PlayButtonTex->GetRendererID()), ImVec2(32, 32), ImVec2(0, 0), ImVec2(1, 1), ImVec4(1.0f, 1.0f, 1.0f, 0.2f)))
|
||||||
|
{
|
||||||
|
OnSceneStop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ImGui::SameLine();
|
||||||
|
if (ImGui::ImageButton("a", (ImTextureID)(m_PlayButtonTex->GetRendererID()), ImVec2(32, 32), ImVec2(0, 0), ImVec2(1, 1), ImVec4(0, 0, 0, 0), ImVec4(1.0f, 1.0f, 1.0f, 0.6f)))
|
||||||
|
{
|
||||||
|
PM_CORE_INFO("PLAY!");
|
||||||
|
}
|
||||||
|
ImGui::End();
|
||||||
|
ImGui::PopStyleColor();
|
||||||
|
ImGui::PopStyleColor();
|
||||||
|
ImGui::PopStyleColor();
|
||||||
|
ImGui::PopStyleVar();
|
||||||
|
ImGui::PopStyleVar();
|
||||||
|
ImGui::PopStyleVar();
|
||||||
|
|
||||||
|
|
||||||
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0, 0));
|
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0, 0));
|
||||||
ImGui::Begin("Viewport");
|
ImGui::Begin("Viewport");
|
||||||
|
|
||||||
|
m_ViewportPanelMouseOver = ImGui::IsWindowHovered();
|
||||||
|
m_ViewportPanelFocused = ImGui::IsWindowFocused();
|
||||||
|
|
||||||
auto viewportOffset = ImGui::GetCursorPos(); // includes tab bar
|
auto viewportOffset = ImGui::GetCursorPos(); // includes tab bar
|
||||||
auto viewportSize = ImGui::GetContentRegionAvail();
|
auto viewportSize = ImGui::GetContentRegionAvail();
|
||||||
SceneRenderer::SetViewportSize((uint32_t)viewportSize.x, (uint32_t)viewportSize.y);
|
SceneRenderer::SetViewportSize((uint32_t)viewportSize.x, (uint32_t)viewportSize.y);
|
||||||
m_CameraEntity.GetComponent<CameraComponent>().Camera.SetProjectionMatrix(glm::perspectiveFov(glm::radians(45.0f), viewportSize.x, viewportSize.y, 0.1f, 10000.0f));
|
m_EditorScene->SetViewportSize((uint32_t)viewportSize.x, (uint32_t)viewportSize.y);
|
||||||
m_CameraEntity.GetComponent<CameraComponent>().Camera.SetViewportSize((uint32_t)viewportSize.x, (uint32_t)viewportSize.y);
|
if (m_RuntimeScene)
|
||||||
|
m_RuntimeScene->SetViewportSize((uint32_t)viewportSize.x, (uint32_t)viewportSize.y);
|
||||||
|
m_EditorCamera.SetProjectionMatrix(glm::perspectiveFov(glm::radians(45.0f), viewportSize.x, viewportSize.y, 0.1f, 10000.0f));
|
||||||
|
m_EditorCamera.SetViewportSize((uint32_t)viewportSize.x, (uint32_t)viewportSize.y);
|
||||||
ImGui::Image((ImTextureRef)SceneRenderer::GetFinalColorBufferRendererID(), viewportSize, { 0, 1 }, { 1, 0 });
|
ImGui::Image((ImTextureRef)SceneRenderer::GetFinalColorBufferRendererID(), viewportSize, { 0, 1 }, { 1, 0 });
|
||||||
|
|
||||||
|
|
||||||
@ -702,7 +611,7 @@ namespace Prism
|
|||||||
m_AllowViewportCameraEvents = ImGui::IsMouseHoveringRect(minBound, maxBound);
|
m_AllowViewportCameraEvents = ImGui::IsMouseHoveringRect(minBound, maxBound);
|
||||||
|
|
||||||
// ImGuizmo
|
// ImGuizmo
|
||||||
if (m_GizmoType != -1 && m_CurrentlySelectedTransform)
|
if (m_GizmoType != -1 && !m_SelectionContext.empty())
|
||||||
{
|
{
|
||||||
auto& selection = m_SelectionContext[0];
|
auto& selection = m_SelectionContext[0];
|
||||||
|
|
||||||
@ -712,25 +621,24 @@ namespace Prism
|
|||||||
ImGuizmo::SetDrawlist();
|
ImGuizmo::SetDrawlist();
|
||||||
ImGuizmo::SetRect(ImGui::GetWindowPos().x, ImGui::GetWindowPos().y, rw, rh);
|
ImGuizmo::SetRect(ImGui::GetWindowPos().x, ImGui::GetWindowPos().y, rw, rh);
|
||||||
|
|
||||||
const auto& camera = m_CameraEntity.GetComponent<CameraComponent>().Camera;
|
|
||||||
bool snap = Input::IsKeyPressed(Key::LEFT_CONTROL);
|
bool snap = Input::IsKeyPressed(Key::LEFT_CONTROL);
|
||||||
|
|
||||||
auto& entityTransform = selection.Entity.Transform();
|
auto& entityTransform = selection.Entity.Transform();
|
||||||
float snapValue[3] = { m_SnapValue, m_SnapValue, m_SnapValue };
|
float snapValue[3] = { m_SnapValue, m_SnapValue, m_SnapValue };
|
||||||
if (m_SelectionMode == SelectionMode::Entity)
|
if (m_SelectionMode == SelectionMode::Entity)
|
||||||
{
|
{
|
||||||
ImGuizmo::Manipulate(glm::value_ptr(camera.GetViewMatrix()),
|
ImGuizmo::Manipulate(glm::value_ptr(m_EditorCamera.GetViewMatrix()),
|
||||||
glm::value_ptr(camera.GetProjectionMatrix()),
|
glm::value_ptr(m_EditorCamera.GetProjectionMatrix()),
|
||||||
(ImGuizmo::OPERATION)m_GizmoType,
|
(ImGuizmo::OPERATION)m_GizmoType,
|
||||||
ImGuizmo::LOCAL,
|
ImGuizmo::LOCAL,
|
||||||
glm::value_ptr(m_MeshEntity.GetComponent<TransformComponent>().Transform),
|
glm::value_ptr(entityTransform),
|
||||||
nullptr,
|
nullptr,
|
||||||
snap ? snapValue : nullptr);
|
snap ? snapValue : nullptr);
|
||||||
}else
|
}else
|
||||||
{
|
{
|
||||||
glm::mat4 transformBase = entityTransform * selection.Mesh->Transform;
|
glm::mat4 transformBase = entityTransform * selection.Mesh->Transform;
|
||||||
ImGuizmo::Manipulate(glm::value_ptr(camera.GetViewMatrix()),
|
ImGuizmo::Manipulate(glm::value_ptr(m_EditorCamera.GetViewMatrix()),
|
||||||
glm::value_ptr(camera.GetProjectionMatrix()),
|
glm::value_ptr(m_EditorCamera.GetProjectionMatrix()),
|
||||||
(ImGuizmo::OPERATION)m_GizmoType,
|
(ImGuizmo::OPERATION)m_GizmoType,
|
||||||
ImGuizmo::LOCAL,
|
ImGuizmo::LOCAL,
|
||||||
glm::value_ptr(transformBase),
|
glm::value_ptr(transformBase),
|
||||||
@ -748,10 +656,17 @@ namespace Prism
|
|||||||
|
|
||||||
void EditorLayer::OnEvent(Event& e)
|
void EditorLayer::OnEvent(Event& e)
|
||||||
{
|
{
|
||||||
/*
|
if (m_SceneState == SceneState::Edit)
|
||||||
if (m_AllowViewportCameraEvents)
|
{
|
||||||
m_Scene->GetCamera().OnEvent(e);
|
if (m_ViewportPanelMouseOver)
|
||||||
*/
|
m_EditorCamera.OnEvent(e);
|
||||||
|
|
||||||
|
m_EditorScene->OnEvent(e);
|
||||||
|
}
|
||||||
|
else if (m_SceneState == SceneState::Play)
|
||||||
|
{
|
||||||
|
m_RuntimeScene->OnEvent(e);
|
||||||
|
}
|
||||||
|
|
||||||
EventDispatcher dispatcher(e);
|
EventDispatcher dispatcher(e);
|
||||||
dispatcher.Dispatch<KeyPressedEvent>(PM_BIND_EVENT_FN(EditorLayer::OnKeyPressedEvent));
|
dispatcher.Dispatch<KeyPressedEvent>(PM_BIND_EVENT_FN(EditorLayer::OnKeyPressedEvent));
|
||||||
@ -760,35 +675,57 @@ namespace Prism
|
|||||||
|
|
||||||
bool EditorLayer::OnKeyPressedEvent(KeyPressedEvent& e)
|
bool EditorLayer::OnKeyPressedEvent(KeyPressedEvent& e)
|
||||||
{
|
{
|
||||||
switch (e.GetKeyCode())
|
if (m_ViewportPanelFocused)
|
||||||
{
|
{
|
||||||
case KeyCode::Q:
|
switch (e.GetKeyCode())
|
||||||
m_GizmoType = -1;
|
|
||||||
break;
|
|
||||||
case KeyCode::W:
|
|
||||||
m_GizmoType = ImGuizmo::OPERATION::TRANSLATE;
|
|
||||||
break;
|
|
||||||
case KeyCode::E:
|
|
||||||
m_GizmoType = ImGuizmo::OPERATION::ROTATE;
|
|
||||||
break;
|
|
||||||
case KeyCode::R:
|
|
||||||
m_GizmoType = ImGuizmo::OPERATION::SCALE;
|
|
||||||
break;
|
|
||||||
case KeyCode::G:
|
|
||||||
// Toggle grid
|
|
||||||
if (Input::IsKeyPressed(KeyCode::LEFT_CONTROL))
|
|
||||||
SceneRenderer::GetOptions().ShowGrid = !SceneRenderer::GetOptions().ShowGrid;
|
|
||||||
break;
|
|
||||||
case KeyCode::B:
|
|
||||||
// Toggle bounding boxes
|
|
||||||
if (Input::IsKeyPressed(KeyCode::LEFT_CONTROL))
|
|
||||||
{
|
{
|
||||||
|
case KeyCode::Q:
|
||||||
|
m_GizmoType = -1;
|
||||||
|
break;
|
||||||
|
case KeyCode::W:
|
||||||
|
m_GizmoType = ImGuizmo::OPERATION::TRANSLATE;
|
||||||
|
break;
|
||||||
|
case KeyCode::E:
|
||||||
|
m_GizmoType = ImGuizmo::OPERATION::ROTATE;
|
||||||
|
break;
|
||||||
|
case KeyCode::R:
|
||||||
|
m_GizmoType = ImGuizmo::OPERATION::SCALE;
|
||||||
|
break;
|
||||||
|
case KeyCode::DELETE:
|
||||||
|
if (m_SelectionContext.size())
|
||||||
|
{
|
||||||
|
const Entity selectedEntity = m_SelectionContext[0].Entity;
|
||||||
|
m_EditorScene->DestroyEntity(selectedEntity);
|
||||||
|
m_SelectionContext.clear();
|
||||||
|
m_EditorScene->SetSelectedEntity({});
|
||||||
|
m_SceneHierarchyPanel->SetSelected({});
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (Input::IsKeyPressed(KeyCode::LEFT_CONTROL))
|
||||||
|
{
|
||||||
|
switch (e.GetKeyCode())
|
||||||
|
{
|
||||||
|
case KeyCode::G:
|
||||||
|
// Toggle grid
|
||||||
|
SceneRenderer::GetOptions().ShowGrid = !SceneRenderer::GetOptions().ShowGrid;
|
||||||
|
break;
|
||||||
|
case KeyCode::B:
|
||||||
|
// Toggle bounding boxes
|
||||||
m_UIShowBoundingBoxes = !m_UIShowBoundingBoxes;
|
m_UIShowBoundingBoxes = !m_UIShowBoundingBoxes;
|
||||||
ShowBoundingBoxes(m_UIShowBoundingBoxes, m_UIShowBoundingBoxesOnTop);
|
ShowBoundingBoxes(m_UIShowBoundingBoxes, m_UIShowBoundingBoxesOnTop);
|
||||||
|
break;
|
||||||
|
case KeyCode::D:
|
||||||
|
if (m_SelectionContext.size())
|
||||||
|
{
|
||||||
|
Entity selectedEntity = m_SelectionContext[0].Entity;
|
||||||
|
m_EditorScene->DuplicateEntity(selectedEntity);
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -803,10 +740,11 @@ namespace Prism
|
|||||||
auto [origin, direction] = CastRay(mouseX, mouseY);
|
auto [origin, direction] = CastRay(mouseX, mouseY);
|
||||||
|
|
||||||
m_SelectionContext.clear();
|
m_SelectionContext.clear();
|
||||||
const auto meshEntities = m_Scene->GetAllEntitiesWith<MeshComponent>();
|
m_EditorScene->SetSelectedEntity({});
|
||||||
|
const auto meshEntities = m_EditorScene->GetAllEntitiesWith<MeshComponent>();
|
||||||
for (auto e : meshEntities)
|
for (auto e : meshEntities)
|
||||||
{
|
{
|
||||||
Entity entity = { e, m_Scene.Raw() };
|
Entity entity = { e, m_EditorScene.Raw() };
|
||||||
auto mesh = entity.GetComponent<MeshComponent>().Mesh;
|
auto mesh = entity.GetComponent<MeshComponent>().Mesh;
|
||||||
|
|
||||||
if (!mesh)
|
if (!mesh)
|
||||||
@ -857,6 +795,20 @@ namespace Prism
|
|||||||
m_DrawOnTopBoundingBoxes = show && onTop;
|
m_DrawOnTopBoundingBoxes = show && onTop;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void EditorLayer::SelectEntity(Entity entity)
|
||||||
|
{
|
||||||
|
SelectedSubmesh selection;
|
||||||
|
if (entity.HasComponent<MeshComponent>())
|
||||||
|
{
|
||||||
|
selection.Mesh = &entity.GetComponent<MeshComponent>().Mesh->GetSubmeshes()[0];
|
||||||
|
}
|
||||||
|
selection.Entity = entity;
|
||||||
|
m_SelectionContext.clear();
|
||||||
|
m_SelectionContext.push_back(selection);
|
||||||
|
|
||||||
|
m_EditorScene->SetSelectedEntity(entity);
|
||||||
|
}
|
||||||
|
|
||||||
std::pair<float, float> EditorLayer::GetMouseViewportSpace() const
|
std::pair<float, float> EditorLayer::GetMouseViewportSpace() const
|
||||||
{
|
{
|
||||||
auto [mx, my] = ImGui::GetMousePos(); // Input::GetMousePosition();
|
auto [mx, my] = ImGui::GetMousePos(); // Input::GetMousePosition();
|
||||||
@ -872,11 +824,11 @@ namespace Prism
|
|||||||
{
|
{
|
||||||
const glm::vec4 mouseClipPos = { mx, my, -1.0f, 1.0f };
|
const glm::vec4 mouseClipPos = { mx, my, -1.0f, 1.0f };
|
||||||
|
|
||||||
const auto inverseProj = glm::inverse(m_CameraEntity.GetComponent<CameraComponent>().Camera.GetProjectionMatrix());
|
const auto inverseProj = glm::inverse(m_EditorCamera.GetProjectionMatrix());
|
||||||
const auto inverseView = glm::inverse(glm::mat3(m_CameraEntity.GetComponent<CameraComponent>().Camera.GetViewMatrix()));
|
const auto inverseView = glm::inverse(glm::mat3(m_EditorCamera.GetViewMatrix()));
|
||||||
|
|
||||||
const glm::vec4 ray = inverseProj * mouseClipPos;
|
const glm::vec4 ray = inverseProj * mouseClipPos;
|
||||||
glm::vec3 rayPos = m_CameraEntity.GetComponent<CameraComponent>().Camera.GetPosition();
|
glm::vec3 rayPos = m_EditorCamera.GetPosition();
|
||||||
glm::vec3 rayDir = inverseView * glm::vec3(ray);
|
glm::vec3 rayDir = inverseView * glm::vec3(ray);
|
||||||
|
|
||||||
return { rayPos, rayDir };
|
return { rayPos, rayDir };
|
||||||
@ -885,6 +837,16 @@ namespace Prism
|
|||||||
void EditorLayer::OnSelected(const SelectedSubmesh& selectionContext)
|
void EditorLayer::OnSelected(const SelectedSubmesh& selectionContext)
|
||||||
{
|
{
|
||||||
m_SceneHierarchyPanel->SetSelected(selectionContext.Entity);
|
m_SceneHierarchyPanel->SetSelected(selectionContext.Entity);
|
||||||
|
m_EditorScene->SetSelectedEntity(selectionContext.Entity);
|
||||||
|
}
|
||||||
|
|
||||||
|
void EditorLayer::OnEntityDeleted(Entity e)
|
||||||
|
{
|
||||||
|
if (m_SelectionContext[0].Entity == e)
|
||||||
|
{
|
||||||
|
m_SelectionContext.clear();
|
||||||
|
m_EditorScene->SetSelectedEntity({});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ray EditorLayer::CastMouseRay()
|
Ray EditorLayer::CastMouseRay()
|
||||||
@ -897,4 +859,30 @@ namespace Prism
|
|||||||
}
|
}
|
||||||
return Ray::Zero();
|
return Ray::Zero();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void EditorLayer::OnScenePlay()
|
||||||
|
{
|
||||||
|
m_SelectionContext.clear();
|
||||||
|
|
||||||
|
m_SceneState = SceneState::Play;
|
||||||
|
|
||||||
|
m_RuntimeScene = Ref<Scene>::Create();
|
||||||
|
m_EditorScene->CopyTo(m_RuntimeScene);
|
||||||
|
|
||||||
|
m_RuntimeScene->OnRuntimeStart();
|
||||||
|
m_SceneHierarchyPanel->SetContext(m_RuntimeScene);
|
||||||
|
}
|
||||||
|
|
||||||
|
void EditorLayer::OnSceneStop()
|
||||||
|
{
|
||||||
|
m_RuntimeScene->OnRuntimeStop();
|
||||||
|
m_SceneState = SceneState::Edit;
|
||||||
|
|
||||||
|
// Unload runtime scene
|
||||||
|
m_RuntimeScene = nullptr;
|
||||||
|
|
||||||
|
m_SelectionContext.clear();
|
||||||
|
ScriptEngine::SetSceneContext(m_EditorScene);
|
||||||
|
m_SceneHierarchyPanel->SetContext(m_EditorScene);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -27,7 +27,7 @@ namespace Prism
|
|||||||
bool OnMouseButtonPressedEvent(MouseButtonPressedEvent& e);
|
bool OnMouseButtonPressedEvent(MouseButtonPressedEvent& e);
|
||||||
|
|
||||||
void ShowBoundingBoxes(bool show, bool onTop = false);
|
void ShowBoundingBoxes(bool show, bool onTop = false);
|
||||||
|
void SelectEntity(Entity entity);
|
||||||
private:
|
private:
|
||||||
std::pair<float, float> GetMouseViewportSpace() const;
|
std::pair<float, float> GetMouseViewportSpace() const;
|
||||||
std::pair<glm::vec3, glm::vec3> CastRay(float mx, float my);
|
std::pair<glm::vec3, glm::vec3> CastRay(float mx, float my);
|
||||||
@ -35,23 +35,24 @@ namespace Prism
|
|||||||
struct SelectedSubmesh
|
struct SelectedSubmesh
|
||||||
{
|
{
|
||||||
Prism::Entity Entity;
|
Prism::Entity Entity;
|
||||||
Submesh* Mesh;
|
Submesh* Mesh = nullptr;
|
||||||
float Distance;
|
float Distance = 0.0f;
|
||||||
};
|
};
|
||||||
void OnSelected(const SelectedSubmesh& selectionContext);
|
void OnSelected(const SelectedSubmesh& selectionContext);
|
||||||
|
void OnEntityDeleted(Entity e);
|
||||||
Ray CastMouseRay();
|
Ray CastMouseRay();
|
||||||
|
|
||||||
|
void OnScenePlay();
|
||||||
|
void OnSceneStop();
|
||||||
private:
|
private:
|
||||||
Scope<SceneHierarchyPanel> m_SceneHierarchyPanel;
|
Scope<SceneHierarchyPanel> m_SceneHierarchyPanel;
|
||||||
|
|
||||||
Ref<Scene> m_Scene;
|
|
||||||
Ref<Scene> m_SphereScene;
|
|
||||||
Ref<Scene> m_ActiveScene;
|
Ref<Scene> m_ActiveScene;
|
||||||
|
Ref<Scene> m_RuntimeScene, m_EditorScene;
|
||||||
|
|
||||||
Entity m_MeshEntity;
|
EditorCamera m_EditorCamera;
|
||||||
Entity m_CameraEntity;
|
|
||||||
|
|
||||||
Ref<Material> m_SphereBaseMaterial;
|
Ref<Material> m_SphereBaseMaterial;
|
||||||
|
|
||||||
Ref<Material> m_MeshMaterial;
|
Ref<Material> m_MeshMaterial;
|
||||||
|
|
||||||
std::vector<Ref<MaterialInstance>> m_MetalSphereMaterialInstances;
|
std::vector<Ref<MaterialInstance>> m_MetalSphereMaterialInstances;
|
||||||
@ -71,14 +72,6 @@ namespace Prism
|
|||||||
|
|
||||||
std::vector<SelectedSubmesh> m_SelectionContext;
|
std::vector<SelectedSubmesh> m_SelectionContext;
|
||||||
glm::mat4* m_RelativeTransform = nullptr;
|
glm::mat4* m_RelativeTransform = nullptr;
|
||||||
glm::mat4* m_CurrentlySelectedTransform = nullptr;
|
|
||||||
|
|
||||||
// configure button
|
|
||||||
bool m_AllowViewportCameraEvents = false;
|
|
||||||
bool m_DrawOnTopBoundingBoxes = false;
|
|
||||||
|
|
||||||
bool m_UIShowBoundingBoxes = false;
|
|
||||||
bool m_UIShowBoundingBoxesOnTop = false;
|
|
||||||
|
|
||||||
|
|
||||||
struct AlbedoInput
|
struct AlbedoInput
|
||||||
@ -119,14 +112,33 @@ namespace Prism
|
|||||||
|
|
||||||
float m_EnvMapRotation = 0.0f;
|
float m_EnvMapRotation = 0.0f;
|
||||||
|
|
||||||
|
|
||||||
|
// Editor resources
|
||||||
|
Ref<Texture2D> m_CheckerboardTex;
|
||||||
|
Ref<Texture2D> m_PlayButtonTex;
|
||||||
|
|
||||||
|
|
||||||
|
// configure button
|
||||||
|
bool m_AllowViewportCameraEvents = false;
|
||||||
|
bool m_DrawOnTopBoundingBoxes = false;
|
||||||
|
|
||||||
|
bool m_UIShowBoundingBoxes = false;
|
||||||
|
bool m_UIShowBoundingBoxesOnTop = false;
|
||||||
|
|
||||||
enum class SceneType : uint32_t
|
enum class SceneType : uint32_t
|
||||||
{
|
{
|
||||||
Spheres = 0, Model = 1
|
Spheres = 0, Model = 1
|
||||||
};
|
};
|
||||||
SceneType m_SceneType;
|
SceneType m_SceneType;
|
||||||
|
|
||||||
// Editor resources
|
bool m_ViewportPanelMouseOver = false;
|
||||||
Ref<Texture2D> m_CheckerboardTex;
|
bool m_ViewportPanelFocused = false;
|
||||||
|
|
||||||
|
enum class SceneState
|
||||||
|
{
|
||||||
|
Edit = 0, Play = 1, Pause = 2
|
||||||
|
};
|
||||||
|
SceneState m_SceneState = SceneState::Edit;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
BIN
Editor/assets/editor/PlayButton.png
Normal file
BIN
Editor/assets/editor/PlayButton.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 357 B |
66
Editor/assets/scenes/PinkSunrise.hsc
Normal file
66
Editor/assets/scenes/PinkSunrise.hsc
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
Scene: Scene Name
|
||||||
|
Environment:
|
||||||
|
AssetPath: assets\env\birchwood_4k.hdr
|
||||||
|
Light:
|
||||||
|
Direction: [-0.5, -0.5, 1]
|
||||||
|
Radiance: [1, 1, 1]
|
||||||
|
Multiplier: 1
|
||||||
|
Entities:
|
||||||
|
- Entity: 1289165777996378215
|
||||||
|
TagComponent:
|
||||||
|
Tag: Sphere
|
||||||
|
TransformComponent:
|
||||||
|
Position: [0, 21.9805069, -1.64006281]
|
||||||
|
Rotation: [1, 0, 0, 0]
|
||||||
|
Scale: [0.100000024, 0.100000024, 0.100000024]
|
||||||
|
ScriptComponent:
|
||||||
|
ModuleName: Example.Sink
|
||||||
|
StoredFields:
|
||||||
|
- Name: SinkSpeed
|
||||||
|
Type: 1
|
||||||
|
Data: 5
|
||||||
|
MeshComponent:
|
||||||
|
AssetPath: assets\meshes\Sphere1m.fbx
|
||||||
|
- Entity: 5178862374589434728
|
||||||
|
TagComponent:
|
||||||
|
Tag: Camera
|
||||||
|
TransformComponent:
|
||||||
|
Position: [0, 14.75, 79.75]
|
||||||
|
Rotation: [0.995602965, -0.0936739072, 0, 0]
|
||||||
|
Scale: [1, 0.999999821, 0.999999821]
|
||||||
|
ScriptComponent:
|
||||||
|
ModuleName: Example.BasicController
|
||||||
|
StoredFields:
|
||||||
|
- Name: Speed
|
||||||
|
Type: 1
|
||||||
|
Data: 12
|
||||||
|
CameraComponent:
|
||||||
|
Camera: some camera data...
|
||||||
|
Primary: true
|
||||||
|
- Entity: 9095450049242347594
|
||||||
|
TagComponent:
|
||||||
|
Tag: Test Entity
|
||||||
|
TransformComponent:
|
||||||
|
Position: [0.248109579, -1.90734863e-06, -0.268640995]
|
||||||
|
Rotation: [1, 0, 0, 0]
|
||||||
|
Scale: [1, 1, 1]
|
||||||
|
ScriptComponent:
|
||||||
|
ModuleName: Example.Script
|
||||||
|
StoredFields:
|
||||||
|
- Name: VerticalSpeed
|
||||||
|
Type: 1
|
||||||
|
Data: 0
|
||||||
|
- Name: SinkRate
|
||||||
|
Type: 1
|
||||||
|
Data: 0
|
||||||
|
- Name: Speed
|
||||||
|
Type: 1
|
||||||
|
Data: 1
|
||||||
|
- Name: Rotation
|
||||||
|
Type: 1
|
||||||
|
Data: 0
|
||||||
|
- Name: Velocity
|
||||||
|
Type: 6
|
||||||
|
Data: [0, 0, 0]
|
||||||
|
MeshComponent:
|
||||||
|
AssetPath: assets\meshes\TestScene.fbx
|
||||||
27
Editor/assets/shaders/Outline.glsl
Normal file
27
Editor/assets/shaders/Outline.glsl
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
// Outline Shader
|
||||||
|
|
||||||
|
#type vertex
|
||||||
|
#version 430
|
||||||
|
|
||||||
|
layout(location = 0) in vec3 a_Position;
|
||||||
|
layout(location = 1) in vec2 a_TexCoord;
|
||||||
|
|
||||||
|
uniform mat4 u_ViewProjection;
|
||||||
|
uniform mat4 u_Transform;
|
||||||
|
|
||||||
|
out vec2 v_TexCoord;
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
gl_Position = u_ViewProjection * u_Transform * vec4(a_Position, 1.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
#type fragment
|
||||||
|
#version 430
|
||||||
|
|
||||||
|
layout(location = 0) out vec4 color;
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
color = vec4(1.0, 0.5, 0.0, 1.0);
|
||||||
|
}
|
||||||
@ -1,5 +1,5 @@
|
|||||||
// -----------------------------
|
// -----------------------------
|
||||||
// -- Hazel Engine PBR shader --
|
// -- From Hazel Engine PBR shader --
|
||||||
// -----------------------------
|
// -----------------------------
|
||||||
// Note: this shader is still very much in progress. There are likely many bugs and future additions that will go in.
|
// Note: this shader is still very much in progress. There are likely many bugs and future additions that will go in.
|
||||||
// Currently heavily updated.
|
// Currently heavily updated.
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
// -----------------------------
|
// -----------------------------
|
||||||
// -- Hazel Engine PBR shader --
|
// -- From Hazel Engine PBR shader --
|
||||||
// -----------------------------
|
// -----------------------------
|
||||||
// Note: this shader is still very much in progress. There are likely many bugs and future additions that will go in.
|
// Note: this shader is still very much in progress. There are likely many bugs and future additions that will go in.
|
||||||
// Currently heavily updated.
|
// Currently heavily updated.
|
||||||
|
|||||||
36
ExampleApp/Src/BasicContorller.cs
Normal file
36
ExampleApp/Src/BasicContorller.cs
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
using Prism;
|
||||||
|
|
||||||
|
namespace Example
|
||||||
|
{
|
||||||
|
public class BasicController : Entity
|
||||||
|
{
|
||||||
|
public float Speed;
|
||||||
|
|
||||||
|
public void OnCreate()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public void OnUpdate(float ts)
|
||||||
|
{
|
||||||
|
Mat4 transform = GetTransform();
|
||||||
|
Vec3 translation = transform.Translation;
|
||||||
|
|
||||||
|
float speed = Speed * ts;
|
||||||
|
|
||||||
|
if (Input.IsKeyPressed(KeyCode.Up))
|
||||||
|
translation.Y += speed;
|
||||||
|
else if (Input.IsKeyPressed(KeyCode.Down))
|
||||||
|
translation.Y -= speed;
|
||||||
|
if (Input.IsKeyPressed(KeyCode.Right))
|
||||||
|
translation.X += speed;
|
||||||
|
else if (Input.IsKeyPressed(KeyCode.Left))
|
||||||
|
translation.X -= speed;
|
||||||
|
|
||||||
|
|
||||||
|
transform.Translation = translation;
|
||||||
|
SetTransform(transform);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -10,7 +10,7 @@ namespace Example
|
|||||||
{
|
{
|
||||||
public class MapGenerator : Entity
|
public class MapGenerator : Entity
|
||||||
{
|
{
|
||||||
// TODO: [EditorSlider("MapWidth Custom Name", 2, 0, 1024)]
|
// [EditorSlider("MapWidth Custom Name", 2, 0, 1024)]
|
||||||
public int MapWidth = 128;
|
public int MapWidth = 128;
|
||||||
public int MapHeight = 128;
|
public int MapHeight = 128;
|
||||||
public int Octaves = 4;
|
public int Octaves = 4;
|
||||||
@ -20,6 +20,8 @@ namespace Example
|
|||||||
public Vec2 Offset = new Vec2(13.4f, 6.26f);
|
public Vec2 Offset = new Vec2(13.4f, 6.26f);
|
||||||
public float NoiseScale = 0.5f;
|
public float NoiseScale = 0.5f;
|
||||||
|
|
||||||
|
public float speed = 0.0f;
|
||||||
|
|
||||||
public void GenerateMap()
|
public void GenerateMap()
|
||||||
{
|
{
|
||||||
// float[,] noiseMap = Noise.GenerateNoiseMap(MapWidth, MapHeight, NoiseScale);
|
// float[,] noiseMap = Noise.GenerateNoiseMap(MapWidth, MapHeight, NoiseScale);
|
||||||
@ -76,7 +78,19 @@ namespace Example
|
|||||||
|
|
||||||
void OnUpdate(float ts)
|
void OnUpdate(float ts)
|
||||||
{
|
{
|
||||||
|
Mat4 transform = GetTransform();
|
||||||
|
Vec3 translation = transform.Translation;
|
||||||
|
translation.Y += ts * speed;
|
||||||
|
|
||||||
|
if (Input.IsKeyPressed(KeyCode.Space))
|
||||||
|
{
|
||||||
|
Console.WriteLine("Space Pressed");
|
||||||
|
translation.Y -= 10.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
transform.Translation = translation;
|
||||||
|
|
||||||
|
SetTransform(transform);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -6,7 +6,12 @@ namespace Example
|
|||||||
{
|
{
|
||||||
public class Script : Entity
|
public class Script : Entity
|
||||||
{
|
{
|
||||||
|
public float VerticalSpeed = 5.0f;
|
||||||
public float Speed = 5.0f;
|
public float Speed = 5.0f;
|
||||||
|
public float Rotation = 0.0f;
|
||||||
|
public Vec3 Velocity;
|
||||||
|
public float SinkRate = 1.0f;
|
||||||
|
|
||||||
|
|
||||||
public void OnCreate()
|
public void OnCreate()
|
||||||
{
|
{
|
||||||
@ -16,11 +21,20 @@ namespace Example
|
|||||||
|
|
||||||
public void OnUpdate(float ts)
|
public void OnUpdate(float ts)
|
||||||
{
|
{
|
||||||
|
Rotation += ts;
|
||||||
|
|
||||||
|
|
||||||
Mat4 transform = GetTransform();
|
Mat4 transform = GetTransform();
|
||||||
Vec3 translation = transform.Translation;
|
Vec3 translation = transform.Translation;
|
||||||
|
|
||||||
float speed = Speed * ts;
|
float speed = Speed * ts;
|
||||||
|
|
||||||
|
translation.X += Velocity.X * ts;
|
||||||
|
translation.Y += Velocity.Y * ts;
|
||||||
|
translation.Z += Velocity.Z * ts;
|
||||||
|
|
||||||
|
translation.Y -= SinkRate * ts;
|
||||||
|
/*
|
||||||
if (Input.IsKeyPressed(KeyCode.Up))
|
if (Input.IsKeyPressed(KeyCode.Up))
|
||||||
translation.Y += speed;
|
translation.Y += speed;
|
||||||
else if (Input.IsKeyPressed(KeyCode.Down))
|
else if (Input.IsKeyPressed(KeyCode.Down))
|
||||||
@ -29,6 +43,7 @@ namespace Example
|
|||||||
translation.X += speed;
|
translation.X += speed;
|
||||||
else if (Input.IsKeyPressed(KeyCode.Left))
|
else if (Input.IsKeyPressed(KeyCode.Left))
|
||||||
translation.X -= speed;
|
translation.X -= speed;
|
||||||
|
*/
|
||||||
|
|
||||||
transform.Translation = translation;
|
transform.Translation = translation;
|
||||||
SetTransform(transform);
|
SetTransform(transform);
|
||||||
|
|||||||
27
ExampleApp/Src/Sink.cs
Normal file
27
ExampleApp/Src/Sink.cs
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
using Prism;
|
||||||
|
|
||||||
|
namespace Example
|
||||||
|
{
|
||||||
|
class Sink : Entity
|
||||||
|
{
|
||||||
|
|
||||||
|
public float SinkSpeed = 1.0f;
|
||||||
|
|
||||||
|
void OnCreate()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void OnUpdate(float ts)
|
||||||
|
{
|
||||||
|
Mat4 transform = GetTransform();
|
||||||
|
Vec3 translation = transform.Translation;
|
||||||
|
|
||||||
|
translation.Y -= SinkSpeed * ts;
|
||||||
|
|
||||||
|
transform.Translation = translation;
|
||||||
|
SetTransform(transform);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -4,17 +4,15 @@ namespace Prism
|
|||||||
{
|
{
|
||||||
public class Entity
|
public class Entity
|
||||||
{
|
{
|
||||||
public uint SceneID { get; private set; }
|
public ulong ID { get; private set; }
|
||||||
public uint EntityID { get; private set; }
|
|
||||||
|
|
||||||
~Entity()
|
~Entity()
|
||||||
{
|
{
|
||||||
Console.WriteLine("Destroyed Entity {0}:{1}", SceneID, EntityID);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public T CreateComponent<T>() where T : Component, new()
|
public T CreateComponent<T>() where T : Component, new()
|
||||||
{
|
{
|
||||||
CreateComponent_Native(SceneID, EntityID, typeof(T));
|
CreateComponent_Native(ID, typeof(T));
|
||||||
T component = new T();
|
T component = new T();
|
||||||
component.Entity = this;
|
component.Entity = this;
|
||||||
return component;
|
return component;
|
||||||
@ -22,7 +20,7 @@ namespace Prism
|
|||||||
|
|
||||||
public bool HasComponent<T>() where T : Component, new()
|
public bool HasComponent<T>() where T : Component, new()
|
||||||
{
|
{
|
||||||
return HasComponent_Native(SceneID, EntityID, typeof(T));
|
return HasComponent_Native(ID, typeof(T));
|
||||||
}
|
}
|
||||||
|
|
||||||
public T GetComponent<T>() where T : Component, new()
|
public T GetComponent<T>() where T : Component, new()
|
||||||
@ -39,23 +37,23 @@ namespace Prism
|
|||||||
public Mat4 GetTransform()
|
public Mat4 GetTransform()
|
||||||
{
|
{
|
||||||
Mat4 mat4Instance;
|
Mat4 mat4Instance;
|
||||||
GetTransform_Native(SceneID, EntityID, out mat4Instance);
|
GetTransform_Native(ID, out mat4Instance);
|
||||||
return mat4Instance;
|
return mat4Instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetTransform(Mat4 transform)
|
public void SetTransform(Mat4 transform)
|
||||||
{
|
{
|
||||||
SetTransform_Native(SceneID, EntityID, ref transform);
|
SetTransform_Native(ID, ref transform);
|
||||||
}
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||||
private static extern void CreateComponent_Native(uint sceneID, uint entityID, Type type);
|
private static extern void CreateComponent_Native(ulong entityID, Type type);
|
||||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||||
private static extern bool HasComponent_Native(uint sceneID, uint entityID, Type type);
|
private static extern bool HasComponent_Native(ulong entityID, Type type);
|
||||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||||
private static extern void GetTransform_Native(uint sceneID, uint entityID, out Mat4 matrix);
|
private static extern void GetTransform_Native(ulong entityID, out Mat4 matrix);
|
||||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||||
private static extern void SetTransform_Native(uint sceneID, uint entityID, ref Mat4 matrix);
|
private static extern void SetTransform_Native(ulong entityID, ref Mat4 matrix);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -14,7 +14,7 @@ namespace Prism
|
|||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
return GetTag_Native(Entity.SceneID, Entity.EntityID);
|
return GetTag_Native(Entity.ID);
|
||||||
}
|
}
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
@ -23,7 +23,7 @@ namespace Prism
|
|||||||
}
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||||
public static extern string GetTag_Native(uint sceneID, uint entityID);
|
public static extern string GetTag_Native(ulong entityID);
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||||
public static extern void SetTag_Native(string tag);
|
public static extern void SetTag_Native(string tag);
|
||||||
@ -37,20 +37,20 @@ namespace Prism
|
|||||||
get
|
get
|
||||||
{
|
{
|
||||||
Mat4 result;
|
Mat4 result;
|
||||||
GetTransform_Native(Entity.SceneID, Entity.EntityID, out result);
|
GetTransform_Native(Entity.ID, out result);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
SetTransform_Native(Entity.SceneID, Entity.EntityID, ref value);
|
SetTransform_Native(Entity.ID, ref value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||||
public static extern void GetTransform_Native(uint sceneID, uint entityID, out Mat4 result);
|
public static extern void GetTransform_Native(ulong entityID, out Mat4 result);
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||||
public static extern void SetTransform_Native(uint sceneID, uint entityID, ref Mat4 result);
|
public static extern void SetTransform_Native(ulong entityID, ref Mat4 result);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -60,21 +60,21 @@ namespace Prism
|
|||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
Mesh result = new Mesh(GetMesh_Native(Entity.SceneID, Entity.EntityID));
|
Mesh result = new Mesh(GetMesh_Native(Entity.ID));
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
IntPtr ptr = value == null ? IntPtr.Zero : value.m_UnmanagedInstance;
|
IntPtr ptr = value == null ? IntPtr.Zero : value.m_UnmanagedInstance;
|
||||||
SetMesh_Native(Entity.SceneID, Entity.EntityID, ptr);
|
SetMesh_Native(Entity.ID, ptr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||||
public static extern IntPtr GetMesh_Native(uint sceneID, uint entityID);
|
public static extern IntPtr GetMesh_Native(ulong entityID);
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||||
public static extern void SetMesh_Native(uint sceneID, uint entityID, IntPtr unmanagedInstance);
|
public static extern void SetMesh_Native(ulong entityID, IntPtr unmanagedInstance);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -16,6 +16,7 @@ add_subdirectory(vendor/TinyFileDialog EXCLUDE_FROM_ALL)
|
|||||||
add_subdirectory(vendor/EnTT EXCLUDE_FROM_ALL)
|
add_subdirectory(vendor/EnTT EXCLUDE_FROM_ALL)
|
||||||
add_subdirectory(vendor/mono EXCLUDE_FROM_ALL)
|
add_subdirectory(vendor/mono EXCLUDE_FROM_ALL)
|
||||||
add_subdirectory(vendor/FastNoise EXCLUDE_FROM_ALL)
|
add_subdirectory(vendor/FastNoise EXCLUDE_FROM_ALL)
|
||||||
|
add_subdirectory(vendor/yaml-cpp EXCLUDE_FROM_ALL)
|
||||||
|
|
||||||
|
|
||||||
# ------------- imgui -------------
|
# ------------- imgui -------------
|
||||||
@ -52,6 +53,7 @@ set(LINK_LIBRARIES_PRIVATE
|
|||||||
stb
|
stb
|
||||||
tinyFileDialogs
|
tinyFileDialogs
|
||||||
FastNoise
|
FastNoise
|
||||||
|
yaml-cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
set(LINK_LIBRARIES_PUBLIC
|
set(LINK_LIBRARIES_PUBLIC
|
||||||
|
|||||||
@ -36,5 +36,8 @@
|
|||||||
// Scene
|
// Scene
|
||||||
#include "Prism/Scene/Entity.h"
|
#include "Prism/Scene/Entity.h"
|
||||||
#include "Prism/Scene/Scene.h"
|
#include "Prism/Scene/Scene.h"
|
||||||
|
#include "Prism/Scene/SceneCamera.h"
|
||||||
|
#include "Prism/Scene/SceneSerializer.h"
|
||||||
|
#include "Prism/Scene/Components.h"
|
||||||
|
|
||||||
#endif //PRISM_H
|
#endif //PRISM_H
|
||||||
|
|||||||
@ -42,6 +42,7 @@ namespace Prism
|
|||||||
|
|
||||||
Application::~Application()
|
Application::~Application()
|
||||||
{
|
{
|
||||||
|
ScriptEngine::Shutdown();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Application::Run()
|
void Application::Run()
|
||||||
@ -104,6 +105,7 @@ namespace Prism
|
|||||||
m_ImGuiLayer->End();
|
m_ImGuiLayer->End();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: fix this to prase filter
|
||||||
std::string Application::OpenFile(const std::string& filter) const
|
std::string Application::OpenFile(const std::string& filter) const
|
||||||
{
|
{
|
||||||
// TODO: will move it to other folder
|
// TODO: will move it to other folder
|
||||||
@ -151,7 +153,17 @@ namespace Prism
|
|||||||
filterDesc = ss.str();
|
filterDesc = ss.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const char* result = tinyfd_openFileDialog(
|
||||||
|
"Open File", // 对话框标题
|
||||||
|
nullptr, // 初始路径,nullptr 表示使用默认
|
||||||
|
0, // 过滤器数量 (注意:这里需要根据解析情况调整,见下文)
|
||||||
|
nullptr, // 过滤器模式数组
|
||||||
|
nullptr, // 过滤器描述
|
||||||
|
0 // 是否允许多选:0 为单选,1 为多选
|
||||||
|
);
|
||||||
|
|
||||||
// 调用文件对话框
|
// 调用文件对话框
|
||||||
|
/*
|
||||||
const char* result = tinyfd_openFileDialog(
|
const char* result = tinyfd_openFileDialog(
|
||||||
"Open File", // 标题
|
"Open File", // 标题
|
||||||
nullptr, // 初始目录
|
nullptr, // 初始目录
|
||||||
@ -160,11 +172,17 @@ namespace Prism
|
|||||||
filterDesc.empty() ? nullptr : filterDesc.c_str(), // 描述
|
filterDesc.empty() ? nullptr : filterDesc.c_str(), // 描述
|
||||||
0 // 单选
|
0 // 单选
|
||||||
);
|
);
|
||||||
|
*/
|
||||||
|
|
||||||
return result ? std::string(result) : std::string();
|
return result ? std::string(result) : std::string();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string Application::SaveFile(const std::string& filter) const
|
||||||
|
{
|
||||||
|
return OpenFile(filter);
|
||||||
|
}
|
||||||
|
|
||||||
Application& Application::Get()
|
Application& Application::Get()
|
||||||
{
|
{
|
||||||
return *s_Instance;
|
return *s_Instance;
|
||||||
|
|||||||
@ -35,7 +35,8 @@ namespace Prism
|
|||||||
|
|
||||||
void RenderImGui();
|
void RenderImGui();
|
||||||
|
|
||||||
std::string OpenFile(const std::string& filter) const;
|
std::string OpenFile(const std::string& filter = "All\0*.*\0") const;
|
||||||
|
std::string SaveFile(const std::string& filter = "All\0*.*\0") const;
|
||||||
|
|
||||||
inline Window& GetWindow() { return *m_Window; }
|
inline Window& GetWindow() { return *m_Window; }
|
||||||
|
|
||||||
|
|||||||
@ -6,6 +6,7 @@
|
|||||||
#define MOUSEEVENT_H
|
#define MOUSEEVENT_H
|
||||||
|
|
||||||
#include "Event.h"
|
#include "Event.h"
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
namespace Prism {
|
namespace Prism {
|
||||||
|
|
||||||
|
|||||||
29
Prism/src/Prism/Core/UUID.cpp
Normal file
29
Prism/src/Prism/Core/UUID.cpp
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
//
|
||||||
|
// Created by sfd on 25-12-9.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "UUID.h"
|
||||||
|
|
||||||
|
#include <random>
|
||||||
|
|
||||||
|
namespace Prism
|
||||||
|
{
|
||||||
|
static std::random_device s_RandomDevice;
|
||||||
|
static std::mt19937_64 eng(s_RandomDevice());
|
||||||
|
static std::uniform_int_distribution<uint64_t> s_UniformDistribution;
|
||||||
|
|
||||||
|
UUID::UUID()
|
||||||
|
: m_UUID(s_UniformDistribution(eng))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
UUID::UUID(const uint64_t uuid)
|
||||||
|
: m_UUID(uuid)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
UUID::UUID(const UUID& other)
|
||||||
|
: m_UUID(other.m_UUID)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
42
Prism/src/Prism/Core/UUID.h
Normal file
42
Prism/src/Prism/Core/UUID.h
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
//
|
||||||
|
// Created by sfd on 25-12-9.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef UUID_H
|
||||||
|
#define UUID_H
|
||||||
|
|
||||||
|
#include <functional>
|
||||||
|
|
||||||
|
|
||||||
|
namespace Prism
|
||||||
|
{
|
||||||
|
class UUID
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
UUID();
|
||||||
|
UUID(uint64_t uuid);
|
||||||
|
UUID(const UUID& other);
|
||||||
|
|
||||||
|
operator uint64_t() { return m_UUID; }
|
||||||
|
operator const uint64_t() const { return m_UUID; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
uint64_t m_UUID;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace std
|
||||||
|
{
|
||||||
|
template<>
|
||||||
|
struct hash<Prism::UUID>
|
||||||
|
{
|
||||||
|
std::size_t operator()(const Prism::UUID& uuid) const
|
||||||
|
{
|
||||||
|
return hash<uint64_t>()((uint64_t)uuid);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#endif //UUID_H
|
||||||
161
Prism/src/Prism/Editor/EditorCamera.cpp
Normal file
161
Prism/src/Prism/Editor/EditorCamera.cpp
Normal file
@ -0,0 +1,161 @@
|
|||||||
|
//
|
||||||
|
// Created by sfd on 25-12-9.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "EditorCamera.h"
|
||||||
|
|
||||||
|
#include "GLFW/glfw3.h"
|
||||||
|
#include "glm/detail/type_quat.hpp"
|
||||||
|
|
||||||
|
#include "glm/gtc/quaternion.hpp"
|
||||||
|
#define GLM_ENABLE_EXPERIMENTAL
|
||||||
|
#include "glm/gtx/quaternion.hpp"
|
||||||
|
#include "Prism/Core/Application.h"
|
||||||
|
#include "Prism/Core/Input.h"
|
||||||
|
#include "Prism/Core/Events/MouseEvent.h"
|
||||||
|
|
||||||
|
#ifndef M_PI
|
||||||
|
#define M_PI 3.1415926f
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace Prism
|
||||||
|
{
|
||||||
|
EditorCamera::EditorCamera(const glm::mat4& projectionMatrix)
|
||||||
|
: Camera(projectionMatrix)
|
||||||
|
{
|
||||||
|
m_Rotation = glm::vec3(90.0f, 0.0f, 0.0f);
|
||||||
|
|
||||||
|
m_FocalPoint = glm::vec3(0.0f);
|
||||||
|
|
||||||
|
glm::vec3 position = { -5, 5, 5};
|
||||||
|
m_Distance = glm::distance(position, m_FocalPoint);
|
||||||
|
|
||||||
|
m_Yaw = 3.0f * (float)M_PI / 4.0f;
|
||||||
|
m_Pitch = M_PI / 4.0f;
|
||||||
|
|
||||||
|
UpdateCameraView();
|
||||||
|
}
|
||||||
|
|
||||||
|
void EditorCamera::Focus()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void EditorCamera::OnUpdate(TimeStep deltaTime)
|
||||||
|
{
|
||||||
|
if (Input::IsKeyPressed(Key::LEFT_ALT))
|
||||||
|
{
|
||||||
|
const glm::vec2& mouse{ Input::GetMouseX(), Input::GetMouseY() };
|
||||||
|
const glm::vec2 delta = (mouse - m_InitialMousePosition) * 0.003f;
|
||||||
|
m_InitialMousePosition = mouse;
|
||||||
|
|
||||||
|
if (Input::IsMouseButtonPressed(GLFW_MOUSE_BUTTON_MIDDLE))
|
||||||
|
MousePan(delta);
|
||||||
|
else if (Input::IsMouseButtonPressed(GLFW_MOUSE_BUTTON_LEFT))
|
||||||
|
MouseRotate(delta);
|
||||||
|
else if (Input::IsMouseButtonPressed(GLFW_MOUSE_BUTTON_RIGHT))
|
||||||
|
MouseZoom(delta.y);
|
||||||
|
}
|
||||||
|
|
||||||
|
UpdateCameraView();
|
||||||
|
}
|
||||||
|
|
||||||
|
void EditorCamera::OnEvent(Event& e)
|
||||||
|
{
|
||||||
|
EventDispatcher dispatcher(e);
|
||||||
|
dispatcher.Dispatch<MouseScrolledEvent>(PM_BIND_EVENT_FN(EditorCamera::OnMouseScroll));
|
||||||
|
}
|
||||||
|
|
||||||
|
glm::vec3 EditorCamera::GetUpDirection() const
|
||||||
|
{
|
||||||
|
return glm::rotate(GetOrientation(), glm::vec3(0.0f, 1.0f, 0.0f));
|
||||||
|
}
|
||||||
|
|
||||||
|
glm::vec3 EditorCamera::GetRightDirection() const
|
||||||
|
{
|
||||||
|
return glm::rotate(GetOrientation(), glm::vec3(1.0f, 0.0f, 0.0f));
|
||||||
|
}
|
||||||
|
|
||||||
|
glm::vec3 EditorCamera::GetForwardDirection() const
|
||||||
|
{
|
||||||
|
return glm::rotate(GetOrientation(), glm::vec3(0.0f, 0.0f, -1.0f));
|
||||||
|
}
|
||||||
|
|
||||||
|
void EditorCamera::UpdateCameraView()
|
||||||
|
{
|
||||||
|
m_Position = CalculatePosition();
|
||||||
|
|
||||||
|
const glm::quat orientation = GetOrientation();
|
||||||
|
m_Rotation = glm::eulerAngles(orientation) * (180.0f / (float)M_PI);
|
||||||
|
m_ViewMatrix = glm::translate(glm::mat4(1.0f), m_Position) * glm::toMat4(orientation);
|
||||||
|
m_ViewMatrix = glm::inverse(m_ViewMatrix);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool EditorCamera::OnMouseScroll(MouseScrolledEvent& e)
|
||||||
|
{
|
||||||
|
const float delta = e.GetOffsetY() * 0.1f;
|
||||||
|
MouseZoom(delta);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void EditorCamera::MousePan(const glm::vec2& delta)
|
||||||
|
{
|
||||||
|
auto [xSpeed, ySpeed] = PanSpeed();
|
||||||
|
// PM_CORE_TRACE("{0}, {1}", xSpeed, ySpeed);
|
||||||
|
m_FocalPoint += -GetRightDirection() * delta.x * xSpeed * m_Distance;
|
||||||
|
m_FocalPoint += GetUpDirection() * delta.y * ySpeed * m_Distance;
|
||||||
|
}
|
||||||
|
|
||||||
|
void EditorCamera::MouseRotate(const glm::vec2& delta)
|
||||||
|
{
|
||||||
|
float yawSign = GetUpDirection().y < 0 ? -1.0f : 1.0f;
|
||||||
|
m_Yaw += yawSign * delta.x * RotationSpeed();
|
||||||
|
m_Pitch += delta.y * RotationSpeed();
|
||||||
|
}
|
||||||
|
|
||||||
|
void EditorCamera::MouseZoom(const float delta)
|
||||||
|
{
|
||||||
|
m_Distance -= delta * ZoomSpeed();
|
||||||
|
if (m_Distance < 1.0f)
|
||||||
|
{
|
||||||
|
m_FocalPoint += GetForwardDirection() * delta;
|
||||||
|
m_Distance = 1.0f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
glm::vec3 EditorCamera::CalculatePosition() const
|
||||||
|
{
|
||||||
|
return m_FocalPoint - GetForwardDirection() * m_Distance;
|
||||||
|
}
|
||||||
|
|
||||||
|
glm::quat EditorCamera::GetOrientation() const
|
||||||
|
{
|
||||||
|
return glm::quat(glm::vec3(-m_Pitch, -m_Yaw, 0.0f));
|
||||||
|
}
|
||||||
|
|
||||||
|
std::pair<float, float> EditorCamera::PanSpeed() const
|
||||||
|
{
|
||||||
|
const float x = std::min(m_ViewportWidth / 1000.0f, 2.4f); // max = 2.4f
|
||||||
|
float xFactor = 0.0366f * (x * x) - 0.1778f * x + 0.3021f;
|
||||||
|
|
||||||
|
const float y = std::min(m_ViewportHeight / 1000.0f, 2.4f); // max = 2.4f
|
||||||
|
float yFactor = 0.0366f * (y * y) - 0.1778f * y + 0.3021f;
|
||||||
|
|
||||||
|
return { xFactor, yFactor };
|
||||||
|
}
|
||||||
|
|
||||||
|
float EditorCamera::RotationSpeed() const
|
||||||
|
{
|
||||||
|
return 0.8f;
|
||||||
|
}
|
||||||
|
|
||||||
|
float EditorCamera::ZoomSpeed() const
|
||||||
|
{
|
||||||
|
float distance = m_Distance * 0.2f;
|
||||||
|
distance = std::max(distance, 0.0f);
|
||||||
|
float speed = distance * distance;
|
||||||
|
speed = std::min(speed, 100.0f); // max speed = 100
|
||||||
|
return speed;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
84
Prism/src/Prism/Editor/EditorCamera.h
Normal file
84
Prism/src/Prism/Editor/EditorCamera.h
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
//
|
||||||
|
// Created by sfd on 25-12-9.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef EDITORCAMERA_H
|
||||||
|
#define EDITORCAMERA_H
|
||||||
|
#include "glm/fwd.hpp"
|
||||||
|
#include "glm/vec2.hpp"
|
||||||
|
#include "glm/vec3.hpp"
|
||||||
|
#include "Prism/Core/TimeStep.h"
|
||||||
|
#include "Prism/Core/Events/Event.h"
|
||||||
|
#include "Prism/Core/Events/MouseEvent.h"
|
||||||
|
#include "Prism/Renderer/Camera.h"
|
||||||
|
|
||||||
|
|
||||||
|
namespace Prism
|
||||||
|
{
|
||||||
|
class PRISM_API EditorCamera : public Camera
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
EditorCamera() = default;
|
||||||
|
EditorCamera(const glm::mat4& projectionMatrix);
|
||||||
|
|
||||||
|
void Focus();
|
||||||
|
void OnUpdate(TimeStep deltaTime);
|
||||||
|
void OnEvent(Event& e);
|
||||||
|
|
||||||
|
inline float GetDistance() const { return m_Distance; }
|
||||||
|
inline void SetDistance(float distance) { m_Distance = distance; }
|
||||||
|
|
||||||
|
inline void SetProjectionMatrix(const glm::mat4& projectionMatrix) { m_ProjectionMatrix = projectionMatrix; }
|
||||||
|
|
||||||
|
const glm::mat4& GetProjectionMatrix() const { return m_ProjectionMatrix; }
|
||||||
|
const glm::mat4& GetViewMatrix() const { return m_ViewMatrix; }
|
||||||
|
glm::mat4 GetViewProjection() const { return m_ProjectionMatrix * m_ViewMatrix; }
|
||||||
|
|
||||||
|
glm::vec3 GetUpDirection() const;
|
||||||
|
glm::vec3 GetRightDirection() const;
|
||||||
|
glm::vec3 GetForwardDirection() const;
|
||||||
|
const glm::vec3& GetPosition() const { return m_Position; }
|
||||||
|
glm::quat GetOrientation() const;
|
||||||
|
|
||||||
|
float GetExposure() const { return m_Exposure; }
|
||||||
|
float& GetExposure() { return m_Exposure; }
|
||||||
|
|
||||||
|
float GetPitch() const { return m_Pitch; }
|
||||||
|
float GetYaw() const { return m_Yaw; }
|
||||||
|
|
||||||
|
public:
|
||||||
|
inline void SetViewportSize(const uint32_t width, const uint32_t height) { m_ViewportWidth = width; m_ViewportHeight = height; }
|
||||||
|
private:
|
||||||
|
void UpdateCameraView();
|
||||||
|
|
||||||
|
bool OnMouseScroll(MouseScrolledEvent& e);
|
||||||
|
void MousePan(const glm::vec2& delta);
|
||||||
|
void MouseRotate(const glm::vec2& delta);
|
||||||
|
void MouseZoom(float delta);
|
||||||
|
|
||||||
|
glm::vec3 CalculatePosition() const;
|
||||||
|
|
||||||
|
std::pair<float, float> PanSpeed() const;
|
||||||
|
float RotationSpeed() const;
|
||||||
|
float ZoomSpeed() const;
|
||||||
|
private:
|
||||||
|
glm::mat4 m_ViewMatrix;
|
||||||
|
glm::vec3 m_Position, m_Rotation, m_FocalPoint;
|
||||||
|
|
||||||
|
bool m_Panning, m_Rotating;
|
||||||
|
glm::vec2 m_InitialMousePosition;
|
||||||
|
glm::vec3 m_InitialFocalPoint, m_InitialRotation;
|
||||||
|
|
||||||
|
uint32_t m_ViewportWidth = 1280, m_ViewportHeight = 720;
|
||||||
|
|
||||||
|
float m_Distance;
|
||||||
|
|
||||||
|
float m_Exposure = 0.8f;
|
||||||
|
|
||||||
|
float m_Pitch, m_Yaw;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#endif //EDITORCAMERA_H
|
||||||
@ -9,6 +9,8 @@
|
|||||||
#define GLM_ENABLE_EXPERIMENTAL
|
#define GLM_ENABLE_EXPERIMENTAL
|
||||||
#include "assimp/scene.h"
|
#include "assimp/scene.h"
|
||||||
#include "glm/gtx/matrix_decompose.hpp"
|
#include "glm/gtx/matrix_decompose.hpp"
|
||||||
|
#include "glm/gtx/quaternion.hpp"
|
||||||
|
#include "Prism/Core/Application.h"
|
||||||
#include "Prism/Script/ScriptEngine.h"
|
#include "Prism/Script/ScriptEngine.h"
|
||||||
|
|
||||||
namespace Prism
|
namespace Prism
|
||||||
@ -24,6 +26,15 @@ namespace Prism
|
|||||||
void SceneHierarchyPanel::SetContext(const Ref<Scene>& scene)
|
void SceneHierarchyPanel::SetContext(const Ref<Scene>& scene)
|
||||||
{
|
{
|
||||||
m_Context = scene;
|
m_Context = scene;
|
||||||
|
m_SelectionContext = {};
|
||||||
|
if (m_SelectionContext && false)
|
||||||
|
{
|
||||||
|
// Try and find same entity in new scene
|
||||||
|
auto& entityMap = m_Context->GetEntityMap();
|
||||||
|
UUID selectedEntityID = m_SelectionContext.GetUUID();
|
||||||
|
if (entityMap.find(selectedEntityID) != entityMap.end())
|
||||||
|
m_SelectionContext = entityMap.at(selectedEntityID);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SceneHierarchyPanel::SetSelected(Entity entity)
|
void SceneHierarchyPanel::SetSelected(Entity entity)
|
||||||
@ -34,34 +45,76 @@ namespace Prism
|
|||||||
void SceneHierarchyPanel::OnImGuiRender()
|
void SceneHierarchyPanel::OnImGuiRender()
|
||||||
{
|
{
|
||||||
ImGui::Begin("Scene Hierarchy");
|
ImGui::Begin("Scene Hierarchy");
|
||||||
|
if (m_Context)
|
||||||
uint32_t entityCount = 0, meshCount = 0;
|
|
||||||
for(const auto entity : m_Context->m_Registry.view<entt::entity>())
|
|
||||||
{
|
{
|
||||||
DrawEntityNode(Entity(entity, m_Context.Raw()));
|
uint32_t entityCount = 0, meshCount = 0;
|
||||||
}
|
m_Context->m_Registry.view<entt::entity>().each([&](auto entity)
|
||||||
|
{
|
||||||
|
const Entity e(entity, m_Context.Raw());
|
||||||
|
if (e.HasComponent<IDComponent>())
|
||||||
|
DrawEntityNode(e);
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
if (ImGui::BeginPopupContextWindow())
|
if (ImGui::BeginPopupContextWindow())
|
||||||
{
|
|
||||||
if (ImGui::MenuItem("Create Empty Entity"))
|
|
||||||
{
|
{
|
||||||
m_Context->CreateEntity("Empty Entity");
|
if (ImGui::MenuItem("Create Empty Entity"))
|
||||||
|
{
|
||||||
|
m_Context->CreateEntity("Empty Entity");
|
||||||
|
}
|
||||||
|
ImGui::EndPopup();
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::End();
|
||||||
|
|
||||||
|
|
||||||
|
ImGui::Begin("Properties");
|
||||||
|
|
||||||
|
if (m_SelectionContext)
|
||||||
|
{
|
||||||
|
DrawComponents(m_SelectionContext);
|
||||||
|
|
||||||
|
if (ImGui::Button("Add Component"))
|
||||||
|
ImGui::OpenPopup("AddComponentPanel");
|
||||||
|
|
||||||
|
if (ImGui::BeginPopup("AddComponentPanel"))
|
||||||
|
{
|
||||||
|
if (!m_SelectionContext.HasComponent<CameraComponent>())
|
||||||
|
{
|
||||||
|
if (ImGui::Button("Camera"))
|
||||||
|
{
|
||||||
|
m_SelectionContext.AddComponent<CameraComponent>();
|
||||||
|
ImGui::CloseCurrentPopup();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!m_SelectionContext.HasComponent<MeshComponent>())
|
||||||
|
{
|
||||||
|
if (ImGui::Button("Mesh"))
|
||||||
|
{
|
||||||
|
m_SelectionContext.AddComponent<MeshComponent>();
|
||||||
|
ImGui::CloseCurrentPopup();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!m_SelectionContext.HasComponent<ScriptComponent>())
|
||||||
|
{
|
||||||
|
if (ImGui::Button("Script"))
|
||||||
|
{
|
||||||
|
m_SelectionContext.AddComponent<ScriptComponent>();
|
||||||
|
ImGui::CloseCurrentPopup();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!m_SelectionContext.HasComponent<SpriteRendererComponent>())
|
||||||
|
{
|
||||||
|
if (ImGui::Button("Sprite Renderer"))
|
||||||
|
{
|
||||||
|
m_SelectionContext.AddComponent<SpriteRendererComponent>();
|
||||||
|
ImGui::CloseCurrentPopup();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ImGui::EndPopup();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
ImGui::EndPopup();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
ImGui::End();
|
|
||||||
|
|
||||||
ImGui::Begin("Properties");
|
|
||||||
|
|
||||||
if (m_SelectionContext)
|
|
||||||
{
|
|
||||||
DrawComponents(m_SelectionContext);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
ImGui::End();
|
ImGui::End();
|
||||||
|
|
||||||
|
|
||||||
@ -95,7 +148,11 @@ namespace Prism
|
|||||||
const ImGuiTreeNodeFlags node_flags = (entity == m_SelectionContext ? ImGuiTreeNodeFlags_Selected : 0) | ImGuiTreeNodeFlags_OpenOnArrow;
|
const ImGuiTreeNodeFlags node_flags = (entity == m_SelectionContext ? ImGuiTreeNodeFlags_Selected : 0) | ImGuiTreeNodeFlags_OpenOnArrow;
|
||||||
const bool opened = ImGui::TreeNodeEx((void*)(uint32_t)entity, node_flags, name);
|
const bool opened = ImGui::TreeNodeEx((void*)(uint32_t)entity, node_flags, name);
|
||||||
if (ImGui::IsItemClicked())
|
if (ImGui::IsItemClicked())
|
||||||
|
{
|
||||||
m_SelectionContext = entity;
|
m_SelectionContext = entity;
|
||||||
|
if (m_SelectionChangedCallback)
|
||||||
|
m_SelectionChangedCallback(m_SelectionContext);
|
||||||
|
}
|
||||||
|
|
||||||
bool entityDeleted = false;
|
bool entityDeleted = false;
|
||||||
if (ImGui::BeginPopupContextItem())
|
if (ImGui::BeginPopupContextItem())
|
||||||
@ -123,6 +180,8 @@ namespace Prism
|
|||||||
m_Context->DestroyEntity(entity);
|
m_Context->DestroyEntity(entity);
|
||||||
if (entity == m_SelectionContext)
|
if (entity == m_SelectionContext)
|
||||||
m_SelectionContext = {};
|
m_SelectionContext = {};
|
||||||
|
|
||||||
|
m_EntityDeletedCallback(entity);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -211,7 +270,7 @@ namespace Prism
|
|||||||
ImGui::Columns(2);
|
ImGui::Columns(2);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool Property(const char* label, std::string& value)
|
static bool Property(const char* label, std::string& value, bool error = false)
|
||||||
{
|
{
|
||||||
bool modified = false;
|
bool modified = false;
|
||||||
|
|
||||||
@ -226,12 +285,19 @@ namespace Prism
|
|||||||
s_IDBuffer[1] = '#';
|
s_IDBuffer[1] = '#';
|
||||||
memset(s_IDBuffer + 2, 0, 14);
|
memset(s_IDBuffer + 2, 0, 14);
|
||||||
itoa(s_Counter++, s_IDBuffer + 2, 16);
|
itoa(s_Counter++, s_IDBuffer + 2, 16);
|
||||||
|
|
||||||
|
if (error)
|
||||||
|
ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(0.9f, 0.2f, 0.2f, 1.0f));
|
||||||
|
|
||||||
if (ImGui::InputText(s_IDBuffer, buffer, 256))
|
if (ImGui::InputText(s_IDBuffer, buffer, 256))
|
||||||
{
|
{
|
||||||
value = buffer;
|
value = buffer;
|
||||||
modified = true;
|
modified = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (error)
|
||||||
|
ImGui::PopStyleColor();
|
||||||
|
|
||||||
ImGui::PopItemWidth();
|
ImGui::PopItemWidth();
|
||||||
ImGui::NextColumn();
|
ImGui::NextColumn();
|
||||||
|
|
||||||
@ -317,6 +383,48 @@ namespace Prism
|
|||||||
return modified;
|
return modified;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool Property(const char* label, glm::vec3& value, float delta = 0.1f)
|
||||||
|
{
|
||||||
|
bool modified = false;
|
||||||
|
|
||||||
|
ImGui::Text(label);
|
||||||
|
ImGui::NextColumn();
|
||||||
|
ImGui::PushItemWidth(-1);
|
||||||
|
|
||||||
|
s_IDBuffer[0] = '#';
|
||||||
|
s_IDBuffer[1] = '#';
|
||||||
|
memset(s_IDBuffer + 2, 0, 14);
|
||||||
|
itoa(s_Counter++, s_IDBuffer + 2, 16);
|
||||||
|
if (ImGui::DragFloat3(s_IDBuffer, glm::value_ptr(value), delta))
|
||||||
|
modified = true;
|
||||||
|
|
||||||
|
ImGui::PopItemWidth();
|
||||||
|
ImGui::NextColumn();
|
||||||
|
|
||||||
|
return modified;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool Property(const char* label, glm::vec4& value, float delta = 0.1f)
|
||||||
|
{
|
||||||
|
bool modified = false;
|
||||||
|
|
||||||
|
ImGui::Text(label);
|
||||||
|
ImGui::NextColumn();
|
||||||
|
ImGui::PushItemWidth(-1);
|
||||||
|
|
||||||
|
s_IDBuffer[0] = '#';
|
||||||
|
s_IDBuffer[1] = '#';
|
||||||
|
memset(s_IDBuffer + 2, 0, 14);
|
||||||
|
itoa(s_Counter++, s_IDBuffer + 2, 16);
|
||||||
|
if (ImGui::DragFloat4(s_IDBuffer, glm::value_ptr(value), delta))
|
||||||
|
modified = true;
|
||||||
|
|
||||||
|
ImGui::PopItemWidth();
|
||||||
|
ImGui::NextColumn();
|
||||||
|
|
||||||
|
return modified;
|
||||||
|
}
|
||||||
|
|
||||||
static void EndPropertyGrid()
|
static void EndPropertyGrid()
|
||||||
{
|
{
|
||||||
ImGui::Columns(1);
|
ImGui::Columns(1);
|
||||||
@ -327,6 +435,8 @@ namespace Prism
|
|||||||
{
|
{
|
||||||
ImGui::AlignTextToFramePadding();
|
ImGui::AlignTextToFramePadding();
|
||||||
|
|
||||||
|
auto id = entity.GetComponent<IDComponent>().ID;
|
||||||
|
|
||||||
if (entity.HasComponent<TagComponent>())
|
if (entity.HasComponent<TagComponent>())
|
||||||
{
|
{
|
||||||
auto& tag = entity.GetComponent<TagComponent>().Tag;
|
auto& tag = entity.GetComponent<TagComponent>().Tag;
|
||||||
@ -337,25 +447,47 @@ namespace Prism
|
|||||||
{
|
{
|
||||||
tag = std::string(buffer);
|
tag = std::string(buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
ImGui::Separator();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ID
|
||||||
|
ImGui::SameLine();
|
||||||
|
ImGui::TextDisabled("%llx", id);
|
||||||
|
|
||||||
|
ImGui::Separator();
|
||||||
|
|
||||||
|
|
||||||
if (entity.HasComponent<TransformComponent>())
|
if (entity.HasComponent<TransformComponent>())
|
||||||
{
|
{
|
||||||
auto& tc = entity.GetComponent<TransformComponent>();
|
auto& tc = entity.GetComponent<TransformComponent>();
|
||||||
if (ImGui::TreeNodeEx((void*)((uint32_t)entity | typeid(MeshComponent).hash_code()), ImGuiTreeNodeFlags_DefaultOpen, "Transform"))
|
if (ImGui::TreeNodeEx((void*)((uint32_t)entity | typeid(TransformComponent).hash_code()), ImGuiTreeNodeFlags_DefaultOpen, "Transform"))
|
||||||
{
|
{
|
||||||
auto [translation, rotation, scale] = GetTransformDecomposition(tc);
|
auto [translation, rotationQuat, scale] = GetTransformDecomposition(tc);
|
||||||
|
glm::vec3 rotation = glm::degrees(glm::eulerAngles(rotationQuat));
|
||||||
|
|
||||||
ImGui::Columns(2);
|
ImGui::Columns(2);
|
||||||
ImGui::Text("Translation");
|
ImGui::Text("Translation");
|
||||||
ImGui::NextColumn();
|
ImGui::NextColumn();
|
||||||
ImGui::PushItemWidth(-1);
|
ImGui::PushItemWidth(-1);
|
||||||
|
|
||||||
|
bool updateTransform = false;
|
||||||
|
|
||||||
if (ImGui::DragFloat3("##translation", glm::value_ptr(translation), 0.25f))
|
if (ImGui::DragFloat3("##translation", glm::value_ptr(translation), 0.25f))
|
||||||
{
|
{
|
||||||
tc.Transform[3] = glm::vec4(translation, 1.0f);
|
// tc.Transform[3] = glm::vec4(translation, 1.0f);
|
||||||
|
updateTransform = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::PopItemWidth();
|
||||||
|
ImGui::NextColumn();
|
||||||
|
|
||||||
|
ImGui::Text("Rotation");
|
||||||
|
ImGui::NextColumn();
|
||||||
|
ImGui::PushItemWidth(-1);
|
||||||
|
|
||||||
|
if (ImGui::DragFloat3("##rotation", glm::value_ptr(rotation), 0.25f))
|
||||||
|
{
|
||||||
|
updateTransform = true;
|
||||||
|
// tc.Transform[3] = glm::vec4(translation, 1.0f);
|
||||||
}
|
}
|
||||||
|
|
||||||
ImGui::PopItemWidth();
|
ImGui::PopItemWidth();
|
||||||
@ -367,7 +499,7 @@ namespace Prism
|
|||||||
|
|
||||||
if (ImGui::DragFloat3("##scale", glm::value_ptr(scale), 0.25f))
|
if (ImGui::DragFloat3("##scale", glm::value_ptr(scale), 0.25f))
|
||||||
{
|
{
|
||||||
|
updateTransform = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
ImGui::PopItemWidth();
|
ImGui::PopItemWidth();
|
||||||
@ -375,8 +507,13 @@ namespace Prism
|
|||||||
|
|
||||||
ImGui::Columns(1);
|
ImGui::Columns(1);
|
||||||
|
|
||||||
// ImGui::Text("Translation: %.2f, %.2f, %.2f", translation.x, translation.y, translation.z);
|
|
||||||
// ImGui::Text("Scale: %.2f, %.2f, %.2f", scale.x, scale.y, scale.z);
|
if (updateTransform)
|
||||||
|
{
|
||||||
|
tc.Transform = glm::translate(glm::mat4(1.0f), translation) *
|
||||||
|
glm::toMat4(glm::quat(glm::radians(rotation))) *
|
||||||
|
glm::scale(glm::mat4(1.0f), scale);
|
||||||
|
}
|
||||||
ImGui::TreePop();
|
ImGui::TreePop();
|
||||||
}
|
}
|
||||||
ImGui::Separator();
|
ImGui::Separator();
|
||||||
@ -386,12 +523,32 @@ namespace Prism
|
|||||||
if (entity.HasComponent<MeshComponent>())
|
if (entity.HasComponent<MeshComponent>())
|
||||||
{
|
{
|
||||||
auto& mc = entity.GetComponent<MeshComponent>();
|
auto& mc = entity.GetComponent<MeshComponent>();
|
||||||
if (ImGui::TreeNodeEx((void*)((uint32_t)entity | typeid(TransformComponent).hash_code()), ImGuiTreeNodeFlags_DefaultOpen, "Mesh"))
|
if (ImGui::TreeNodeEx((void*)((uint32_t)entity | typeid(MeshComponent).hash_code()), ImGuiTreeNodeFlags_DefaultOpen, "Mesh"))
|
||||||
{
|
{
|
||||||
|
ImGui::Columns(3);
|
||||||
|
ImGui::SetColumnWidth(0, 100);
|
||||||
|
ImGui::SetColumnWidth(1, 300);
|
||||||
|
ImGui::SetColumnWidth(2, 40);
|
||||||
|
ImGui::Text("File Path");
|
||||||
|
ImGui::NextColumn();
|
||||||
|
ImGui::PushItemWidth(-1);
|
||||||
|
|
||||||
if (mc.Mesh)
|
if (mc.Mesh)
|
||||||
ImGui::InputText("File Path", (char*)mc.Mesh->GetFilePath().c_str(), 256, ImGuiInputTextFlags_ReadOnly);
|
ImGui::InputText("##meshFilePath", (char*)mc.Mesh->GetFilePath().c_str(), 256, ImGuiInputTextFlags_ReadOnly);
|
||||||
else
|
else
|
||||||
ImGui::InputText("File Path", (char*)"Null", 256, ImGuiInputTextFlags_ReadOnly);
|
ImGui::InputText("##meshFilePath", (char*)"Null", 256, ImGuiInputTextFlags_ReadOnly);
|
||||||
|
|
||||||
|
ImGui::PopItemWidth();
|
||||||
|
ImGui::NextColumn();
|
||||||
|
if (ImGui::Button("...##openmesh"))
|
||||||
|
{
|
||||||
|
const std::string file = Application::Get().OpenFile();
|
||||||
|
if (!file.empty())
|
||||||
|
mc.Mesh = Ref<Mesh>::Create(file);
|
||||||
|
}
|
||||||
|
ImGui::NextColumn();
|
||||||
|
ImGui::Columns(1);
|
||||||
|
|
||||||
ImGui::TreePop();
|
ImGui::TreePop();
|
||||||
}
|
}
|
||||||
ImGui::Separator();
|
ImGui::Separator();
|
||||||
@ -402,6 +559,59 @@ namespace Prism
|
|||||||
auto& cc = entity.GetComponent<CameraComponent>();
|
auto& cc = entity.GetComponent<CameraComponent>();
|
||||||
if (ImGui::TreeNodeEx((void*)((uint32_t)entity | typeid(CameraComponent).hash_code()), ImGuiTreeNodeFlags_DefaultOpen, "Camera"))
|
if (ImGui::TreeNodeEx((void*)((uint32_t)entity | typeid(CameraComponent).hash_code()), ImGuiTreeNodeFlags_DefaultOpen, "Camera"))
|
||||||
{
|
{
|
||||||
|
// Projection Type
|
||||||
|
const char* projTypeStrings[] = { "Perspective", "Orthographic" };
|
||||||
|
const char* currentProj = projTypeStrings[(int)cc.Camera.GetProjectionType()];
|
||||||
|
if (ImGui::BeginCombo("Projection", currentProj))
|
||||||
|
{
|
||||||
|
for (int type = 0; type < 2; type++)
|
||||||
|
{
|
||||||
|
bool is_selected = (currentProj == projTypeStrings[type]);
|
||||||
|
if (ImGui::Selectable(projTypeStrings[type], is_selected))
|
||||||
|
{
|
||||||
|
currentProj = projTypeStrings[type];
|
||||||
|
cc.Camera.SetProjectionType((SceneCamera::ProjectionType)type);
|
||||||
|
}
|
||||||
|
if (is_selected)
|
||||||
|
ImGui::SetItemDefaultFocus();
|
||||||
|
}
|
||||||
|
ImGui::EndCombo();
|
||||||
|
}
|
||||||
|
|
||||||
|
BeginPropertyGrid();
|
||||||
|
// Perspective parameters
|
||||||
|
if (cc.Camera.GetProjectionType() == SceneCamera::ProjectionType::Perspective)
|
||||||
|
{
|
||||||
|
float verticalFOV = cc.Camera.GetPerspectiveVerticalFOV();
|
||||||
|
if (Property("Vertical FOV", verticalFOV))
|
||||||
|
cc.Camera.SetPerspectiveVerticalFOV(verticalFOV);
|
||||||
|
|
||||||
|
float nearClip = cc.Camera.GetPerspectiveNearClip();
|
||||||
|
if (Property("Near Clip", nearClip))
|
||||||
|
cc.Camera.SetPerspectiveNearClip(nearClip);
|
||||||
|
ImGui::SameLine();
|
||||||
|
float farClip = cc.Camera.GetPerspectiveFarClip();
|
||||||
|
if (Property("Far Clip", farClip))
|
||||||
|
cc.Camera.SetPerspectiveFarClip(farClip);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Orthographic parameters
|
||||||
|
else if (cc.Camera.GetProjectionType() == SceneCamera::ProjectionType::Orthographic)
|
||||||
|
{
|
||||||
|
float orthoSize = cc.Camera.GetOrthographicSize();
|
||||||
|
if (Property("Size", orthoSize))
|
||||||
|
cc.Camera.SetOrthographicSize(orthoSize);
|
||||||
|
|
||||||
|
float nearClip = cc.Camera.GetOrthographicNearClip();
|
||||||
|
if (Property("Near Clip", nearClip))
|
||||||
|
cc.Camera.SetOrthographicNearClip(nearClip);
|
||||||
|
ImGui::SameLine();
|
||||||
|
float farClip = cc.Camera.GetOrthographicFarClip();
|
||||||
|
if (Property("Far Clip", farClip))
|
||||||
|
cc.Camera.SetOrthographicFarClip(farClip);
|
||||||
|
}
|
||||||
|
|
||||||
|
EndPropertyGrid();
|
||||||
|
|
||||||
ImGui::TreePop();
|
ImGui::TreePop();
|
||||||
}
|
}
|
||||||
@ -425,53 +635,105 @@ namespace Prism
|
|||||||
if (ImGui::TreeNodeEx((void*)((uint32_t)entity | typeid(ScriptComponent).hash_code()), ImGuiTreeNodeFlags_DefaultOpen, "Script"))
|
if (ImGui::TreeNodeEx((void*)((uint32_t)entity | typeid(ScriptComponent).hash_code()), ImGuiTreeNodeFlags_DefaultOpen, "Script"))
|
||||||
{
|
{
|
||||||
BeginPropertyGrid();
|
BeginPropertyGrid();
|
||||||
Property("Module Name", sc.ModuleName.c_str());
|
std::string oldName = sc.ModuleName;
|
||||||
|
|
||||||
// Public Fields
|
if (Property("Module Name", sc.ModuleName, !ScriptEngine::ModuleExists(sc.ModuleName))) // TODO: no live edit
|
||||||
auto& fieldMap = ScriptEngine::GetFieldMap();
|
|
||||||
if (fieldMap.find(sc.ModuleName) != fieldMap.end())
|
|
||||||
{
|
{
|
||||||
auto& publicFields = fieldMap.at(sc.ModuleName);
|
// Shutdown old script
|
||||||
for (auto& field : publicFields)
|
if (ScriptEngine::ModuleExists(oldName))
|
||||||
|
ScriptEngine::ShutdownScriptEntity(entity, oldName);
|
||||||
|
|
||||||
|
if (ScriptEngine::ModuleExists(sc.ModuleName))
|
||||||
|
ScriptEngine::InitScriptEntity(entity);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ScriptEngine::ModuleExists(sc.ModuleName))
|
||||||
|
{
|
||||||
|
EntityInstanceData& entityInstanceData = ScriptEngine::GetEntityInstanceData(entity.GetSceneUUID(), id);
|
||||||
|
auto& moduleFieldMap = entityInstanceData.ModuleFieldMap;
|
||||||
|
if (moduleFieldMap.find(sc.ModuleName) != moduleFieldMap.end())
|
||||||
{
|
{
|
||||||
switch (field.Type)
|
auto& publicFields = moduleFieldMap.at(sc.ModuleName);
|
||||||
|
for (auto& [name, field] : publicFields)
|
||||||
{
|
{
|
||||||
case FieldType::Int:
|
bool isRuntime = m_Context->m_IsPlaying && field.IsRuntimeAvailable();
|
||||||
{
|
switch (field.Type)
|
||||||
int value = field.GetValue<int>();
|
|
||||||
if (Property(field.Name.c_str(), value))
|
|
||||||
{
|
{
|
||||||
field.SetValue(value);
|
case FieldType::Int:
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case FieldType::Float:
|
|
||||||
{
|
|
||||||
float value = field.GetValue<float>();
|
|
||||||
if (Property(field.Name.c_str(), value, 0.2f))
|
|
||||||
{
|
{
|
||||||
field.SetValue(value);
|
int value = isRuntime ? field.GetRuntimeValue<int>() : field.GetStoredValue<int>();
|
||||||
|
if (Property(field.Name.c_str(), value))
|
||||||
|
{
|
||||||
|
if (isRuntime)
|
||||||
|
field.SetRuntimeValue(value);
|
||||||
|
else
|
||||||
|
field.SetStoredValue(value);
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
break;
|
case FieldType::Float:
|
||||||
}
|
|
||||||
case FieldType::Vec2:
|
|
||||||
{
|
|
||||||
glm::vec2 value = field.GetValue<glm::vec2>();
|
|
||||||
if (Property(field.Name.c_str(), value, 0.2f))
|
|
||||||
{
|
{
|
||||||
field.SetValue(value);
|
float value = isRuntime ? field.GetRuntimeValue<float>() : field.GetStoredValue<float>();
|
||||||
|
if (Property(field.Name.c_str(), value, 0.2f))
|
||||||
|
{
|
||||||
|
if (isRuntime)
|
||||||
|
field.SetRuntimeValue(value);
|
||||||
|
else
|
||||||
|
field.SetStoredValue(value);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case FieldType::Vec2:
|
||||||
|
{
|
||||||
|
glm::vec2 value = isRuntime ? field.GetRuntimeValue<glm::vec2>() : field.GetStoredValue<glm::vec2>();
|
||||||
|
if (Property(field.Name.c_str(), value, 0.2f))
|
||||||
|
{
|
||||||
|
if (isRuntime)
|
||||||
|
field.SetRuntimeValue(value);
|
||||||
|
else
|
||||||
|
field.SetStoredValue(value);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case FieldType::Vec3:
|
||||||
|
{
|
||||||
|
glm::vec3 value = isRuntime ? field.GetRuntimeValue<glm::vec3>() : field.GetStoredValue<glm::vec3>();
|
||||||
|
if (Property(field.Name.c_str(), value, 0.2f))
|
||||||
|
{
|
||||||
|
if (isRuntime)
|
||||||
|
field.SetRuntimeValue(value);
|
||||||
|
else
|
||||||
|
field.SetStoredValue(value);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case FieldType::Vec4:
|
||||||
|
{
|
||||||
|
glm::vec4 value = isRuntime ? field.GetRuntimeValue<glm::vec4>() : field.GetStoredValue<glm::vec4>();
|
||||||
|
if (Property(field.Name.c_str(), value, 0.2f))
|
||||||
|
{
|
||||||
|
if (isRuntime)
|
||||||
|
field.SetRuntimeValue(value);
|
||||||
|
else
|
||||||
|
field.SetStoredValue(value);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
EndPropertyGrid();
|
EndPropertyGrid();
|
||||||
|
|
||||||
|
#if TODO
|
||||||
|
|
||||||
if (ImGui::Button("Run Script"))
|
if (ImGui::Button("Run Script"))
|
||||||
{
|
{
|
||||||
ScriptEngine::OnCreateEntity(entity);
|
ScriptEngine::OnCreateEntity(entity);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
ImGui::TreePop();
|
ImGui::TreePop();
|
||||||
}
|
}
|
||||||
ImGui::Separator();
|
ImGui::Separator();
|
||||||
|
|||||||
@ -18,6 +18,8 @@ namespace Prism
|
|||||||
|
|
||||||
void SetContext(const Ref<Scene>& scene);
|
void SetContext(const Ref<Scene>& scene);
|
||||||
void SetSelected(Entity entity);
|
void SetSelected(Entity entity);
|
||||||
|
void SetSelectionChangedCallback(const std::function<void(Entity)>& func) { m_SelectionChangedCallback = func; }
|
||||||
|
void SetEntityDeletedCallback(const std::function<void(Entity)>& func) { m_EntityDeletedCallback = func; }
|
||||||
|
|
||||||
void OnImGuiRender();
|
void OnImGuiRender();
|
||||||
private:
|
private:
|
||||||
@ -28,6 +30,8 @@ namespace Prism
|
|||||||
private:
|
private:
|
||||||
Ref<Scene> m_Context;
|
Ref<Scene> m_Context;
|
||||||
Entity m_SelectionContext;
|
Entity m_SelectionContext;
|
||||||
|
|
||||||
|
std::function<void(Entity)> m_SelectionChangedCallback, m_EntityDeletedCallback;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -51,8 +51,9 @@ namespace Prism
|
|||||||
#ifdef __MINGW32__
|
#ifdef __MINGW32__
|
||||||
glDeleteBuffers(1, &m_RendererID);
|
glDeleteBuffers(1, &m_RendererID);
|
||||||
#else
|
#else
|
||||||
Renderer::Submit([this](){
|
GLuint rendererID = m_RendererID;
|
||||||
glDeleteBuffers(1, &m_RendererID);
|
Renderer::Submit([rendererID](){
|
||||||
|
glDeleteBuffers(1, &rendererID);
|
||||||
});
|
});
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
@ -69,13 +70,9 @@ namespace Prism
|
|||||||
|
|
||||||
void OpenGLVertexBuffer::Bind() const
|
void OpenGLVertexBuffer::Bind() const
|
||||||
{
|
{
|
||||||
Renderer::Submit([this](){
|
Ref<const OpenGLVertexBuffer> instance = this;
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, m_RendererID);
|
Renderer::Submit([instance]() {
|
||||||
|
glBindBuffer(GL_ARRAY_BUFFER, instance->m_RendererID);
|
||||||
glEnableVertexAttribArray(0);
|
|
||||||
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(float) * 5, 0);
|
|
||||||
glEnableVertexAttribArray(1);
|
|
||||||
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 5, (const void*)(3 * sizeof(float)));
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -68,7 +68,7 @@ namespace Prism
|
|||||||
glCreateTextures(GL_TEXTURE_2D_MULTISAMPLE, 1, &m_ColorAttachment);
|
glCreateTextures(GL_TEXTURE_2D_MULTISAMPLE, 1, &m_ColorAttachment);
|
||||||
glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, m_ColorAttachment);
|
glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, m_ColorAttachment);
|
||||||
|
|
||||||
// TODO: Create Hazel texture object based on format here
|
// TODO: Create Prism texture object based on format here
|
||||||
if (m_Specification.Format == FramebufferFormat::RGBA16F)
|
if (m_Specification.Format == FramebufferFormat::RGBA16F)
|
||||||
{
|
{
|
||||||
glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, m_Specification.Samples, GL_RGBA16F, m_Specification.Width, m_Specification.Height, GL_FALSE);
|
glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, m_Specification.Samples, GL_RGBA16F, m_Specification.Width, m_Specification.Height, GL_FALSE);
|
||||||
@ -89,7 +89,7 @@ namespace Prism
|
|||||||
glCreateTextures(GL_TEXTURE_2D, 1, &m_ColorAttachment);
|
glCreateTextures(GL_TEXTURE_2D, 1, &m_ColorAttachment);
|
||||||
glBindTexture(GL_TEXTURE_2D, m_ColorAttachment);
|
glBindTexture(GL_TEXTURE_2D, m_ColorAttachment);
|
||||||
|
|
||||||
// TODO: Create Hazel texture object based on format here
|
// TODO: Create texture object based on format here
|
||||||
if (m_Specification.Format == FramebufferFormat::RGBA16F)
|
if (m_Specification.Format == FramebufferFormat::RGBA16F)
|
||||||
{
|
{
|
||||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F, m_Specification.Width, m_Specification.Height, 0, GL_RGBA, GL_FLOAT, nullptr);
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F, m_Specification.Width, m_Specification.Height, 0, GL_RGBA, GL_FLOAT, nullptr);
|
||||||
|
|||||||
@ -120,6 +120,7 @@ namespace Prism
|
|||||||
glEnable(GL_BLEND);
|
glEnable(GL_BLEND);
|
||||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||||
glEnable(GL_MULTISAMPLE);
|
glEnable(GL_MULTISAMPLE);
|
||||||
|
glEnable(GL_STENCIL_TEST);
|
||||||
|
|
||||||
auto& caps = GetCapabilities();
|
auto& caps = GetCapabilities();
|
||||||
|
|
||||||
@ -147,7 +148,7 @@ namespace Prism
|
|||||||
void RendererAPI::Clear(const float r, const float g, const float b, const float a)
|
void RendererAPI::Clear(const float r, const float g, const float b, const float a)
|
||||||
{
|
{
|
||||||
glClearColor(r, g, b, a);
|
glClearColor(r, g, b, a);
|
||||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
|
||||||
}
|
}
|
||||||
|
|
||||||
void RendererAPI::SetClearColor(const float r, const float g, const float b, const float a)
|
void RendererAPI::SetClearColor(const float r, const float g, const float b, const float a)
|
||||||
|
|||||||
@ -207,7 +207,7 @@ namespace Prism
|
|||||||
{
|
{
|
||||||
PM_CORE_ASSERT(false, "Could not load shader file");
|
PM_CORE_ASSERT(false, "Could not load shader file");
|
||||||
}
|
}
|
||||||
|
file.close();
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -3,6 +3,8 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
#include "OpenGLVertexArray.h"
|
#include "OpenGLVertexArray.h"
|
||||||
|
|
||||||
|
#include "OpenGLBuffer.h"
|
||||||
#include "glad/glad.h"
|
#include "glad/glad.h"
|
||||||
#include "Prism/Renderer/Renderer.h"
|
#include "Prism/Renderer/Renderer.h"
|
||||||
|
|
||||||
@ -31,7 +33,7 @@ namespace Prism
|
|||||||
|
|
||||||
OpenGLVertexArray::OpenGLVertexArray()
|
OpenGLVertexArray::OpenGLVertexArray()
|
||||||
{
|
{
|
||||||
Renderer::Submit([this](){
|
Renderer::Submit([this]() {
|
||||||
glCreateVertexArrays(1, &m_RendererID);
|
glCreateVertexArrays(1, &m_RendererID);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -41,8 +43,9 @@ namespace Prism
|
|||||||
#ifdef __MINGW32__
|
#ifdef __MINGW32__
|
||||||
glDeleteVertexArrays(1, &m_RendererID);
|
glDeleteVertexArrays(1, &m_RendererID);
|
||||||
#else
|
#else
|
||||||
Renderer::Submit([this](){
|
GLuint rendererID = m_RendererID;
|
||||||
glDeleteVertexArrays(1, &m_RendererID);
|
Renderer::Submit([rendererID](){
|
||||||
|
glDeleteVertexArrays(1, &rendererID);
|
||||||
});
|
});
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|||||||
@ -4,157 +4,13 @@
|
|||||||
|
|
||||||
#include "Camera.h"
|
#include "Camera.h"
|
||||||
|
|
||||||
#include "GLFW/glfw3.h"
|
|
||||||
#include "glm/detail/type_quat.hpp"
|
|
||||||
|
|
||||||
#include "glm/gtc/quaternion.hpp"
|
|
||||||
#define GLM_ENABLE_EXPERIMENTAL
|
|
||||||
#include "glm/gtx/quaternion.hpp"
|
|
||||||
#include "Prism/Core/Application.h"
|
|
||||||
#include "Prism/Core/Input.h"
|
|
||||||
#include "Prism/Core/Events/MouseEvent.h"
|
|
||||||
|
|
||||||
#ifndef M_PI
|
|
||||||
#define M_PI 3.1415926f
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
namespace Prism
|
namespace Prism
|
||||||
{
|
{
|
||||||
Camera::Camera(const glm::mat4& projectionMatrix)
|
Camera::Camera(const glm::mat4& projectionMatrix)
|
||||||
: m_ProjectionMatrix(projectionMatrix)
|
: m_ProjectionMatrix(projectionMatrix)
|
||||||
{
|
|
||||||
m_Rotation = glm::vec3(90.0f, 0.0f, 0.0f);
|
|
||||||
|
|
||||||
m_FocalPoint = glm::vec3(0.0f);
|
|
||||||
|
|
||||||
glm::vec3 position = { -5, 5, 5};
|
|
||||||
m_Distance = glm::distance(position, m_FocalPoint);
|
|
||||||
|
|
||||||
m_Yaw = 3.0f * (float)M_PI / 4.0f;
|
|
||||||
m_Pitch = M_PI / 4.0f;
|
|
||||||
|
|
||||||
UpdateCameraView();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Camera::Focus()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void Camera::OnUpdate(TimeStep deltaTime)
|
|
||||||
{
|
|
||||||
if (Input::IsKeyPressed(Key::LEFT_ALT))
|
|
||||||
{
|
{
|
||||||
const glm::vec2& mouse{ Input::GetMouseX(), Input::GetMouseY() };
|
|
||||||
const glm::vec2 delta = (mouse - m_InitialMousePosition) * 0.003f;
|
|
||||||
m_InitialMousePosition = mouse;
|
|
||||||
|
|
||||||
if (Input::IsMouseButtonPressed(GLFW_MOUSE_BUTTON_MIDDLE))
|
|
||||||
MousePan(delta);
|
|
||||||
else if (Input::IsMouseButtonPressed(GLFW_MOUSE_BUTTON_LEFT))
|
|
||||||
MouseRotate(delta);
|
|
||||||
else if (Input::IsMouseButtonPressed(GLFW_MOUSE_BUTTON_RIGHT))
|
|
||||||
MouseZoom(delta.y);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
UpdateCameraView();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Camera::OnEvent(Event& e)
|
|
||||||
{
|
|
||||||
EventDispatcher dispatcher(e);
|
|
||||||
dispatcher.Dispatch<MouseScrolledEvent>(PM_BIND_EVENT_FN(Camera::OnMouseScroll));
|
|
||||||
}
|
|
||||||
|
|
||||||
glm::vec3 Camera::GetUpDirection() const
|
|
||||||
{
|
|
||||||
return glm::rotate(GetOrientation(), glm::vec3(0.0f, 1.0f, 0.0f));
|
|
||||||
}
|
|
||||||
|
|
||||||
glm::vec3 Camera::GetRightDirection() const
|
|
||||||
{
|
|
||||||
return glm::rotate(GetOrientation(), glm::vec3(1.0f, 0.0f, 0.0f));
|
|
||||||
}
|
|
||||||
|
|
||||||
glm::vec3 Camera::GetForwardDirection() const
|
|
||||||
{
|
|
||||||
return glm::rotate(GetOrientation(), glm::vec3(0.0f, 0.0f, -1.0f));
|
|
||||||
}
|
|
||||||
|
|
||||||
void Camera::UpdateCameraView()
|
|
||||||
{
|
|
||||||
m_Position = CalculatePosition();
|
|
||||||
|
|
||||||
const glm::quat orientation = GetOrientation();
|
|
||||||
m_Rotation = glm::eulerAngles(orientation) * (180.0f / (float)M_PI);
|
|
||||||
m_ViewMatrix = glm::translate(glm::mat4(1.0f), m_Position) * glm::toMat4(orientation);
|
|
||||||
m_ViewMatrix = glm::inverse(m_ViewMatrix);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Camera::OnMouseScroll(MouseScrolledEvent& e)
|
|
||||||
{
|
|
||||||
const float delta = e.GetOffsetY() * 0.1f;
|
|
||||||
MouseZoom(delta);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Camera::MousePan(const glm::vec2& delta)
|
|
||||||
{
|
|
||||||
auto [xSpeed, ySpeed] = PanSpeed();
|
|
||||||
// PM_CORE_TRACE("{0}, {1}", xSpeed, ySpeed);
|
|
||||||
m_FocalPoint += -GetRightDirection() * delta.x * xSpeed * m_Distance;
|
|
||||||
m_FocalPoint += GetUpDirection() * delta.y * ySpeed * m_Distance;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Camera::MouseRotate(const glm::vec2& delta)
|
|
||||||
{
|
|
||||||
float yawSign = GetUpDirection().y < 0 ? -1.0f : 1.0f;
|
|
||||||
m_Yaw += yawSign * delta.x * RotationSpeed();
|
|
||||||
m_Pitch += delta.y * RotationSpeed();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Camera::MouseZoom(const float delta)
|
|
||||||
{
|
|
||||||
m_Distance -= delta * ZoomSpeed();
|
|
||||||
if (m_Distance < 1.0f)
|
|
||||||
{
|
|
||||||
m_FocalPoint += GetForwardDirection() * delta;
|
|
||||||
m_Distance = 1.0f;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
glm::vec3 Camera::CalculatePosition() const
|
|
||||||
{
|
|
||||||
return m_FocalPoint - GetForwardDirection() * m_Distance;
|
|
||||||
}
|
|
||||||
|
|
||||||
glm::quat Camera::GetOrientation() const
|
|
||||||
{
|
|
||||||
return glm::quat(glm::vec3(-m_Pitch, -m_Yaw, 0.0f));
|
|
||||||
}
|
|
||||||
|
|
||||||
std::pair<float, float> Camera::PanSpeed() const
|
|
||||||
{
|
|
||||||
const float x = std::min(m_ViewportWidth / 1000.0f, 2.4f); // max = 2.4f
|
|
||||||
float xFactor = 0.0366f * (x * x) - 0.1778f * x + 0.3021f;
|
|
||||||
|
|
||||||
const float y = std::min(m_ViewportHeight / 1000.0f, 2.4f); // max = 2.4f
|
|
||||||
float yFactor = 0.0366f * (y * y) - 0.1778f * y + 0.3021f;
|
|
||||||
|
|
||||||
return { xFactor, yFactor };
|
|
||||||
}
|
|
||||||
|
|
||||||
float Camera::RotationSpeed() const
|
|
||||||
{
|
|
||||||
return 0.8f;
|
|
||||||
}
|
|
||||||
|
|
||||||
float Camera::ZoomSpeed() const
|
|
||||||
{
|
|
||||||
float distance = m_Distance * 0.2f;
|
|
||||||
distance = std::max(distance, 0.0f);
|
|
||||||
float speed = distance * distance;
|
|
||||||
speed = std::min(speed, 100.0f); // max speed = 100
|
|
||||||
return speed;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -18,62 +18,18 @@ namespace Prism
|
|||||||
public:
|
public:
|
||||||
Camera() = default;
|
Camera() = default;
|
||||||
Camera(const glm::mat4& projectionMatrix);
|
Camera(const glm::mat4& projectionMatrix);
|
||||||
|
~Camera() = default;
|
||||||
void Focus();
|
|
||||||
void OnUpdate(TimeStep deltaTime);
|
|
||||||
void OnEvent(Event& e);
|
|
||||||
|
|
||||||
inline float GetDistance() const { return m_Distance; }
|
|
||||||
inline void SetDistance(float distance) { m_Distance = distance; }
|
|
||||||
|
|
||||||
inline void SetProjectionMatrix(const glm::mat4& projectionMatrix) { m_ProjectionMatrix = projectionMatrix; }
|
|
||||||
|
|
||||||
const glm::mat4& GetProjectionMatrix() const { return m_ProjectionMatrix; }
|
const glm::mat4& GetProjectionMatrix() const { return m_ProjectionMatrix; }
|
||||||
const glm::mat4& GetViewMatrix() const { return m_ViewMatrix; }
|
|
||||||
glm::mat4 GetViewProjection() const { return m_ProjectionMatrix * m_ViewMatrix; }
|
|
||||||
|
|
||||||
glm::vec3 GetUpDirection() const;
|
void SetProjectionMatrix(const glm::mat4& projectionMatrix) { m_ProjectionMatrix = projectionMatrix; }
|
||||||
glm::vec3 GetRightDirection() const;
|
|
||||||
glm::vec3 GetForwardDirection() const;
|
|
||||||
const glm::vec3& GetPosition() const { return m_Position; }
|
|
||||||
glm::quat GetOrientation() const;
|
|
||||||
|
|
||||||
float GetExposure() const { return m_Exposure; }
|
float GetExposure() const { return m_Exposure; }
|
||||||
float& GetExposure() { return m_Exposure; }
|
float& GetExposure() { return m_Exposure; }
|
||||||
|
|
||||||
float GetPitch() const { return m_Pitch; }
|
protected:
|
||||||
float GetYaw() const { return m_Yaw; }
|
glm::mat4 m_ProjectionMatrix;
|
||||||
|
|
||||||
public:
|
|
||||||
inline void SetViewportSize(const uint32_t width, const uint32_t height) { m_ViewportWidth = width; m_ViewportHeight = height; }
|
|
||||||
private:
|
|
||||||
void UpdateCameraView();
|
|
||||||
|
|
||||||
bool OnMouseScroll(MouseScrolledEvent& e);
|
|
||||||
void MousePan(const glm::vec2& delta);
|
|
||||||
void MouseRotate(const glm::vec2& delta);
|
|
||||||
void MouseZoom(float delta);
|
|
||||||
|
|
||||||
glm::vec3 CalculatePosition() const;
|
|
||||||
|
|
||||||
std::pair<float, float> PanSpeed() const;
|
|
||||||
float RotationSpeed() const;
|
|
||||||
float ZoomSpeed() const;
|
|
||||||
private:
|
|
||||||
glm::mat4 m_ProjectionMatrix, m_ViewMatrix;
|
|
||||||
glm::vec3 m_Position, m_Rotation, m_FocalPoint;
|
|
||||||
|
|
||||||
bool m_Panning, m_Rotating;
|
|
||||||
glm::vec2 m_InitialMousePosition;
|
|
||||||
glm::vec3 m_InitialFocalPoint, m_InitialRotation;
|
|
||||||
|
|
||||||
uint32_t m_ViewportWidth = 1280, m_ViewportHeight = 720;
|
|
||||||
|
|
||||||
float m_Distance;
|
|
||||||
|
|
||||||
float m_Exposure = 0.8f;
|
float m_Exposure = 0.8f;
|
||||||
|
|
||||||
float m_Pitch, m_Yaw;
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -283,7 +283,7 @@ namespace Prism
|
|||||||
bool hasAlbedoMap = aiMaterial->GetTexture(aiTextureType_DIFFUSE, 0, &aiTexPath) == AI_SUCCESS;
|
bool hasAlbedoMap = aiMaterial->GetTexture(aiTextureType_DIFFUSE, 0, &aiTexPath) == AI_SUCCESS;
|
||||||
if (hasAlbedoMap)
|
if (hasAlbedoMap)
|
||||||
{
|
{
|
||||||
// TODO: Temp - this should be handled by Hazel's filesystem
|
// TODO: Temp - this should be handled by Prism's filesystem
|
||||||
std::filesystem::path path = filename;
|
std::filesystem::path path = filename;
|
||||||
auto parentPath = path.parent_path();
|
auto parentPath = path.parent_path();
|
||||||
parentPath /= std::string(aiTexPath.data);
|
parentPath /= std::string(aiTexPath.data);
|
||||||
@ -315,7 +315,7 @@ namespace Prism
|
|||||||
|
|
||||||
if (aiMaterial->GetTexture(aiTextureType_NORMALS, 0, &aiTexPath) == AI_SUCCESS)
|
if (aiMaterial->GetTexture(aiTextureType_NORMALS, 0, &aiTexPath) == AI_SUCCESS)
|
||||||
{
|
{
|
||||||
// TODO: Temp - this should be handled by Hazel's filesystem
|
// TODO: Temp - this should be handled by Prism's filesystem
|
||||||
std::filesystem::path path = filename;
|
std::filesystem::path path = filename;
|
||||||
auto parentPath = path.parent_path();
|
auto parentPath = path.parent_path();
|
||||||
parentPath /= std::string(aiTexPath.data);
|
parentPath /= std::string(aiTexPath.data);
|
||||||
@ -343,7 +343,7 @@ namespace Prism
|
|||||||
// mi->Set("u_RoughnessTexToggle", 0.0f);
|
// mi->Set("u_RoughnessTexToggle", 0.0f);
|
||||||
if (aiMaterial->GetTexture(aiTextureType_SHININESS, 0, &aiTexPath) == AI_SUCCESS)
|
if (aiMaterial->GetTexture(aiTextureType_SHININESS, 0, &aiTexPath) == AI_SUCCESS)
|
||||||
{
|
{
|
||||||
// TODO: Temp - this should be handled by Hazel's filesystem
|
// TODO: Temp - this should be handled by Prism's filesystem
|
||||||
std::filesystem::path path = filename;
|
std::filesystem::path path = filename;
|
||||||
auto parentPath = path.parent_path();
|
auto parentPath = path.parent_path();
|
||||||
parentPath /= std::string(aiTexPath.data);
|
parentPath /= std::string(aiTexPath.data);
|
||||||
@ -375,7 +375,7 @@ namespace Prism
|
|||||||
// mi->Set("u_MetalnessTexToggle", 0.0f);
|
// mi->Set("u_MetalnessTexToggle", 0.0f);
|
||||||
if (aiMaterial->Get("$raw.ReflectionFactor|file", aiPTI_String, 0, aiTexPath) == AI_SUCCESS)
|
if (aiMaterial->Get("$raw.ReflectionFactor|file", aiPTI_String, 0, aiTexPath) == AI_SUCCESS)
|
||||||
{
|
{
|
||||||
// TODO: Temp - this should be handled by Hazel's filesystem
|
// TODO: Temp - this should be handled by Prism's filesystem
|
||||||
std::filesystem::path path = filename;
|
std::filesystem::path path = filename;
|
||||||
auto parentPath = path.parent_path();
|
auto parentPath = path.parent_path();
|
||||||
parentPath /= std::string(aiTexPath.data);
|
parentPath /= std::string(aiTexPath.data);
|
||||||
@ -437,7 +437,7 @@ namespace Prism
|
|||||||
{
|
{
|
||||||
metalnessTextureFound = true;
|
metalnessTextureFound = true;
|
||||||
|
|
||||||
// TODO: Temp - this should be handled by Hazel's filesystem
|
// TODO: Temp - this should be handled by Prism's filesystem
|
||||||
std::filesystem::path path = filename;
|
std::filesystem::path path = filename;
|
||||||
auto parentPath = path.parent_path();
|
auto parentPath = path.parent_path();
|
||||||
parentPath /= str;
|
parentPath /= str;
|
||||||
|
|||||||
@ -170,7 +170,7 @@ namespace Prism
|
|||||||
for (Submesh& submesh : mesh->m_Submeshes)
|
for (Submesh& submesh : mesh->m_Submeshes)
|
||||||
{
|
{
|
||||||
// Material
|
// Material
|
||||||
auto material = materials[submesh.MaterialIndex];
|
auto material = overrideMaterial ? overrideMaterial : materials[submesh.MaterialIndex];
|
||||||
auto shader = material->GetShader();
|
auto shader = material->GetShader();
|
||||||
material->Bind();
|
material->Bind();
|
||||||
|
|
||||||
|
|||||||
@ -20,7 +20,7 @@ namespace Prism
|
|||||||
const Scene* ActiveScene = nullptr;
|
const Scene* ActiveScene = nullptr;
|
||||||
struct SceneInfo
|
struct SceneInfo
|
||||||
{
|
{
|
||||||
Camera SceneCamera;
|
SceneRendererCamera SceneCamera;
|
||||||
|
|
||||||
// Resources
|
// Resources
|
||||||
Ref<MaterialInstance> SkyboxMaterial;
|
Ref<MaterialInstance> SkyboxMaterial;
|
||||||
@ -41,9 +41,11 @@ namespace Prism
|
|||||||
glm::mat4 Transform;
|
glm::mat4 Transform;
|
||||||
};
|
};
|
||||||
std::vector<DrawCommand> DrawList;
|
std::vector<DrawCommand> DrawList;
|
||||||
|
std::vector<DrawCommand> SelectedMeshDrawList;
|
||||||
|
|
||||||
// Grid
|
// Grid
|
||||||
Ref<MaterialInstance> GridMaterial;
|
Ref<MaterialInstance> GridMaterial;
|
||||||
|
Ref<MaterialInstance> OutlineMaterial;
|
||||||
|
|
||||||
SceneRendererOptions Options;
|
SceneRendererOptions Options;
|
||||||
};
|
};
|
||||||
@ -85,6 +87,12 @@ namespace Prism
|
|||||||
constexpr float gridSize = 0.025f;
|
constexpr float gridSize = 0.025f;
|
||||||
s_Data.GridMaterial->Set("u_Scale", gridScale);
|
s_Data.GridMaterial->Set("u_Scale", gridScale);
|
||||||
s_Data.GridMaterial->Set("u_Res", gridSize);
|
s_Data.GridMaterial->Set("u_Res", gridSize);
|
||||||
|
|
||||||
|
// outline
|
||||||
|
const auto outlineShader = Shader::Create("assets/shaders/Outline.glsl");
|
||||||
|
s_Data.OutlineMaterial = MaterialInstance::Create(Material::Create(outlineShader));
|
||||||
|
s_Data.OutlineMaterial->SetFlag(MaterialFlag::DepthTest, false);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SceneRenderer::SetViewportSize(uint32_t width, uint32_t height)
|
void SceneRenderer::SetViewportSize(uint32_t width, uint32_t height)
|
||||||
@ -93,7 +101,7 @@ namespace Prism
|
|||||||
s_Data.CompositePass->GetSpecification().TargetFramebuffer->Resize(width, height);
|
s_Data.CompositePass->GetSpecification().TargetFramebuffer->Resize(width, height);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SceneRenderer::BeginScene(const Scene* scene, const Camera& camera)
|
void SceneRenderer::BeginScene(const Scene* scene, const SceneRendererCamera& camera)
|
||||||
{
|
{
|
||||||
PM_CORE_ASSERT(!s_Data.ActiveScene);
|
PM_CORE_ASSERT(!s_Data.ActiveScene);
|
||||||
|
|
||||||
@ -121,6 +129,11 @@ namespace Prism
|
|||||||
s_Data.DrawList.push_back({ mesh, overrideMaterial, transform });
|
s_Data.DrawList.push_back({ mesh, overrideMaterial, transform });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SceneRenderer::SubmitSelectedMesh(const Ref<Mesh>& mesh, const glm::mat4& transform)
|
||||||
|
{
|
||||||
|
s_Data.SelectedMeshDrawList.push_back({ mesh, nullptr, transform });
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static Ref<Shader> equirectangularConversionShader, envFilteringShader, envIrradianceShader;
|
static Ref<Shader> equirectangularConversionShader, envFilteringShader, envIrradianceShader;
|
||||||
|
|
||||||
@ -217,14 +230,34 @@ namespace Prism
|
|||||||
CompositePass();
|
CompositePass();
|
||||||
|
|
||||||
s_Data.DrawList.clear();
|
s_Data.DrawList.clear();
|
||||||
|
s_Data.SelectedMeshDrawList.clear();
|
||||||
s_Data.SceneData = {};
|
s_Data.SceneData = {};
|
||||||
}
|
}
|
||||||
|
|
||||||
void SceneRenderer::GeometryPass()
|
void SceneRenderer::GeometryPass()
|
||||||
{
|
{
|
||||||
|
bool outline = s_Data.SelectedMeshDrawList.size() > 0;
|
||||||
|
|
||||||
|
if (outline)
|
||||||
|
{
|
||||||
|
Renderer::Submit([]()
|
||||||
|
{
|
||||||
|
glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
Renderer::BeginRenderPass(s_Data.GeoPass);
|
Renderer::BeginRenderPass(s_Data.GeoPass);
|
||||||
|
|
||||||
const auto viewProjection = s_Data.SceneData.SceneCamera.GetViewProjection();
|
if (outline)
|
||||||
|
{
|
||||||
|
Renderer::Submit([]()
|
||||||
|
{
|
||||||
|
glStencilMask(0);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto viewProjection = s_Data.SceneData.SceneCamera.Camera.GetProjectionMatrix() * s_Data.SceneData.SceneCamera.ViewMatrix;
|
||||||
|
glm::vec3 cameraPosition = glm::inverse(s_Data.SceneData.SceneCamera.ViewMatrix)[3];
|
||||||
|
|
||||||
// Skybox
|
// Skybox
|
||||||
auto skyboxShader = s_Data.SceneData.SkyboxMaterial->GetShader();
|
auto skyboxShader = s_Data.SceneData.SkyboxMaterial->GetShader();
|
||||||
@ -237,7 +270,7 @@ namespace Prism
|
|||||||
{
|
{
|
||||||
auto baseMaterial = dc.mesh->GetMaterial();
|
auto baseMaterial = dc.mesh->GetMaterial();
|
||||||
baseMaterial->Set("u_ViewProjectionMatrix", viewProjection);
|
baseMaterial->Set("u_ViewProjectionMatrix", viewProjection);
|
||||||
baseMaterial->Set("u_CameraPosition", s_Data.SceneData.SceneCamera.GetPosition());
|
baseMaterial->Set("u_CameraPosition", cameraPosition);
|
||||||
|
|
||||||
// Environment (TODO: don't do this per mesh)
|
// Environment (TODO: don't do this per mesh)
|
||||||
baseMaterial->Set("u_EnvRadianceTex", s_Data.SceneData.SceneEnvironment.RadianceMap);
|
baseMaterial->Set("u_EnvRadianceTex", s_Data.SceneData.SceneEnvironment.RadianceMap);
|
||||||
@ -251,6 +284,73 @@ namespace Prism
|
|||||||
Renderer::SubmitMesh(dc.mesh, dc.Transform, overrideMaterial);
|
Renderer::SubmitMesh(dc.mesh, dc.Transform, overrideMaterial);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (outline)
|
||||||
|
{
|
||||||
|
Renderer::Submit([]()
|
||||||
|
{
|
||||||
|
glStencilFunc(GL_ALWAYS, 1, 0xff);
|
||||||
|
glStencilMask(0xff);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto& dc : s_Data.SelectedMeshDrawList)
|
||||||
|
{
|
||||||
|
auto baseMaterial = dc.mesh->GetMaterial();
|
||||||
|
baseMaterial->Set("u_ViewProjectionMatrix", viewProjection);
|
||||||
|
baseMaterial->Set("u_CameraPosition", cameraPosition);
|
||||||
|
|
||||||
|
// Environment (TODO: don't do this per mesh)
|
||||||
|
baseMaterial->Set("u_EnvRadianceTex", s_Data.SceneData.SceneEnvironment.RadianceMap);
|
||||||
|
baseMaterial->Set("u_EnvIrradianceTex", s_Data.SceneData.SceneEnvironment.IrradianceMap);
|
||||||
|
baseMaterial->Set("u_BRDFLUTTexture", s_Data.BRDFLUT);
|
||||||
|
|
||||||
|
// Set lights (TODO: move to light environment and don't do per mesh)
|
||||||
|
baseMaterial->Set("lights", s_Data.SceneData.ActiveLight);
|
||||||
|
|
||||||
|
auto overrideMaterial = nullptr; // dc.Material;
|
||||||
|
Renderer::SubmitMesh(dc.mesh, dc.Transform, overrideMaterial);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (outline)
|
||||||
|
{
|
||||||
|
Renderer::Submit([]()
|
||||||
|
{
|
||||||
|
glStencilFunc(GL_NOTEQUAL, 1, 0xff);
|
||||||
|
glStencilMask(0);
|
||||||
|
|
||||||
|
glLineWidth(10);
|
||||||
|
glEnable(GL_LINE_SMOOTH);
|
||||||
|
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
|
||||||
|
glDisable(GL_DEPTH_TEST);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Draw outline here
|
||||||
|
s_Data.OutlineMaterial->Set("u_ViewProjection", viewProjection);
|
||||||
|
for (auto& dc : s_Data.SelectedMeshDrawList)
|
||||||
|
{
|
||||||
|
Renderer::SubmitMesh(dc.mesh, dc.Transform, s_Data.OutlineMaterial);
|
||||||
|
}
|
||||||
|
|
||||||
|
Renderer::Submit([]()
|
||||||
|
{
|
||||||
|
glPointSize(10);
|
||||||
|
glPolygonMode(GL_FRONT_AND_BACK, GL_POINT);
|
||||||
|
});
|
||||||
|
for (auto& dc : s_Data.SelectedMeshDrawList)
|
||||||
|
{
|
||||||
|
Renderer::SubmitMesh(dc.mesh, dc.Transform, s_Data.OutlineMaterial);
|
||||||
|
}
|
||||||
|
|
||||||
|
Renderer::Submit([]()
|
||||||
|
{
|
||||||
|
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
|
||||||
|
glStencilMask(0xff);
|
||||||
|
glStencilFunc(GL_ALWAYS, 1, 0xff);
|
||||||
|
glEnable(GL_DEPTH_TEST);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// Grid
|
// Grid
|
||||||
const auto option = GetOptions();
|
const auto option = GetOptions();
|
||||||
if (option.ShowGrid)
|
if (option.ShowGrid)
|
||||||
@ -274,7 +374,7 @@ namespace Prism
|
|||||||
{
|
{
|
||||||
Renderer::BeginRenderPass(s_Data.CompositePass);
|
Renderer::BeginRenderPass(s_Data.CompositePass);
|
||||||
s_Data.CompositeShader->Bind();
|
s_Data.CompositeShader->Bind();
|
||||||
s_Data.CompositeShader->SetFloat("u_Exposure", s_Data.SceneData.SceneCamera.GetExposure());
|
s_Data.CompositeShader->SetFloat("u_Exposure", s_Data.SceneData.SceneCamera.Camera.GetExposure());
|
||||||
s_Data.CompositeShader->SetInt("u_TextureSamples", s_Data.GeoPass->GetSpecification().TargetFramebuffer->GetSpecification().Samples);
|
s_Data.CompositeShader->SetInt("u_TextureSamples", s_Data.GeoPass->GetSpecification().TargetFramebuffer->GetSpecification().Samples);
|
||||||
s_Data.GeoPass->GetSpecification().TargetFramebuffer->BindTexture();
|
s_Data.GeoPass->GetSpecification().TargetFramebuffer->BindTexture();
|
||||||
Renderer::SubmitFullscreenQuad(nullptr);
|
Renderer::SubmitFullscreenQuad(nullptr);
|
||||||
|
|||||||
@ -18,6 +18,12 @@ namespace Prism
|
|||||||
bool ShowBoundingBoxes = false;
|
bool ShowBoundingBoxes = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct SceneRendererCamera
|
||||||
|
{
|
||||||
|
Prism::Camera Camera;
|
||||||
|
glm::mat4 ViewMatrix;
|
||||||
|
};
|
||||||
|
|
||||||
class PRISM_API SceneRenderer
|
class PRISM_API SceneRenderer
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@ -25,10 +31,11 @@ namespace Prism
|
|||||||
|
|
||||||
static void SetViewportSize(uint32_t width, uint32_t height);
|
static void SetViewportSize(uint32_t width, uint32_t height);
|
||||||
|
|
||||||
static void BeginScene(const Scene* scene, const Camera& camera);
|
static void BeginScene(const Scene* scene, const SceneRendererCamera& camera);
|
||||||
static void EndScene();
|
static void EndScene();
|
||||||
|
|
||||||
static void SubmitMesh(const Ref<Mesh>& mesh, const glm::mat4& transform = glm::mat4(1.0f), const Ref<MaterialInstance>& overrideMaterial = nullptr);
|
static void SubmitMesh(const Ref<Mesh>& mesh, const glm::mat4& transform = glm::mat4(1.0f), const Ref<MaterialInstance>& overrideMaterial = nullptr);
|
||||||
|
static void SubmitSelectedMesh(const Ref<Mesh>& mesh, const glm::mat4& transform = glm::mat4(1.0f));
|
||||||
|
|
||||||
static std::pair<Ref<TextureCube>, Ref<TextureCube>> CreateEnvironmentMap(const std::string& filepath);
|
static std::pair<Ref<TextureCube>, Ref<TextureCube>> CreateEnvironmentMap(const std::string& filepath);
|
||||||
|
|
||||||
|
|||||||
@ -7,18 +7,30 @@
|
|||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
|
#include "SceneCamera.h"
|
||||||
#include "glm/glm.hpp"
|
#include "glm/glm.hpp"
|
||||||
#include "Prism/Core/Ref.h"
|
#include "Prism/Core/Ref.h"
|
||||||
|
#include "Prism/Core/UUID.h"
|
||||||
#include "Prism/Renderer/Camera.h"
|
#include "Prism/Renderer/Camera.h"
|
||||||
#include "Prism/Renderer/Mesh.h"
|
#include "Prism/Renderer/Mesh.h"
|
||||||
|
|
||||||
namespace Prism
|
namespace Prism
|
||||||
{
|
{
|
||||||
|
struct IDComponent
|
||||||
|
{
|
||||||
|
UUID ID = 0;
|
||||||
|
};
|
||||||
|
|
||||||
struct TagComponent
|
struct TagComponent
|
||||||
{
|
{
|
||||||
std::string Tag;
|
std::string Tag;
|
||||||
|
|
||||||
|
TagComponent() = default;
|
||||||
|
TagComponent(const TagComponent& other)
|
||||||
|
: Tag(other.Tag) {}
|
||||||
|
TagComponent(const std::string& tag)
|
||||||
|
: Tag(tag) {}
|
||||||
|
|
||||||
explicit operator std::string& () { return Tag; }
|
explicit operator std::string& () { return Tag; }
|
||||||
explicit operator const std::string& () const { return Tag; }
|
explicit operator const std::string& () const { return Tag; }
|
||||||
};
|
};
|
||||||
@ -28,6 +40,12 @@ namespace Prism
|
|||||||
{
|
{
|
||||||
glm::mat4 Transform;
|
glm::mat4 Transform;
|
||||||
|
|
||||||
|
TransformComponent() = default;
|
||||||
|
TransformComponent(const TransformComponent& other)
|
||||||
|
: Transform(other.Transform) {}
|
||||||
|
TransformComponent(const glm::mat4& transform)
|
||||||
|
: Transform(transform) {}
|
||||||
|
|
||||||
operator glm::mat4& () { return Transform; }
|
operator glm::mat4& () { return Transform; }
|
||||||
operator const glm::mat4& () const { return Transform; }
|
operator const glm::mat4& () const { return Transform; }
|
||||||
};
|
};
|
||||||
@ -37,25 +55,39 @@ namespace Prism
|
|||||||
{
|
{
|
||||||
Ref<Prism::Mesh> Mesh;
|
Ref<Prism::Mesh> Mesh;
|
||||||
|
|
||||||
|
MeshComponent() = default;
|
||||||
|
MeshComponent(const MeshComponent& other)
|
||||||
|
: Mesh(other.Mesh) {}
|
||||||
|
MeshComponent(const Ref<Prism::Mesh>& mesh)
|
||||||
|
: Mesh(mesh) {}
|
||||||
|
|
||||||
operator Ref<Prism::Mesh> () { return Mesh; }
|
operator Ref<Prism::Mesh> () { return Mesh; }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
struct ScriptComponent
|
struct ScriptComponent
|
||||||
{
|
{
|
||||||
// TODO: C# script
|
|
||||||
std::string ModuleName;
|
std::string ModuleName;
|
||||||
|
|
||||||
|
ScriptComponent() = default;
|
||||||
|
ScriptComponent(const ScriptComponent& other)
|
||||||
|
: ModuleName(other.ModuleName) {}
|
||||||
|
ScriptComponent(const std::string& moduleName)
|
||||||
|
: ModuleName(moduleName) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
struct CameraComponent
|
struct CameraComponent
|
||||||
{
|
{
|
||||||
//OrthographicCamera Camera;
|
SceneCamera Camera;
|
||||||
Prism::Camera Camera;
|
|
||||||
bool Primary = true;
|
bool Primary = true;
|
||||||
|
|
||||||
explicit operator Prism::Camera& () { return Camera; }
|
CameraComponent() = default;
|
||||||
explicit operator const Prism::Camera& () const { return Camera; }
|
CameraComponent(const CameraComponent& other)
|
||||||
|
: Camera(other.Camera), Primary(other.Primary) {}
|
||||||
|
|
||||||
|
operator SceneCamera& () { return Camera; }
|
||||||
|
operator const SceneCamera& () const { return Camera; }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -64,6 +96,10 @@ namespace Prism
|
|||||||
glm::vec4 Color = { 1.0f, 1.0f, 1.0f, 1.0f };
|
glm::vec4 Color = { 1.0f, 1.0f, 1.0f, 1.0f };
|
||||||
Ref<Texture2D> Texture;
|
Ref<Texture2D> Texture;
|
||||||
float TilingFactor = 1.0f;
|
float TilingFactor = 1.0f;
|
||||||
|
|
||||||
|
SpriteRendererComponent() = default;
|
||||||
|
SpriteRendererComponent(const SpriteRendererComponent& other)
|
||||||
|
: Color(other.Color), Texture(other.Texture), TilingFactor(other.TilingFactor) {}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -44,6 +44,7 @@ namespace Prism
|
|||||||
const glm::mat4& Transform() const { return m_Scene->m_Registry.get<TransformComponent>(m_EntityHandle); }
|
const glm::mat4& Transform() const { return m_Scene->m_Registry.get<TransformComponent>(m_EntityHandle); }
|
||||||
|
|
||||||
operator uint32_t () const { return (uint32_t)m_EntityHandle; }
|
operator uint32_t () const { return (uint32_t)m_EntityHandle; }
|
||||||
|
operator entt::entity() const{ return m_EntityHandle; }
|
||||||
operator bool () const { return (uint32_t)m_EntityHandle && m_Scene; }
|
operator bool () const { return (uint32_t)m_EntityHandle && m_Scene; }
|
||||||
|
|
||||||
bool operator==(const Entity& other) const
|
bool operator==(const Entity& other) const
|
||||||
@ -55,6 +56,10 @@ namespace Prism
|
|||||||
{
|
{
|
||||||
return !(*this == other);
|
return !(*this == other);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
UUID GetUUID() { return GetComponent<IDComponent>().ID; }
|
||||||
|
UUID GetSceneUUID() { return m_Scene->GetUUID(); }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
explicit Entity(const std::string& name);
|
explicit Entity(const std::string& name);
|
||||||
private:
|
private:
|
||||||
@ -63,6 +68,7 @@ namespace Prism
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
friend class Scene;
|
friend class Scene;
|
||||||
|
friend class SceneSerializer;
|
||||||
friend class ScriptEngine;
|
friend class ScriptEngine;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@ -11,13 +11,13 @@
|
|||||||
|
|
||||||
namespace Prism
|
namespace Prism
|
||||||
{
|
{
|
||||||
std::unordered_map<uint32_t, Scene*> s_ActiveScenes;
|
std::unordered_map<UUID, Scene*> s_ActiveScenes;
|
||||||
|
|
||||||
static uint32_t s_SceneIDCounter = 0;
|
static uint32_t s_SceneIDCounter = 0;
|
||||||
|
|
||||||
struct SceneComponent
|
struct SceneComponent
|
||||||
{
|
{
|
||||||
uint32_t SceneID;
|
UUID SceneID;
|
||||||
};
|
};
|
||||||
|
|
||||||
void OnTransformConstruct(entt::registry& registry, entt::entity entity)
|
void OnTransformConstruct(entt::registry& registry, entt::entity entity)
|
||||||
@ -28,21 +28,20 @@ namespace Prism
|
|||||||
void OnScriptComponentConstruct(entt::registry& registry, entt::entity entity)
|
void OnScriptComponentConstruct(entt::registry& registry, entt::entity entity)
|
||||||
{
|
{
|
||||||
// Note: there should be exactly one scene component per registry
|
// Note: there should be exactly one scene component per registry
|
||||||
auto view = registry.view<SceneComponent>();
|
const auto sceneView = registry.view<SceneComponent>();
|
||||||
uint32_t sceneID = 0;
|
UUID sceneID = registry.get<SceneComponent>(sceneView.front()).SceneID;
|
||||||
for (const auto aEntity : view)
|
|
||||||
{
|
|
||||||
const auto& scene = registry.get<SceneComponent>(aEntity);
|
|
||||||
sceneID = scene.SceneID;
|
|
||||||
}
|
|
||||||
|
|
||||||
ScriptEngine::OnInitEntity(registry.get<ScriptComponent>(entity), (uint32_t)entity, sceneID);
|
Scene* scene = s_ActiveScenes[sceneID];
|
||||||
|
|
||||||
|
auto entityID = registry.get<IDComponent>(entity).ID;
|
||||||
|
PM_CORE_ASSERT(scene->m_EntityIDMap.find(entityID) != scene->m_EntityIDMap.end());
|
||||||
|
ScriptEngine::InitScriptEntity(scene->m_EntityIDMap.at(entityID));
|
||||||
}
|
}
|
||||||
|
|
||||||
Environment Environment::Load(const std::string& filepath)
|
Environment Environment::Load(const std::string& filepath)
|
||||||
{
|
{
|
||||||
auto [radiance, irradiance] = SceneRenderer::CreateEnvironmentMap(filepath);
|
auto [radiance, irradiance] = SceneRenderer::CreateEnvironmentMap(filepath);
|
||||||
return { radiance, irradiance };
|
return { filepath, radiance, irradiance };
|
||||||
}
|
}
|
||||||
|
|
||||||
Scene::Scene(const std::string& debugName)
|
Scene::Scene(const std::string& debugName)
|
||||||
@ -75,30 +74,52 @@ namespace Prism
|
|||||||
|
|
||||||
void Scene::OnUpdate(TimeStep ts)
|
void Scene::OnUpdate(TimeStep ts)
|
||||||
{
|
{
|
||||||
|
|
||||||
Camera* camera = nullptr;
|
|
||||||
{
|
|
||||||
auto view = m_Registry.view<CameraComponent>();
|
|
||||||
for (auto entity : view)
|
|
||||||
{
|
|
||||||
auto& comp = view.get<CameraComponent>(entity);
|
|
||||||
camera = &comp.Camera;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
PM_CORE_ASSERT(camera, "Scene does not contain any cameras!");
|
|
||||||
camera->OnUpdate(ts);
|
|
||||||
|
|
||||||
// Update all entities
|
// Update all entities
|
||||||
{
|
{
|
||||||
auto view = m_Registry.view<ScriptComponent>();
|
auto view = m_Registry.view<ScriptComponent>();
|
||||||
for (auto entity : view)
|
for (auto entity : view)
|
||||||
ScriptEngine::OnUpdateEntity((uint32_t)entity, ts);
|
{
|
||||||
|
UUID entityID = m_Registry.get<IDComponent>(entity).ID;
|
||||||
|
Entity e = { entity, this };
|
||||||
|
if (ScriptEngine::ModuleExists(e.GetComponent<ScriptComponent>().ModuleName))
|
||||||
|
ScriptEngine::OnUpdateEntity(m_SceneID, entityID, ts);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Scene::OnRenderRuntime(TimeStep ts)
|
||||||
|
{
|
||||||
|
/////////////////////////////////////////////////////////////////////
|
||||||
|
// RENDER 3D SCENE //
|
||||||
|
/////////////////////////////////////////////////////////////////////
|
||||||
|
Entity cameraEntity = GetMainCameraEntity();
|
||||||
|
if (!cameraEntity)
|
||||||
|
return;
|
||||||
|
|
||||||
|
glm::mat4 cameraViewMatrix = glm::inverse(cameraEntity.GetComponent<TransformComponent>().Transform);
|
||||||
|
PM_CORE_ASSERT(cameraEntity, "Scene does not contain any cameras!");
|
||||||
|
SceneCamera& camera = cameraEntity.GetComponent<CameraComponent>();
|
||||||
|
camera.SetViewportSize(m_ViewportWidth, m_ViewportHeight);
|
||||||
|
|
||||||
|
m_SkyboxMaterial->Set("u_TextureLod", m_SkyboxLod);
|
||||||
|
|
||||||
|
auto group = m_Registry.group<MeshComponent>(entt::get<TransformComponent>);
|
||||||
|
SceneRenderer::BeginScene(this, { camera, cameraViewMatrix });
|
||||||
|
for (auto entity : group)
|
||||||
|
{
|
||||||
|
auto [transformComponent, meshComponent] = group.get<TransformComponent, MeshComponent>(entity);
|
||||||
|
if (meshComponent.Mesh)
|
||||||
|
{
|
||||||
|
meshComponent.Mesh->OnUpdate(ts);
|
||||||
|
|
||||||
|
// TODO: Should we render (logically)
|
||||||
|
SceneRenderer::SubmitMesh(meshComponent, transformComponent, nullptr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
SceneRenderer::EndScene();
|
||||||
|
/////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
|
|
||||||
// Render all sprites
|
// Render all sprites
|
||||||
Renderer2D::BeginScene(*camera);
|
Renderer2D::BeginScene(*camera);
|
||||||
{
|
{
|
||||||
@ -115,22 +136,17 @@ namespace Prism
|
|||||||
|
|
||||||
Renderer2D::EndScene();
|
Renderer2D::EndScene();
|
||||||
#endif
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void Scene::OnRenderEditor(TimeStep ts, const EditorCamera& editorCamera)
|
||||||
|
{
|
||||||
/////////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////////
|
||||||
// RENDER 3D SCENE //
|
// RENDER 3D SCENE //
|
||||||
/////////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
m_SkyboxMaterial->Set("u_TextureLod", m_SkyboxLod);
|
m_SkyboxMaterial->Set("u_TextureLod", m_SkyboxLod);
|
||||||
|
|
||||||
auto entities = m_Registry.view<TransformComponent>();
|
|
||||||
for (auto entity : entities)
|
|
||||||
{
|
|
||||||
auto meshComponent = m_Registry.try_get<MeshComponent>(entity);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
auto group = m_Registry.group<MeshComponent>(entt::get<TransformComponent>);
|
auto group = m_Registry.group<MeshComponent>(entt::get<TransformComponent>);
|
||||||
SceneRenderer::BeginScene(this, *camera);
|
SceneRenderer::BeginScene(this, { static_cast<Camera>(editorCamera), editorCamera.GetViewMatrix() });
|
||||||
for (auto entity : group)
|
for (auto entity : group)
|
||||||
{
|
{
|
||||||
auto [transformComponent, meshComponent] = group.get<TransformComponent, MeshComponent>(entity);
|
auto [transformComponent, meshComponent] = group.get<TransformComponent, MeshComponent>(entity);
|
||||||
@ -139,23 +155,63 @@ namespace Prism
|
|||||||
meshComponent.Mesh->OnUpdate(ts);
|
meshComponent.Mesh->OnUpdate(ts);
|
||||||
|
|
||||||
// TODO: Should we render (logically)
|
// TODO: Should we render (logically)
|
||||||
SceneRenderer::SubmitMesh(meshComponent, transformComponent, nullptr);
|
|
||||||
|
if (m_SelectedEntity == entity)
|
||||||
|
SceneRenderer::SubmitSelectedMesh(meshComponent, transformComponent);
|
||||||
|
else
|
||||||
|
SceneRenderer::SubmitMesh(meshComponent, transformComponent, nullptr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
SceneRenderer::EndScene();
|
||||||
|
/////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
// Render all sprites
|
||||||
|
Renderer2D::BeginScene(*camera);
|
||||||
|
{
|
||||||
|
auto group = m_Registry.group<TransformComponent>(entt::get<SpriteRenderer>);
|
||||||
|
for (auto entity : group)
|
||||||
|
{
|
||||||
|
auto [transformComponent, spriteRendererComponent] = group.get<TransformComponent, SpriteRenderer>(entity);
|
||||||
|
if (spriteRendererComponent.Texture)
|
||||||
|
Renderer2D::DrawQuad(transformComponent.Transform, spriteRendererComponent.Texture, spriteRendererComponent.TilingFactor);
|
||||||
|
else
|
||||||
|
Renderer2D::DrawQuad(transformComponent.Transform, spriteRendererComponent.Color);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SceneRenderer::EndScene();
|
Renderer2D::EndScene();
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void Scene::OnEvent(Event& e)
|
void Scene::OnEvent(Event& e)
|
||||||
{
|
{
|
||||||
const auto view = m_Registry.view<CameraComponent>();
|
}
|
||||||
for (const auto entity : view)
|
|
||||||
|
void Scene::OnRuntimeStart()
|
||||||
|
{
|
||||||
|
ScriptEngine::SetSceneContext(this);
|
||||||
|
|
||||||
|
auto view = m_Registry.view<ScriptComponent>();
|
||||||
|
for (auto entity : view)
|
||||||
{
|
{
|
||||||
auto& comp = view.get<CameraComponent>(entity);
|
Entity e = { entity, this };
|
||||||
comp.Camera.OnEvent(e);
|
if (ScriptEngine::ModuleExists(e.GetComponent<ScriptComponent>().ModuleName))
|
||||||
break;
|
ScriptEngine::InstantiateEntityClass(e);
|
||||||
}
|
}
|
||||||
m_Camera.OnEvent(e);
|
|
||||||
|
m_IsPlaying = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Scene::OnRuntimeStop()
|
||||||
|
{
|
||||||
|
m_IsPlaying = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Scene::SetViewportSize(const uint32_t width, const uint32_t height)
|
||||||
|
{
|
||||||
|
m_ViewportWidth = width;
|
||||||
|
m_ViewportHeight = height;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Scene::SetEnvironment(const Environment& environment)
|
void Scene::SetEnvironment(const Environment& environment)
|
||||||
@ -170,6 +226,18 @@ namespace Prism
|
|||||||
m_SkyboxMaterial->Set("u_Texture", skybox);
|
m_SkyboxMaterial->Set("u_Texture", skybox);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Entity Scene::GetMainCameraEntity()
|
||||||
|
{
|
||||||
|
auto view = m_Registry.view<CameraComponent>();
|
||||||
|
for (auto entity : view)
|
||||||
|
{
|
||||||
|
auto& comp = view.get<CameraComponent>(entity);
|
||||||
|
if (comp.Primary)
|
||||||
|
return { entity, this };
|
||||||
|
}
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
void Scene::AddEntity(Entity* entity)
|
void Scene::AddEntity(Entity* entity)
|
||||||
{
|
{
|
||||||
m_Entities.push_back(entity);
|
m_Entities.push_back(entity);
|
||||||
@ -178,14 +246,117 @@ namespace Prism
|
|||||||
Entity Scene::CreateEntity(const std::string& name)
|
Entity Scene::CreateEntity(const std::string& name)
|
||||||
{
|
{
|
||||||
auto entity = Entity{ m_Registry.create(), this };
|
auto entity = Entity{ m_Registry.create(), this };
|
||||||
|
auto& idComponent = entity.AddComponent<IDComponent>();
|
||||||
|
idComponent.ID = {};
|
||||||
|
|
||||||
entity.AddComponent<TransformComponent>(glm::mat4(1.0f));
|
entity.AddComponent<TransformComponent>(glm::mat4(1.0f));
|
||||||
if (!name.empty())
|
if (!name.empty())
|
||||||
entity.AddComponent<TagComponent>(name);
|
entity.AddComponent<TagComponent>(name);
|
||||||
|
|
||||||
|
m_EntityIDMap[idComponent.ID] = entity;
|
||||||
return entity;
|
return entity;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Scene::DestroyEntity(const Entity entity)
|
Entity Scene::CreateEntityWithID(UUID uuid, const std::string& name, bool runtimeMap)
|
||||||
{
|
{
|
||||||
m_Registry.destroy(entity.m_EntityHandle);
|
auto entity = Entity{ m_Registry.create(), this };
|
||||||
|
auto& idComponent = entity.AddComponent<IDComponent>();
|
||||||
|
idComponent.ID = uuid;
|
||||||
|
|
||||||
|
entity.AddComponent<TransformComponent>(glm::mat4(1.0f));
|
||||||
|
if (!name.empty())
|
||||||
|
entity.AddComponent<TagComponent>(name);
|
||||||
|
|
||||||
|
PM_CORE_ASSERT(m_EntityIDMap.find(uuid) == m_EntityIDMap.end());
|
||||||
|
m_EntityIDMap[uuid] = entity;
|
||||||
|
return entity;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
static void CopyComponent(entt::registry& dstRegistry, entt::registry& srcRegistry, const std::unordered_map<UUID, entt::entity>& enttMap)
|
||||||
|
{
|
||||||
|
auto components = srcRegistry.view<T>();
|
||||||
|
for (auto srcEntity : components)
|
||||||
|
{
|
||||||
|
entt::entity destEntity = enttMap.at(srcRegistry.get<IDComponent>(srcEntity).ID);
|
||||||
|
|
||||||
|
auto& srcComponent = srcRegistry.get<T>(srcEntity);
|
||||||
|
auto& destComponent = dstRegistry.emplace_or_replace<T>(destEntity, srcComponent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
static void CopyComponentIfExists(entt::entity dst, entt::entity src, entt::registry& registry)
|
||||||
|
{
|
||||||
|
if (registry.storage<T>().contains(src))
|
||||||
|
{
|
||||||
|
auto& srcComponent = registry.get<T>(src);
|
||||||
|
registry.emplace_or_replace<T>(dst, srcComponent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Scene::DuplicateEntity(Entity entity)
|
||||||
|
{
|
||||||
|
Entity newEntity;
|
||||||
|
if (entity.HasComponent<TagComponent>())
|
||||||
|
newEntity = CreateEntity(entity.GetComponent<TagComponent>().Tag);
|
||||||
|
else
|
||||||
|
newEntity = CreateEntity();
|
||||||
|
|
||||||
|
CopyComponentIfExists<TransformComponent>(newEntity.m_EntityHandle, entity.m_EntityHandle, m_Registry);
|
||||||
|
CopyComponentIfExists<MeshComponent>(newEntity.m_EntityHandle, entity.m_EntityHandle, m_Registry);
|
||||||
|
CopyComponentIfExists<ScriptComponent>(newEntity.m_EntityHandle, entity.m_EntityHandle, m_Registry);
|
||||||
|
CopyComponentIfExists<CameraComponent>(newEntity.m_EntityHandle, entity.m_EntityHandle, m_Registry);
|
||||||
|
CopyComponentIfExists<SpriteRendererComponent>(newEntity.m_EntityHandle, entity.m_EntityHandle, m_Registry);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Scene::CopyTo(Ref<Scene>& target)
|
||||||
|
{
|
||||||
|
target->m_Light = m_Light;
|
||||||
|
target->m_LightMultiplier = m_LightMultiplier;
|
||||||
|
|
||||||
|
target->m_Environment = m_Environment;
|
||||||
|
target->m_SkyboxTexture = m_SkyboxTexture;
|
||||||
|
target->m_SkyboxMaterial = m_SkyboxMaterial;
|
||||||
|
target->m_SkyboxLod = m_SkyboxLod;
|
||||||
|
|
||||||
|
std::unordered_map<UUID, entt::entity> enttMap;
|
||||||
|
auto idComponents = m_Registry.view<IDComponent>();
|
||||||
|
for (auto entity : idComponents)
|
||||||
|
{
|
||||||
|
auto uuid = m_Registry.get<IDComponent>(entity).ID;
|
||||||
|
Entity e = target->CreateEntityWithID(uuid, "", true);
|
||||||
|
enttMap[uuid] = e.m_EntityHandle;
|
||||||
|
}
|
||||||
|
|
||||||
|
CopyComponent<TagComponent>(target->m_Registry, m_Registry, enttMap);
|
||||||
|
CopyComponent<TransformComponent>(target->m_Registry, m_Registry, enttMap);
|
||||||
|
CopyComponent<MeshComponent>(target->m_Registry, m_Registry, enttMap);
|
||||||
|
CopyComponent<ScriptComponent>(target->m_Registry, m_Registry, enttMap);
|
||||||
|
CopyComponent<CameraComponent>(target->m_Registry, m_Registry, enttMap);
|
||||||
|
CopyComponent<SpriteRendererComponent>(target->m_Registry, m_Registry, enttMap);
|
||||||
|
|
||||||
|
const auto& entityInstanceMap = ScriptEngine::GetEntityInstanceMap();
|
||||||
|
if (entityInstanceMap.find(target->GetUUID()) != entityInstanceMap.end())
|
||||||
|
ScriptEngine::CopyEntityScriptData(target->GetUUID(), m_SceneID);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ref<Scene> Scene::GetScene(const UUID& uuid)
|
||||||
|
{
|
||||||
|
if (s_ActiveScenes.find(uuid) != s_ActiveScenes.end())
|
||||||
|
return s_ActiveScenes.at(uuid);
|
||||||
|
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Scene::DestroyEntity(Entity entity)
|
||||||
|
{
|
||||||
|
if (entity.HasComponent<ScriptComponent>())
|
||||||
|
ScriptEngine::OnScriptComponentDestroyed(m_SceneID, entity.GetUUID());
|
||||||
|
|
||||||
|
m_Registry.destroy(entity.m_EntityHandle);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -11,11 +11,15 @@
|
|||||||
|
|
||||||
#include <entt/entt.hpp>
|
#include <entt/entt.hpp>
|
||||||
|
|
||||||
|
#include "Prism/Core/UUID.h"
|
||||||
|
#include "Prism/Editor/EditorCamera.h"
|
||||||
|
|
||||||
namespace Prism
|
namespace Prism
|
||||||
{
|
{
|
||||||
|
|
||||||
struct PRISM_API Environment
|
struct PRISM_API Environment
|
||||||
{
|
{
|
||||||
|
std::string FilePath;
|
||||||
Ref<TextureCube> RadianceMap;
|
Ref<TextureCube> RadianceMap;
|
||||||
Ref<TextureCube> IrradianceMap;
|
Ref<TextureCube> IrradianceMap;
|
||||||
|
|
||||||
@ -24,13 +28,14 @@ namespace Prism
|
|||||||
|
|
||||||
struct Light
|
struct Light
|
||||||
{
|
{
|
||||||
glm::vec3 Direction;
|
glm::vec3 Direction{0.0f, 0.0f, 0.0f};
|
||||||
glm::vec3 Radiance;
|
glm::vec3 Radiance{ 0.0f, 0.0f, 0.0f};
|
||||||
|
|
||||||
float Multiplier = 1.0f;
|
float Multiplier = 1.0f;
|
||||||
};
|
};
|
||||||
|
|
||||||
class Entity;
|
class Entity;
|
||||||
|
using EntityMap = std::unordered_map<UUID, Entity>;
|
||||||
|
|
||||||
class PRISM_API Scene : public RefCounted
|
class PRISM_API Scene : public RefCounted
|
||||||
{
|
{
|
||||||
@ -41,36 +46,68 @@ namespace Prism
|
|||||||
void Init();
|
void Init();
|
||||||
|
|
||||||
void OnUpdate(TimeStep ts);
|
void OnUpdate(TimeStep ts);
|
||||||
|
void OnRenderRuntime(TimeStep ts);
|
||||||
|
void OnRenderEditor(TimeStep ts, const EditorCamera& editorCamera);
|
||||||
void OnEvent(Event& e);
|
void OnEvent(Event& e);
|
||||||
|
|
||||||
|
void OnRuntimeStart();
|
||||||
|
void OnRuntimeStop();
|
||||||
|
|
||||||
|
void SetViewportSize(uint32_t width, uint32_t height);
|
||||||
|
|
||||||
void SetEnvironment(const Environment& environment);
|
void SetEnvironment(const Environment& environment);
|
||||||
|
const Environment& GetEnvironment() const { return m_Environment; }
|
||||||
void SetSkybox(const Ref<TextureCube>& skybox);
|
void SetSkybox(const Ref<TextureCube>& skybox);
|
||||||
|
|
||||||
Light& GetLight() { return m_Light; }
|
|
||||||
float& GetSkyboxLod() { return m_SkyboxLod; }
|
float& GetSkyboxLod() { return m_SkyboxLod; }
|
||||||
|
|
||||||
|
Light& GetLight() { return m_Light; }
|
||||||
|
const Light& GetLight() const { return m_Light; }
|
||||||
|
|
||||||
|
Entity GetMainCameraEntity();
|
||||||
|
|
||||||
void AddEntity(Entity* entity);
|
void AddEntity(Entity* entity);
|
||||||
Entity CreateEntity(const std::string& name = "");
|
Entity CreateEntity(const std::string& name = "");
|
||||||
|
Entity CreateEntityWithID(UUID uuid, const std::string& name = "", bool runtimeMap = false);
|
||||||
|
|
||||||
void DestroyEntity(Entity entity);
|
void DestroyEntity(Entity entity);
|
||||||
|
|
||||||
|
void DuplicateEntity(Entity entity);
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
auto GetAllEntitiesWith()
|
auto GetAllEntitiesWith()
|
||||||
{
|
{
|
||||||
return m_Registry.view<T>();
|
return m_Registry.view<T>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const EntityMap& GetEntityMap() const { return m_EntityIDMap; }
|
||||||
|
void CopyTo(Ref<Scene>& target);
|
||||||
|
|
||||||
|
UUID GetUUID() const { return m_SceneID; }
|
||||||
|
|
||||||
|
static Ref<Scene> GetScene(const UUID& uuid);
|
||||||
|
|
||||||
|
// Editor-specific
|
||||||
|
void SetSelectedEntity(entt::entity entity) { m_SelectedEntity = entity; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
uint32_t m_SceneID;
|
UUID m_SceneID;
|
||||||
entt::entity m_SceneEntity;
|
entt::entity m_SceneEntity;
|
||||||
entt::registry m_Registry;
|
entt::registry m_Registry;
|
||||||
|
|
||||||
std::string m_DebugName;
|
|
||||||
std::vector<Entity*> m_Entities;
|
std::vector<Entity*> m_Entities;
|
||||||
Camera m_Camera;
|
Camera m_Camera;
|
||||||
|
|
||||||
|
std::string m_DebugName;
|
||||||
|
uint32_t m_ViewportWidth = 0, m_ViewportHeight = 0;
|
||||||
|
|
||||||
|
EntityMap m_EntityIDMap;
|
||||||
|
|
||||||
|
entt::entity m_SelectedEntity;
|
||||||
|
|
||||||
Light m_Light;
|
Light m_Light;
|
||||||
float m_LightMultiplier = 0.3f;
|
float m_LightMultiplier = 0.3f;
|
||||||
|
bool m_IsPlaying = false;
|
||||||
|
|
||||||
Environment m_Environment;
|
Environment m_Environment;
|
||||||
Ref<TextureCube> m_SkyboxTexture;
|
Ref<TextureCube> m_SkyboxTexture;
|
||||||
@ -81,7 +118,9 @@ namespace Prism
|
|||||||
private:
|
private:
|
||||||
friend class Entity;
|
friend class Entity;
|
||||||
friend class SceneRenderer;
|
friend class SceneRenderer;
|
||||||
|
friend class SceneSerializer;
|
||||||
friend class SceneHierarchyPanel;
|
friend class SceneHierarchyPanel;
|
||||||
|
friend void OnScriptComponentConstruct(entt::registry& registry, entt::entity entity);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
50
Prism/src/Prism/Scene/SceneCamera.cpp
Normal file
50
Prism/src/Prism/Scene/SceneCamera.cpp
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
//
|
||||||
|
// Created by sfd on 25-12-9.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "SceneCamera.h"
|
||||||
|
|
||||||
|
#include "glm/ext/matrix_clip_space.hpp"
|
||||||
|
|
||||||
|
namespace Prism
|
||||||
|
{
|
||||||
|
SceneCamera::SceneCamera()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
SceneCamera::~SceneCamera()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void SceneCamera::SetPerspective(const float verticalFOV, const float nearClip, const float farClip)
|
||||||
|
{
|
||||||
|
m_ProjectionType = ProjectionType::Perspective;
|
||||||
|
m_PerspectiveFOV = verticalFOV;
|
||||||
|
m_PerspectiveNear = nearClip;
|
||||||
|
m_PerspectiveFar = farClip;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SceneCamera::SetOrthographic(const float size, const float nearClip, const float farClip)
|
||||||
|
{
|
||||||
|
m_ProjectionType = ProjectionType::Orthographic;
|
||||||
|
m_OrthographicSize = size;
|
||||||
|
m_OrthographicNear = nearClip;
|
||||||
|
m_OrthographicFar = farClip;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SceneCamera::SetViewportSize(const uint32_t width, const uint32_t height)
|
||||||
|
{
|
||||||
|
switch (m_ProjectionType)
|
||||||
|
{
|
||||||
|
case ProjectionType::Perspective:
|
||||||
|
m_ProjectionMatrix = glm::perspectiveFov(m_PerspectiveFOV, (float)width, (float)height, m_PerspectiveNear, m_PerspectiveFar);
|
||||||
|
break;
|
||||||
|
case ProjectionType::Orthographic:
|
||||||
|
const float aspect = (float)width / (float)height;
|
||||||
|
const float w = m_OrthographicSize * aspect;
|
||||||
|
const float h = m_OrthographicSize;
|
||||||
|
m_ProjectionMatrix = glm::ortho(-w * 0.5f, w * 0.5f, -h * 0.5f, h * 0.5f);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
54
Prism/src/Prism/Scene/SceneCamera.h
Normal file
54
Prism/src/Prism/Scene/SceneCamera.h
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
//
|
||||||
|
// Created by sfd on 25-12-9.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef SCENECAMERA_H
|
||||||
|
#define SCENECAMERA_H
|
||||||
|
#include "Prism/Renderer/Camera.h"
|
||||||
|
|
||||||
|
|
||||||
|
namespace Prism
|
||||||
|
{
|
||||||
|
class SceneCamera : public Camera
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
enum class ProjectionType { Perspective = 0, Orthographic = 1 };
|
||||||
|
public:
|
||||||
|
SceneCamera();
|
||||||
|
virtual ~SceneCamera();
|
||||||
|
|
||||||
|
|
||||||
|
void SetPerspective(float verticalFOV, float nearClip = 0.01f, float farClip = 10000.0f);
|
||||||
|
void SetOrthographic(float size, float nearClip = -1.0f, float farClip = 1.0f);
|
||||||
|
void SetViewportSize(uint32_t width, uint32_t height);
|
||||||
|
|
||||||
|
|
||||||
|
void SetPerspectiveVerticalFOV(const float verticalFov) { m_PerspectiveFOV = glm::radians(verticalFov); }
|
||||||
|
float GetPerspectiveVerticalFOV() const { return glm::degrees(m_PerspectiveFOV); }
|
||||||
|
void SetPerspectiveNearClip(const float nearClip) { m_PerspectiveNear = nearClip; }
|
||||||
|
float GetPerspectiveNearClip() const { return m_PerspectiveNear; }
|
||||||
|
void SetPerspectiveFarClip(const float farClip) { m_PerspectiveFar = farClip; }
|
||||||
|
float GetPerspectiveFarClip() const { return m_PerspectiveFar; }
|
||||||
|
|
||||||
|
void SetOrthographicSize(const float size) { m_OrthographicSize = size; }
|
||||||
|
float GetOrthographicSize() const { return m_OrthographicSize; }
|
||||||
|
void SetOrthographicNearClip(const float nearClip) { m_OrthographicNear = nearClip; }
|
||||||
|
float GetOrthographicNearClip() const { return m_OrthographicNear; }
|
||||||
|
void SetOrthographicFarClip(const float farClip) { m_OrthographicFar = farClip; }
|
||||||
|
float GetOrthographicFarClip() const { return m_OrthographicFar; }
|
||||||
|
|
||||||
|
void SetProjectionType(const ProjectionType type) { m_ProjectionType = type; }
|
||||||
|
ProjectionType GetProjectionType() const { return m_ProjectionType; }
|
||||||
|
private:
|
||||||
|
ProjectionType m_ProjectionType = ProjectionType::Perspective;
|
||||||
|
|
||||||
|
float m_PerspectiveFOV = glm::radians(45.0f);
|
||||||
|
float m_PerspectiveNear = 0.01f, m_PerspectiveFar = 10000.0f;
|
||||||
|
|
||||||
|
float m_OrthographicSize = 10.0f;
|
||||||
|
float m_OrthographicNear = -1.0f, m_OrthographicFar = 1.0f;
|
||||||
|
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif //SCENECAMERA_H
|
||||||
515
Prism/src/Prism/Scene/SceneSerializer.cpp
Normal file
515
Prism/src/Prism/Scene/SceneSerializer.cpp
Normal file
@ -0,0 +1,515 @@
|
|||||||
|
//
|
||||||
|
// Created by sfd on 25-12-9.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "SceneSerializer.h"
|
||||||
|
|
||||||
|
#include "SceneSerializer.h"
|
||||||
|
|
||||||
|
#include "Entity.h"
|
||||||
|
#include "Components.h"
|
||||||
|
#include "Prism/Script/ScriptEngine.h"
|
||||||
|
|
||||||
|
#include "yaml-cpp/yaml.h"
|
||||||
|
|
||||||
|
#define GLM_ENABLE_EXPERIMENTAL
|
||||||
|
#include <glm/gtx/quaternion.hpp>
|
||||||
|
#include <glm/gtx/matrix_decompose.hpp>
|
||||||
|
#include <glm/gtc/type_ptr.hpp>
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
#include <fstream>
|
||||||
|
|
||||||
|
namespace YAML
|
||||||
|
{
|
||||||
|
|
||||||
|
template<>
|
||||||
|
struct convert<glm::vec2>
|
||||||
|
{
|
||||||
|
static Node encode(const glm::vec2& rhs)
|
||||||
|
{
|
||||||
|
Node node;
|
||||||
|
node.push_back(rhs.x);
|
||||||
|
node.push_back(rhs.y);
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool decode(const Node& node, glm::vec2& rhs)
|
||||||
|
{
|
||||||
|
if (!node.IsSequence() || node.size() != 2)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
rhs.x = node[0].as<float>();
|
||||||
|
rhs.y = node[1].as<float>();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<>
|
||||||
|
struct convert<glm::vec3>
|
||||||
|
{
|
||||||
|
static Node encode(const glm::vec3& rhs)
|
||||||
|
{
|
||||||
|
Node node;
|
||||||
|
node.push_back(rhs.x);
|
||||||
|
node.push_back(rhs.y);
|
||||||
|
node.push_back(rhs.z);
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool decode(const Node& node, glm::vec3& rhs)
|
||||||
|
{
|
||||||
|
if (!node.IsSequence() || node.size() != 3)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
rhs.x = node[0].as<float>();
|
||||||
|
rhs.y = node[1].as<float>();
|
||||||
|
rhs.z = node[2].as<float>();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<>
|
||||||
|
struct convert<glm::vec4>
|
||||||
|
{
|
||||||
|
static Node encode(const glm::vec4& rhs)
|
||||||
|
{
|
||||||
|
Node node;
|
||||||
|
node.push_back(rhs.x);
|
||||||
|
node.push_back(rhs.y);
|
||||||
|
node.push_back(rhs.z);
|
||||||
|
node.push_back(rhs.w);
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool decode(const Node& node, glm::vec4& rhs)
|
||||||
|
{
|
||||||
|
if (!node.IsSequence() || node.size() != 4)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
rhs.x = node[0].as<float>();
|
||||||
|
rhs.y = node[1].as<float>();
|
||||||
|
rhs.z = node[2].as<float>();
|
||||||
|
rhs.w = node[3].as<float>();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<>
|
||||||
|
struct convert<glm::quat>
|
||||||
|
{
|
||||||
|
static Node encode(const glm::quat& rhs)
|
||||||
|
{
|
||||||
|
Node node;
|
||||||
|
node.push_back(rhs.w);
|
||||||
|
node.push_back(rhs.x);
|
||||||
|
node.push_back(rhs.y);
|
||||||
|
node.push_back(rhs.z);
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool decode(const Node& node, glm::quat& rhs)
|
||||||
|
{
|
||||||
|
if (!node.IsSequence() || node.size() != 4)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
rhs.w = node[0].as<float>();
|
||||||
|
rhs.x = node[1].as<float>();
|
||||||
|
rhs.y = node[2].as<float>();
|
||||||
|
rhs.z = node[3].as<float>();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace Prism
|
||||||
|
{
|
||||||
|
|
||||||
|
YAML::Emitter& operator<<(YAML::Emitter& out, const glm::vec2& v)
|
||||||
|
{
|
||||||
|
out << YAML::Flow;
|
||||||
|
out << YAML::BeginSeq << v.x << v.y << YAML::EndSeq;
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
YAML::Emitter& operator<<(YAML::Emitter& out, const glm::vec3& v)
|
||||||
|
{
|
||||||
|
out << YAML::Flow;
|
||||||
|
out << YAML::BeginSeq << v.x << v.y << v.z << YAML::EndSeq;
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
YAML::Emitter& operator<<(YAML::Emitter& out, const glm::vec4& v)
|
||||||
|
{
|
||||||
|
out << YAML::Flow;
|
||||||
|
out << YAML::BeginSeq << v.x << v.y << v.z << v.w << YAML::EndSeq;
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
YAML::Emitter& operator<<(YAML::Emitter& out, const glm::quat& v)
|
||||||
|
{
|
||||||
|
out << YAML::Flow;
|
||||||
|
out << YAML::BeginSeq << v.w << v.x << v.y << v.z << YAML::EndSeq;
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
SceneSerializer::SceneSerializer(const Ref<Scene>& scene)
|
||||||
|
: m_Scene(scene)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::tuple<glm::vec3, glm::quat, glm::vec3> GetTransformDecomposition(const glm::mat4& transform)
|
||||||
|
{
|
||||||
|
glm::vec3 scale, translation, skew;
|
||||||
|
glm::vec4 perspective;
|
||||||
|
glm::quat orientation;
|
||||||
|
glm::decompose(transform, scale, orientation, translation, skew, perspective);
|
||||||
|
|
||||||
|
return { translation, orientation, scale };
|
||||||
|
}
|
||||||
|
|
||||||
|
static void SerializeEntity(YAML::Emitter& out, Entity entity)
|
||||||
|
{
|
||||||
|
UUID uuid = entity.GetComponent<IDComponent>().ID;
|
||||||
|
out << YAML::BeginMap; // Entity
|
||||||
|
out << YAML::Key << "Entity";
|
||||||
|
out << YAML::Value << uuid;
|
||||||
|
|
||||||
|
if (entity.HasComponent<TagComponent>())
|
||||||
|
{
|
||||||
|
out << YAML::Key << "TagComponent";
|
||||||
|
out << YAML::BeginMap; // TagComponent
|
||||||
|
|
||||||
|
auto& tag = entity.GetComponent<TagComponent>().Tag;
|
||||||
|
out << YAML::Key << "Tag" << YAML::Value << tag;
|
||||||
|
|
||||||
|
out << YAML::EndMap; // TagComponent
|
||||||
|
}
|
||||||
|
|
||||||
|
if (entity.HasComponent<TransformComponent>())
|
||||||
|
{
|
||||||
|
out << YAML::Key << "TransformComponent";
|
||||||
|
out << YAML::BeginMap; // TransformComponent
|
||||||
|
|
||||||
|
auto& transform = entity.GetComponent<TransformComponent>().Transform;
|
||||||
|
auto[pos, rot, scale] = GetTransformDecomposition(transform);
|
||||||
|
out << YAML::Key << "Position" << YAML::Value << pos;
|
||||||
|
out << YAML::Key << "Rotation" << YAML::Value << rot;
|
||||||
|
out << YAML::Key << "Scale" << YAML::Value << scale;
|
||||||
|
|
||||||
|
out << YAML::EndMap; // TransformComponent
|
||||||
|
}
|
||||||
|
|
||||||
|
if (entity.HasComponent<ScriptComponent>())
|
||||||
|
{
|
||||||
|
out << YAML::Key << "ScriptComponent";
|
||||||
|
out << YAML::BeginMap; // ScriptComponent
|
||||||
|
|
||||||
|
auto& moduleName = entity.GetComponent<ScriptComponent>().ModuleName;
|
||||||
|
out << YAML::Key << "ModuleName" << YAML::Value << moduleName;
|
||||||
|
|
||||||
|
EntityInstanceData& data = ScriptEngine::GetEntityInstanceData(entity.GetSceneUUID(), uuid);
|
||||||
|
const auto& moduleFieldMap = data.ModuleFieldMap;
|
||||||
|
if (moduleFieldMap.find(moduleName) != moduleFieldMap.end())
|
||||||
|
{
|
||||||
|
const auto& fields = moduleFieldMap.at(moduleName);
|
||||||
|
out << YAML::Key << "StoredFields" << YAML::Value;
|
||||||
|
out << YAML::BeginSeq;
|
||||||
|
for (const auto& [name, field] : fields)
|
||||||
|
{
|
||||||
|
out << YAML::BeginMap; // Field
|
||||||
|
out << YAML::Key << "Name" << YAML::Value << name;
|
||||||
|
out << YAML::Key << "Type" << YAML::Value << (uint32_t)field.Type;
|
||||||
|
out << YAML::Key << "Data" << YAML::Value;
|
||||||
|
|
||||||
|
switch (field.Type)
|
||||||
|
{
|
||||||
|
case FieldType::Int:
|
||||||
|
out << field.GetStoredValue<int>();
|
||||||
|
break;
|
||||||
|
case FieldType::UnsignedInt:
|
||||||
|
out << field.GetStoredValue<uint32_t>();
|
||||||
|
break;
|
||||||
|
case FieldType::Float:
|
||||||
|
out << field.GetStoredValue<float>();
|
||||||
|
break;
|
||||||
|
case FieldType::Vec2:
|
||||||
|
out << field.GetStoredValue<glm::vec2>();
|
||||||
|
break;
|
||||||
|
case FieldType::Vec3:
|
||||||
|
out << field.GetStoredValue<glm::vec3>();
|
||||||
|
break;
|
||||||
|
case FieldType::Vec4:
|
||||||
|
out << field.GetStoredValue<glm::vec4>();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
out << YAML::EndMap; // Field
|
||||||
|
}
|
||||||
|
out << YAML::EndSeq;
|
||||||
|
}
|
||||||
|
|
||||||
|
out << YAML::EndMap; // ScriptComponent
|
||||||
|
}
|
||||||
|
|
||||||
|
if (entity.HasComponent<MeshComponent>())
|
||||||
|
{
|
||||||
|
out << YAML::Key << "MeshComponent";
|
||||||
|
out << YAML::BeginMap; // MeshComponent
|
||||||
|
|
||||||
|
auto mesh = entity.GetComponent<MeshComponent>().Mesh;
|
||||||
|
out << YAML::Key << "AssetPath" << YAML::Value << mesh->GetFilePath();
|
||||||
|
|
||||||
|
out << YAML::EndMap; // MeshComponent
|
||||||
|
}
|
||||||
|
|
||||||
|
if (entity.HasComponent<CameraComponent>())
|
||||||
|
{
|
||||||
|
out << YAML::Key << "CameraComponent";
|
||||||
|
out << YAML::BeginMap; // CameraComponent
|
||||||
|
|
||||||
|
auto cameraComponent = entity.GetComponent<CameraComponent>();
|
||||||
|
out << YAML::Key << "Camera" << YAML::Value << "some camera data...";
|
||||||
|
out << YAML::Key << "Primary" << YAML::Value << cameraComponent.Primary;
|
||||||
|
|
||||||
|
out << YAML::EndMap; // CameraComponent
|
||||||
|
}
|
||||||
|
|
||||||
|
if (entity.HasComponent<SpriteRendererComponent>())
|
||||||
|
{
|
||||||
|
out << YAML::Key << "SpriteRendererComponent";
|
||||||
|
out << YAML::BeginMap; // SpriteRendererComponent
|
||||||
|
|
||||||
|
auto spriteRendererComponent = entity.GetComponent<SpriteRendererComponent>();
|
||||||
|
out << YAML::Key << "Color" << YAML::Value << spriteRendererComponent.Color;
|
||||||
|
if (spriteRendererComponent.Texture)
|
||||||
|
out << YAML::Key << "TextureAssetPath" << YAML::Value << "path/to/asset";
|
||||||
|
out << YAML::Key << "TilingFactor" << YAML::Value << spriteRendererComponent.TilingFactor;
|
||||||
|
|
||||||
|
out << YAML::EndMap; // SpriteRendererComponent
|
||||||
|
}
|
||||||
|
|
||||||
|
out << YAML::EndMap; // Entity
|
||||||
|
}
|
||||||
|
|
||||||
|
static void SerializeEnvironment(YAML::Emitter& out, const Ref<Scene>& scene)
|
||||||
|
{
|
||||||
|
out << YAML::Key << "Environment";
|
||||||
|
out << YAML::Value;
|
||||||
|
out << YAML::BeginMap; // Environment
|
||||||
|
out << YAML::Key << "AssetPath" << YAML::Value << scene->GetEnvironment().FilePath;
|
||||||
|
const auto& light = scene->GetLight();
|
||||||
|
out << YAML::Key << "Light" << YAML::Value;
|
||||||
|
out << YAML::BeginMap; // Light
|
||||||
|
out << YAML::Key << "Direction" << YAML::Value << light.Direction;
|
||||||
|
out << YAML::Key << "Radiance" << YAML::Value << light.Radiance;
|
||||||
|
out << YAML::Key << "Multiplier" << YAML::Value << light.Multiplier;
|
||||||
|
out << YAML::EndMap; // Light
|
||||||
|
out << YAML::EndMap; // Environment
|
||||||
|
}
|
||||||
|
|
||||||
|
void SceneSerializer::Serialize(const std::string& filepath)
|
||||||
|
{
|
||||||
|
YAML::Emitter out;
|
||||||
|
out << YAML::BeginMap;
|
||||||
|
out << YAML::Key << "Scene";
|
||||||
|
out << YAML::Value << "Scene Name";
|
||||||
|
SerializeEnvironment(out, m_Scene);
|
||||||
|
out << YAML::Key << "Entities";
|
||||||
|
out << YAML::Value << YAML::BeginSeq;
|
||||||
|
m_Scene->m_Registry.view<entt::entity>().each([&](auto entityID)
|
||||||
|
{
|
||||||
|
const Entity entity = { entityID, m_Scene.Raw() };
|
||||||
|
if (!entity || !entity.HasComponent<IDComponent>())
|
||||||
|
return;
|
||||||
|
|
||||||
|
SerializeEntity(out, entity);
|
||||||
|
});
|
||||||
|
out << YAML::EndSeq;
|
||||||
|
out << YAML::EndMap;
|
||||||
|
|
||||||
|
std::ofstream fout(filepath);
|
||||||
|
fout << out.c_str();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SceneSerializer::SerializeRuntime(const std::string& filepath)
|
||||||
|
{
|
||||||
|
// Not implemented
|
||||||
|
PM_CORE_ASSERT(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SceneSerializer::Deserialize(const std::string& filepath)
|
||||||
|
{
|
||||||
|
std::ifstream stream(filepath);
|
||||||
|
std::stringstream strStream;
|
||||||
|
strStream << stream.rdbuf();
|
||||||
|
|
||||||
|
YAML::Node data = YAML::Load(strStream.str());
|
||||||
|
if (!data["Scene"])
|
||||||
|
return false;
|
||||||
|
|
||||||
|
std::string sceneName = data["Scene"].as<std::string>();
|
||||||
|
PM_CORE_INFO("Deserializing scene '{0}'", sceneName);
|
||||||
|
|
||||||
|
auto environment = data["Environment"];
|
||||||
|
if (environment)
|
||||||
|
{
|
||||||
|
std::string envPath = environment["AssetPath"].as<std::string>();
|
||||||
|
m_Scene->SetEnvironment(Environment::Load(envPath));
|
||||||
|
|
||||||
|
auto lightNode = environment["Light"];
|
||||||
|
if (lightNode)
|
||||||
|
{
|
||||||
|
auto& light = m_Scene->GetLight();
|
||||||
|
light.Direction = lightNode["Direction"].as<glm::vec3>();
|
||||||
|
light.Radiance = lightNode["Radiance"].as<glm::vec3>();
|
||||||
|
light.Multiplier = lightNode["Multiplier"].as<float>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
auto entities = data["Entities"];
|
||||||
|
if (entities)
|
||||||
|
{
|
||||||
|
for (auto entity : entities)
|
||||||
|
{
|
||||||
|
uint64_t uuid = entity["Entity"].as<uint64_t>();
|
||||||
|
|
||||||
|
std::string name;
|
||||||
|
auto tagComponent = entity["TagComponent"];
|
||||||
|
if (tagComponent)
|
||||||
|
name = tagComponent["Tag"].as<std::string>();
|
||||||
|
|
||||||
|
PM_CORE_INFO("Deserialized entity with ID = {0}, name = {1}", uuid, name);
|
||||||
|
|
||||||
|
Entity deserializedEntity = m_Scene->CreateEntityWithID(uuid, name);
|
||||||
|
|
||||||
|
auto transformComponent = entity["TransformComponent"];
|
||||||
|
if (transformComponent)
|
||||||
|
{
|
||||||
|
// Entities always have transforms
|
||||||
|
auto& transform = deserializedEntity.GetComponent<TransformComponent>().Transform;
|
||||||
|
glm::vec3 translation = transformComponent["Position"].as<glm::vec3>();
|
||||||
|
glm::quat rotation = transformComponent["Rotation"].as<glm::quat>();
|
||||||
|
glm::vec3 scale = transformComponent["Scale"].as<glm::vec3>();
|
||||||
|
|
||||||
|
transform = glm::translate(glm::mat4(1.0f), translation) *
|
||||||
|
glm::toMat4(rotation) * glm::scale(glm::mat4(1.0f), scale);
|
||||||
|
|
||||||
|
PM_CORE_INFO(" Entity Transform:");
|
||||||
|
PM_CORE_INFO(" Translation: {0}, {1}, {2}", translation.x, translation.y, translation.z);
|
||||||
|
PM_CORE_INFO(" Rotation: {0}, {1}, {2}, {3}", rotation.w, rotation.x, rotation.y, rotation.z);
|
||||||
|
PM_CORE_INFO(" Scale: {0}, {1}, {2}", scale.x, scale.y, scale.z);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto scriptComponent = entity["ScriptComponent"];
|
||||||
|
if (scriptComponent)
|
||||||
|
{
|
||||||
|
std::string moduleName = scriptComponent["ModuleName"].as<std::string>();
|
||||||
|
deserializedEntity.AddComponent<ScriptComponent>(moduleName);
|
||||||
|
|
||||||
|
PM_CORE_INFO(" Script Module: {0}", moduleName);
|
||||||
|
|
||||||
|
if (ScriptEngine::ModuleExists(moduleName))
|
||||||
|
{
|
||||||
|
auto storedFields = scriptComponent["StoredFields"];
|
||||||
|
if (storedFields)
|
||||||
|
{
|
||||||
|
for (auto field : storedFields)
|
||||||
|
{
|
||||||
|
std::string name = field["Name"].as<std::string>();
|
||||||
|
FieldType type = (FieldType)field["Type"].as<uint32_t>();
|
||||||
|
EntityInstanceData& data = ScriptEngine::GetEntityInstanceData(m_Scene->GetUUID(), uuid);
|
||||||
|
auto& moduleFieldMap = data.ModuleFieldMap;
|
||||||
|
auto& publicFields = moduleFieldMap[moduleName];
|
||||||
|
if (publicFields.find(name) == publicFields.end())
|
||||||
|
{
|
||||||
|
PublicField pf = { name, type };
|
||||||
|
publicFields.emplace(name, std::move(pf));
|
||||||
|
}
|
||||||
|
auto dataNode = field["Data"];
|
||||||
|
switch (type)
|
||||||
|
{
|
||||||
|
case FieldType::Float:
|
||||||
|
{
|
||||||
|
publicFields.at(name).SetStoredValue(dataNode.as<float>());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case FieldType::Int:
|
||||||
|
{
|
||||||
|
publicFields.at(name).SetStoredValue(dataNode.as<int32_t>());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case FieldType::UnsignedInt:
|
||||||
|
{
|
||||||
|
publicFields.at(name).SetStoredValue(dataNode.as<uint32_t>());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case FieldType::String:
|
||||||
|
{
|
||||||
|
PM_CORE_ASSERT(false, "Unimplemented");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case FieldType::Vec2:
|
||||||
|
{
|
||||||
|
publicFields.at(name).SetStoredValue(dataNode.as<glm::vec2>());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case FieldType::Vec3:
|
||||||
|
{
|
||||||
|
publicFields.at(name).SetStoredValue(dataNode.as<glm::vec3>());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case FieldType::Vec4:
|
||||||
|
{
|
||||||
|
publicFields.at(name).SetStoredValue(dataNode.as<glm::vec4>());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
auto meshComponent = entity["MeshComponent"];
|
||||||
|
if (meshComponent)
|
||||||
|
{
|
||||||
|
std::string meshPath = meshComponent["AssetPath"].as<std::string>();
|
||||||
|
// TEMP (because script creates mesh component...)
|
||||||
|
if (!deserializedEntity.HasComponent<MeshComponent>())
|
||||||
|
deserializedEntity.AddComponent<MeshComponent>(Ref<Mesh>::Create(meshPath));
|
||||||
|
|
||||||
|
PM_CORE_INFO(" Mesh Asset Path: {0}", meshPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto cameraComponent = entity["CameraComponent"];
|
||||||
|
if (cameraComponent)
|
||||||
|
{
|
||||||
|
auto& component = deserializedEntity.AddComponent<CameraComponent>();
|
||||||
|
component.Camera = SceneCamera();
|
||||||
|
component.Primary = cameraComponent["Primary"].as<bool>();
|
||||||
|
|
||||||
|
PM_CORE_INFO(" Primary Camera: {0}", component.Primary);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto spriteRendererComponent = entity["SpriteRendererComponent"];
|
||||||
|
if (spriteRendererComponent)
|
||||||
|
{
|
||||||
|
auto& component = deserializedEntity.AddComponent<SpriteRendererComponent>();
|
||||||
|
component.Color = spriteRendererComponent["Color"].as<glm::vec4>();
|
||||||
|
component.TilingFactor = spriteRendererComponent["TilingFactor"].as<float>();
|
||||||
|
|
||||||
|
PM_CORE_INFO(" SpriteRendererComponent present.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SceneSerializer::DeserializeRuntime(const std::string& filepath)
|
||||||
|
{
|
||||||
|
// Not implemented
|
||||||
|
PM_CORE_ASSERT(false);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
30
Prism/src/Prism/Scene/SceneSerializer.h
Normal file
30
Prism/src/Prism/Scene/SceneSerializer.h
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
//
|
||||||
|
// Created by sfd on 25-12-9.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef SCENESERIALIZER_H
|
||||||
|
#define SCENESERIALIZER_H
|
||||||
|
#include "Scene.h"
|
||||||
|
#include "Prism/Core/Ref.h"
|
||||||
|
|
||||||
|
|
||||||
|
namespace Prism
|
||||||
|
{
|
||||||
|
class PRISM_API SceneSerializer
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
SceneSerializer(const Ref<Scene>& scene);
|
||||||
|
|
||||||
|
void Serialize(const std::string& filepath);
|
||||||
|
void SerializeRuntime(const std::string& filepath);
|
||||||
|
|
||||||
|
bool Deserialize(const std::string& filepath);
|
||||||
|
bool DeserializeRuntime(const std::string& filepath);
|
||||||
|
private:
|
||||||
|
Ref<Scene> m_Scene;
|
||||||
|
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#endif //SCENESERIALIZER_H
|
||||||
@ -16,14 +16,17 @@
|
|||||||
#include <mono/metadata/appdomain.h>
|
#include <mono/metadata/appdomain.h>
|
||||||
#include <mono/metadata/class.h>
|
#include <mono/metadata/class.h>
|
||||||
#include <mono/metadata/object.h>
|
#include <mono/metadata/object.h>
|
||||||
|
#include <mono/metadata/reflection.h>
|
||||||
|
|
||||||
|
#include "imgui.h"
|
||||||
|
|
||||||
namespace Prism
|
namespace Prism
|
||||||
{
|
{
|
||||||
static MonoDomain* s_MonoDomain = nullptr;
|
static MonoDomain* s_MonoDomain = nullptr;
|
||||||
static std::string s_AssemblyPath;
|
static std::string s_AssemblyPath;
|
||||||
|
static Ref<Scene> s_SceneContext;
|
||||||
|
|
||||||
static ScriptModuleFieldMap s_PublicFields;
|
static EntityInstanceMap s_EntityInstanceMap;
|
||||||
|
|
||||||
static MonoMethod* GetMethod(MonoImage* image, const std::string& methodDesc);
|
static MonoMethod* GetMethod(MonoImage* image, const std::string& methodDesc);
|
||||||
|
|
||||||
@ -33,10 +36,10 @@ namespace Prism
|
|||||||
std::string ClassName;
|
std::string ClassName;
|
||||||
std::string NamespaceName;
|
std::string NamespaceName;
|
||||||
|
|
||||||
MonoClass* Class;
|
MonoClass* Class = nullptr;
|
||||||
MonoMethod* OnCreateMethod;
|
MonoMethod* OnCreateMethod = nullptr;
|
||||||
MonoMethod* OnDestroyMethod;
|
MonoMethod* OnDestroyMethod = nullptr;
|
||||||
MonoMethod* OnUpdateMethod;
|
MonoMethod* OnUpdateMethod = nullptr;
|
||||||
|
|
||||||
void InitClassMethods(MonoImage* image)
|
void InitClassMethods(MonoImage* image)
|
||||||
{
|
{
|
||||||
@ -45,21 +48,8 @@ namespace Prism
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct EntityInstance
|
|
||||||
{
|
|
||||||
EntityScriptClass* ScriptClass;
|
|
||||||
|
|
||||||
uint32_t Handle;
|
|
||||||
Scene* SceneInstance;
|
|
||||||
|
|
||||||
MonoObject* GetInstance()
|
|
||||||
{
|
|
||||||
return mono_gchandle_get_target(Handle);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
static std::unordered_map<std::string, EntityScriptClass> s_EntityClassMap;
|
static std::unordered_map<std::string, EntityScriptClass> s_EntityClassMap;
|
||||||
static std::unordered_map<uint32_t, EntityInstance> s_EntityInstanceMap;
|
|
||||||
|
|
||||||
|
|
||||||
MonoAssembly* LoadAssemblyFromFile(const char* filepath)
|
MonoAssembly* LoadAssemblyFromFile(const char* filepath)
|
||||||
@ -100,17 +90,11 @@ namespace Prism
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
MonoAssembly* assembly = mono_assembly_load_from_full(
|
const auto assembly = mono_assembly_load_from_full(image, filepath, &status, 0);
|
||||||
image,
|
|
||||||
filepath,
|
|
||||||
&status,
|
|
||||||
0
|
|
||||||
);
|
|
||||||
|
|
||||||
mono_image_close(image);
|
mono_image_close(image);
|
||||||
|
|
||||||
return assembly;
|
return assembly;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void InitMono()
|
static void InitMono()
|
||||||
@ -125,6 +109,11 @@ namespace Prism
|
|||||||
s_MonoDomain = mono_domain_create_appdomain(name, nullptr);
|
s_MonoDomain = mono_domain_create_appdomain(name, nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void ShutdownMono()
|
||||||
|
{
|
||||||
|
mono_jit_cleanup(s_MonoDomain);
|
||||||
|
}
|
||||||
|
|
||||||
static MonoAssembly* LoadAssembly(const std::string& path)
|
static MonoAssembly* LoadAssembly(const std::string& path)
|
||||||
{
|
{
|
||||||
MonoAssembly* assembly = LoadAssemblyFromFile(path.c_str()); //mono_domain_assembly_open(s_MonoDomain, path.c_str());
|
MonoAssembly* assembly = LoadAssemblyFromFile(path.c_str()); //mono_domain_assembly_open(s_MonoDomain, path.c_str());
|
||||||
@ -242,6 +231,89 @@ namespace Prism
|
|||||||
ScriptEngineRegistry::RegisterAll();
|
ScriptEngineRegistry::RegisterAll();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static uint32_t GetFieldSize(FieldType type)
|
||||||
|
{
|
||||||
|
switch (type)
|
||||||
|
{
|
||||||
|
case FieldType::Float: return 4;
|
||||||
|
case FieldType::Int: return 4;
|
||||||
|
case FieldType::UnsignedInt: return 4;
|
||||||
|
// case FieldType::String: return 8; // TODO
|
||||||
|
case FieldType::Vec2: return 4 * 2;
|
||||||
|
case FieldType::Vec3: return 4 * 3;
|
||||||
|
case FieldType::Vec4: return 4 * 4;
|
||||||
|
}
|
||||||
|
PM_CORE_ASSERT(false, "Unknown field type!");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static FieldType GetPrismFieldType(MonoType* monoType)
|
||||||
|
{
|
||||||
|
int type = mono_type_get_type(monoType);
|
||||||
|
switch (type)
|
||||||
|
{
|
||||||
|
case MONO_TYPE_R4: return FieldType::Float;
|
||||||
|
case MONO_TYPE_I4: return FieldType::Int;
|
||||||
|
case MONO_TYPE_U4: return FieldType::UnsignedInt;
|
||||||
|
case MONO_TYPE_STRING: return FieldType::String;
|
||||||
|
case MONO_TYPE_VALUETYPE:
|
||||||
|
{
|
||||||
|
const char* name = mono_type_get_name(monoType);
|
||||||
|
if (strcmp(name, "Prism.Vec2") == 0) return FieldType::Vec2;
|
||||||
|
if (strcmp(name, "Prism.Vec3") == 0) return FieldType::Vec3;
|
||||||
|
if (strcmp(name, "Prism.Vec4") == 0) return FieldType::Vec4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return FieldType::None;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* FieldTypeToString(FieldType type)
|
||||||
|
{
|
||||||
|
switch (type)
|
||||||
|
{
|
||||||
|
case FieldType::Float: return "Float";
|
||||||
|
case FieldType::Int: return "Int";
|
||||||
|
case FieldType::UnsignedInt: return "UnsignedInt";
|
||||||
|
case FieldType::String: return "String";
|
||||||
|
case FieldType::Vec2: return "Vec2";
|
||||||
|
case FieldType::Vec3: return "Vec3";
|
||||||
|
case FieldType::Vec4: return "Vec4";
|
||||||
|
}
|
||||||
|
return "Unknown";
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t* PublicField::AllocateBuffer(FieldType type)
|
||||||
|
{
|
||||||
|
uint32_t size = GetFieldSize(type);
|
||||||
|
uint8_t* buffer = new uint8_t[size];
|
||||||
|
memset(buffer, 0, size);
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PublicField::SetStoredValue_Internal(void* value) const
|
||||||
|
{
|
||||||
|
const uint32_t size = GetFieldSize(Type);
|
||||||
|
memcpy(m_StoredValueBuffer, value, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PublicField::GetStoredValue_Internal(void* outValue) const
|
||||||
|
{
|
||||||
|
const uint32_t size = GetFieldSize(Type);
|
||||||
|
memcpy(outValue, m_StoredValueBuffer, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PublicField::SetRuntimeValue_Internal(void* value) const
|
||||||
|
{
|
||||||
|
PM_CORE_ASSERT(m_EntityInstance->GetInstance());
|
||||||
|
mono_field_set_value(m_EntityInstance->GetInstance(), m_MonoClassField, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PublicField::GetRuntimeValue_Internal(void* outValue) const
|
||||||
|
{
|
||||||
|
PM_CORE_ASSERT(m_EntityInstance->GetInstance());
|
||||||
|
mono_field_get_value(m_EntityInstance->GetInstance(), m_MonoClassField, outValue);
|
||||||
|
}
|
||||||
|
|
||||||
void ScriptEngine::Init(const std::string& assemblyPath)
|
void ScriptEngine::Init(const std::string& assemblyPath)
|
||||||
{
|
{
|
||||||
s_AssemblyPath = assemblyPath;
|
s_AssemblyPath = assemblyPath;
|
||||||
@ -254,85 +326,193 @@ namespace Prism
|
|||||||
void ScriptEngine::Shutdown()
|
void ScriptEngine::Shutdown()
|
||||||
{
|
{
|
||||||
// shutdown mono
|
// shutdown mono
|
||||||
|
s_SceneContext = nullptr;
|
||||||
|
s_EntityInstanceMap.clear();
|
||||||
|
ShutdownMono();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScriptEngine::OnSceneDestruct(UUID sceneID)
|
||||||
|
{
|
||||||
|
if (s_EntityInstanceMap.find(sceneID) != s_EntityInstanceMap.end())
|
||||||
|
{
|
||||||
|
s_EntityInstanceMap.at(sceneID).clear();
|
||||||
|
s_EntityInstanceMap.erase(sceneID);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScriptEngine::LoadPrismRuntimeAssembly(const std::string& path)
|
||||||
|
{
|
||||||
|
MonoDomain* domain = nullptr;
|
||||||
|
bool cleanup = false;
|
||||||
|
if (s_MonoDomain)
|
||||||
|
{
|
||||||
|
domain = mono_domain_create_appdomain((char*)"Prism Runtime", nullptr);
|
||||||
|
mono_domain_set(domain, false);
|
||||||
|
|
||||||
|
cleanup = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
s_CoreAssembly = LoadAssembly("assets/scripts/Prism-ScriptCore.dll");
|
||||||
|
s_CoreAssemblyImage = GetAssemblyImage(s_CoreAssembly);
|
||||||
|
|
||||||
|
auto appAssembly = LoadAssembly(path);
|
||||||
|
auto appAssemblyImage = GetAssemblyImage(appAssembly);
|
||||||
|
ScriptEngineRegistry::RegisterAll();
|
||||||
|
|
||||||
|
if (cleanup)
|
||||||
|
{
|
||||||
|
mono_domain_unload(s_MonoDomain);
|
||||||
|
s_MonoDomain = domain;
|
||||||
|
}
|
||||||
|
|
||||||
|
s_AppAssembly = appAssembly;
|
||||||
|
s_AppAssemblyImage = appAssemblyImage;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScriptEngine::ReloadAssembly(const std::string& path)
|
||||||
|
{
|
||||||
|
LoadPrismRuntimeAssembly(path);
|
||||||
|
if (s_EntityInstanceMap.size())
|
||||||
|
{
|
||||||
|
Ref<Scene> scene = ScriptEngine::GetCurrentSceneContext();
|
||||||
|
PM_CORE_ASSERT(scene, "No active scene!");
|
||||||
|
if (s_EntityInstanceMap.find(scene->GetUUID()) != s_EntityInstanceMap.end())
|
||||||
|
{
|
||||||
|
auto& entityMap = s_EntityInstanceMap.at(scene->GetUUID());
|
||||||
|
for (auto&[entityID, entityInstanceData]: entityMap)
|
||||||
|
{
|
||||||
|
const auto& interalEntityMap = scene->GetEntityMap();
|
||||||
|
PM_CORE_ASSERT(entityMap.find(entityID) != entityMap.end(), "Invalid entity ID or entity doesn't exist in scene!");
|
||||||
|
InitScriptEntity(interalEntityMap.at(entityID));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScriptEngine::SetSceneContext(const Ref<Scene>& scene)
|
||||||
|
{
|
||||||
|
s_SceneContext = scene;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Ref<Scene>& ScriptEngine::GetCurrentSceneContext()
|
||||||
|
{
|
||||||
|
return s_SceneContext;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScriptEngine::CopyEntityScriptData(UUID dst, UUID src)
|
||||||
|
{
|
||||||
|
PM_CORE_ASSERT(s_EntityInstanceMap.find(dst) != s_EntityInstanceMap.end());
|
||||||
|
PM_CORE_ASSERT(s_EntityInstanceMap.find(src) != s_EntityInstanceMap.end());
|
||||||
|
|
||||||
|
auto& dstEntityMap = s_EntityInstanceMap.at(dst);
|
||||||
|
auto& srcEntityMap = s_EntityInstanceMap.at(src);
|
||||||
|
|
||||||
|
for (auto& [entityID, entityInstanceData] : srcEntityMap)
|
||||||
|
{
|
||||||
|
for (auto& [moduleName, srcFieldMap] : srcEntityMap[entityID].ModuleFieldMap)
|
||||||
|
{
|
||||||
|
auto& dstModuleFieldMap = dstEntityMap[entityID].ModuleFieldMap;
|
||||||
|
for (auto& [fieldName, field] : srcFieldMap)
|
||||||
|
{
|
||||||
|
PM_CORE_ASSERT(dstModuleFieldMap.find(moduleName) != dstModuleFieldMap.end());
|
||||||
|
auto& fieldMap = dstModuleFieldMap.at(moduleName);
|
||||||
|
PM_CORE_ASSERT(fieldMap.find(fieldName) != fieldMap.end());
|
||||||
|
fieldMap.at(fieldName).SetStoredValueRaw(field.m_StoredValueBuffer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ScriptEngine::OnCreateEntity(Entity entity)
|
void ScriptEngine::OnCreateEntity(Entity entity)
|
||||||
{
|
{
|
||||||
EntityInstance& entityInstance = s_EntityInstanceMap[(uint32_t)entity.m_EntityHandle];
|
OnCreateEntity(entity.m_Scene->GetUUID(), entity.GetComponent<IDComponent>().ID);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScriptEngine::OnCreateEntity(UUID sceneID, UUID entityID)
|
||||||
|
{
|
||||||
|
EntityInstance& entityInstance = GetEntityInstanceData(sceneID, entityID).Instance;
|
||||||
if (entityInstance.ScriptClass->OnCreateMethod)
|
if (entityInstance.ScriptClass->OnCreateMethod)
|
||||||
CallMethod(entityInstance.GetInstance(), entityInstance.ScriptClass->OnCreateMethod);
|
CallMethod(entityInstance.GetInstance(), entityInstance.ScriptClass->OnCreateMethod);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ScriptEngine::OnUpdateEntity(uint32_t entityID, TimeStep ts)
|
void ScriptEngine::OnUpdateEntity(UUID sceneID, UUID entityID, TimeStep ts)
|
||||||
{
|
{
|
||||||
PM_CORE_ASSERT(s_EntityInstanceMap.find(entityID) != s_EntityInstanceMap.end(), "Could not find entity in instance map!");
|
EntityInstance& entityInstance = GetEntityInstanceData(sceneID, entityID).Instance;
|
||||||
|
if (entityInstance.ScriptClass->OnUpdateMethod)
|
||||||
auto& entity = s_EntityInstanceMap[entityID];
|
|
||||||
|
|
||||||
if (entity.ScriptClass->OnUpdateMethod)
|
|
||||||
{
|
{
|
||||||
void* args[] = { &ts };
|
void* args[] = { &ts };
|
||||||
CallMethod(entity.GetInstance(), entity.ScriptClass->OnUpdateMethod, args);
|
CallMethod(entityInstance.GetInstance(), entityInstance.ScriptClass->OnUpdateMethod, args);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static FieldType GetPrismFieldType(MonoType* monoType)
|
void ScriptEngine::OnScriptComponentDestroyed(UUID sceneID, UUID entityID)
|
||||||
{
|
{
|
||||||
int type = mono_type_get_type(monoType);
|
PM_CORE_ASSERT(s_EntityInstanceMap.find(sceneID) != s_EntityInstanceMap.end());
|
||||||
switch (type)
|
auto& entityMap = s_EntityInstanceMap.at(sceneID);
|
||||||
{
|
PM_CORE_ASSERT(entityMap.find(entityID) != entityMap.end());
|
||||||
case MONO_TYPE_R4: return FieldType::Float;
|
entityMap.erase(entityID);
|
||||||
case MONO_TYPE_I4: return FieldType::Int;
|
|
||||||
case MONO_TYPE_U4: return FieldType::UnsignedInt;
|
|
||||||
case MONO_TYPE_STRING: return FieldType::String;
|
|
||||||
case MONO_TYPE_VALUETYPE:
|
|
||||||
{
|
|
||||||
char* name = mono_type_get_name(monoType);
|
|
||||||
if (strcmp(name, "Prism.Vector2") == 0) return FieldType::Vec2;
|
|
||||||
if (strcmp(name, "Prism.Vector3") == 0) return FieldType::Vec3;
|
|
||||||
if (strcmp(name, "Prism.Vector4") == 0) return FieldType::Vec4;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return FieldType::None;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ScriptEngine::OnInitEntity(ScriptComponent& script, uint32_t entityID, uint32_t sceneID)
|
bool ScriptEngine::ModuleExists(const std::string& moduleName)
|
||||||
{
|
{
|
||||||
EntityScriptClass& scriptClass = s_EntityClassMap[script.ModuleName];
|
std::string NamespaceName, ClassName;
|
||||||
scriptClass.FullName = script.ModuleName;
|
if (moduleName.find('.') != std::string::npos)
|
||||||
if (script.ModuleName.find('.') != std::string::npos)
|
|
||||||
{
|
{
|
||||||
scriptClass.NamespaceName = script.ModuleName.substr(0, script.ModuleName.find_last_of('.'));
|
NamespaceName = moduleName.substr(0, moduleName.find_last_of('.'));
|
||||||
scriptClass.ClassName = script.ModuleName.substr(script.ModuleName.find_last_of('.') + 1);
|
ClassName = moduleName.substr(moduleName.find_last_of('.') + 1);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
scriptClass.ClassName = script.ModuleName;
|
ClassName = moduleName;
|
||||||
|
}
|
||||||
|
|
||||||
|
const MonoClass* monoClass = mono_class_from_name(s_AppAssemblyImage, NamespaceName.c_str(), ClassName.c_str());
|
||||||
|
return monoClass != nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScriptEngine::InitScriptEntity(Entity entity)
|
||||||
|
{
|
||||||
|
const Scene* scene = entity.m_Scene;
|
||||||
|
const UUID id = entity.GetComponent<IDComponent>().ID;
|
||||||
|
auto& moduleName = entity.GetComponent<ScriptComponent>().ModuleName;
|
||||||
|
if (moduleName.empty())
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!ModuleExists(moduleName))
|
||||||
|
{
|
||||||
|
PM_CORE_ERROR("Entity references non-existent script module '{0}'", moduleName);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
EntityScriptClass& scriptClass = s_EntityClassMap[moduleName];
|
||||||
|
scriptClass.FullName = moduleName;
|
||||||
|
if (moduleName.find('.') != std::string::npos)
|
||||||
|
{
|
||||||
|
scriptClass.NamespaceName = moduleName.substr(0, moduleName.find_last_of('.'));
|
||||||
|
scriptClass.ClassName = moduleName.substr(moduleName.find_last_of('.') + 1);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
scriptClass.ClassName = moduleName;
|
||||||
}
|
}
|
||||||
|
|
||||||
scriptClass.Class = GetClass(s_AppAssemblyImage, scriptClass);
|
scriptClass.Class = GetClass(s_AppAssemblyImage, scriptClass);
|
||||||
scriptClass.InitClassMethods(s_AppAssemblyImage);
|
scriptClass.InitClassMethods(s_AppAssemblyImage);
|
||||||
|
|
||||||
EntityInstance& entityInstance = s_EntityInstanceMap[entityID];
|
EntityInstanceData& entityInstanceData = s_EntityInstanceMap[scene->GetUUID()][id];
|
||||||
|
EntityInstance& entityInstance = entityInstanceData.Instance;
|
||||||
entityInstance.ScriptClass = &scriptClass;
|
entityInstance.ScriptClass = &scriptClass;
|
||||||
entityInstance.Handle = Instantiate(scriptClass);
|
ScriptModuleFieldMap& moduleFieldMap = entityInstanceData.ModuleFieldMap;
|
||||||
|
auto& fieldMap = moduleFieldMap[moduleName];
|
||||||
|
|
||||||
MonoProperty* entityIDPropery = mono_class_get_property_from_name(scriptClass.Class, "EntityID");
|
// Save old fields
|
||||||
mono_property_get_get_method(entityIDPropery);
|
std::unordered_map<std::string, PublicField> oldFields;
|
||||||
MonoMethod* entityIDSetMethod = mono_property_get_set_method(entityIDPropery);
|
oldFields.reserve(fieldMap.size());
|
||||||
void* param[] = { &entityID };
|
for (auto& [fieldName, field] : fieldMap)
|
||||||
CallMethod(entityInstance.GetInstance(), entityIDSetMethod, param);
|
oldFields.emplace(fieldName, std::move(field));
|
||||||
|
fieldMap.clear();
|
||||||
|
|
||||||
MonoProperty* sceneIDPropery = mono_class_get_property_from_name(scriptClass.Class, "SceneID");
|
// Retrieve public fields (TODO: cache these fields if the module is used more than once)
|
||||||
mono_property_get_get_method(sceneIDPropery);
|
|
||||||
MonoMethod* sceneIDSetMethod = mono_property_get_set_method(sceneIDPropery);
|
|
||||||
param[0] = { &sceneID };
|
|
||||||
CallMethod(entityInstance.GetInstance(), sceneIDSetMethod, param);
|
|
||||||
|
|
||||||
if (scriptClass.OnCreateMethod)
|
|
||||||
CallMethod(entityInstance.GetInstance(), scriptClass.OnCreateMethod);
|
|
||||||
|
|
||||||
// Retrieve public fields
|
|
||||||
{
|
{
|
||||||
MonoClassField* iter;
|
MonoClassField* iter;
|
||||||
void* ptr = 0;
|
void* ptr = 0;
|
||||||
@ -340,35 +520,171 @@ namespace Prism
|
|||||||
{
|
{
|
||||||
const char* name = mono_field_get_name(iter);
|
const char* name = mono_field_get_name(iter);
|
||||||
const uint32_t flags = mono_field_get_flags(iter);
|
const uint32_t flags = mono_field_get_flags(iter);
|
||||||
if ((flags & MONO_FIELD_ATTR_PUBLIC )== 0)
|
if ((flags & MONO_FIELD_ATTR_PUBLIC) == 0)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
MonoType* fieldType = mono_field_get_type(iter);
|
MonoType* fieldType = mono_field_get_type(iter);
|
||||||
FieldType hazelFieldType = GetPrismFieldType(fieldType);
|
const FieldType prismFieldType = GetPrismFieldType(fieldType);
|
||||||
|
|
||||||
// TODO: Attributes
|
// TODO: Attributes
|
||||||
// MonoCustomAttrInfo* attr = mono_custom_attrs_from_field(scriptClass.Class, iter);
|
MonoCustomAttrInfo* attr = mono_custom_attrs_from_field(scriptClass.Class, iter);
|
||||||
|
|
||||||
auto& publicField = s_PublicFields[script.ModuleName].emplace_back(name, hazelFieldType);
|
if (oldFields.find(name) != oldFields.end())
|
||||||
publicField.m_EntityInstance = &entityInstance;
|
{
|
||||||
publicField.m_MonoClassField = iter;
|
fieldMap.emplace(name, std::move(oldFields.at(name)));
|
||||||
// mono_field_set_value(entityInstance.Instance, iter, )
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
PublicField field = { name, prismFieldType };
|
||||||
|
field.m_EntityInstance = &entityInstance;
|
||||||
|
field.m_MonoClassField = iter;
|
||||||
|
fieldMap.emplace(name, std::move(field));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const ScriptModuleFieldMap& ScriptEngine::GetFieldMap()
|
void ScriptEngine::ShutdownScriptEntity(Entity entity, const std::string& moduleName)
|
||||||
{
|
{
|
||||||
return s_PublicFields;
|
EntityInstanceData& entityInstanceData = GetEntityInstanceData(entity.GetSceneUUID(), entity.GetUUID());
|
||||||
|
ScriptModuleFieldMap& moduleFieldMap = entityInstanceData.ModuleFieldMap;
|
||||||
|
if (moduleFieldMap.find(moduleName) != moduleFieldMap.end())
|
||||||
|
moduleFieldMap.erase(moduleName);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PublicField::SetValue_Internal(void* value) const
|
void ScriptEngine::InstantiateEntityClass(Entity entity)
|
||||||
{
|
{
|
||||||
mono_field_set_value(m_EntityInstance->GetInstance(), m_MonoClassField, value);
|
const Scene* scene = entity.m_Scene;
|
||||||
|
UUID id = entity.GetComponent<IDComponent>().ID;
|
||||||
|
const auto& moduleName = entity.GetComponent<ScriptComponent>().ModuleName;
|
||||||
|
|
||||||
|
EntityInstanceData& entityInstanceData = GetEntityInstanceData(scene->GetUUID(), id);
|
||||||
|
EntityInstance& entityInstance = entityInstanceData.Instance;
|
||||||
|
PM_CORE_ASSERT(entityInstance.ScriptClass);
|
||||||
|
entityInstance.Handle = Instantiate(*entityInstance.ScriptClass);
|
||||||
|
|
||||||
|
MonoProperty* entityIDPropery = mono_class_get_property_from_name(entityInstance.ScriptClass->Class, "ID");
|
||||||
|
mono_property_get_get_method(entityIDPropery);
|
||||||
|
MonoMethod* entityIDSetMethod = mono_property_get_set_method(entityIDPropery);
|
||||||
|
void* param[] = { &id };
|
||||||
|
CallMethod(entityInstance.GetInstance(), entityIDSetMethod, param);
|
||||||
|
|
||||||
|
// Set all public fields to appropriate values
|
||||||
|
ScriptModuleFieldMap& moduleFieldMap = entityInstanceData.ModuleFieldMap;
|
||||||
|
if (moduleFieldMap.find(moduleName) != moduleFieldMap.end())
|
||||||
|
{
|
||||||
|
auto& publicFields = moduleFieldMap.at(moduleName);
|
||||||
|
for (auto&[name, field] : publicFields)
|
||||||
|
field.CopyStoredValueToRuntime();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Call OnCreate function (if exists)
|
||||||
|
OnCreateEntity(entity);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PublicField::GetValue_Internal(void* outValue) const
|
EntityInstanceMap& ScriptEngine::GetEntityInstanceMap()
|
||||||
{
|
{
|
||||||
mono_field_get_value(m_EntityInstance->GetInstance(), m_MonoClassField, outValue);
|
return s_EntityInstanceMap;
|
||||||
|
}
|
||||||
|
|
||||||
|
EntityInstanceData& ScriptEngine::GetEntityInstanceData(UUID sceneID, UUID entityID)
|
||||||
|
{
|
||||||
|
PM_CORE_ASSERT(s_EntityInstanceMap.find(sceneID) != s_EntityInstanceMap.end(), "Invalid scene ID!");
|
||||||
|
auto& entityIDMap = s_EntityInstanceMap.at(sceneID);
|
||||||
|
PM_CORE_ASSERT(entityIDMap.find(entityID) != entityIDMap.end(), "Invalid entity ID!");
|
||||||
|
return entityIDMap.at(entityID);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScriptEngine::OnImGuiRender()
|
||||||
|
{
|
||||||
|
ImGui::Begin("Script Engine Debug");
|
||||||
|
for (auto& [sceneID, entityMap] : s_EntityInstanceMap)
|
||||||
|
{
|
||||||
|
bool opened = ImGui::TreeNode((void*)(uint64_t)sceneID, "Scene (%llx)", sceneID);
|
||||||
|
if (opened)
|
||||||
|
{
|
||||||
|
Ref<Scene> scene = Scene::GetScene(sceneID);
|
||||||
|
for (auto& [entityID, entityInstanceData] : entityMap)
|
||||||
|
{
|
||||||
|
Entity entity = scene->GetScene(sceneID)->GetEntityMap().at(entityID);
|
||||||
|
std::string entityName = "Unnamed Entity";
|
||||||
|
if (entity.HasComponent<TagComponent>())
|
||||||
|
entityName = entity.GetComponent<TagComponent>().Tag;
|
||||||
|
opened = ImGui::TreeNode((void*)(uint64_t)entityID, "%s (%llx)", entityName.c_str(), entityID);
|
||||||
|
if (opened)
|
||||||
|
{
|
||||||
|
for (auto& [moduleName, fieldMap] : entityInstanceData.ModuleFieldMap)
|
||||||
|
{
|
||||||
|
opened = ImGui::TreeNode(moduleName.c_str());
|
||||||
|
if (opened)
|
||||||
|
{
|
||||||
|
for (auto& [fieldName, field] : fieldMap)
|
||||||
|
{
|
||||||
|
|
||||||
|
opened = ImGui::TreeNodeEx((void*)&field, ImGuiTreeNodeFlags_Leaf , fieldName.c_str());
|
||||||
|
if (opened)
|
||||||
|
{
|
||||||
|
|
||||||
|
ImGui::TreePop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ImGui::TreePop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ImGui::TreePop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ImGui::TreePop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ImGui::End();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
MonoObject* EntityInstance::GetInstance()
|
||||||
|
{
|
||||||
|
PM_CORE_ASSERT(Handle, "Entity has not been instantiated!");
|
||||||
|
return mono_gchandle_get_target(Handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
PublicField::PublicField(const std::string& name, FieldType type)
|
||||||
|
: Name(name), Type(type)
|
||||||
|
{
|
||||||
|
m_StoredValueBuffer = AllocateBuffer(type);
|
||||||
|
}
|
||||||
|
|
||||||
|
PublicField::PublicField(PublicField&& other)
|
||||||
|
{
|
||||||
|
Name = std::move(other.Name);
|
||||||
|
Type = other.Type;
|
||||||
|
m_EntityInstance = other.m_EntityInstance;
|
||||||
|
m_MonoClassField = other.m_MonoClassField;
|
||||||
|
m_StoredValueBuffer = other.m_StoredValueBuffer;
|
||||||
|
|
||||||
|
other.m_EntityInstance = nullptr;
|
||||||
|
other.m_MonoClassField = nullptr;
|
||||||
|
other.m_StoredValueBuffer = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
PublicField::~PublicField()
|
||||||
|
{
|
||||||
|
delete[] m_StoredValueBuffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PublicField::CopyStoredValueToRuntime()
|
||||||
|
{
|
||||||
|
PM_CORE_ASSERT(m_EntityInstance->GetInstance());
|
||||||
|
mono_field_set_value(m_EntityInstance->GetInstance(), m_MonoClassField, m_StoredValueBuffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool PublicField::IsRuntimeAvailable() const
|
||||||
|
{
|
||||||
|
return m_EntityInstance->Handle != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PublicField::SetStoredValueRaw(void* src)
|
||||||
|
{
|
||||||
|
uint32_t size = GetFieldSize(Type);
|
||||||
|
memcpy(m_StoredValueBuffer, src, size);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -19,56 +19,118 @@ namespace Prism
|
|||||||
None = 0, Float, Int, UnsignedInt, String, Vec2, Vec3, Vec4
|
None = 0, Float, Int, UnsignedInt, String, Vec2, Vec3, Vec4
|
||||||
};
|
};
|
||||||
|
|
||||||
struct EntityInstance;
|
const char* FieldTypeToString(FieldType type);
|
||||||
|
|
||||||
|
struct EntityScriptClass;
|
||||||
|
struct EntityInstance
|
||||||
|
{
|
||||||
|
EntityScriptClass* ScriptClass = nullptr;
|
||||||
|
|
||||||
|
uint32_t Handle = 0;
|
||||||
|
Scene* SceneInstance = nullptr;
|
||||||
|
|
||||||
|
MonoObject* GetInstance();
|
||||||
|
};
|
||||||
|
|
||||||
struct PublicField
|
struct PublicField
|
||||||
{
|
{
|
||||||
std::string Name;
|
std::string Name;
|
||||||
FieldType Type;
|
FieldType Type;
|
||||||
|
|
||||||
PublicField(const std::string& name, FieldType type)
|
PublicField(const std::string& name, FieldType type);
|
||||||
: Name(name), Type(type)
|
PublicField(const PublicField&) = delete;
|
||||||
|
PublicField(PublicField&& other);
|
||||||
|
~PublicField();
|
||||||
|
|
||||||
|
void CopyStoredValueToRuntime();
|
||||||
|
bool IsRuntimeAvailable() const;
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
T GetStoredValue() const
|
||||||
{
|
{
|
||||||
|
T value;
|
||||||
|
GetStoredValue_Internal(&value);
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
void SetStoredValue(T value) const
|
||||||
|
{
|
||||||
|
SetStoredValue_Internal(&value);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
T GetValue() const
|
T GetRuntimeValue() const
|
||||||
{
|
{
|
||||||
T value;
|
T value;
|
||||||
GetValue_Internal(&value);
|
GetRuntimeValue_Internal(&value);
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
void SetValue(T value) const
|
void SetRuntimeValue(T value) const
|
||||||
{
|
{
|
||||||
SetValue_Internal(&value);
|
SetRuntimeValue_Internal(&value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SetStoredValueRaw(void* src);
|
||||||
private:
|
private:
|
||||||
EntityInstance* m_EntityInstance;
|
EntityInstance* m_EntityInstance;
|
||||||
MonoClassField* m_MonoClassField;
|
MonoClassField* m_MonoClassField;
|
||||||
|
uint8_t* m_StoredValueBuffer = nullptr;
|
||||||
|
|
||||||
void SetValue_Internal(void* value) const;
|
uint8_t* AllocateBuffer(FieldType type);
|
||||||
void GetValue_Internal(void* outValue) const;
|
void SetStoredValue_Internal(void* value) const;
|
||||||
|
void GetStoredValue_Internal(void* outValue) const;
|
||||||
|
void SetRuntimeValue_Internal(void* value) const;
|
||||||
|
void GetRuntimeValue_Internal(void* outValue) const;
|
||||||
|
|
||||||
friend class ScriptEngine;
|
friend class ScriptEngine;
|
||||||
};
|
};
|
||||||
|
|
||||||
using ScriptModuleFieldMap = std::unordered_map<std::string, std::vector<PublicField>>;
|
// using ScriptModuleFieldMap = std::unordered_map<std::string, std::vector<PublicField>>;
|
||||||
|
using ScriptModuleFieldMap = std::unordered_map<std::string, std::unordered_map<std::string, PublicField>>;
|
||||||
|
struct EntityInstanceData
|
||||||
|
{
|
||||||
|
EntityInstance Instance;
|
||||||
|
ScriptModuleFieldMap ModuleFieldMap;
|
||||||
|
};
|
||||||
|
|
||||||
class ScriptEngine
|
using EntityInstanceMap = std::unordered_map<UUID, std::unordered_map<UUID, EntityInstanceData>>;
|
||||||
|
|
||||||
|
class PRISM_API ScriptEngine
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
static void Init(const std::string& assemblyPath);
|
static void Init(const std::string& assemblyPath);
|
||||||
static void Shutdown();
|
static void Shutdown();
|
||||||
|
|
||||||
|
static void OnSceneDestruct(UUID sceneID);
|
||||||
|
|
||||||
|
static void LoadPrismRuntimeAssembly(const std::string& path);
|
||||||
|
static void ReloadAssembly(const std::string& path);
|
||||||
|
|
||||||
|
static void SetSceneContext(const Ref<Scene>& scene);
|
||||||
|
static const Ref<Scene>& GetCurrentSceneContext();
|
||||||
|
|
||||||
|
static void CopyEntityScriptData(UUID dst, UUID src);
|
||||||
|
|
||||||
static void OnCreateEntity(Entity entity);
|
static void OnCreateEntity(Entity entity);
|
||||||
static void OnUpdateEntity(uint32_t entityID, TimeStep ts);
|
static void OnCreateEntity(UUID sceneID, UUID entityID);
|
||||||
|
static void OnUpdateEntity(UUID sceneID, UUID entityID, TimeStep ts);
|
||||||
|
|
||||||
static void OnInitEntity(ScriptComponent& script, uint32_t entityID, uint32_t sceneID);
|
static void OnScriptComponentDestroyed(UUID sceneID, UUID entityID);
|
||||||
|
|
||||||
static const ScriptModuleFieldMap& GetFieldMap();
|
static bool ModuleExists(const std::string& moduleName);
|
||||||
|
static void InitScriptEntity(Entity entity);
|
||||||
|
|
||||||
|
static void ShutdownScriptEntity(Entity entity, const std::string& moduleName);
|
||||||
|
static void InstantiateEntityClass(Entity entity);
|
||||||
|
|
||||||
|
static EntityInstanceMap& GetEntityInstanceMap();
|
||||||
|
static EntityInstanceData& GetEntityInstanceData(UUID sceneID, UUID entityID);
|
||||||
|
|
||||||
|
// Debug
|
||||||
|
static void OnImGuiRender();
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -4,6 +4,7 @@
|
|||||||
|
|
||||||
#include "ScriptWarppers.h"
|
#include "ScriptWarppers.h"
|
||||||
|
|
||||||
|
#include "ScriptEngine.h"
|
||||||
#include "mono/metadata/metadata.h"
|
#include "mono/metadata/metadata.h"
|
||||||
#include "mono/metadata/object.h"
|
#include "mono/metadata/object.h"
|
||||||
#include "mono/metadata/reflection.h"
|
#include "mono/metadata/reflection.h"
|
||||||
@ -14,7 +15,6 @@
|
|||||||
|
|
||||||
|
|
||||||
namespace Prism {
|
namespace Prism {
|
||||||
extern std::unordered_map<uint32_t, Scene*> s_ActiveScenes;
|
|
||||||
extern std::unordered_map<MonoType*, std::function<bool(Entity&)>> s_HasComponentFuncs;
|
extern std::unordered_map<MonoType*, std::function<bool(Entity&)>> s_HasComponentFuncs;
|
||||||
extern std::unordered_map<MonoType*, std::function<void(Entity&)>> s_CreateComponentFuncs;
|
extern std::unordered_map<MonoType*, std::function<void(Entity&)>> s_CreateComponentFuncs;
|
||||||
}
|
}
|
||||||
@ -58,63 +58,75 @@ namespace Prism { namespace Script {
|
|||||||
// Entity //////////////////////////////////////////////////////
|
// Entity //////////////////////////////////////////////////////
|
||||||
////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
void Prism_Entity_GetTransform(uint32_t sceneID, uint32_t entityID, glm::mat4* outTransform)
|
void Prism_Entity_GetTransform(uint64_t entityID, glm::mat4* outTransform)
|
||||||
{
|
{
|
||||||
PM_CORE_ASSERT(s_ActiveScenes.find(sceneID) != s_ActiveScenes.end(), "Invalid Scene ID!");
|
Ref<Scene> scene = ScriptEngine::GetCurrentSceneContext();
|
||||||
|
PM_CORE_ASSERT(scene, "No active scene!");
|
||||||
|
const auto& entityMap = scene->GetEntityMap();
|
||||||
|
PM_CORE_ASSERT(entityMap.find(entityID) != entityMap.end(), "Invalid entity ID or entity doesn't exist in scene!");
|
||||||
|
|
||||||
Scene* scene = s_ActiveScenes[sceneID];
|
Entity entity = entityMap.at(entityID);
|
||||||
Entity entity((entt::entity)entityID, scene);
|
|
||||||
auto& transformComponent = entity.GetComponent<TransformComponent>();
|
auto& transformComponent = entity.GetComponent<TransformComponent>();
|
||||||
memcpy(outTransform, glm::value_ptr(transformComponent.Transform), sizeof(glm::mat4));
|
memcpy(outTransform, glm::value_ptr(transformComponent.Transform), sizeof(glm::mat4));
|
||||||
}
|
}
|
||||||
|
|
||||||
void Prism_Entity_SetTransform(uint32_t sceneID, uint32_t entityID, glm::mat4* inTransform)
|
void Prism_Entity_SetTransform(uint64_t entityID, glm::mat4* inTransform)
|
||||||
{
|
{
|
||||||
PM_CORE_ASSERT(s_ActiveScenes.find(sceneID) != s_ActiveScenes.end(), "Invalid Scene ID!");
|
Ref<Scene> scene = ScriptEngine::GetCurrentSceneContext();
|
||||||
|
PM_CORE_ASSERT(scene, "No active scene!");
|
||||||
|
const auto& entityMap = scene->GetEntityMap();
|
||||||
|
PM_CORE_ASSERT(entityMap.find(entityID) != entityMap.end(), "Invalid entity ID or entity doesn't exist in scene!");
|
||||||
|
|
||||||
Scene* scene = s_ActiveScenes[sceneID];
|
Entity entity = entityMap.at(entityID);
|
||||||
Entity entity((entt::entity)entityID, scene);
|
|
||||||
auto& transformComponent = entity.GetComponent<TransformComponent>();
|
auto& transformComponent = entity.GetComponent<TransformComponent>();
|
||||||
memcpy(glm::value_ptr(transformComponent.Transform), inTransform, sizeof(glm::mat4));
|
memcpy(glm::value_ptr(transformComponent.Transform), inTransform, sizeof(glm::mat4));
|
||||||
}
|
}
|
||||||
|
|
||||||
void Prism_Entity_CreateComponent(uint32_t sceneID, uint32_t entityID, void* type)
|
void Prism_Entity_CreateComponent(uint64_t entityID, void* type)
|
||||||
{
|
{
|
||||||
PM_CORE_ASSERT(s_ActiveScenes.find(sceneID) != s_ActiveScenes.end(), "Invalid Scene ID!");
|
Ref<Scene> scene = ScriptEngine::GetCurrentSceneContext();
|
||||||
MonoType* monoType = mono_reflection_type_get_type((MonoReflectionType*)type);
|
PM_CORE_ASSERT(scene, "No active scene!");
|
||||||
|
const auto& entityMap = scene->GetEntityMap();
|
||||||
|
PM_CORE_ASSERT(entityMap.find(entityID) != entityMap.end(), "Invalid entity ID or entity doesn't exist in scene!");
|
||||||
|
|
||||||
Scene* scene = s_ActiveScenes[sceneID];
|
Entity entity = entityMap.at(entityID);
|
||||||
Entity entity((entt::entity)entityID, scene);
|
MonoType* monoType = mono_reflection_type_get_type((MonoReflectionType*)type);
|
||||||
s_CreateComponentFuncs[monoType](entity);
|
s_CreateComponentFuncs[monoType](entity);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Prism_Entity_HasComponent(uint32_t sceneID, uint32_t entityID, void* type)
|
bool Prism_Entity_HasComponent(uint64_t entityID, void* type)
|
||||||
{
|
{
|
||||||
PM_CORE_ASSERT(s_ActiveScenes.find(sceneID) != s_ActiveScenes.end(), "Invalid Scene ID!");
|
Ref<Scene> scene = ScriptEngine::GetCurrentSceneContext();
|
||||||
MonoType* monoType = mono_reflection_type_get_type((MonoReflectionType*)type);
|
PM_CORE_ASSERT(scene, "No active scene!");
|
||||||
|
const auto& entityMap = scene->GetEntityMap();
|
||||||
|
PM_CORE_ASSERT(entityMap.find(entityID) != entityMap.end(), "Invalid entity ID or entity doesn't exist in scene!");
|
||||||
|
|
||||||
Scene* scene = s_ActiveScenes[sceneID];
|
Entity entity = entityMap.at(entityID);
|
||||||
Entity entity((entt::entity)entityID, scene);
|
MonoType* monoType = mono_reflection_type_get_type((MonoReflectionType*)type);
|
||||||
bool result = s_HasComponentFuncs[monoType](entity);
|
bool result = s_HasComponentFuncs[monoType](entity);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
void* Prism_MeshComponent_GetMesh(uint32_t sceneID, uint32_t entityID)
|
void* Prism_MeshComponent_GetMesh(uint64_t entityID)
|
||||||
{
|
{
|
||||||
PM_CORE_ASSERT(s_ActiveScenes.find(sceneID) != s_ActiveScenes.end(), "Invalid Scene ID!");
|
Ref<Scene> scene = ScriptEngine::GetCurrentSceneContext();
|
||||||
|
PM_CORE_ASSERT(scene, "No active scene!");
|
||||||
|
const auto& entityMap = scene->GetEntityMap();
|
||||||
|
PM_CORE_ASSERT(entityMap.find(entityID) != entityMap.end(), "Invalid entity ID or entity doesn't exist in scene!");
|
||||||
|
|
||||||
Scene* scene = s_ActiveScenes[sceneID];
|
Entity entity = entityMap.at(entityID);
|
||||||
Entity entity((entt::entity)entityID, scene);
|
const auto& meshComponent = entity.GetComponent<MeshComponent>();
|
||||||
auto& meshComponent = entity.GetComponent<MeshComponent>();
|
|
||||||
return new Ref<Mesh>(meshComponent.Mesh);
|
return new Ref<Mesh>(meshComponent.Mesh);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Prism_MeshComponent_SetMesh(uint32_t sceneID, uint32_t entityID, Ref<Mesh>* inMesh)
|
void Prism_MeshComponent_SetMesh(uint64_t entityID, Ref<Mesh>* inMesh)
|
||||||
{
|
{
|
||||||
PM_CORE_ASSERT(s_ActiveScenes.find(sceneID) != s_ActiveScenes.end(), "Invalid Scene ID!");
|
Ref<Scene> scene = ScriptEngine::GetCurrentSceneContext();
|
||||||
|
PM_CORE_ASSERT(scene, "No active scene!");
|
||||||
|
const auto& entityMap = scene->GetEntityMap();
|
||||||
|
PM_CORE_ASSERT(entityMap.find(entityID) != entityMap.end(), "Invalid entity ID or entity doesn't exist in scene!");
|
||||||
|
|
||||||
Scene* scene = s_ActiveScenes[sceneID];
|
Entity entity = entityMap.at(entityID);
|
||||||
Entity entity((entt::entity)entityID, scene);
|
|
||||||
auto& meshComponent = entity.GetComponent<MeshComponent>();
|
auto& meshComponent = entity.GetComponent<MeshComponent>();
|
||||||
meshComponent.Mesh = inMesh ? *inMesh : nullptr;
|
meshComponent.Mesh = inMesh ? *inMesh : nullptr;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -24,13 +24,13 @@ namespace Prism { namespace Script {
|
|||||||
bool Prism_Input_IsKeyPressed(KeyCode key);
|
bool Prism_Input_IsKeyPressed(KeyCode key);
|
||||||
|
|
||||||
// Entity
|
// Entity
|
||||||
void Prism_Entity_GetTransform(uint32_t sceneID, uint32_t entityID, glm::mat4* outTransform);
|
void Prism_Entity_GetTransform(uint64_t entityID, glm::mat4* outTransform);
|
||||||
void Prism_Entity_SetTransform(uint32_t sceneID, uint32_t entityID, glm::mat4* inTransform);
|
void Prism_Entity_SetTransform(uint64_t entityID, glm::mat4* inTransform);
|
||||||
void Prism_Entity_CreateComponent(uint32_t sceneID, uint32_t entityID, void* type);
|
void Prism_Entity_CreateComponent(uint64_t entityID, void* type);
|
||||||
bool Prism_Entity_HasComponent(uint32_t sceneID, uint32_t entityID, void* type);
|
bool Prism_Entity_HasComponent(uint64_t entityID, void* type);
|
||||||
|
|
||||||
void* Prism_MeshComponent_GetMesh(uint32_t sceneID, uint32_t entityID);
|
void* Prism_MeshComponent_GetMesh(uint64_t entityID);
|
||||||
void Prism_MeshComponent_SetMesh(uint32_t sceneID, uint32_t entityID, Ref<Mesh>* inMesh);
|
void Prism_MeshComponent_SetMesh(uint64_t entityID, Ref<Mesh>* inMesh);
|
||||||
|
|
||||||
// Renderer
|
// Renderer
|
||||||
// Texture2D
|
// Texture2D
|
||||||
|
|||||||
1
Prism/vendor/yaml-cpp
vendored
Submodule
1
Prism/vendor/yaml-cpp
vendored
Submodule
Submodule Prism/vendor/yaml-cpp added at bbf8bdb087
Reference in New Issue
Block a user