重构项目src框架,添加c#脚本功能
This commit is contained in:
@ -1,688 +0,0 @@
|
||||
//
|
||||
// Created by sfd on 25-5-25.
|
||||
//
|
||||
|
||||
#include "EditorLayer.h"
|
||||
|
||||
#include <imgui.h>
|
||||
#include <ImGuizmo.h>
|
||||
#include <glm/gtc/type_ptr.hpp>
|
||||
#include <Hazel/Core/Input.h>
|
||||
#include <Hazel/Math/Math.h>
|
||||
#include <Hazel/Scene/SceneSerializer.h>
|
||||
#include <Hazel/Utils/PlatformUtils.h>
|
||||
|
||||
#include "glm/gtx/matrix_decompose.hpp"
|
||||
|
||||
namespace Hazel
|
||||
{
|
||||
|
||||
extern const std::filesystem::path g_AssetPath;
|
||||
|
||||
EditorLayer::EditorLayer()
|
||||
: Layer("HazelEditor"), m_CameraController((float)Application::Get().GetWindow().GetWidth() / (float)Application::Get().GetWindow().GetHeight())
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void EditorLayer::OnAttach()
|
||||
{
|
||||
FrameBufferSpecification spec;
|
||||
spec.Width = Application::Get().GetWindow().GetWidth();
|
||||
spec.Height = Application::Get().GetWindow().GetHeight();
|
||||
spec.Attachments = { FrameBufferTextureFormat::RGBA8, FrameBufferTextureFormat::RED_INTEGER,FrameBufferTextureFormat::DEPTH };
|
||||
m_FrameBuffer = FrameBuffer::Create(spec);
|
||||
|
||||
m_ViewPortSize = { spec.Width, spec.Height };
|
||||
|
||||
m_LogoTexture = Texture2D::Create("assets/textures/iceLogo.png");
|
||||
m_CheckerBoardTexture = Texture2D::Create("assets/textures/Checkerboard.png");
|
||||
|
||||
m_IconPlay = Texture2D::Create("Resources/Icons/PlayButton.png");
|
||||
m_IconStop = Texture2D::Create("Resources/Icons/PauseButton.png");
|
||||
m_IconSimulate = Texture2D::Create("Resources/Icons/SimulateButton.png");
|
||||
|
||||
m_EditorScene = CreateRef<Scene>();
|
||||
m_EditorScene->OnViewportResize((uint32_t)m_ViewPortSize.x, (uint32_t)m_ViewPortSize.y);
|
||||
m_ActiveScene = m_EditorScene;
|
||||
|
||||
m_EditorCamera = EditorCamera(45.0f, 1.667f, 0.1f, 1000.0f);
|
||||
|
||||
m_SceneHierachyPanel.SetContext(m_ActiveScene);
|
||||
|
||||
m_GizmoType = ImGuizmo::OPERATION::TRANSLATE;
|
||||
auto commandLineArgs = Application::Get().GetSpecification().commandLineArgs;
|
||||
if (commandLineArgs.count > 1)
|
||||
{
|
||||
auto scenePath = commandLineArgs.args[1];
|
||||
SceneSerializer sceneSerializer(m_ActiveScene);
|
||||
|
||||
sceneSerializer.Deserialize(scenePath);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void EditorLayer::OnDetech()
|
||||
{
|
||||
}
|
||||
|
||||
void EditorLayer::OnUpdate(TimeStep& ts)
|
||||
{
|
||||
// reset Renderer Draw Stats
|
||||
Renderer2D::ResetStats();
|
||||
|
||||
if (const auto& spec = m_FrameBuffer->GetSpecification();
|
||||
spec.Width != m_ViewPortSize.x || spec.Height != m_ViewPortSize.y)
|
||||
{
|
||||
m_FrameBuffer->Resize((uint32_t)m_ViewPortSize.x, (uint32_t)m_ViewPortSize.y);
|
||||
m_CameraController.OnResize(m_ViewPortSize.x, m_ViewPortSize.y);
|
||||
|
||||
m_EditorCamera.SetViewPortSize(m_ViewPortSize.x, m_ViewPortSize.y);
|
||||
m_ActiveScene->OnViewportResize((uint32_t)m_ViewPortSize.x, (uint32_t)m_ViewPortSize.y);
|
||||
|
||||
}
|
||||
|
||||
// update camera
|
||||
|
||||
// update Renderer
|
||||
m_FrameBuffer->Bind();
|
||||
RendererCommand::SetClearColor(m_BackgroundColor);
|
||||
RendererCommand::Clear();
|
||||
|
||||
m_FrameBuffer->ClearAttachment(1, -1);
|
||||
|
||||
switch (m_SceneState)
|
||||
{
|
||||
case SceneState::Play:
|
||||
m_ActiveScene->OnUpdateRuntime(ts);
|
||||
break;
|
||||
case SceneState::Edit:
|
||||
if (m_ViewportFocused)
|
||||
m_CameraController.OnUpdate(ts);
|
||||
|
||||
m_EditorCamera.OnUpdate(ts);
|
||||
m_ActiveScene->OnUpdateEditor(ts, m_EditorCamera);
|
||||
break;
|
||||
case SceneState::Simulate:
|
||||
m_EditorCamera.OnUpdate(ts);
|
||||
m_ActiveScene->OnUpdateSimulation(ts, m_EditorCamera);
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
auto [mx, my] = ImGui::GetMousePos();
|
||||
mx -= m_ViewPortBounds[0].x;
|
||||
my -= m_ViewPortBounds[0].y;
|
||||
const glm::vec2 viewPortSize = m_ViewPortBounds[1] - m_ViewPortBounds[0];
|
||||
my = viewPortSize.y - my;
|
||||
|
||||
const int mouseX = (int)mx;
|
||||
const int mouseY = (int)my;
|
||||
|
||||
if (mouseX >= 0 && mouseY >= 0 && mouseX < m_ViewPortSize.x && mouseY < m_ViewPortSize.y)
|
||||
{
|
||||
int pixelData = m_FrameBuffer->ReadPixel(1, mouseX, mouseY);
|
||||
m_HoveredEntity = pixelData == -1 ? Entity{} : Entity{ (entt::entity)pixelData, m_ActiveScene.get()};
|
||||
}
|
||||
|
||||
// Renderer2D::DrawQuad({0, 0.5f}, {1.0f, 1.0f}, {0.2f, 0.3f, 0.8f, 1.0f});
|
||||
// Renderer2D::DrawQuad({0, -0.5f}, {1.0f, 1.0f}, {0.8f, 0.2f, 0.2f, 1.0f});
|
||||
// Renderer2D::DrawQuad({-1, 0}, {1, 1}, m_LogoTexture);
|
||||
// Renderer2D::DrawQuad({1, 0}, {1, 1}, m_CheckerBoardTexture);
|
||||
OnOverLayRender();
|
||||
|
||||
// Renderer2D::EndScene();
|
||||
m_FrameBuffer->UnBind();
|
||||
}
|
||||
|
||||
void EditorLayer::OnOverLayRender()
|
||||
{
|
||||
|
||||
if (m_SceneState == SceneState::Play)
|
||||
{
|
||||
|
||||
Entity camera = m_ActiveScene->GetPrimaryCameraEntity();
|
||||
if (camera)
|
||||
Renderer2D::BeginScene(camera.GetComponent<CameraComponent>().Camera, camera.GetComponent<TransformComponent>().GetTransform());
|
||||
else
|
||||
Renderer2D::BeginScene(m_EditorCamera);
|
||||
}else
|
||||
{
|
||||
Renderer2D::BeginScene(m_EditorCamera);
|
||||
}
|
||||
|
||||
if (m_ShowPhysicsColliders)
|
||||
{
|
||||
// box collider
|
||||
auto bcview = m_ActiveScene->GetAllEntitiesWith<TransformComponent, BoxCollider2DComponent>();
|
||||
for (auto entity : bcview)
|
||||
{
|
||||
auto [tc, bc2D] = bcview.get<TransformComponent, BoxCollider2DComponent>(entity);
|
||||
|
||||
glm::vec3 scale = tc.Scale * glm::vec3(bc2D.Size * 2.0f, 1.0f);
|
||||
|
||||
glm::mat4 transform =
|
||||
glm::translate(glm::mat4(1.0f), tc.Translation)
|
||||
* glm::rotate(glm::mat4(1.0f), tc.Rotation.z, glm::vec3(0.0f, 0.0f, 1.0f))
|
||||
* glm::translate(glm::mat4(1.0f), glm::vec3(bc2D.Offset, 0.0f))
|
||||
* glm::scale(glm::mat4(1.0f), scale);
|
||||
|
||||
Renderer2D::DrawRect(transform, glm::vec4(0.2f, 1.0f, 0.2f, 1.0f));
|
||||
}
|
||||
|
||||
// circle collider
|
||||
auto ccview = m_ActiveScene->GetAllEntitiesWith<TransformComponent, CircleCollider2DComponent>();
|
||||
for (auto entity : ccview)
|
||||
{
|
||||
auto [tc, cc2D] = ccview.get<TransformComponent, CircleCollider2DComponent>(entity);
|
||||
|
||||
glm::vec3 scale = tc.Scale * glm::vec3(cc2D.Radius * 2.05f);
|
||||
|
||||
glm::mat4 transform =
|
||||
glm::translate(glm::mat4(1.0f), tc.Translation)
|
||||
* glm::rotate(glm::mat4(1.0f), tc.Rotation.z, glm::vec3(0.0f, 0.0f, 1.0f))
|
||||
* glm::translate(glm::mat4(1.0f), glm::vec3(cc2D.Offset, 0.0f))
|
||||
* glm::scale(glm::mat4(1.0f), scale);
|
||||
|
||||
Renderer2D::DrawCircle(transform, glm::vec4(0.2, 1.0f, 0.2f, 1.0f), Renderer2D::GetLineWidth() * 0.015f);
|
||||
}
|
||||
}
|
||||
|
||||
if (Entity selectedEntity = m_SceneHierachyPanel.GetSelectedEntity())
|
||||
{
|
||||
if (!selectedEntity.HasComponent<CameraComponent>())
|
||||
{
|
||||
auto transform = selectedEntity.GetComponent<TransformComponent>();
|
||||
|
||||
Renderer2D::DrawRect(transform.GetTransform(), glm::vec4(0.8f, 0.3f, 0.2f, 1.0f));
|
||||
}
|
||||
}
|
||||
|
||||
Renderer2D::EndScene();
|
||||
}
|
||||
|
||||
void EditorLayer::OnImGuiRender()
|
||||
{
|
||||
static bool showDockspace = true;
|
||||
if (showDockspace)
|
||||
{
|
||||
static bool dockspaceOpen = true;
|
||||
static bool opt_fullscreen = true;
|
||||
static bool opt_padding = false;
|
||||
static ImGuiDockNodeFlags dockspace_flags = ImGuiDockNodeFlags_None;
|
||||
|
||||
// We are using the ImGuiWindowFlags_NoDocking flag to make the parent window not dockable into,
|
||||
// because it would be confusing to have two docking targets within each others.
|
||||
ImGuiWindowFlags window_flags = ImGuiWindowFlags_MenuBar | ImGuiWindowFlags_NoDocking;
|
||||
if (opt_fullscreen)
|
||||
{
|
||||
const ImGuiViewport* viewport = ImGui::GetMainViewport();
|
||||
ImGui::SetNextWindowPos(viewport->WorkPos);
|
||||
ImGui::SetNextWindowSize(viewport->WorkSize);
|
||||
ImGui::SetNextWindowViewport(viewport->ID);
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 0.0f);
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, 0.0f);
|
||||
window_flags |= ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoResize |
|
||||
ImGuiWindowFlags_NoMove;
|
||||
window_flags |= ImGuiWindowFlags_NoBringToFrontOnFocus | ImGuiWindowFlags_NoNavFocus;
|
||||
}
|
||||
else
|
||||
{
|
||||
dockspace_flags &= ~ImGuiDockNodeFlags_PassthruCentralNode;
|
||||
}
|
||||
|
||||
// When using ImGuiDockNodeFlags_PassthruCentralNode, DockSpace() will render our background
|
||||
// and handle the pass-thru hole, so we ask Begin() to not render a background.
|
||||
if (dockspace_flags & ImGuiDockNodeFlags_PassthruCentralNode)
|
||||
window_flags |= ImGuiWindowFlags_NoBackground;
|
||||
|
||||
// Important: note that we proceed even if Begin() returns false (aka window is collapsed).
|
||||
// This is because we want to keep our DockSpace() active. If a DockSpace() is inactive,
|
||||
// all active windows docked into it will lose their parent and become undocked.
|
||||
// We cannot preserve the docking relationship between an active window and an inactive docking, otherwise
|
||||
// any change of dockspace/settings would lead to windows being stuck in limbo and never being visible.
|
||||
if (!opt_padding)
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0.0f, 0.0f));
|
||||
ImGui::Begin("DockSpace", &dockspaceOpen, window_flags);
|
||||
if (!opt_padding)
|
||||
ImGui::PopStyleVar();
|
||||
|
||||
if (opt_fullscreen)
|
||||
ImGui::PopStyleVar(2);
|
||||
|
||||
// Submit the DockSpace
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
ImGuiStyle& style = ImGui::GetStyle();
|
||||
style.WindowMinSize.x = 364.0f;
|
||||
if (io.ConfigFlags & ImGuiConfigFlags_DockingEnable)
|
||||
{
|
||||
ImGuiID dockspace_id = ImGui::GetID("MyDockSpace");
|
||||
ImGui::DockSpace(dockspace_id, ImVec2(0.0f, 0.0f), dockspace_flags);
|
||||
}
|
||||
|
||||
if (ImGui::BeginMenuBar())
|
||||
{
|
||||
if (ImGui::BeginMenu("Options"))
|
||||
{
|
||||
// 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);
|
||||
// ImGui::Separator();
|
||||
if (ImGui::MenuItem("New", "Ctrl+N"))
|
||||
NewScene();
|
||||
if (ImGui::MenuItem("Open...", "Ctrl+O"))
|
||||
OpenScene();
|
||||
if (ImGui::MenuItem("Save", "Ctrl+S", false, m_ActiveScene ? true : false))
|
||||
SaveScene();
|
||||
if (ImGui::MenuItem("Save As...", "Ctrl+Shift+S"))
|
||||
SaveSceneAs();
|
||||
|
||||
ImGui::Separator();
|
||||
if (ImGui::MenuItem("Exit")) { Hazel::Application::Get().Close(); }
|
||||
|
||||
ImGui::EndMenu();
|
||||
}
|
||||
|
||||
ImGui::EndMenuBar();
|
||||
}
|
||||
|
||||
// Scene Hierachy Panel
|
||||
m_SceneHierachyPanel.OnImGuiRender();
|
||||
m_ContentBroswerPanel.OnImGuiRender();
|
||||
|
||||
// Render Status
|
||||
{
|
||||
ImGui::Begin("Render Status");
|
||||
|
||||
auto stats = Renderer2D::GetStats();
|
||||
ImGui::Text("Renderer BatchInfo: ");
|
||||
ImGui::Text("Draw Calls: %d", stats.DrawCalls);
|
||||
ImGui::Text("Quads: %d", stats.QuadCount);
|
||||
ImGui::Text("Vertices: %d", stats.GetTotalVertexCount());
|
||||
ImGui::Text("Indices: %d", stats.GetTotalIndexCount());
|
||||
|
||||
ImGui::Separator();
|
||||
|
||||
ImGui::Text("viewPortSize: (%.2f, %.2f)", m_ViewPortSize.x, m_ViewPortSize.y);
|
||||
|
||||
ImGui::Separator();
|
||||
|
||||
auto editorCameraPos = m_EditorCamera.GetPosition();
|
||||
ImGui::Text("Editor Camera(%.3f, %.3f, %.3f)", editorCameraPos.x, editorCameraPos.y, editorCameraPos.z);
|
||||
ImGui::Text("Editor Camera Distance: %f", m_EditorCamera.GetDistance());
|
||||
|
||||
float lineWidth = Renderer2D::GetLineWidth();
|
||||
if (ImGui::DragFloat("LineWidth", &lineWidth, 0.01f, 0.0f, 10.0f))
|
||||
{
|
||||
Renderer2D::SetLineWidth(lineWidth);
|
||||
}
|
||||
// std::string name = "none";
|
||||
// if (m_HoveredEntity)
|
||||
// name = m_HoveredEntity.GetComponent<TagComponent>().Tag;
|
||||
|
||||
// ImGui::Text("Hovered Entity: %s", name.c_str());
|
||||
|
||||
ImGui::Separator();
|
||||
|
||||
ImGui::Checkbox("Show Colliders", &m_ShowPhysicsColliders);
|
||||
|
||||
ImGui::End();
|
||||
}
|
||||
|
||||
// ViewPort
|
||||
{
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, {0.0f, 0.0f});
|
||||
ImGui::Begin("Viewport", nullptr, ImGuiWindowFlags_NoCollapse);
|
||||
auto viewportOffet = ImGui::GetCursorPos();
|
||||
m_ViewportFocused = ImGui::IsWindowFocused();
|
||||
m_ViewportHovered = ImGui::IsWindowHovered();
|
||||
|
||||
|
||||
ImVec2 viewPortPanelSize = ImGui::GetContentRegionAvail();
|
||||
if (m_ViewPortSize != *reinterpret_cast<glm::vec2*>(&viewPortPanelSize))
|
||||
{
|
||||
m_ViewPortSize = {viewPortPanelSize.x, viewPortPanelSize.y};
|
||||
}
|
||||
// ImGui::Text("Viewport: (%.2f, %.2f)", viewPortPanelSize.x, viewPortPanelSize.y);
|
||||
ImGui::Image(m_FrameBuffer->GetColorAttachmentID(), {m_ViewPortSize.x, m_ViewPortSize.y}, {0, 1},
|
||||
{1, 0});
|
||||
const ImVec2 &viewPortMin = ImGui::GetItemRectMin(); // left-top pos
|
||||
const ImVec2 &viewPortMax = ImGui::GetItemRectMax(); // right-buttom pos
|
||||
|
||||
if (ImGui::BeginDragDropTarget())
|
||||
{
|
||||
if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload("CONTENT_BROSWER_ITEM"))
|
||||
{
|
||||
const wchar_t* path = (const wchar_t*)payload->Data;
|
||||
OpenScene(std::filesystem::path(g_AssetPath) / path);
|
||||
}
|
||||
ImGui::EndDragDropTarget();
|
||||
}
|
||||
|
||||
auto windowsSize = ImGui::GetWindowSize();
|
||||
ImVec2 minBound = ImGui::GetWindowPos();
|
||||
|
||||
|
||||
minBound.x += viewportOffet.x;
|
||||
minBound.y += viewportOffet.y + m_ViewPortSize.y - windowsSize.y;
|
||||
|
||||
ImVec2 maxBound = {minBound.x + windowsSize.x, minBound.y + windowsSize.y};
|
||||
m_ViewPortBounds[0] = {minBound.x, minBound.y};
|
||||
m_ViewPortBounds[1] = {maxBound.x, maxBound.y};
|
||||
|
||||
// ImGuizmo
|
||||
Entity selectedEntity = m_SceneHierachyPanel.GetSelectedEntity();
|
||||
if (selectedEntity)
|
||||
{
|
||||
ImGuizmo::SetOrthographic(false);
|
||||
ImGuizmo::SetDrawlist();
|
||||
|
||||
|
||||
ImGuizmo::SetRect(viewPortMin.x, viewPortMin.y, viewPortMax.x - viewPortMin.x, viewPortMax.y - viewPortMin.y);
|
||||
|
||||
if (m_GizmoType != -1)
|
||||
{
|
||||
|
||||
glm::mat4 cameraProjection;
|
||||
glm::mat4 cameraView;
|
||||
|
||||
if (m_SceneState == SceneState::Play)
|
||||
{
|
||||
auto cameraEntity = m_ActiveScene->GetPrimaryCameraEntity();
|
||||
const auto& camera = cameraEntity.GetComponent<CameraComponent>().Camera;
|
||||
|
||||
cameraProjection = camera.GetProjection();
|
||||
cameraView = glm::inverse(cameraEntity.GetComponent<TransformComponent>().GetTransform());
|
||||
}else
|
||||
{
|
||||
cameraProjection = m_EditorCamera.GetProjection();
|
||||
cameraView = m_EditorCamera.GetViewMatrix();
|
||||
}
|
||||
|
||||
auto& tc = selectedEntity.GetComponent<TransformComponent>();
|
||||
|
||||
glm::mat4 transform = tc.GetTransform();
|
||||
bool snap = SDL_GetModState() & SDL_KMOD_CTRL;
|
||||
float snapValue = 0.5f;
|
||||
if (m_GizmoType == ImGuizmo::OPERATION::TRANSLATE)
|
||||
snapValue = 0.25f;
|
||||
else if (m_GizmoType == ImGuizmo::OPERATION::ROTATE)
|
||||
snapValue = 15.0f;
|
||||
else if (m_GizmoType == ImGuizmo::OPERATION::SCALE)
|
||||
snapValue = 0.25f;
|
||||
|
||||
float snapValues[3] = {snapValue, snapValue, snapValue};
|
||||
if (ImGuizmo::Manipulate(glm::value_ptr(cameraView), glm::value_ptr(cameraProjection),
|
||||
static_cast<ImGuizmo::OPERATION>(m_GizmoType), ImGuizmo::WORLD,
|
||||
glm::value_ptr(transform), nullptr, snap ? snapValues : nullptr) && !Input::IsKeyPressed(KeyCode::LALT))
|
||||
{
|
||||
if (ImGuizmo::IsUsing())
|
||||
{
|
||||
glm::vec3 translation, rotation, scale;
|
||||
|
||||
Hazel::Math::DecomposeTransform(transform, translation, rotation, scale);
|
||||
|
||||
glm::vec3 deltaRotation = rotation - tc.Rotation;
|
||||
|
||||
tc.Translation = translation;
|
||||
tc.Rotation += deltaRotation;
|
||||
tc.Scale = scale;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
ImGui::End();
|
||||
ImGui::PopStyleVar();
|
||||
}
|
||||
|
||||
UI_ToolBar();
|
||||
|
||||
ImGui::End();
|
||||
}
|
||||
}
|
||||
|
||||
void EditorLayer::SaveSceneAs() const
|
||||
{
|
||||
std::string filepath = FileDiaglogs::SaveFile("Hazel Scene (*.scene,*.yaml)\0*.scene;*.yaml\0*\0*.*\0\0");
|
||||
HZ_CORE_INFO("Saving scene to: {}", filepath);
|
||||
if (filepath.empty())
|
||||
{
|
||||
HZ_CORE_WARN("filepath is empty! do not save Scene!");
|
||||
}
|
||||
else
|
||||
{
|
||||
SerializeScene(m_ActiveScene, filepath);
|
||||
HZ_CORE_INFO("scene saved");
|
||||
}
|
||||
}
|
||||
|
||||
void EditorLayer::OpenScene()
|
||||
{
|
||||
std::string filepath = FileDiaglogs::OpenFile("Scene(*.scene, *.yaml)\0*.scene;*.yaml\0All files\0*.*\0\0");
|
||||
if (!filepath.empty())
|
||||
OpenScene(filepath);
|
||||
}
|
||||
|
||||
void EditorLayer::OpenScene(const std::filesystem::path& scenePath)
|
||||
{
|
||||
if (m_SceneState != SceneState::Edit)
|
||||
OnSceneStop();
|
||||
|
||||
Ref<Scene> newScene = CreateRef<Scene>();
|
||||
SceneSerializer serializer(newScene);
|
||||
if (serializer.Deserialize(scenePath.string()))
|
||||
{
|
||||
m_EditorScene = newScene;
|
||||
m_EditorScene->OnViewportResize((uint32_t)m_ViewPortSize.x, (uint32_t)m_ViewPortSize.y);
|
||||
|
||||
m_ActiveScene = m_EditorScene;
|
||||
|
||||
m_SceneHierachyPanel.SetContext(m_ActiveScene);
|
||||
|
||||
m_EditorScenePath = scenePath;
|
||||
}
|
||||
}
|
||||
|
||||
void EditorLayer::NewScene()
|
||||
{
|
||||
m_ActiveScene = CreateRef<Scene>();
|
||||
m_ActiveScene->OnViewportResize((uint32_t)m_ViewPortSize.x, (uint32_t)m_ViewPortSize.y);
|
||||
m_SceneHierachyPanel.SetContext(m_ActiveScene);
|
||||
|
||||
m_EditorScenePath = std::filesystem::path();
|
||||
}
|
||||
|
||||
void EditorLayer::SaveScene() const
|
||||
{
|
||||
if (!m_EditorScenePath.empty())
|
||||
{
|
||||
HZ_CORE_INFO("Saving scene: {}", m_EditorScenePath.string());
|
||||
SerializeScene(m_ActiveScene, m_EditorScenePath);
|
||||
HZ_CORE_INFO("scene saved");
|
||||
}else
|
||||
{
|
||||
SaveSceneAs();
|
||||
}
|
||||
}
|
||||
|
||||
void EditorLayer::SerializeScene(Ref<Scene> scene, const std::filesystem::path& scenePath) const
|
||||
{
|
||||
const SceneSerializer serializer(scene);
|
||||
serializer.Serialize(scenePath.string());
|
||||
}
|
||||
|
||||
void EditorLayer::OnDuplicateEntity()
|
||||
{
|
||||
if (m_SceneState != SceneState::Edit)
|
||||
return;
|
||||
Entity selectedEntity = m_SceneHierachyPanel.GetSelectedEntity();
|
||||
if (selectedEntity)
|
||||
m_EditorScene->DuplicateEntity(selectedEntity);
|
||||
}
|
||||
|
||||
void EditorLayer::OnScenePlay()
|
||||
{
|
||||
if (m_SceneState == SceneState::Simulate)
|
||||
OnSceneStop();
|
||||
|
||||
// SaveScene();
|
||||
m_SceneState = SceneState::Play;
|
||||
|
||||
m_ActiveScene = Scene::Copy(m_EditorScene);
|
||||
m_ActiveScene->OnRuntimeStart();
|
||||
|
||||
m_SceneHierachyPanel.SetContext(m_ActiveScene);
|
||||
}
|
||||
|
||||
void EditorLayer::OnSceneStop()
|
||||
{
|
||||
if (m_SceneState != SceneState::Play && m_SceneState != SceneState::Simulate)
|
||||
{
|
||||
HZ_CORE_WARN("Scene is not playing or simulating!");
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_SceneState == SceneState::Play)
|
||||
m_ActiveScene->OnRuntimeStop();
|
||||
else if (m_SceneState == SceneState::Simulate)
|
||||
m_ActiveScene->OnSimulationStop();
|
||||
|
||||
m_SceneState = SceneState::Edit;
|
||||
m_ActiveScene = m_EditorScene;
|
||||
m_SceneHierachyPanel.SetContext(m_ActiveScene);
|
||||
}
|
||||
|
||||
void EditorLayer::OnSceneSimulation()
|
||||
{
|
||||
if (m_SceneState == SceneState::Simulate)
|
||||
OnSceneStop();
|
||||
// SaveScene();
|
||||
m_SceneState = SceneState::Simulate;
|
||||
|
||||
m_ActiveScene = Scene::Copy(m_EditorScene);
|
||||
m_ActiveScene->OnSimulationStart();
|
||||
|
||||
m_SceneHierachyPanel.SetContext(m_ActiveScene);
|
||||
}
|
||||
|
||||
void EditorLayer::ChangeOptMode(unsigned int mode)
|
||||
{
|
||||
if (m_ViewportHovered)
|
||||
m_GizmoType = mode;
|
||||
}
|
||||
|
||||
void EditorLayer::OnEvent(SDL_Event& e)
|
||||
{
|
||||
if (m_ViewportFocused)
|
||||
{
|
||||
m_CameraController.OnEvent(e);
|
||||
m_EditorCamera.OnEvent(e);
|
||||
}
|
||||
if (e.button.clicks && m_ViewportHovered && !ImGuizmo::IsOver() && Input::IsMouseButtonPressed(MouseButton::BUTTON_LEFT) && !Input::IsKeyPressed(KeyCode::LALT))
|
||||
m_SceneHierachyPanel.SetSelectedEntity(m_HoveredEntity);
|
||||
|
||||
#define SHORTCUT_EXIT (SDL_KMOD_CTRL + SDLK_W)
|
||||
#define SHORTCUT_NEW (SDL_KMOD_CTRL + SDLK_N)
|
||||
#define SHORTCUT_OPEN (SDL_KMOD_CTRL + SDLK_O)
|
||||
#define SHORTCUT_SAVE (SDL_KMOD_CTRL + SDLK_S)
|
||||
#define SHORTCUT_SAVE_AS (SDL_KMOD_CTRL + SDL_KMOD_SHIFT + SDLK_S)
|
||||
#define SHORTCUT_CTRL_D (SDL_KMOD_CTRL + SDLK_D)
|
||||
|
||||
|
||||
if (e.key.down && e.key.repeat == 0)
|
||||
{
|
||||
const auto mod = SDL_GetModState();
|
||||
const auto ctrl = (mod & SDL_KMOD_CTRL) ? SDL_KMOD_CTRL : 0;
|
||||
const auto shift = (mod & SDL_KMOD_SHIFT) ? SDL_KMOD_SHIFT : 0;
|
||||
|
||||
switch (ctrl + shift + e.key.key)
|
||||
{
|
||||
case SHORTCUT_EXIT:
|
||||
Application::Get().Close();
|
||||
break;
|
||||
case SHORTCUT_NEW:
|
||||
NewScene();
|
||||
break;
|
||||
case SHORTCUT_OPEN:
|
||||
OpenScene();
|
||||
break;
|
||||
case SHORTCUT_SAVE:
|
||||
SaveScene();
|
||||
break;
|
||||
case SHORTCUT_SAVE_AS:
|
||||
SaveSceneAs();
|
||||
break;
|
||||
case SHORTCUT_CTRL_D:
|
||||
OnDuplicateEntity();
|
||||
break;
|
||||
|
||||
// GIZMO
|
||||
case SDLK_Q:
|
||||
ChangeOptMode(-1);
|
||||
break;
|
||||
case SDLK_W:
|
||||
ChangeOptMode(ImGuizmo::OPERATION::TRANSLATE);
|
||||
break;
|
||||
case SDLK_E:
|
||||
ChangeOptMode(ImGuizmo::OPERATION::SCALE);
|
||||
break;
|
||||
case SDLK_R:
|
||||
ChangeOptMode(ImGuizmo::OPERATION::ROTATE);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void EditorLayer::UI_ToolBar()
|
||||
{
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0, 2));
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_ItemInnerSpacing, ImVec2(0, 0));
|
||||
|
||||
ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0, 0, 0, 0));
|
||||
auto& colors = ImGui::GetStyle().Colors;
|
||||
auto& buttonHovered = colors[ImGuiCol_ButtonHovered];
|
||||
ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(buttonHovered.x, buttonHovered.y, buttonHovered.z, 0.5f));
|
||||
auto& buttonActive = colors[ImGuiCol_ButtonActive];
|
||||
ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImVec4(buttonActive.x, buttonActive.y, buttonActive.z, 0.5f));
|
||||
|
||||
|
||||
ImGui::Begin("##ToolBar", nullptr, ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoScrollWithMouse);
|
||||
// ImGui::Begin("##ToolBar", nullptr);
|
||||
|
||||
float size = ImGui::GetWindowHeight() - 10.0f;
|
||||
ImGui::SetCursorPosX(ImGui::GetWindowContentRegionMax().x * 0.5f - size * 0.5f);
|
||||
ImGui::SetCursorPosX(ImGui::GetWindowContentRegionMax().x * 0.5f - (size * 0.5f));
|
||||
|
||||
Ref<Texture2D> icon = (m_SceneState == SceneState::Edit || m_SceneState == SceneState::Simulate)? m_IconPlay : m_IconStop;
|
||||
if (ImGui::ImageButton("toolbar-play-edit", icon->GetRendererID(), ImVec2{size, size}, ImVec2{0, 0}, ImVec2{1, 1}))
|
||||
{
|
||||
if (m_SceneState == SceneState::Edit || m_SceneState == SceneState::Simulate)
|
||||
OnScenePlay();
|
||||
else if (m_SceneState == SceneState::Play)
|
||||
OnSceneStop();
|
||||
}
|
||||
|
||||
ImGui::SameLine();
|
||||
{
|
||||
Ref<Texture2D> icon = (m_SceneState == SceneState::Edit || m_SceneState == SceneState::Play)? m_IconSimulate : m_IconStop;
|
||||
if (ImGui::ImageButton("toolbar-simulate", icon->GetRendererID(), ImVec2{size, size}, ImVec2{0, 0}, ImVec2{1, 1}))
|
||||
{
|
||||
if (m_SceneState == SceneState::Edit || m_SceneState == SceneState::Play)
|
||||
OnSceneSimulation();
|
||||
else if (m_SceneState == SceneState::Simulate)
|
||||
OnSceneStop();
|
||||
}
|
||||
}
|
||||
|
||||
ImGui::PopStyleVar(2);
|
||||
ImGui::PopStyleColor(3);
|
||||
ImGui::End();
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,91 +0,0 @@
|
||||
//
|
||||
// Created by sfd on 25-5-25.
|
||||
//
|
||||
|
||||
#ifndef EDITORLAYER_H
|
||||
#define EDITORLAYER_H
|
||||
#include <Hazel.h>
|
||||
|
||||
#include "Panels/ContentBroswerPanel.h"
|
||||
#include "Panels/SceneHierachyPanel.h"
|
||||
|
||||
namespace Hazel
|
||||
{
|
||||
class EditorLayer : public Layer
|
||||
{
|
||||
public:
|
||||
EditorLayer();
|
||||
virtual ~EditorLayer() = default;
|
||||
|
||||
virtual void OnAttach() override;
|
||||
virtual void OnDetech() override;
|
||||
|
||||
virtual void OnUpdate(TimeStep& ts) override;
|
||||
virtual void OnImGuiRender() override;
|
||||
virtual void OnEvent(SDL_Event& e) override;
|
||||
private:
|
||||
void UI_ToolBar();
|
||||
|
||||
void OnScenePlay();
|
||||
void OnSceneSimulation();
|
||||
void OnSceneStop();
|
||||
|
||||
|
||||
void SaveSceneAs() const;
|
||||
void OpenScene();
|
||||
void OpenScene(const std::filesystem::path& scenePath);
|
||||
void NewScene();
|
||||
void SaveScene() const;
|
||||
|
||||
void SerializeScene(Ref<Scene> scene, const std::filesystem::path& scenePath) const;
|
||||
|
||||
void OnDuplicateEntity();
|
||||
|
||||
void ChangeOptMode(unsigned int mode);
|
||||
|
||||
void OnOverLayRender();
|
||||
|
||||
private:
|
||||
OrthographicCameraController m_CameraController;
|
||||
|
||||
Ref<Texture2D> m_LogoTexture;
|
||||
Ref<Texture2D> m_CheckerBoardTexture;
|
||||
|
||||
|
||||
Ref<Scene> m_ActiveScene;
|
||||
Ref<Scene> m_EditorScene;
|
||||
EditorCamera m_EditorCamera;
|
||||
std::filesystem::path m_EditorScenePath;
|
||||
|
||||
Entity m_HoveredEntity;
|
||||
|
||||
glm::vec4 m_BackgroundColor = { 0.2f, 0.2f, 0.2f, 1.0f };
|
||||
glm::vec4 m_SquareColor = { 0.2f, 0.2f, 0.2f, 1.0f };
|
||||
|
||||
bool m_ViewportFocused = false, m_ViewportHovered = false;
|
||||
glm::vec2 m_ViewPortSize = {0, 0};
|
||||
glm::vec2 m_ViewPortBounds[2];
|
||||
|
||||
Ref<FrameBuffer> m_FrameBuffer;
|
||||
Ref<FrameBuffer> m_RuntimeFrameBuffer;
|
||||
|
||||
SceneHierachyPanel m_SceneHierachyPanel;
|
||||
ContentBroswerPanel m_ContentBroswerPanel;
|
||||
|
||||
int m_GizmoType = -1;
|
||||
|
||||
bool m_ShowPhysicsColliders = false;
|
||||
|
||||
enum class SceneState
|
||||
{
|
||||
Edit = 0, Play = 1, Simulate = 2
|
||||
};
|
||||
|
||||
SceneState m_SceneState = SceneState::Edit;
|
||||
|
||||
Ref<Texture2D> m_IconPlay, m_IconStop, m_IconSimulate;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
#endif //EDITORLAYER_H
|
||||
@ -1,101 +0,0 @@
|
||||
//
|
||||
// Created by sfd on 25-6-10.
|
||||
//
|
||||
|
||||
#include "ContentBroswerPanel.h"
|
||||
|
||||
#include <filesystem>
|
||||
#include <../../../../Hazel/vendor/imgui/imgui.h>
|
||||
#include <string>
|
||||
|
||||
namespace Hazel
|
||||
{
|
||||
|
||||
extern const std::filesystem::path g_AssetPath = "assets";
|
||||
|
||||
ContentBroswerPanel::ContentBroswerPanel()
|
||||
: m_CurrentDirectory(g_AssetPath)
|
||||
{
|
||||
m_DirectoryIcon = Texture2D::Create("Resources/Icons/ContentBrowser/DirectoryIcon.png");
|
||||
m_FileIcon = Texture2D::Create("Resources/Icons/ContentBrowser/FileIcon.png");
|
||||
}
|
||||
|
||||
|
||||
void ContentBroswerPanel::OnImGuiRender()
|
||||
{
|
||||
ImGui::Begin("ContentBroswerPanel");
|
||||
|
||||
ImGui::Text("%s", m_CurrentDirectory.string().c_str());
|
||||
ImGui::Separator();
|
||||
|
||||
if (m_CurrentDirectory != std::filesystem::path(g_AssetPath))
|
||||
{
|
||||
if (ImGui::Button(".."))
|
||||
{
|
||||
m_CurrentDirectory = m_CurrentDirectory.parent_path();
|
||||
}
|
||||
}
|
||||
|
||||
static float folderSize = 90.0f;
|
||||
static float padding = 16.0f;
|
||||
float cellSize = folderSize + padding;
|
||||
|
||||
float panelWidth = ImGui::GetContentRegionAvail().x;
|
||||
int columnsCount = (int)panelWidth / cellSize;
|
||||
if (columnsCount <= 1)
|
||||
columnsCount = 1;
|
||||
|
||||
ImGui::Columns(columnsCount, 0, false);
|
||||
|
||||
for (auto& directory : std::filesystem::directory_iterator(m_CurrentDirectory))
|
||||
{
|
||||
auto& path = directory.path();
|
||||
std::string filePathString = path.filename().string();
|
||||
|
||||
|
||||
ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0, 0, 0, 0));
|
||||
Ref<Texture2D> icon = directory.is_directory() ? m_DirectoryIcon : m_FileIcon;
|
||||
ImGui::ImageButton(std::to_string(hash_value(path)).c_str(),icon->GetRendererID(), {folderSize, folderSize}, {0, 1}, {1, 0});
|
||||
ImGui::PopStyleColor();
|
||||
|
||||
if (ImGui::BeginDragDropSource())
|
||||
{
|
||||
auto relativePath = std::filesystem::relative(path, g_AssetPath);
|
||||
const wchar_t* itemPath = relativePath.c_str();
|
||||
ImGui::SetDragDropPayload("CONTENT_BROSWER_ITEM", itemPath, (wcslen(itemPath) + 1) * sizeof(wchar_t), ImGuiCond_Once);
|
||||
ImGui::EndDragDropSource();
|
||||
}
|
||||
|
||||
if (ImGui::IsItemHovered() && ImGui::IsMouseClicked(ImGuiMouseButton_Left))
|
||||
{
|
||||
if (directory.is_directory())
|
||||
m_CurrentDirectory /= path.filename();
|
||||
}
|
||||
ImGui::TextWrapped(filePathString.c_str());
|
||||
ImGui::NextColumn();
|
||||
|
||||
/*
|
||||
if (directory.is_directory())
|
||||
{
|
||||
if (ImGui::Button(filePathString.c_str()))
|
||||
{
|
||||
m_CurrentDirectory /= path.filename();
|
||||
}
|
||||
}else
|
||||
{
|
||||
if (ImGui::Button(filePathString.c_str()))
|
||||
{
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
}
|
||||
|
||||
ImGui::Columns(1);
|
||||
|
||||
ImGui::SliderFloat("folder size", &folderSize, 16, 512);
|
||||
ImGui::SliderFloat("padding", &padding, 0, 32);
|
||||
|
||||
ImGui::End();
|
||||
}
|
||||
}
|
||||
@ -1,32 +0,0 @@
|
||||
//
|
||||
// Created by sfd on 25-6-10.
|
||||
//
|
||||
|
||||
#ifndef CONTENTBROSWERPANEL_H
|
||||
#define CONTENTBROSWERPANEL_H
|
||||
#include <filesystem>
|
||||
#include <Hazel/Core/Core.h>
|
||||
#include <Hazel/Renderer/Texture.h>
|
||||
|
||||
namespace Hazel
|
||||
{
|
||||
class ContentBroswerPanel
|
||||
{
|
||||
public:
|
||||
ContentBroswerPanel();
|
||||
virtual ~ContentBroswerPanel() = default;
|
||||
|
||||
void OnImGuiRender();
|
||||
private:
|
||||
|
||||
std::filesystem::path m_CurrentDirectory;
|
||||
|
||||
Ref<Texture2D> m_DirectoryIcon;
|
||||
Ref<Texture2D> m_FileIcon;
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endif //CONTENTBROSWERPANEL_H
|
||||
@ -1,476 +0,0 @@
|
||||
//
|
||||
// Created by sfd on 25-5-29.
|
||||
//
|
||||
|
||||
#include "SceneHierachyPanel.h"
|
||||
|
||||
#include <filesystem>
|
||||
#include <imgui.h>
|
||||
#include <imgui_internal.h>
|
||||
#include <glm/gtc/type_ptr.hpp>
|
||||
#include <Hazel/Scene/Components.h>
|
||||
|
||||
namespace Hazel
|
||||
{
|
||||
extern const std::filesystem::path g_AssetPath;
|
||||
|
||||
SceneHierachyPanel::SceneHierachyPanel(const Ref<Scene>& context)
|
||||
{
|
||||
SetContext(context);
|
||||
}
|
||||
|
||||
void SceneHierachyPanel::SetContext(const Ref<Scene>& context)
|
||||
{
|
||||
m_Context = context;
|
||||
m_SelectionContext = {};
|
||||
}
|
||||
|
||||
void SceneHierachyPanel::OnImGuiRender()
|
||||
{
|
||||
if (m_Context)
|
||||
{
|
||||
ImGui::Begin("Scene Hierachy");
|
||||
|
||||
m_Context->m_Registry.view<entt::entity>().each([&](auto entityID)
|
||||
{
|
||||
DrawEntityNode({entityID, m_Context.get()});
|
||||
});
|
||||
|
||||
if (ImGui::IsMouseDown(0) && ImGui::IsWindowHovered())
|
||||
{
|
||||
m_SelectionContext = {};
|
||||
}
|
||||
|
||||
if (ImGui::BeginPopupContextWindow(0, ImGuiPopupFlags_MouseButtonRight | ImGuiPopupFlags_NoOpenOverItems))
|
||||
{
|
||||
if (ImGui::MenuItem("Create Empty Entity"))
|
||||
{
|
||||
m_SelectionContext = m_Context->CreateEntity("Empty Entity");
|
||||
}
|
||||
else if (ImGui::MenuItem("Create Camera"))
|
||||
{
|
||||
m_SelectionContext = m_Context->CreateEntity("Camera");
|
||||
m_SelectionContext.AddComponent<CameraComponent>();
|
||||
}
|
||||
ImGui::EndPopup();
|
||||
}
|
||||
|
||||
ImGui::End();
|
||||
}
|
||||
|
||||
ImGui::Begin("Properties");
|
||||
if (m_SelectionContext)
|
||||
{
|
||||
DrawComponents(m_SelectionContext);
|
||||
}
|
||||
ImGui::End();
|
||||
}
|
||||
|
||||
|
||||
void SceneHierachyPanel::DrawEntityNode(Entity entity)
|
||||
{
|
||||
auto& tag = entity.GetComponent<TagComponent>().Tag;
|
||||
bool entityDeleted = false;
|
||||
|
||||
ImGuiTreeNodeFlags flags = ((m_SelectionContext == entity) ? ImGuiTreeNodeFlags_Selected : 0) | ImGuiTreeNodeFlags_OpenOnArrow;
|
||||
flags |= ImGuiTreeNodeFlags_SpanAvailWidth;
|
||||
const bool isopened = ImGui::TreeNodeEx((void*)(uint64_t)(uint32_t)entity, flags, tag.c_str());
|
||||
if (ImGui::IsItemClicked())
|
||||
{
|
||||
m_SelectionContext = entity;
|
||||
}
|
||||
|
||||
if (ImGui::BeginPopupContextItem())
|
||||
{
|
||||
if (ImGui::MenuItem("Delete Entity"))
|
||||
entityDeleted = true;
|
||||
ImGui::EndPopup();
|
||||
}
|
||||
|
||||
if (isopened)
|
||||
{
|
||||
ImGui::TreePop();
|
||||
}
|
||||
|
||||
if (entityDeleted)
|
||||
{
|
||||
m_Context->DestoryEntity(entity);
|
||||
if (m_SelectionContext == entity)
|
||||
{
|
||||
m_SelectionContext = {};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static bool DrawVec3Control(const std::string& label, glm::vec3& values, float resetValue = 0.0f, float columnWidth = 100.0f)
|
||||
{
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
auto boldFont = io.Fonts->Fonts[0];
|
||||
bool isChanged = false;
|
||||
ImGui::PushID(label.c_str());
|
||||
const ImGuiContext* context = ImGui::GetCurrentContext();
|
||||
|
||||
ImGui::Columns(2);
|
||||
|
||||
ImGui::SetColumnWidth(0, columnWidth);
|
||||
ImGui::Text(label.c_str());
|
||||
ImGui::NextColumn();
|
||||
|
||||
ImGui::PushMultiItemsWidths(3, ImGui::CalcItemWidth());
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, {0.0f, 0.0f});
|
||||
|
||||
float lineHeight = context->Font->FontSize + context->Style.FramePadding.y * 2.0f;
|
||||
// float lineHeight = GImGui->Font->FontSize + GImGui->Style.FramePadding.y * 2.0f;
|
||||
|
||||
|
||||
ImVec2 buttonSize = {lineHeight + 3.0f, lineHeight};
|
||||
|
||||
ImGui::PushStyleColor(ImGuiCol_Button, ImVec4{0.8f, 0.1f, 0.15f, 1.0f});
|
||||
ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4{0.9f, 0.2f, 0.2f, 1.0f});
|
||||
ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImVec4{0.8f, 0.1f, 0.15f, 1.0f});
|
||||
ImGui::PushFont(boldFont);
|
||||
if (ImGui::Button("X", buttonSize))
|
||||
{
|
||||
values.x = resetValue;
|
||||
isChanged = true;
|
||||
}
|
||||
ImGui::PopFont();
|
||||
ImGui::PopStyleColor(3);
|
||||
|
||||
ImGui::SameLine();
|
||||
if (ImGui::DragFloat("##X", &values.x, 0.1f))
|
||||
{
|
||||
isChanged = true;
|
||||
}
|
||||
ImGui::PopItemWidth();
|
||||
ImGui::SameLine();
|
||||
|
||||
ImGui::PushStyleColor(ImGuiCol_Button, ImVec4{0.2f, 0.7f, 0.2f, 1.0f});
|
||||
ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4{0.3f, 0.8f, 0.3f, 1.0f});
|
||||
ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImVec4{0.2f, 0.7f, 0.2f, 1.0f});
|
||||
ImGui::PushFont(boldFont);
|
||||
if (ImGui::Button("Y", buttonSize))
|
||||
{
|
||||
values.y = resetValue;
|
||||
isChanged = true;
|
||||
}
|
||||
ImGui::PopFont();
|
||||
ImGui::PopStyleColor(3);
|
||||
|
||||
ImGui::SameLine();
|
||||
if (ImGui::DragFloat("##Y", &values.y, 0.1f))
|
||||
{
|
||||
isChanged = true;
|
||||
}
|
||||
ImGui::PopItemWidth();
|
||||
ImGui::SameLine();
|
||||
|
||||
ImGui::PushStyleColor(ImGuiCol_Button, ImVec4{0.1f, 0.25f, 0.8f, 1.0f});
|
||||
ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4{0.2f, 0.35f, 0.9f, 1.0f});
|
||||
ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImVec4{0.1f, 0.25f, 0.8f, 1.0f});
|
||||
ImGui::PushFont(boldFont);
|
||||
if (ImGui::Button("Z", buttonSize))
|
||||
{
|
||||
values.z = resetValue;
|
||||
isChanged = true;
|
||||
}
|
||||
ImGui::PopFont();
|
||||
ImGui::PopStyleColor(3);
|
||||
|
||||
ImGui::SameLine();
|
||||
if (ImGui::DragFloat("##Z", &values.z, 0.1f))
|
||||
{
|
||||
isChanged = true;
|
||||
}
|
||||
ImGui::PopItemWidth();
|
||||
|
||||
|
||||
ImGui::PopStyleVar();
|
||||
ImGui::Columns(1);
|
||||
|
||||
ImGui::PopID();
|
||||
|
||||
return isChanged;
|
||||
}
|
||||
|
||||
template<typename T, typename UIfunction>
|
||||
void DrawComponent(const std::string& name, Entity entity, UIfunction uiFunction)
|
||||
{
|
||||
constexpr ImGuiTreeNodeFlags treeNodeFlags = ImGuiTreeNodeFlags_DefaultOpen | ImGuiTreeNodeFlags_Framed | ImGuiTreeNodeFlags_SpanAvailWidth | ImGuiTreeNodeFlags_AllowItemOverlap | ImGuiTreeNodeFlags_FramePadding;;
|
||||
|
||||
if (entity.HasComponent<T>())
|
||||
{
|
||||
ImGui::PushID(&entity);
|
||||
auto& component = entity.GetComponent<T>();
|
||||
|
||||
ImVec2 contextReginAvail = ImGui::GetContentRegionAvail();
|
||||
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, {4.0f, 4.0f});
|
||||
auto context = ImGui::GetCurrentContext();
|
||||
float lineHeight = context->Font->FontSize + context->Style.FramePadding.y * 2.0f;
|
||||
|
||||
ImGui::Separator();
|
||||
bool open = ImGui::TreeNodeEx((void*)(uint64_t)typeid(T).hash_code(), treeNodeFlags, name.c_str());
|
||||
ImGui::PopStyleVar();
|
||||
ImGui::SameLine(contextReginAvail.x - lineHeight * 0.5f);
|
||||
if (ImGui::Button("+", ImVec2(lineHeight, lineHeight)))
|
||||
{
|
||||
ImGui::OpenPopup("ComponentSettings");
|
||||
}
|
||||
|
||||
|
||||
bool removeComponent = false;
|
||||
if (ImGui::BeginPopup("ComponentSettings"))
|
||||
{
|
||||
if (ImGui::MenuItem("Remove Component"))
|
||||
removeComponent = true;
|
||||
|
||||
ImGui::EndPopup();
|
||||
}
|
||||
|
||||
if (open)
|
||||
{
|
||||
uiFunction(component);
|
||||
ImGui::TreePop();
|
||||
}
|
||||
|
||||
if (removeComponent)
|
||||
entity.RemoveComponent<T>();
|
||||
ImGui::PopID();
|
||||
}
|
||||
}
|
||||
|
||||
void SceneHierachyPanel::DrawComponents(Entity entity)
|
||||
{
|
||||
|
||||
if (entity.HasComponent<TagComponent>())
|
||||
{
|
||||
auto& tag = entity.GetComponent<TagComponent>().Tag;
|
||||
|
||||
char buffer[256] = {};
|
||||
strcpy_s(buffer,sizeof(buffer), tag.c_str());
|
||||
if (ImGui::InputText("Tag", buffer, sizeof(buffer)))
|
||||
{
|
||||
tag = std::string(buffer);
|
||||
}
|
||||
}
|
||||
|
||||
ImGui::SameLine();
|
||||
ImGui::PushItemWidth(-1);
|
||||
if (ImGui::Button("Add"))
|
||||
ImGui::OpenPopup("Add");
|
||||
if (ImGui::BeginPopup("Add"))
|
||||
{
|
||||
if (!m_SelectionContext.HasComponent<CameraComponent>())
|
||||
{
|
||||
if (ImGui::MenuItem("Camera"))
|
||||
{
|
||||
m_SelectionContext.AddComponent<CameraComponent>();
|
||||
ImGui::CloseCurrentPopup();
|
||||
}
|
||||
}
|
||||
|
||||
if (!m_SelectionContext.HasComponent<SpriteRendererComponent>())
|
||||
{
|
||||
if (ImGui::MenuItem("Sprite Renderer"))
|
||||
{
|
||||
m_SelectionContext.AddComponent<SpriteRendererComponent>();
|
||||
ImGui::CloseCurrentPopup();
|
||||
}
|
||||
}
|
||||
|
||||
if (!m_SelectionContext.HasComponent<CircleRendererComponent>())
|
||||
{
|
||||
if (ImGui::MenuItem("Circle Renderer"))
|
||||
{
|
||||
m_SelectionContext.AddComponent<CircleRendererComponent>();
|
||||
ImGui::CloseCurrentPopup();
|
||||
}
|
||||
}
|
||||
|
||||
if (!m_SelectionContext.HasComponent<RigidBody2DComponent>())
|
||||
{
|
||||
if (ImGui::MenuItem("RigidBody 2D"))
|
||||
{
|
||||
m_SelectionContext.AddComponent<RigidBody2DComponent>();
|
||||
ImGui::CloseCurrentPopup();
|
||||
}
|
||||
}
|
||||
|
||||
if (!m_SelectionContext.HasComponent<BoxCollider2DComponent>())
|
||||
{
|
||||
if (ImGui::MenuItem("Box Collider 2D"))
|
||||
{
|
||||
m_SelectionContext.AddComponent<BoxCollider2DComponent>();
|
||||
ImGui::CloseCurrentPopup();
|
||||
}
|
||||
}
|
||||
|
||||
if (!m_SelectionContext.HasComponent<CircleCollider2DComponent>())
|
||||
{
|
||||
if (ImGui::MenuItem("Circle Collider 2D"))
|
||||
{
|
||||
m_SelectionContext.AddComponent<CircleCollider2DComponent>();
|
||||
ImGui::CloseCurrentPopup();
|
||||
}
|
||||
}
|
||||
|
||||
ImGui::EndPopup();
|
||||
}
|
||||
ImGui::PopItemWidth();
|
||||
|
||||
DrawComponent<TransformComponent>("Transform", entity, [](auto& component)
|
||||
{
|
||||
DrawVec3Control("Translation", component.Translation);
|
||||
glm::vec3 rotation = glm::degrees(component.Rotation);
|
||||
if (DrawVec3Control("Rotation", rotation))
|
||||
{
|
||||
component.Rotation = glm::radians(rotation);
|
||||
}
|
||||
DrawVec3Control("Scale", component.Scale, 1.0f);
|
||||
|
||||
});
|
||||
|
||||
DrawComponent<CameraComponent>("Camera", entity, [](auto& component)
|
||||
{
|
||||
auto& camera = component.Camera;
|
||||
|
||||
ImGui::Checkbox("isPrimary", &component.Primary);
|
||||
static const char* projectionTypeStrings[] = { "Perspective", "Orthographic" };
|
||||
|
||||
const char* currentProjectionTypeString = projectionTypeStrings[(int)camera.GetProjectionType()];
|
||||
if (ImGui::BeginCombo("Projection", currentProjectionTypeString))
|
||||
{
|
||||
for (int i = 0; i < 2; i++)
|
||||
{
|
||||
const bool isSelected = currentProjectionTypeString == projectionTypeStrings[i];
|
||||
if (ImGui::Selectable(projectionTypeStrings[i], isSelected))
|
||||
{
|
||||
currentProjectionTypeString = projectionTypeStrings[i];
|
||||
camera.SetProjectionType(static_cast<ScenceCamera::ProjectionType>(i));
|
||||
}
|
||||
|
||||
if (isSelected)
|
||||
{
|
||||
ImGui::SetItemDefaultFocus();
|
||||
}
|
||||
}
|
||||
ImGui::EndCombo();
|
||||
}
|
||||
|
||||
if (camera.GetProjectionType() == ScenceCamera::ProjectionType::Perspective)
|
||||
{
|
||||
float fov = glm::degrees(camera.GetPerspectiveVerticalFOV());
|
||||
if (ImGui::DragFloat("FOV", &fov, 0.1f))
|
||||
camera.SetPerspectiveVerticalFOV(glm::radians(fov));
|
||||
|
||||
float near = camera.GetPerspectiveNearCLip();
|
||||
if (ImGui::DragFloat("Near", &near))
|
||||
camera.SetPerspectiveNearClip(near);
|
||||
|
||||
float far = camera.GetPerspectiveFarCLip();
|
||||
if (ImGui::DragFloat("Far", &far))
|
||||
camera.SetPerspectiveFarClip(far);
|
||||
}
|
||||
if (camera.GetProjectionType() == ScenceCamera::ProjectionType::Orthographic)
|
||||
{
|
||||
float size = camera.GetOrthographicSize();
|
||||
if (ImGui::DragFloat("Size", &size))
|
||||
camera.SetOrthographicSize(size);
|
||||
|
||||
float near = camera.GetOrthographicNearCLip();
|
||||
if (ImGui::DragFloat("Near", &near))
|
||||
camera.SetOrthographicNearClip(near);
|
||||
|
||||
float far = camera.GetOrthographicFarCLip();
|
||||
if (ImGui::DragFloat("Far", &far))
|
||||
camera.SetOrthographicFarClip(far);
|
||||
|
||||
ImGui::Checkbox("Fixed Aspect Ratio", &component.FixedAspectRatio);
|
||||
}
|
||||
});
|
||||
|
||||
DrawComponent<SpriteRendererComponent>("Sprite Renderer", entity, [](auto& component)
|
||||
{
|
||||
ImGui::ColorEdit4("Color", glm::value_ptr(component.Color));
|
||||
// Texture
|
||||
ImGui::Button("Texture", ImVec2(100.f, 0.0f));
|
||||
|
||||
if (ImGui::BeginDragDropTarget())
|
||||
{
|
||||
if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload("CONTENT_BROSWER_ITEM"))
|
||||
{
|
||||
const wchar_t* path = (const wchar_t*)payload->Data;
|
||||
std::filesystem::path texturePath = std::filesystem::path(g_AssetPath) / path;
|
||||
component.Texture = Texture2D::Create(texturePath.string());
|
||||
}
|
||||
ImGui::EndDragDropTarget();
|
||||
}
|
||||
|
||||
ImGui::DragFloat("Tiling Color", &component.TilingFactor, 0.1f, 0.0f, 100.f);
|
||||
});
|
||||
|
||||
DrawComponent<CircleRendererComponent>("Circle Renderer", entity, [](auto& component)
|
||||
{
|
||||
ImGui::ColorEdit4("Color", glm::value_ptr(component.Color));
|
||||
// ImGui::DragFloat("Radius", &component.Radius, 0.01f, 0.0f, 1.f);
|
||||
ImGui::DragFloat("Thickness", &component.Thickness, 0.01f, 0.0f, 1.f);
|
||||
ImGui::DragFloat("Fade", &component.Fade, 0.00001f, 0.0f, 1.f);
|
||||
});
|
||||
|
||||
DrawComponent<RigidBody2DComponent>("Rigidbody 2D", entity, [](auto& component)
|
||||
{
|
||||
static const char* bodyTypeStrings[] = {"Static", "Dynamic", "Kinematic"};
|
||||
|
||||
const char* currentBodyTypeString = bodyTypeStrings[(int)component.Type];
|
||||
if (ImGui::BeginCombo("Body Type", currentBodyTypeString))
|
||||
{
|
||||
for (int i = 0; i < 3; i++)
|
||||
{
|
||||
const bool isSelected = currentBodyTypeString == bodyTypeStrings[i];
|
||||
if (ImGui::Selectable(bodyTypeStrings[i], isSelected))
|
||||
{
|
||||
currentBodyTypeString = bodyTypeStrings[i];
|
||||
component.Type = (RigidBody2DComponent::BodyType)i;
|
||||
}
|
||||
|
||||
if (isSelected)
|
||||
{
|
||||
ImGui::SetItemDefaultFocus();
|
||||
}
|
||||
}
|
||||
ImGui::EndCombo();
|
||||
}
|
||||
|
||||
ImGui::Checkbox("Fixed Rotation", &component.FixedRotation);
|
||||
});
|
||||
|
||||
DrawComponent<BoxCollider2DComponent>("Box Collider 2D", entity, [](auto& component)
|
||||
{
|
||||
ImGui::DragFloat2("Offset", glm::value_ptr(component.Offset), 0.001f);
|
||||
ImGui::DragFloat2("Size", glm::value_ptr(component.Size), 0.001f);
|
||||
|
||||
ImGui::DragFloat("Density", &component.Density, 0.01f, 0.0f);
|
||||
ImGui::DragFloat("Friction", &component.Friction, 0.01f, 0.0f, 1.0f);
|
||||
ImGui::DragFloat("Restitution", &component.Restitution, 0.01f, 0.0f, 1.0f);
|
||||
ImGui::DragFloat("Restitution Threshold", &component.RestitutionThreshold, 0.01f, 0.0f);
|
||||
});
|
||||
|
||||
DrawComponent<CircleCollider2DComponent>("Circle Collider 2D", entity, [](auto& component)
|
||||
{
|
||||
ImGui::DragFloat2("Offset", glm::value_ptr(component.Offset), 0.001f);
|
||||
ImGui::DragFloat("Radius", &component.Radius, 0.001f);
|
||||
|
||||
ImGui::DragFloat("Density", &component.Density, 0.01f, 0.0f);
|
||||
ImGui::DragFloat("Friction", &component.Friction, 0.01f, 0.0f, 1.0f);
|
||||
ImGui::DragFloat("Restitution", &component.Restitution, 0.01f, 0.0f, 1.0f);
|
||||
ImGui::DragFloat("Restitution Threshold", &component.RestitutionThreshold, 0.01f, 0.0f);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
void SceneHierachyPanel::SetSelectedEntity(const Entity entity)
|
||||
{
|
||||
m_SelectionContext = entity;
|
||||
}
|
||||
}
|
||||
@ -1,37 +0,0 @@
|
||||
//
|
||||
// Created by sfd on 25-5-29.
|
||||
//
|
||||
|
||||
#ifndef SCENEHIERACHYPANEL_H
|
||||
#define SCENEHIERACHYPANEL_H
|
||||
#include <Hazel/Core/Core.h>
|
||||
#include <Hazel/Scene/Entity.h>
|
||||
#include <Hazel/Scene/Scene.h>
|
||||
|
||||
namespace Hazel
|
||||
{
|
||||
class SceneHierachyPanel
|
||||
{
|
||||
public:
|
||||
SceneHierachyPanel() = default;
|
||||
SceneHierachyPanel(const Ref<Scene>& context);
|
||||
|
||||
void SetContext(const Ref<Scene>& context);
|
||||
void OnImGuiRender();
|
||||
|
||||
void DrawComponents(Entity entity);
|
||||
void SetSelectedEntity(const Entity entity);
|
||||
|
||||
Entity GetSelectedEntity() const { return m_SelectionContext; }
|
||||
private:
|
||||
void DrawEntityNode(Entity entity);
|
||||
|
||||
private:
|
||||
|
||||
Ref<Scene> m_Context;
|
||||
Entity m_SelectionContext;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
#endif //SCENEHIERACHYPANEL_H
|
||||
@ -1,21 +1,20 @@
|
||||
#include <Hazel.h>
|
||||
#include "Hazel/Core/EntryPoint.h"
|
||||
|
||||
#include "Editor/EditorLayer.h"
|
||||
#include "SandBox2D/SandBox2D.h"
|
||||
|
||||
|
||||
namespace Hazel
|
||||
{
|
||||
class HazelEditor : public Application
|
||||
class Sandbox : public Application
|
||||
{
|
||||
public:
|
||||
HazelEditor(const ApplicationSpecification& specification)
|
||||
Sandbox(const ApplicationSpecification& specification)
|
||||
: Application(specification)
|
||||
{
|
||||
PushLayer(new EditorLayer());
|
||||
PushLayer(new SandBox2D());
|
||||
}
|
||||
|
||||
~HazelEditor() = default;
|
||||
~Sandbox() = default;
|
||||
|
||||
};
|
||||
|
||||
@ -23,9 +22,9 @@ namespace Hazel
|
||||
Application* CreateApplication(ApplicationCommandLineArgs args)
|
||||
{
|
||||
ApplicationSpecification spec;
|
||||
spec.name = "Editor app";
|
||||
spec.name = "Sandbox2D";
|
||||
spec.commandLineArgs = args;
|
||||
|
||||
return new HazelEditor(spec);
|
||||
return new Sandbox(spec);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user