add custom fonts to support 中文, add material edit for selected mesh

This commit is contained in:
2025-12-14 16:48:40 +08:00
parent c92c831d02
commit 0f7eb7cc95
9 changed files with 292 additions and 194 deletions

View File

@ -328,45 +328,21 @@ namespace Prism
{
if (ImGui::MenuItem("New Scene"))
{
}
if (ImGui::MenuItem("Open Scene..."))
if (ImGui::MenuItem("Open Scene...", "Ctrl+O"))
{
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;
std::filesystem::path path = filepath;
UpdateWindowTitle(path.filename().string());
m_SceneHierarchyPanel->SetContext(m_EditorScene);
ScriptEngine::SetSceneContext(m_EditorScene);
m_EditorScene->SetSelectedEntity({});
m_SelectionContext.clear();
}
OpenScene();
}
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);
std::filesystem::path path = filepath;
UpdateWindowTitle(path.filename().string());
}
ImGui::Separator();
if (ImGui::MenuItem("Save Scene...", "Ctrl+S"))
{
SaveScene();
}
if (ImGui::MenuItem("Save Scene As...", "Ctrl+Shift+S"))
{
SaveSceneAs();
}
/*
if (ImGui::MenuItem("Reload C# Assembly"))
ScriptEngine::ReloadAssembly("assets/scripts/ExampleApp.dll");
*/
ImGui::Separator();
if (ImGui::MenuItem("Exit"))
p_open = false;
@ -375,6 +351,7 @@ namespace Prism
if (ImGui::BeginMenu("Script"))
{
// temp
if (ImGui::MenuItem("Reload C# Assembly"))
ScriptEngine::ReloadAssembly("assets/scripts/ExampleApp.dll");
@ -397,7 +374,7 @@ namespace Prism
Ref<Mesh> mesh = selectedEntity.GetComponent<MeshComponent>().Mesh;
if (mesh)
{
const auto& materials = mesh->GetMaterials();
auto& materials = mesh->GetMaterials();
static uint32_t selectedMaterialIndex = 0;
for (uint32_t i = 0; i < materials.size(); i++)
{
@ -418,7 +395,172 @@ namespace Prism
if (selectedMaterialIndex < materials.size())
{
ImGui::Text("Shader: %s", materials[selectedMaterialIndex]->GetShader()->GetName().c_str());
auto& materialInstance = materials[selectedMaterialIndex];
ImGui::Text("Shader: %s", materialInstance->GetShader()->GetName().c_str());
// Textures ------------------------------------------------------------------------------
{
// Albedo
if (ImGui::CollapsingHeader("Albedo", nullptr, ImGuiTreeNodeFlags_DefaultOpen))
{
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(10, 10));
auto& albedoColor = materialInstance->Get<glm::vec3>("u_AlbedoColor");
bool useAlbedoMap = materialInstance->Get<float>("u_AlbedoTexToggle");
Ref<Texture2D> albedoMap = materialInstance->TryGetResource<Texture2D>("u_AlbedoTexture");
ImGui::Image(albedoMap ? (ImTextureRef)albedoMap->GetRendererID() : (ImTextureRef)m_CheckerboardTex->GetRendererID(), ImVec2(64, 64));
ImGui::PopStyleVar();
if (ImGui::IsItemHovered())
{
if (albedoMap)
{
ImGui::BeginTooltip();
ImGui::PushTextWrapPos(ImGui::GetFontSize() * 35.0f);
ImGui::TextUnformatted(albedoMap->GetPath().c_str());
ImGui::PopTextWrapPos();
ImGui::Image((ImTextureRef)albedoMap->GetRendererID(), ImVec2(384, 384));
ImGui::EndTooltip();
}
if (ImGui::IsItemClicked())
{
std::string filename = Application::Get().OpenFile("");
if (filename != "")
{
albedoMap = Texture2D::Create(filename, true/*m_AlbedoInput.SRGB*/);
materialInstance->Set("u_AlbedoTexture", albedoMap);
}
}
}
ImGui::SameLine();
ImGui::BeginGroup();
if (ImGui::Checkbox("Use##AlbedoMap", &useAlbedoMap))
materialInstance->Set<float>("u_AlbedoTexToggle", useAlbedoMap ? 1.0f : 0.0f);
/*if (ImGui::Checkbox("sRGB##AlbedoMap", &m_AlbedoInput.SRGB))
{
if (m_AlbedoInput.TextureMap)
m_AlbedoInput.TextureMap = Texture2D::Create(m_AlbedoInput.TextureMap->GetPath(), m_AlbedoInput.SRGB);
}*/
ImGui::EndGroup();
ImGui::SameLine();
ImGui::ColorEdit3("Color##Albedo", glm::value_ptr(albedoColor), ImGuiColorEditFlags_NoInputs);
}
}
{
// Normals
if (ImGui::CollapsingHeader("Normals", nullptr, ImGuiTreeNodeFlags_DefaultOpen))
{
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(10, 10));
bool useNormalMap = materialInstance->Get<float>("u_NormalTexToggle");
Ref<Texture2D> normalMap = materialInstance->TryGetResource<Texture2D>("u_NormalTexture");
ImGui::Image(normalMap ? (ImTextureRef)normalMap->GetRendererID() : (ImTextureRef)m_CheckerboardTex->GetRendererID(), ImVec2(64, 64));
ImGui::PopStyleVar();
if (ImGui::IsItemHovered())
{
if (normalMap)
{
ImGui::BeginTooltip();
ImGui::PushTextWrapPos(ImGui::GetFontSize() * 35.0f);
ImGui::TextUnformatted(normalMap->GetPath().c_str());
ImGui::PopTextWrapPos();
ImGui::Image((ImTextureRef)normalMap->GetRendererID(), ImVec2(384, 384));
ImGui::EndTooltip();
}
if (ImGui::IsItemClicked())
{
std::string filename = Application::Get().OpenFile("");
if (filename != "")
{
normalMap = Texture2D::Create(filename);
materialInstance->Set("u_NormalTexture", normalMap);
}
}
}
ImGui::SameLine();
if (ImGui::Checkbox("Use##NormalMap", &useNormalMap))
materialInstance->Set<float>("u_NormalTexToggle", useNormalMap ? 1.0f : 0.0f);
}
}
{
// Metalness
if (ImGui::CollapsingHeader("Metalness", nullptr, ImGuiTreeNodeFlags_DefaultOpen))
{
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(10, 10));
float& metalnessValue = materialInstance->Get<float>("u_Metalness");
bool useMetalnessMap = materialInstance->Get<float>("u_MetalnessTexToggle");
Ref<Texture2D> metalnessMap = materialInstance->TryGetResource<Texture2D>("u_MetalnessTexture");
ImGui::Image(metalnessMap ? (ImTextureRef)metalnessMap->GetRendererID() : (ImTextureRef)m_CheckerboardTex->GetRendererID(), ImVec2(64, 64));
ImGui::PopStyleVar();
if (ImGui::IsItemHovered())
{
if (metalnessMap)
{
ImGui::BeginTooltip();
ImGui::PushTextWrapPos(ImGui::GetFontSize() * 35.0f);
ImGui::TextUnformatted(metalnessMap->GetPath().c_str());
ImGui::PopTextWrapPos();
ImGui::Image((ImTextureRef)metalnessMap->GetRendererID(), ImVec2(384, 384));
ImGui::EndTooltip();
}
if (ImGui::IsItemClicked())
{
std::string filename = Application::Get().OpenFile("");
if (filename != "")
{
metalnessMap = Texture2D::Create(filename);
materialInstance->Set("u_MetalnessTexture", metalnessMap);
}
}
}
ImGui::SameLine();
if (ImGui::Checkbox("Use##MetalnessMap", &useMetalnessMap))
materialInstance->Set<float>("u_MetalnessTexToggle", useMetalnessMap ? 1.0f : 0.0f);
ImGui::SameLine();
ImGui::SliderFloat("Value##MetalnessInput", &metalnessValue, 0.0f, 1.0f);
}
}
{
// Roughness
if (ImGui::CollapsingHeader("Roughness", nullptr, ImGuiTreeNodeFlags_DefaultOpen))
{
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(10, 10));
float& roughnessValue = materialInstance->Get<float>("u_Roughness");
bool useRoughnessMap = materialInstance->Get<float>("u_RoughnessTexToggle");
Ref<Texture2D> roughnessMap = materialInstance->TryGetResource<Texture2D>("u_RoughnessTexture");
ImGui::Image(roughnessMap ? (ImTextureRef)roughnessMap->GetRendererID() : (ImTextureRef)m_CheckerboardTex->GetRendererID(), ImVec2(64, 64));
ImGui::PopStyleVar();
if (ImGui::IsItemHovered())
{
if (roughnessMap)
{
ImGui::BeginTooltip();
ImGui::PushTextWrapPos(ImGui::GetFontSize() * 35.0f);
ImGui::TextUnformatted(roughnessMap->GetPath().c_str());
ImGui::PopTextWrapPos();
ImGui::Image((ImTextureRef)roughnessMap->GetRendererID(), ImVec2(384, 384));
ImGui::EndTooltip();
}
if (ImGui::IsItemClicked())
{
std::string filename = Application::Get().OpenFile("");
if (filename != "")
{
roughnessMap = Texture2D::Create(filename);
materialInstance->Set("u_RoughnessTexture", roughnessMap);
}
}
}
ImGui::SameLine();
if (ImGui::Checkbox("Use##RoughnessMap", &useRoughnessMap))
materialInstance->Set<float>("u_RoughnessTexToggle", useRoughnessMap ? 1.0f : 0.0f);
ImGui::SameLine();
ImGui::SliderFloat("Value##RoughnessInput", &roughnessValue, 0.0f, 1.0f);
}
}
}
}
}
@ -516,145 +658,6 @@ namespace Prism
}
ImGui::Separator();
// Textures ------------------------------------------------------------------------------
{
// Albedo
if (ImGui::CollapsingHeader("Albedo", nullptr, ImGuiTreeNodeFlags_DefaultOpen))
{
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(10, 10));
ImGui::Image((ImTextureRef)(m_AlbedoInput.TextureMap
? m_AlbedoInput.TextureMap->GetRendererID()
: m_CheckerboardTex->GetRendererID()), ImVec2(64, 64));
ImGui::PopStyleVar();
if (ImGui::IsItemHovered())
{
if (m_AlbedoInput.TextureMap)
{
ImGui::BeginTooltip();
ImGui::PushTextWrapPos(ImGui::GetFontSize() * 35.0f);
ImGui::TextUnformatted(m_AlbedoInput.TextureMap->GetPath().c_str());
ImGui::PopTextWrapPos();
ImGui::Image((ImTextureRef)m_AlbedoInput.TextureMap->GetRendererID(), ImVec2(384, 384));
ImGui::EndTooltip();
}
if (ImGui::IsItemClicked())
{
std::string filename = Application::Get().OpenFile("");
if (!filename.empty())
m_AlbedoInput.TextureMap = Texture2D::Create(filename, m_AlbedoInput.SRGB);
}
}
ImGui::SameLine();
ImGui::BeginGroup();
ImGui::Checkbox("Use##AlbedoMap", &m_AlbedoInput.UseTexture);
if (ImGui::Checkbox("sRGB##AlbedoMap", &m_AlbedoInput.SRGB))
{
if (m_AlbedoInput.TextureMap)
m_AlbedoInput.TextureMap = Texture2D::Create(m_AlbedoInput.TextureMap->GetPath(), m_AlbedoInput.SRGB);
}
ImGui::EndGroup();
ImGui::SameLine();
ImGui::ColorEdit3("Color##Albedo", glm::value_ptr(m_AlbedoInput.Color), ImGuiColorEditFlags_NoInputs);
}
}
{
// Normals
if (ImGui::CollapsingHeader("Normals", nullptr, ImGuiTreeNodeFlags_DefaultOpen))
{
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(10, 10));
ImGui::Image((ImTextureRef)(m_NormalInput.TextureMap
? m_NormalInput.TextureMap->GetRendererID()
: m_CheckerboardTex->GetRendererID()), ImVec2(64, 64));
ImGui::PopStyleVar();
if (ImGui::IsItemHovered())
{
if (m_NormalInput.TextureMap)
{
ImGui::BeginTooltip();
ImGui::PushTextWrapPos(ImGui::GetFontSize() * 35.0f);
ImGui::TextUnformatted(m_NormalInput.TextureMap->GetPath().c_str());
ImGui::PopTextWrapPos();
ImGui::Image((ImTextureRef)m_NormalInput.TextureMap->GetRendererID(), ImVec2(384, 384));
ImGui::EndTooltip();
}
if (ImGui::IsItemClicked())
{
std::string filename = Application::Get().OpenFile("");
if (!filename.empty())
m_NormalInput.TextureMap = Texture2D::Create(filename);
}
}
ImGui::SameLine();
ImGui::Checkbox("Use##NormalMap", &m_NormalInput.UseTexture);
}
}
{
// Metalness
if (ImGui::CollapsingHeader("Metalness", nullptr, ImGuiTreeNodeFlags_DefaultOpen))
{
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(10, 10));
ImGui::Image((ImTextureRef)(m_MetalnessInput.TextureMap
? m_MetalnessInput.TextureMap->GetRendererID()
: m_CheckerboardTex->GetRendererID()), ImVec2(64, 64));
ImGui::PopStyleVar();
if (ImGui::IsItemHovered())
{
if (m_MetalnessInput.TextureMap)
{
ImGui::BeginTooltip();
ImGui::PushTextWrapPos(ImGui::GetFontSize() * 35.0f);
ImGui::TextUnformatted(m_MetalnessInput.TextureMap->GetPath().c_str());
ImGui::PopTextWrapPos();
ImGui::Image((ImTextureRef)m_MetalnessInput.TextureMap->GetRendererID(), ImVec2(384, 384));
ImGui::EndTooltip();
}
if (ImGui::IsItemClicked())
{
std::string filename = Application::Get().OpenFile("");
if (!filename.empty())
m_MetalnessInput.TextureMap = Texture2D::Create(filename);
}
}
ImGui::SameLine();
ImGui::Checkbox("Use##MetalnessMap", &m_MetalnessInput.UseTexture);
ImGui::SameLine();
ImGui::SliderFloat("Value##MetalnessInput", &m_MetalnessInput.Value, 0.0f, 1.0f);
}
}
{
// Roughness
if (ImGui::CollapsingHeader("Roughness", nullptr, ImGuiTreeNodeFlags_DefaultOpen))
{
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(10, 10));
ImGui::Image((ImTextureRef)(m_RoughnessInput.TextureMap
? m_RoughnessInput.TextureMap->GetRendererID()
: m_CheckerboardTex->GetRendererID()), ImVec2(64, 64));
ImGui::PopStyleVar();
if (ImGui::IsItemHovered())
{
if (m_RoughnessInput.TextureMap)
{
ImGui::BeginTooltip();
ImGui::PushTextWrapPos(ImGui::GetFontSize() * 35.0f);
ImGui::TextUnformatted(m_RoughnessInput.TextureMap->GetPath().c_str());
ImGui::PopTextWrapPos();
ImGui::Image((ImTextureRef)m_RoughnessInput.TextureMap->GetRendererID(), ImVec2(384, 384));
ImGui::EndTooltip();
}
if (ImGui::IsItemClicked())
{
std::string filename = Application::Get().OpenFile("");
if (!filename.empty())
m_RoughnessInput.TextureMap = Texture2D::Create(filename);
}
}
ImGui::SameLine();
ImGui::Checkbox("Use##RoughnessMap", &m_RoughnessInput.UseTexture);
ImGui::SameLine();
ImGui::SliderFloat("Value##RoughnessInput", &m_RoughnessInput.Value, 0.0f, 1.0f);
}
}
if (ImGui::TreeNode("Shaders"))
{
auto& shaders = Shader::GetAllShaders();
@ -754,7 +757,8 @@ namespace Prism
bool snap = Input::IsKeyPressed(Key::LEFT_CONTROL);
auto& entityTransform = selection.Entity.Transform();
float snapValue[3] = { m_SnapValue, m_SnapValue, m_SnapValue };
float snapValue = GetSnapValue();
float snapValues[3] = { snapValue, snapValue, snapValue };
if (m_SelectionMode == SelectionMode::Entity)
{
ImGuizmo::Manipulate(glm::value_ptr(m_EditorCamera.GetViewMatrix()),
@ -763,7 +767,7 @@ namespace Prism
ImGuizmo::LOCAL,
glm::value_ptr(entityTransform),
nullptr,
snap ? snapValue : nullptr);
snap ? snapValues : nullptr);
}else
{
glm::mat4 transformBase = entityTransform * selection.Mesh->Transform;
@ -773,7 +777,7 @@ namespace Prism
ImGuizmo::LOCAL,
glm::value_ptr(transformBase),
nullptr,
snap ? snapValue : nullptr);
snap ? snapValues : nullptr);
selection.Mesh->Transform = glm::inverse(entityTransform) * transformBase;
}
@ -833,14 +837,18 @@ namespace Prism
break;
}
}
if (Input::IsKeyPressed(KeyCode::LEFT_CONTROL))
{
switch (e.GetKeyCode())
{
case KeyCode::G:
// Toggle grid
SceneRenderer::GetOptions().ShowGrid = !SceneRenderer::GetOptions().ShowGrid;
case KeyCode::O:
OpenScene();
break;
case KeyCode::S:
SaveScene();
break;
case KeyCode::B:
// Toggle bounding boxes
m_UIShowBoundingBoxes = !m_UIShowBoundingBoxes;
@ -853,6 +861,20 @@ namespace Prism
m_EditorScene->DuplicateEntity(selectedEntity);
}
break;
case KeyCode::G:
// Toggle grid
SceneRenderer::GetOptions().ShowGrid = !SceneRenderer::GetOptions().ShowGrid;
break;
}
if (Input::IsKeyPressed(PM_KEY_LEFT_SHIFT))
{
switch (e.GetKeyCode())
{
case KeyCode::S:
SaveSceneAs();
break;
}
}
}
@ -998,6 +1020,49 @@ namespace Prism
return Ray::Zero();
}
void EditorLayer::OpenScene()
{
const auto& app = Application::Get();
const std::string filepath = app.OpenFile("Hazel Scene (*.hsc)\0*.hsc\0");
if (!filepath.empty())
{
const Ref<Scene> newScene = Ref<Scene>::Create();
SceneSerializer serializer(newScene);
serializer.Deserialize(filepath);
m_EditorScene = newScene;
const std::filesystem::path path = filepath;
UpdateWindowTitle(path.filename().string());
m_SceneHierarchyPanel->SetContext(m_EditorScene);
ScriptEngine::SetSceneContext(m_EditorScene);
m_EditorScene->SetSelectedEntity({});
m_SelectionContext.clear();
m_SceneFilePath = filepath;
}
}
void EditorLayer::SaveScene()
{
SceneSerializer serializer(m_EditorScene);
serializer.Serialize(m_SceneFilePath);
}
void EditorLayer::SaveSceneAs()
{
auto& app = Application::Get();
std::string filepath = app.SaveFile("Hazel Scene (*.hsc)\0*.hsc\0");
if (!filepath.empty())
{
SceneSerializer serializer(m_EditorScene);
serializer.Serialize(filepath);
std::filesystem::path path = filepath;
UpdateWindowTitle(path.filename().string());
m_SceneFilePath = filepath;
}
}
void EditorLayer::OnScenePlay()
{
m_SelectionContext.clear();
@ -1026,4 +1091,15 @@ namespace Prism
ScriptEngine::SetSceneContext(m_EditorScene);
m_SceneHierarchyPanel->SetContext(m_EditorScene);
}
float EditorLayer::GetSnapValue()
{
switch (m_GizmoType)
{
case ImGuizmo::OPERATION::TRANSLATE: return 0.5f;
case ImGuizmo::OPERATION::ROTATE: return 45.0f;
case ImGuizmo::OPERATION::SCALE: return 0.5f;
}
return 0.0f;
}
}

View File

@ -44,13 +44,21 @@ namespace Prism
void OnEntityDeleted(Entity e);
Ray CastMouseRay();
void OpenScene();
void SaveScene();
void SaveSceneAs();
void OnScenePlay();
void OnSceneStop();
float GetSnapValue();
private:
Scope<SceneHierarchyPanel> m_SceneHierarchyPanel;
Ref<Scene> m_ActiveScene;
Ref<Scene> m_RuntimeScene, m_EditorScene;
std::string m_SceneFilePath;
bool m_ReloadScriptOnPlay = false;
EditorCamera m_EditorCamera;
@ -66,6 +74,7 @@ namespace Prism
glm::vec2 m_ViewportBounds[2] = {};
int m_GizmoType = -1; // -1 = no gizmo
float m_SnapValue = 0.5f;
float m_RotationSnapValue = 45.0f;
enum class SelectionMode
{
@ -84,14 +93,14 @@ namespace Prism
bool SRGB = true;
bool UseTexture = false;
};
AlbedoInput m_AlbedoInput;
// AlbedoInput m_AlbedoInput;
struct NormalInput
{
Ref<Texture2D> TextureMap;
bool UseTexture = false;
};
NormalInput m_NormalInput;
// NormalInput m_NormalInput;
struct MetalnessInput
{
@ -99,7 +108,7 @@ namespace Prism
Ref<Texture2D> TextureMap;
bool UseTexture = false;
};
MetalnessInput m_MetalnessInput;
// MetalnessInput m_MetalnessInput;
struct RoughnessInput
{
@ -107,7 +116,7 @@ namespace Prism
Ref<Texture2D> TextureMap;
bool UseTexture = false;
};
RoughnessInput m_RoughnessInput;
// RoughnessInput m_RoughnessInput;
// PBR params

Binary file not shown.