From 66a3171ccd8470e51fdd8c8a8ffc324644558b51 Mon Sep 17 00:00:00 2001 From: Atdunbg <979541498@qq.com> Date: Fri, 31 Oct 2025 00:53:18 +0800 Subject: [PATCH] add TextComponent --- .../src/Editor/Panels/SceneHierachyPanel.cpp | 12 +++- Hazel/src/Hazel/ImGui/ImGuiLayer.cpp | 1 + Hazel/src/Hazel/Renderer/Renderer2D.cpp | 48 +++++++++---- Hazel/src/Hazel/Renderer/Renderer2D.h | 9 ++- Hazel/src/Hazel/Scene/Components.h | 14 +++- Hazel/src/Hazel/Scene/Scene.cpp | 20 ++++-- Hazel/src/Hazel/Scene/SceneSerializer.cpp | 69 +++++++++++++------ 7 files changed, 131 insertions(+), 42 deletions(-) diff --git a/Editor/src/Editor/Panels/SceneHierachyPanel.cpp b/Editor/src/Editor/Panels/SceneHierachyPanel.cpp index c03a1fa..1aac2e2 100644 --- a/Editor/src/Editor/Panels/SceneHierachyPanel.cpp +++ b/Editor/src/Editor/Panels/SceneHierachyPanel.cpp @@ -9,9 +9,10 @@ #include #include #include -#include "Hazel/UI/UI.h" +#include #include "Hazel/Scripting/ScriptEngine.h" +#include "Hazel/UI/UI.h" namespace Hazel { @@ -285,6 +286,7 @@ namespace Hazel DisplayAddComponentEntry("RigidBody 2D"); DisplayAddComponentEntry("Box Collider 2D"); DisplayAddComponentEntry("Circle Collider 2D"); + DisplayAddComponentEntry("Text Component"); ImGui::EndPopup(); } @@ -525,6 +527,14 @@ namespace Hazel ImGui::DragFloat("Restitution", &component.Restitution, 0.01f, 0.0f, 1.0f); ImGui::DragFloat("Restitution Threshold", &component.RestitutionThreshold, 0.01f, 0.0f); }); + + DrawComponent("Text Renderer", entity, [](auto& component) + { + ImGui::InputTextMultiline("Text string", &component.TextString); + ImGui::ColorEdit4("Color", glm::value_ptr(component.Color)); + ImGui::DragFloat("Kerning", &component.Kerning, 0.01f); + ImGui::DragFloat("LineSpacing", &component.LineSpacing, 0.01f); + }); } diff --git a/Hazel/src/Hazel/ImGui/ImGuiLayer.cpp b/Hazel/src/Hazel/ImGui/ImGuiLayer.cpp index 2686fe8..418c5d0 100644 --- a/Hazel/src/Hazel/ImGui/ImGuiLayer.cpp +++ b/Hazel/src/Hazel/ImGui/ImGuiLayer.cpp @@ -9,6 +9,7 @@ #include #include #include +#include #include "ImGuizmo.h" #include "imgui_internal.h" diff --git a/Hazel/src/Hazel/Renderer/Renderer2D.cpp b/Hazel/src/Hazel/Renderer/Renderer2D.cpp index e54d24e..f2cab0a 100644 --- a/Hazel/src/Hazel/Renderer/Renderer2D.cpp +++ b/Hazel/src/Hazel/Renderer/Renderer2D.cpp @@ -759,8 +759,8 @@ namespace Hazel DrawLine(lineVectices[3], lineVectices[0], color, entityID); } - void Renderer2D::DrawString(const std::string& string, const Ref& font, const glm::mat4& transform, - const glm::vec4& color, int entityID) + void Renderer2D::DrawString(const std::string& string, const Ref& font, const glm::mat4& transform, + const TextParams& textParams, int entityID) { const auto& fontGeomatry = font->GetMSDFData()->FontGeometry; const auto& metrics = fontGeomatry.getMetrics(); @@ -772,7 +772,8 @@ namespace Hazel double x = 0.0; double fsScale = 1.0 / (metrics.ascenderY - metrics.descenderY); double y = 0.0; - float lineHeightOffset = 0.0f; + + const float spaceGlyphAdvance = fontGeomatry.getGlyph(' ')->getAdvance(); for (size_t i = 0; i < string.size(); i++) { @@ -783,17 +784,35 @@ namespace Hazel if (character == '\n') { x = 0; - y -= fsScale * metrics.lineHeight + lineHeightOffset; + y -= fsScale * metrics.lineHeight + textParams.LineSpacing; continue; } + if (character == ' ') + { + float advance = spaceGlyphAdvance; + if ( i < string.size() - 1) + { + char nextCharacter = string[i + 1]; + double dAdvance; + fontGeomatry.getAdvance(dAdvance, character, nextCharacter); + advance = (float)dAdvance; + } + + x += fsScale * advance + textParams.Kerning; + continue; + } + if (character == '\t') + { + x += 4.0f * (fsScale * spaceGlyphAdvance + textParams.Kerning) ; + continue; + } + auto glphy = fontGeomatry.getGlyph(character); if (!glphy) glphy = fontGeomatry.getGlyph('?'); if (!glphy) return; - if (character == '\t') - glphy = fontGeomatry.getGlyph(' '); // Atlas bound double aLeft, aButtom, aRight, aTop; @@ -822,25 +841,25 @@ namespace Hazel // Render s_Data.TextVertexBufferPtr->Position = transform * glm::vec4(quadMin, 0.0f, 1.0f); - s_Data.TextVertexBufferPtr->Color = color; + s_Data.TextVertexBufferPtr->Color = textParams.Color; s_Data.TextVertexBufferPtr->TexCoord = texCoordMin; s_Data.TextVertexBufferPtr->EntityID = entityID; s_Data.TextVertexBufferPtr++; s_Data.TextVertexBufferPtr->Position = transform * glm::vec4(quadMin.x, quadMax.y, 0.0f, 1.0f); - s_Data.TextVertexBufferPtr->Color = color; + s_Data.TextVertexBufferPtr->Color = textParams.Color; s_Data.TextVertexBufferPtr->TexCoord = { texCoordMin.x, texCoordMax.y }; s_Data.TextVertexBufferPtr->EntityID = entityID; s_Data.TextVertexBufferPtr++; s_Data.TextVertexBufferPtr->Position = transform * glm::vec4(quadMax, 0.0f, 1.0f); - s_Data.TextVertexBufferPtr->Color = color; + s_Data.TextVertexBufferPtr->Color = textParams.Color; s_Data.TextVertexBufferPtr->TexCoord = texCoordMax; s_Data.TextVertexBufferPtr->EntityID = entityID; s_Data.TextVertexBufferPtr++; s_Data.TextVertexBufferPtr->Position = transform * glm::vec4(quadMax.x, quadMin.y, 0.0f, 1.0f); - s_Data.TextVertexBufferPtr->Color = color; + s_Data.TextVertexBufferPtr->Color = textParams.Color; s_Data.TextVertexBufferPtr->TexCoord = {texCoordMax.x, texCoordMin.y}; s_Data.TextVertexBufferPtr->EntityID = entityID; s_Data.TextVertexBufferPtr++; @@ -854,12 +873,17 @@ namespace Hazel const char nextCharacter = string[i + 1]; fontGeomatry.getAdvance(advance, character, nextCharacter); - float kerningOffset = 0.0f; - x += fsScale * advance + kerningOffset; + x += fsScale * advance + textParams.Kerning; } } } + void Renderer2D::DrawString(const std::string& string, const glm::mat4& transform, const TextComponent& component, + int entityID) + { + DrawString(string, component.FontAsset, transform, {component.Color, component.Kerning, component.LineSpacing}, entityID); + } + float Renderer2D::GetLineWidth() { return s_Data.LineWidth; diff --git a/Hazel/src/Hazel/Renderer/Renderer2D.h b/Hazel/src/Hazel/Renderer/Renderer2D.h index 7d593d6..d9ae7cd 100644 --- a/Hazel/src/Hazel/Renderer/Renderer2D.h +++ b/Hazel/src/Hazel/Renderer/Renderer2D.h @@ -62,7 +62,14 @@ namespace Hazel static void DrawRect(const glm::mat4& transform, const glm::vec4& color, int entityID = -1); - static void DrawString(const std::string& string, const Ref& font, const glm::mat4& transform, const glm::vec4& color, int entityID = -1); + struct TextParams + { + glm::vec4 Color {0.0f}; + float Kerning = 0.0f; + float LineSpacing = 0.0f; + }; + static void DrawString(const std::string& string, const Ref& font, const glm::mat4& transform, const TextParams& textParams, int entityID = -1); + static void DrawString(const std::string& string, const glm::mat4& transform, const TextComponent& component, int entityID = -1); static float GetLineWidth(); static void SetLineWidth(float width); diff --git a/Hazel/src/Hazel/Scene/Components.h b/Hazel/src/Hazel/Scene/Components.h index f24b349..fd978fe 100644 --- a/Hazel/src/Hazel/Scene/Components.h +++ b/Hazel/src/Hazel/Scene/Components.h @@ -17,6 +17,8 @@ #include #include +#include "Hazel/Renderer/Font.h" + namespace Hazel { struct IDComponent @@ -168,6 +170,16 @@ namespace Hazel CircleCollider2DComponent(const CircleCollider2DComponent&) = default; }; + struct TextComponent + { + std::string TextString; + Ref FontAsset = Font::GetDefault(); + glm::vec4 Color{1.0f, 1.0f, 1.0f, 1.0f}; + float Kerning = 0.0f; + float LineSpacing = -.0f; + }; + + template struct ComponentGroup { @@ -177,7 +189,7 @@ namespace Hazel CircleRendererComponent, BoxCollider2DComponent, CircleCollider2DComponent, CameraComponent, ScriptComponent, NativeScriptComponent, - RigidBody2DComponent>; + RigidBody2DComponent, TextComponent>; } diff --git a/Hazel/src/Hazel/Scene/Scene.cpp b/Hazel/src/Hazel/Scene/Scene.cpp index 6c83fde..410c24e 100644 --- a/Hazel/src/Hazel/Scene/Scene.cpp +++ b/Hazel/src/Hazel/Scene/Scene.cpp @@ -223,11 +223,15 @@ namespace Hazel Renderer2D::DrawCircle(transform.GetTransform(), circle.Color, circle.Thickness, circle.Fade, (int)entity); } - // Renderer2D::DrawString("hello", Font::GetDefault(), glm::mat4(1.0f), glm::vec4(1.0f), 0); - - Renderer2D::DrawString(R"( - Hello World! - )", Font::GetDefault(), glm::mat4(1.0f), glm::vec4(0.2f, 0.5f, 0.3f, 1.0f)); + // Draw Text + { + const auto& view = m_Registry.view(); + for (const auto& entity : view) + { + auto [transform, text] = view.get(entity); + Renderer2D::DrawString(text.TextString, transform.GetTransform(), text, (int)entity); + } + } Renderer2D::EndScene(); } @@ -532,6 +536,11 @@ namespace Hazel { } + template <> + void Scene::OnComponentAdded(Entity entity, TextComponent& component) + { + } + template HAZEL_API void Scene::OnComponentAdded(Entity, IDComponent&); template HAZEL_API void Scene::OnComponentAdded(Entity, TransformComponent&); @@ -544,4 +553,5 @@ namespace Hazel template HAZEL_API void Scene::OnComponentAdded(Entity, RigidBody2DComponent&); template HAZEL_API void Scene::OnComponentAdded(Entity, BoxCollider2DComponent&); template HAZEL_API void Scene::OnComponentAdded(Entity, CircleCollider2DComponent&); + template HAZEL_API void Scene::OnComponentAdded(Entity, TextComponent&); } diff --git a/Hazel/src/Hazel/Scene/SceneSerializer.cpp b/Hazel/src/Hazel/Scene/SceneSerializer.cpp index 97fbd88..3a9061c 100644 --- a/Hazel/src/Hazel/Scene/SceneSerializer.cpp +++ b/Hazel/src/Hazel/Scene/SceneSerializer.cpp @@ -197,7 +197,7 @@ namespace Hazel out << YAML::Key << "TransformComponent"; out << YAML::BeginMap; // TransformComponent - auto& transform = entity.GetComponent(); + const auto& transform = entity.GetComponent(); out << YAML::Key << "Translation" << YAML::Value << transform.Translation; out << YAML::Key << "Rotation" << YAML::Value << transform.Rotation; out << YAML::Key << "Scale" << YAML::Value << transform.Scale; @@ -211,8 +211,8 @@ namespace Hazel out << YAML::BeginMap; // CameraComponent - auto& cameraComponent = entity.GetComponent(); - auto& camera = cameraComponent.Camera; + const auto& cameraComponent = entity.GetComponent(); + const auto& camera = cameraComponent.Camera; out << YAML::Key << "Camera" << YAML::Value; // CameraComponent out << YAML::BeginMap; // Camera @@ -234,7 +234,7 @@ namespace Hazel if (entity.HasComponent()) { - auto& scriptComponent = entity.GetComponent(); + const auto& scriptComponent = entity.GetComponent(); out << YAML::Key << "ScriptComponent"; @@ -242,7 +242,7 @@ namespace Hazel out << YAML::Key << "ClassName" << YAML::Value << scriptComponent.ClassName; // fields - Ref entityClass = ScriptEngine::GetEntityClass(scriptComponent.ClassName); + const Ref entityClass = ScriptEngine::GetEntityClass(scriptComponent.ClassName); const auto& fields = entityClass->GetFields(); if (fields.size() > 0) { @@ -303,7 +303,7 @@ namespace Hazel out << YAML::Key << "CircleRendererComponent"; out << YAML::BeginMap; // CircleRendererComponent - auto& circleRendererComponent = entity.GetComponent(); + const auto& circleRendererComponent = entity.GetComponent(); out << YAML::Key << "Color" << YAML::Value << circleRendererComponent.Color; out << YAML::Key << "Radius" << YAML::Value << circleRendererComponent.Radius; out << YAML::Key << "Thickness" << YAML::Value << circleRendererComponent.Thickness; @@ -316,7 +316,7 @@ namespace Hazel out << YAML::Key << "SpriteRendererComponent"; out << YAML::BeginMap; // SpriteRendererComponent - auto& spriteRendererComponent = entity.GetComponent(); + const auto& spriteRendererComponent = entity.GetComponent(); out << YAML::Key << "Color" << YAML::Value << spriteRendererComponent.Color; if (spriteRendererComponent.Texture) out << YAML::Key << "TexturePath" << YAML::Value << spriteRendererComponent.Texture->GetPath(); @@ -329,7 +329,7 @@ namespace Hazel out << YAML::Key << "RigidBody2DComponent"; out << YAML::BeginMap; // RigidBody2DComponent - auto& rb2dComponent = entity.GetComponent(); + const auto& rb2dComponent = entity.GetComponent(); out << YAML::Key << "BodyType" << YAML::Value << YAML::RigidBody2DTypeToString(rb2dComponent.Type); out << YAML::Key << "FixedRotation" << YAML::Value << rb2dComponent.FixedRotation; out << YAML::EndMap; // RigidBody2DComponent @@ -340,7 +340,7 @@ namespace Hazel out << YAML::Key << "BoxCollider2DComponent"; out << YAML::BeginMap; // BoxCollider2DComponent - auto& bc2dComponent = entity.GetComponent(); + const auto& bc2dComponent = entity.GetComponent(); out << YAML::Key << "Offset" << YAML::Value << bc2dComponent.Offset; out << YAML::Key << "Size" << YAML::Value << bc2dComponent.Size; out << YAML::Key << "Density" << YAML::Value << bc2dComponent.Density; @@ -356,7 +356,7 @@ namespace Hazel out << YAML::Key << "CircleCollider2DComponent"; out << YAML::BeginMap; // CircleCollider2DComponent - auto& cc2dComponent = entity.GetComponent(); + const auto& cc2dComponent = entity.GetComponent(); out << YAML::Key << "Offset" << YAML::Value << cc2dComponent.Offset; out << YAML::Key << "Radius" << YAML::Value << cc2dComponent.Radius; out << YAML::Key << "Density" << YAML::Value << cc2dComponent.Density; @@ -367,6 +367,20 @@ namespace Hazel out << YAML::EndMap; // CircleCollider2DComponent } + if (entity.HasComponent()) + { + out << YAML::Key << "TextComponent"; + + out << YAML::BeginMap; // TextComponent + const auto& textComponent = entity.GetComponent(); + out << YAML::Key << "TextString" << YAML::Value << textComponent.TextString; + // TODO: textComponent.FontAsset + out << YAML::Key << "Color" << YAML::Value << textComponent.Color; + out << YAML::Key << "Kerning" << YAML::Value << textComponent.Kerning; + out << YAML::Key << "LineSpacing" << YAML::Value << textComponent.LineSpacing; + out << YAML::EndMap; // TextComponent + } + out << YAML::EndMap; // entity } @@ -438,15 +452,15 @@ namespace Hazel HZ_CORE_DEBUG("Deserializing Scene {}", strStream.str()); - auto entities = data["Entities"]; + const auto& entities = data["Entities"]; if (entities) { - for (auto entity : entities) + for (const auto& entity : entities) { uint64_t uuid = entity["Entity"].as(); std::string name; - auto TagComponent = entity["TagComponent"]; + const auto& TagComponent = entity["TagComponent"]; if (TagComponent) name = TagComponent["Tag"].as(); @@ -454,7 +468,7 @@ namespace Hazel Entity deserializedEntity = m_Scene->CreateEntityWithUUID(uuid, name); - auto transformComponent = entity["TransformComponent"]; + const auto& transformComponent = entity["TransformComponent"]; if (transformComponent) { auto& transform = deserializedEntity.GetComponent(); @@ -463,7 +477,7 @@ namespace Hazel transform.Scale = transformComponent["Scale"].as(); } - auto cameraComponent = entity["CameraComponent"]; + const auto& cameraComponent = entity["CameraComponent"]; if (cameraComponent) { auto& camera = deserializedEntity.AddComponent(); @@ -483,13 +497,13 @@ namespace Hazel camera.FixedAspectRatio = cameraProps["FixedAspectRatio"].as(); } - auto scriptComponent = entity["ScriptComponent"]; + const auto& scriptComponent = entity["ScriptComponent"]; if (scriptComponent) { auto& sc = deserializedEntity.AddComponent(); sc.ClassName = scriptComponent["ClassName"].as(); - auto scriptFields = scriptComponent["ScriptFields"]; + const auto& scriptFields = scriptComponent["ScriptFields"]; if (scriptFields) { Ref entityClass = ScriptEngine::GetEntityClass(sc.ClassName); @@ -535,7 +549,7 @@ namespace Hazel } } - auto spriteRendererComponent = entity["SpriteRendererComponent"]; + const auto& spriteRendererComponent = entity["SpriteRendererComponent"]; if (spriteRendererComponent) { auto& sprite = deserializedEntity.AddComponent(); @@ -550,7 +564,7 @@ namespace Hazel } } - auto circleRendererComponent = entity["CircleRendererComponent"]; + const auto& circleRendererComponent = entity["CircleRendererComponent"]; if (circleRendererComponent) { auto& circle = deserializedEntity.AddComponent(); @@ -560,7 +574,7 @@ namespace Hazel circle.Fade = circleRendererComponent["Fade"].as(); } - auto rigidBody2DComponent = entity["RigidBody2DComponent"]; + const auto& rigidBody2DComponent = entity["RigidBody2DComponent"]; if (rigidBody2DComponent) { auto& rb2d = deserializedEntity.AddComponent(); @@ -568,7 +582,7 @@ namespace Hazel rb2d.FixedRotation = rigidBody2DComponent["FixedRotation"].as(); } - auto boxCollider2DComponent = entity["BoxCollider2DComponent"]; + const auto& boxCollider2DComponent = entity["BoxCollider2DComponent"]; if (boxCollider2DComponent) { auto& bc2d = deserializedEntity.AddComponent(); @@ -580,7 +594,7 @@ namespace Hazel bc2d.RestitutionThreshold = boxCollider2DComponent["RestitutionThreshold"].as(); } - auto circleCollider2DComponent = entity["CircleCollider2DComponent"]; + const auto& circleCollider2DComponent = entity["CircleCollider2DComponent"]; if (circleCollider2DComponent) { auto& cc2d = deserializedEntity.AddComponent(); @@ -591,6 +605,17 @@ namespace Hazel cc2d.Restitution = circleCollider2DComponent["Restitution"].as(); cc2d.RestitutionThreshold = circleCollider2DComponent["RestitutionThreshold"].as(); } + + const auto& textComponent = entity["TextComponent"]; + if (textComponent) + { + auto& tc = deserializedEntity.AddComponent(); + tc.TextString = textComponent["TextString"].as(); + // TODO: tc.FontAsset + tc.Color = textComponent["Color"].as(); + tc.Kerning = textComponent["Kerning"].as(); + tc.LineSpacing = textComponent["LineSpacing"].as(); + } } }