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:
2025-12-09 16:30:53 +08:00
parent 3ffb4cc449
commit dc53f9517a
49 changed files with 2801 additions and 796 deletions

View File

@ -6,6 +6,7 @@
#include "ImGuizmo.h"
#include "Prism/Core/Input.h"
#include "Prism/Renderer/Renderer2D.h"
#include "Prism/Script/ScriptEngine.h"
namespace Prism
{
@ -119,7 +120,7 @@ namespace Prism
}
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()
{
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
m_CheckerboardTex = Texture2D::Create("assets/editor/Checkerboard.tga");
m_PlayButtonTex = Texture2D::Create("assets/editor/PlayButton.png");
// set lights
auto& light = m_Scene->GetLight();
light.Direction = { -0.5f, -0.5f, 1.0f };
light.Radiance = { 1.0f, 1.0f, 1.0f };
m_EditorScene = Ref<Scene>::Create();
ScriptEngine::SetSceneContext(m_EditorScene);
m_SceneHierarchyPanel = CreateScope<SceneHierarchyPanel>(m_EditorScene);
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()
@ -234,72 +148,61 @@ namespace Prism
void EditorLayer::OnUpdate(const TimeStep deltaTime)
{
// THINGS TO LOOK AT:
// - 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)
switch (m_SceneState)
{
Renderer::BeginRenderPass(SceneRenderer::GetFinalRenderPass(), false);
auto viewProj = m_CameraEntity.GetComponent<CameraComponent>().Camera.GetViewProjection();
Renderer2D::BeginScene(viewProj, false);
Renderer::DrawAABB(m_MeshEntity.GetComponent<MeshComponent>(), m_MeshEntity.GetComponent<TransformComponent>());
case SceneState::Edit:
{
if (m_ViewportPanelFocused)
m_EditorCamera.OnUpdate(deltaTime);
Renderer2D::EndScene();
Renderer::EndRenderPass();
}
m_EditorScene->OnRenderEditor(deltaTime, m_EditorCamera);
if (!m_SelectionContext.empty())
{
auto& selection = m_SelectionContext[0];
if (m_DrawOnTopBoundingBoxes)
{
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);
const auto viewProj = m_CameraEntity.GetComponent<CameraComponent>().Camera.GetViewProjection();
Renderer2D::BeginScene(viewProj, false);
if (m_SelectionContext.size() && 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 };
Renderer::DrawAABB(selection.Mesh->BoundingBox, selection.Entity.GetComponent<TransformComponent>().Transform * selection.Mesh->Transform, color);
if (selection.Mesh && selection.Entity.HasComponent<MeshComponent>())
{
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
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,
// 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("New Scene"))
{
}
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();
if (ImGui::MenuItem("Flag: NoDockingOverCentralNode", "",
(dockspace_flags & ImGuiDockNodeFlags_NoDockingOverCentralNode) != 0))
{
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;
}
if (ImGui::MenuItem("Reload C# Assembly"))
ScriptEngine::ReloadAssembly("assets/scripts/ExampleApp.dll");
ImGui::Separator();
if (ImGui::MenuItem("Close", NULL, false, p_open != false))
if (ImGui::MenuItem("Exit"))
p_open = false;
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();
}
m_SceneHierarchyPanel->OnImGuiRender();
ScriptEngine::OnImGuiRender();
ImGui::End();
#endif
// Editor Panel ------------------------------------------------------------------------------
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");
if (ImGui::Button("Load Environment Map"))
{
std::string filename = Application::Get().OpenFile("*.hdr");
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::AlignTextToFramePadding();
auto& light = m_Scene->GetLight();
auto& light = m_EditorScene->GetLight();
Property("Light Direction", light.Direction);
Property("Light Radiance", light.Radiance, PropertyFlag::ColorProperty);
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("Env Map Rotation", m_EnvMapRotation, -360.0f, 360.0f);
@ -500,6 +364,7 @@ namespace Prism
ImGui::Separator();
{
ImGui::Text("Mesh");
/*
auto meshComponent = m_MeshEntity.GetComponent<MeshComponent>();
std::string fullpath = meshComponent.Mesh ? meshComponent.Mesh->GetFilePath() : "None";
size_t found = fullpath.find_last_of("/\\");
@ -517,6 +382,7 @@ namespace Prism
meshComponent.Mesh = newMesh;
}
}
*/
}
ImGui::Separator();
@ -679,14 +545,57 @@ namespace Prism
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::Begin("Viewport");
m_ViewportPanelMouseOver = ImGui::IsWindowHovered();
m_ViewportPanelFocused = ImGui::IsWindowFocused();
auto viewportOffset = ImGui::GetCursorPos(); // includes tab bar
auto viewportSize = ImGui::GetContentRegionAvail();
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_CameraEntity.GetComponent<CameraComponent>().Camera.SetViewportSize((uint32_t)viewportSize.x, (uint32_t)viewportSize.y);
m_EditorScene->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 });
@ -702,7 +611,7 @@ namespace Prism
m_AllowViewportCameraEvents = ImGui::IsMouseHoveringRect(minBound, maxBound);
// ImGuizmo
if (m_GizmoType != -1 && m_CurrentlySelectedTransform)
if (m_GizmoType != -1 && !m_SelectionContext.empty())
{
auto& selection = m_SelectionContext[0];
@ -712,25 +621,24 @@ namespace Prism
ImGuizmo::SetDrawlist();
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);
auto& entityTransform = selection.Entity.Transform();
float snapValue[3] = { m_SnapValue, m_SnapValue, m_SnapValue };
if (m_SelectionMode == SelectionMode::Entity)
{
ImGuizmo::Manipulate(glm::value_ptr(camera.GetViewMatrix()),
glm::value_ptr(camera.GetProjectionMatrix()),
ImGuizmo::Manipulate(glm::value_ptr(m_EditorCamera.GetViewMatrix()),
glm::value_ptr(m_EditorCamera.GetProjectionMatrix()),
(ImGuizmo::OPERATION)m_GizmoType,
ImGuizmo::LOCAL,
glm::value_ptr(m_MeshEntity.GetComponent<TransformComponent>().Transform),
glm::value_ptr(entityTransform),
nullptr,
snap ? snapValue : nullptr);
}else
{
glm::mat4 transformBase = entityTransform * selection.Mesh->Transform;
ImGuizmo::Manipulate(glm::value_ptr(camera.GetViewMatrix()),
glm::value_ptr(camera.GetProjectionMatrix()),
ImGuizmo::Manipulate(glm::value_ptr(m_EditorCamera.GetViewMatrix()),
glm::value_ptr(m_EditorCamera.GetProjectionMatrix()),
(ImGuizmo::OPERATION)m_GizmoType,
ImGuizmo::LOCAL,
glm::value_ptr(transformBase),
@ -748,10 +656,17 @@ namespace Prism
void EditorLayer::OnEvent(Event& e)
{
/*
if (m_AllowViewportCameraEvents)
m_Scene->GetCamera().OnEvent(e);
*/
if (m_SceneState == SceneState::Edit)
{
if (m_ViewportPanelMouseOver)
m_EditorCamera.OnEvent(e);
m_EditorScene->OnEvent(e);
}
else if (m_SceneState == SceneState::Play)
{
m_RuntimeScene->OnEvent(e);
}
EventDispatcher dispatcher(e);
dispatcher.Dispatch<KeyPressedEvent>(PM_BIND_EVENT_FN(EditorLayer::OnKeyPressedEvent));
@ -760,35 +675,57 @@ namespace Prism
bool EditorLayer::OnKeyPressedEvent(KeyPressedEvent& e)
{
switch (e.GetKeyCode())
if (m_ViewportPanelFocused)
{
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::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))
switch (e.GetKeyCode())
{
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;
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;
}
@ -803,10 +740,11 @@ namespace Prism
auto [origin, direction] = CastRay(mouseX, mouseY);
m_SelectionContext.clear();
const auto meshEntities = m_Scene->GetAllEntitiesWith<MeshComponent>();
m_EditorScene->SetSelectedEntity({});
const auto meshEntities = m_EditorScene->GetAllEntitiesWith<MeshComponent>();
for (auto e : meshEntities)
{
Entity entity = { e, m_Scene.Raw() };
Entity entity = { e, m_EditorScene.Raw() };
auto mesh = entity.GetComponent<MeshComponent>().Mesh;
if (!mesh)
@ -857,6 +795,20 @@ namespace Prism
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
{
auto [mx, my] = ImGui::GetMousePos(); // Input::GetMousePosition();
@ -872,11 +824,11 @@ namespace Prism
{
const glm::vec4 mouseClipPos = { mx, my, -1.0f, 1.0f };
const auto inverseProj = glm::inverse(m_CameraEntity.GetComponent<CameraComponent>().Camera.GetProjectionMatrix());
const auto inverseView = glm::inverse(glm::mat3(m_CameraEntity.GetComponent<CameraComponent>().Camera.GetViewMatrix()));
const auto inverseProj = glm::inverse(m_EditorCamera.GetProjectionMatrix());
const auto inverseView = glm::inverse(glm::mat3(m_EditorCamera.GetViewMatrix()));
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);
return { rayPos, rayDir };
@ -885,6 +837,16 @@ namespace Prism
void EditorLayer::OnSelected(const SelectedSubmesh& selectionContext)
{
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()
@ -897,4 +859,30 @@ namespace Prism
}
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);
}
}

View File

@ -27,7 +27,7 @@ namespace Prism
bool OnMouseButtonPressedEvent(MouseButtonPressedEvent& e);
void ShowBoundingBoxes(bool show, bool onTop = false);
void SelectEntity(Entity entity);
private:
std::pair<float, float> GetMouseViewportSpace() const;
std::pair<glm::vec3, glm::vec3> CastRay(float mx, float my);
@ -35,23 +35,24 @@ namespace Prism
struct SelectedSubmesh
{
Prism::Entity Entity;
Submesh* Mesh;
float Distance;
Submesh* Mesh = nullptr;
float Distance = 0.0f;
};
void OnSelected(const SelectedSubmesh& selectionContext);
void OnEntityDeleted(Entity e);
Ray CastMouseRay();
void OnScenePlay();
void OnSceneStop();
private:
Scope<SceneHierarchyPanel> m_SceneHierarchyPanel;
Ref<Scene> m_Scene;
Ref<Scene> m_SphereScene;
Ref<Scene> m_ActiveScene;
Ref<Scene> m_RuntimeScene, m_EditorScene;
Entity m_MeshEntity;
Entity m_CameraEntity;
EditorCamera m_EditorCamera;
Ref<Material> m_SphereBaseMaterial;
Ref<Material> m_MeshMaterial;
std::vector<Ref<MaterialInstance>> m_MetalSphereMaterialInstances;
@ -71,14 +72,6 @@ namespace Prism
std::vector<SelectedSubmesh> m_SelectionContext;
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
@ -119,14 +112,33 @@ namespace Prism
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
{
Spheres = 0, Model = 1
};
SceneType m_SceneType;
// Editor resources
Ref<Texture2D> m_CheckerboardTex;
bool m_ViewportPanelMouseOver = false;
bool m_ViewportPanelFocused = false;
enum class SceneState
{
Edit = 0, Play = 1, Pause = 2
};
SceneState m_SceneState = SceneState::Edit;
};
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 357 B

View 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

View 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);
}

View File

@ -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.
// Currently heavily updated.

View File

@ -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.
// Currently heavily updated.