#pragma once #include #include #include #include #include #include namespace XCEngine { namespace Editor { namespace XCUIBackend { class ImGuiTransitionBackend { public: void BeginFrame() { m_lastFlushedDrawListCount = 0; m_lastFlushedCommandCount = 0; m_pendingCommandCount = 0; m_pendingDrawLists.clear(); } void Submit(const ::XCEngine::UI::UIDrawList& drawList) { m_pendingCommandCount += drawList.GetCommandCount(); m_pendingDrawLists.push_back(drawList); } void Submit(::XCEngine::UI::UIDrawList&& drawList) { m_pendingCommandCount += drawList.GetCommandCount(); m_pendingDrawLists.push_back(std::move(drawList)); } void Submit(const ::XCEngine::UI::UIDrawData& drawData) { for (const ::XCEngine::UI::UIDrawList& drawList : drawData.GetDrawLists()) { Submit(drawList); } } bool HasPendingDrawData() const { return !m_pendingDrawLists.empty(); } std::size_t GetPendingDrawListCount() const { return m_pendingDrawLists.size(); } std::size_t GetPendingCommandCount() const { return m_pendingCommandCount; } std::size_t GetLastFlushedDrawListCount() const { return m_lastFlushedDrawListCount; } std::size_t GetLastFlushedCommandCount() const { return m_lastFlushedCommandCount; } bool EndFrame(ImDrawList* targetDrawList = nullptr) { ImDrawList* drawList = targetDrawList != nullptr ? targetDrawList : ImGui::GetWindowDrawList(); if (drawList == nullptr) { ClearPendingState(); return false; } std::size_t clipDepth = 0; for (const ::XCEngine::UI::UIDrawList& pendingDrawList : m_pendingDrawLists) { for (const ::XCEngine::UI::UIDrawCommand& command : pendingDrawList.GetCommands()) { RenderCommand(*drawList, command, clipDepth); } } while (clipDepth > 0) { drawList->PopClipRect(); --clipDepth; } m_lastFlushedDrawListCount = m_pendingDrawLists.size(); m_lastFlushedCommandCount = m_pendingCommandCount; ClearPendingState(); return true; } private: static ImVec2 ToImVec2(const ::XCEngine::UI::UIPoint& point) { return ImVec2(point.x, point.y); } static ImVec2 ToImVec2Min(const ::XCEngine::UI::UIRect& rect) { return ImVec2(rect.x, rect.y); } static ImVec2 ToImVec2Max(const ::XCEngine::UI::UIRect& rect) { return ImVec2(rect.x + rect.width, rect.y + rect.height); } static ImTextureID ToImTextureId(const ::XCEngine::UI::UITextureHandle& texture) { return static_cast(texture.nativeHandle); } static ImU32 ToImU32(const ::XCEngine::UI::UIColor& color) { const float r = (std::max)(0.0f, (std::min)(1.0f, color.r)); const float g = (std::max)(0.0f, (std::min)(1.0f, color.g)); const float b = (std::max)(0.0f, (std::min)(1.0f, color.b)); const float a = (std::max)(0.0f, (std::min)(1.0f, color.a)); return IM_COL32( static_cast(r * 255.0f), static_cast(g * 255.0f), static_cast(b * 255.0f), static_cast(a * 255.0f)); } static void RenderCommand( ImDrawList& drawList, const ::XCEngine::UI::UIDrawCommand& command, std::size_t& clipDepth) { switch (command.type) { case ::XCEngine::UI::UIDrawCommandType::FilledRect: drawList.AddRectFilled( ToImVec2Min(command.rect), ToImVec2Max(command.rect), ToImU32(command.color), command.rounding); break; case ::XCEngine::UI::UIDrawCommandType::RectOutline: drawList.AddRect( ToImVec2Min(command.rect), ToImVec2Max(command.rect), ToImU32(command.color), command.rounding, 0, command.thickness > 0.0f ? command.thickness : 1.0f); break; case ::XCEngine::UI::UIDrawCommandType::Text: if (!command.text.empty()) { drawList.AddText( nullptr, command.fontSize > 0.0f ? command.fontSize : ImGui::GetFontSize(), ToImVec2(command.position), ToImU32(command.color), command.text.c_str()); } break; case ::XCEngine::UI::UIDrawCommandType::Image: if (command.texture.IsValid()) { drawList.AddImage( ToImTextureId(command.texture), ToImVec2Min(command.rect), ToImVec2Max(command.rect), ImVec2(0.0f, 0.0f), ImVec2(1.0f, 1.0f), ToImU32(command.color)); } break; case ::XCEngine::UI::UIDrawCommandType::PushClipRect: drawList.PushClipRect( ToImVec2Min(command.rect), ToImVec2Max(command.rect), command.intersectWithCurrentClip); ++clipDepth; break; case ::XCEngine::UI::UIDrawCommandType::PopClipRect: if (clipDepth > 0) { drawList.PopClipRect(); --clipDepth; } break; default: break; } } void ClearPendingState() { m_pendingCommandCount = 0; m_pendingDrawLists.clear(); } std::vector<::XCEngine::UI::UIDrawList> m_pendingDrawLists; std::size_t m_pendingCommandCount = 0; std::size_t m_lastFlushedDrawListCount = 0; std::size_t m_lastFlushedCommandCount = 0; }; } // namespace XCUIBackend } // namespace Editor } // namespace XCEngine