diff --git a/Source/Engine/Debug/DebugDraw.cpp b/Source/Engine/Debug/DebugDraw.cpp index 729148bac..0373b9f5c 100644 --- a/Source/Engine/Debug/DebugDraw.cpp +++ b/Source/Engine/Debug/DebugDraw.cpp @@ -65,6 +65,16 @@ struct DebugText2D float TimeLeft; }; +struct DebugText3D +{ + Array> Text; + Transform Transform; + bool FaceCamera; + int32 Size; + Color Color; + float TimeLeft; +}; + PACK_STRUCT(struct Vertex { Vector3 Position; Color32 Color; @@ -146,10 +156,12 @@ struct DebugDrawData Array OneFrameWireTriangles; Array DefaultText2D; Array OneFrameText2D; + Array DefaultText3D; + Array OneFrameText3D; inline int32 Count() const { - return LinesCount() + TrianglesCount() + Text2DCount(); + return LinesCount() + TrianglesCount() + TextCount(); } inline int32 LinesCount() const @@ -162,9 +174,9 @@ struct DebugDrawData return DefaultTriangles.Count() + OneFrameTriangles.Count() + DefaultWireTriangles.Count() + OneFrameWireTriangles.Count(); } - inline int32 Text2DCount() const + inline int32 TextCount() const { - return DefaultText2D.Count() + OneFrameText2D.Count(); + return DefaultText2D.Count() + OneFrameText2D.Count() + DefaultText3D.Count() + OneFrameText3D.Count(); } inline void Add(const DebugLine& l) @@ -197,11 +209,13 @@ struct DebugDrawData UpdateList(deltaTime, DefaultTriangles); UpdateList(deltaTime, DefaultWireTriangles); UpdateList(deltaTime, DefaultText2D); + UpdateList(deltaTime, DefaultText3D); OneFrameLines.Clear(); OneFrameTriangles.Clear(); OneFrameWireTriangles.Clear(); OneFrameText2D.Clear(); + OneFrameText3D.Clear(); } inline void Clear() @@ -214,6 +228,8 @@ struct DebugDrawData OneFrameWireTriangles.Clear(); DefaultText2D.Clear(); OneFrameText2D.Clear(); + DefaultText3D.Clear(); + OneFrameText3D.Clear(); } inline void Release() @@ -226,6 +242,8 @@ struct DebugDrawData OneFrameWireTriangles.Resize(0); DefaultText2D.Resize(0); OneFrameText2D.Resize(0); + DefaultText3D.Resize(0); + OneFrameText3D.Resize(0); } }; @@ -324,6 +342,21 @@ DebugDrawCall WriteLists(int32& vertexCounter, const Array& listA, const Arra return drawCall; } +inline void DrawText3D(const DebugText3D& t, const RenderContext& renderContext, const Vector3& viewUp, const Matrix& f, const Matrix& vp, const Viewport& viewport, GPUContext* context, GPUTextureView* target, GPUTextureView* depthBuffer) +{ + Matrix w, fw, m; + if (t.FaceCamera) + Matrix::CreateWorld(t.Transform.Translation, renderContext.View.Direction, viewUp, w); + else + t.Transform.GetWorld(w); + Matrix::Multiply(f, w, fw); + Matrix::Multiply(fw, vp, m); + Render2D::Begin(context, target, depthBuffer, viewport, m); + const StringView text(t.Text.Get(), t.Text.Count() - 1); + Render2D::DrawText(DebugDrawFont->CreateFont(t.Size), text, t.Color, Vector2::Zero); + Render2D::End(); +} + class DebugDrawService : public EngineService { public: @@ -594,7 +627,7 @@ void DebugDraw::Draw(RenderContext& renderContext, GPUTextureView* target, GPUTe return; auto context = GPUDevice::Instance->GetMainContext(); - // Fallback to task backbuffer + // Fallback to task buffers if (target == nullptr && renderContext.Task) target = renderContext.Task->GetOutputView(); @@ -696,29 +729,49 @@ void DebugDraw::Draw(RenderContext& renderContext, GPUTextureView* target, GPUTe } } - // Text 2D - if (Context->DebugDrawDefault.TrianglesCount()) + // Text + if (Context->DebugDrawDefault.TextCount() + Context->DebugDrawDepthTest.TextCount()) { - PROFILE_GPU_CPU_NAMED("2D"); + PROFILE_GPU_CPU_NAMED("Text"); + auto features = Render2D::Features; + Render2D::Features = (Render2D::RenderingFeatures)((uint32)features & ~(uint32)Render2D::RenderingFeatures::VertexSnapping); if (!DebugDrawFont) - { DebugDrawFont = Content::LoadAsyncInternal(TEXT("Editor/Fonts/Roboto-Regular")); - } if (DebugDrawFont && DebugDrawFont->IsLoaded()) { Viewport viewport = renderContext.Task->GetViewport(); - Render2D::Begin(context, target, nullptr, viewport); - for (auto& t : Context->DebugDrawDefault.DefaultText2D) + + if (Context->DebugDrawDefault.DefaultText2D.Count() + Context->DebugDrawDefault.OneFrameText2D.Count()) { + Render2D::Begin(context, target, nullptr, viewport); + for (auto& t : Context->DebugDrawDefault.DefaultText2D) + { + const StringView text(t.Text.Get(), t.Text.Count() - 1); + Render2D::DrawText(DebugDrawFont->CreateFont(t.Size), text, t.Color, t.Position); + } + for (auto& t : Context->DebugDrawDefault.OneFrameText2D) + { + const StringView text(t.Text.Get(), t.Text.Count() - 1); + Render2D::DrawText(DebugDrawFont->CreateFont(t.Size), text, t.Color, t.Position); + } + Render2D::End(); } - for (auto& t : Context->DebugDrawDefault.OneFrameText2D) + + if (Context->DebugDrawDefault.DefaultText3D.Count() + Context->DebugDrawDefault.OneFrameText3D.Count()) { - const StringView text(t.Text.Get(), t.Text.Count() - 1); - Render2D::DrawText(DebugDrawFont->CreateFont(t.Size), text, t.Color, t.Position); + Matrix f; + Matrix::RotationZ(PI, f); + Vector3 viewUp; + Vector3::Transform(Vector3::Up, Quaternion::LookRotation(renderContext.View.Direction, Vector3::Up), viewUp); + for (auto& t : Context->DebugDrawDefault.DefaultText3D) + DrawText3D(t, renderContext, viewUp, f, vp, viewport, context, target, nullptr); + for (auto& t : Context->DebugDrawDefault.OneFrameText3D) + DrawText3D(t, renderContext, viewUp, f, vp, viewport, context, target, nullptr); } - Render2D::End(); } + + Render2D::Features = features; } } @@ -1337,4 +1390,36 @@ void DebugDraw::DrawText(const StringView& text, const Vector2& position, const t.TimeLeft = duration; } +void DebugDraw::DrawText(const StringView& text, const Vector3& position, const Color& color, int32 size, float duration) +{ + if (text.Length() == 0 || size < 4) + return; + Array* list = duration > 0 ? &Context->DebugDrawDefault.DefaultText3D : &Context->DebugDrawDefault.OneFrameText3D; + auto& t = list->AddOne(); + t.Text.Resize(text.Length() + 1); + Platform::MemoryCopy(t.Text.Get(), text.Get(), text.Length() * sizeof(Char)); + t.Text[text.Length()] = 0; + t.Transform = position; + t.FaceCamera = true; + t.Size = size; + t.Color = color; + t.TimeLeft = duration; +} + +void DebugDraw::DrawText(const StringView& text, const Transform& transform, const Color& color, int32 size, float duration) +{ + if (text.Length() == 0 || size < 4) + return; + Array* list = duration > 0 ? &Context->DebugDrawDefault.DefaultText3D : &Context->DebugDrawDefault.OneFrameText3D; + auto& t = list->AddOne(); + t.Text.Resize(text.Length() + 1); + Platform::MemoryCopy(t.Text.Get(), text.Get(), text.Length() * sizeof(Char)); + t.Text[text.Length()] = 0; + t.Transform = transform; + t.FaceCamera = false; + t.Size = size; + t.Color = color; + t.TimeLeft = duration; +} + #endif diff --git a/Source/Engine/Debug/DebugDraw.h b/Source/Engine/Debug/DebugDraw.h index 6b77d09dd..13aa5c3ac 100644 --- a/Source/Engine/Debug/DebugDraw.h +++ b/Source/Engine/Debug/DebugDraw.h @@ -15,6 +15,7 @@ class GPUContext; class RenderTask; class SceneRenderTask; class Actor; +struct Transform; /// /// The debug shapes rendering service. Not available in final game. For use only in the editor. @@ -317,6 +318,26 @@ DECLARE_SCRIPTING_TYPE_NO_SPAWN(DebugDraw); /// The font size. /// The duration (in seconds). Use 0 to draw it only once. API_FUNCTION() static void DrawText(const StringView& text, const Vector2& position, const Color& color, int32 size = 20, float duration = 0.0f); + + /// + /// Draws the text (3D) that automatically faces the camera. + /// + /// The text. + /// The position of the text (world-space). + /// The color. + /// The font size. + /// The duration (in seconds). Use 0 to draw it only once. + API_FUNCTION() static void DrawText(const StringView& text, const Vector3& position, const Color& color, int32 size = 32, float duration = 0.0f); + + /// + /// Draws the text (3D). + /// + /// The text. + /// The transformation of the text (world-space). + /// The color. + /// The font size. + /// The duration (in seconds). Use 0 to draw it only once. + API_FUNCTION() static void DrawText(const StringView& text, const Transform& transform, const Color& color, int32 size = 32, float duration = 0.0f); }; #define DEBUG_DRAW_LINE(start, end, color, duration, depthTest) DebugDraw::DrawLine(start, end, color, duration, depthTest)