#include "XCUIBackend/ImGuiTextAtlasProvider.h" #include #include namespace XCEngine { namespace Editor { namespace XCUIBackend { namespace { IXCUITextAtlasProvider::FontHandle MakeFontHandle(const ImFont* font) { IXCUITextAtlasProvider::FontHandle handle = {}; handle.value = reinterpret_cast(font); return handle; } ImFont* ResolveFontHandle(IXCUITextAtlasProvider::FontHandle handle) { return reinterpret_cast(handle.value); } ImFontAtlas* ResolveAtlas(::ImGuiContext* context) { if (context == nullptr) { return nullptr; } return context->IO.Fonts; } ImFont* ResolveDefaultFont(::ImGuiContext* context) { ImFontAtlas* atlas = ResolveAtlas(context); if (atlas == nullptr) { return nullptr; } ImFont* font = context->IO.FontDefault; if (font == nullptr && atlas->Fonts.Size > 0) { font = atlas->Fonts[0]; } return font; } float ResolveNominalFontSize(const ImFont& font) { return font.LegacySize > 0.0f ? font.LegacySize : 16.0f; } float ResolveRequestedFontSize(const ImFont& font, float requestedFontSize) { return requestedFontSize > 0.0f ? requestedFontSize : ResolveNominalFontSize(font); } bool IsFontOwnedByAtlas(const ImFont* font, const ImFontAtlas* atlas) { return font != nullptr && atlas != nullptr && font->OwnerAtlas == atlas; } ImFontBaked* ResolveBakedFont( IXCUITextAtlasProvider::FontHandle fontHandle, ImFontAtlas* atlas, float requestedFontSize) { ImFont* font = ResolveFontHandle(fontHandle); if (!IsFontOwnedByAtlas(font, atlas)) { return nullptr; } const float resolvedFontSize = ResolveRequestedFontSize(*font, requestedFontSize); if (resolvedFontSize <= 0.0f) { return nullptr; } return font->GetFontBaked(resolvedFontSize); } } // namespace ImGuiTextAtlasProvider::ImGuiTextAtlasProvider(::ImGuiContext* context) : m_context(context) { } void ImGuiTextAtlasProvider::SetContext(::ImGuiContext* context) { m_context = context; } ::ImGuiContext* ImGuiTextAtlasProvider::GetContext() const { return m_context; } bool ImGuiTextAtlasProvider::GetAtlasTextureView( PixelFormat preferredFormat, AtlasTextureView& outView) const { outView = {}; ImFontAtlas* atlas = ResolveAtlas(ResolveContext()); if (atlas == nullptr) { return false; } unsigned char* pixels = nullptr; int width = 0; int height = 0; int bytesPerPixel = 0; PixelFormat resolvedFormat = preferredFormat; switch (preferredFormat) { case PixelFormat::Alpha8: atlas->GetTexDataAsAlpha8(&pixels, &width, &height, &bytesPerPixel); break; case PixelFormat::RGBA32: case PixelFormat::Unknown: default: atlas->GetTexDataAsRGBA32(&pixels, &width, &height, &bytesPerPixel); resolvedFormat = PixelFormat::RGBA32; break; } if (pixels == nullptr || width <= 0 || height <= 0 || bytesPerPixel <= 0) { return false; } outView.pixels = pixels; outView.width = width; outView.height = height; outView.stride = width * bytesPerPixel; outView.bytesPerPixel = bytesPerPixel; outView.format = resolvedFormat; outView.atlasStorageKey = reinterpret_cast(atlas); outView.pixelDataKey = reinterpret_cast(pixels); return true; } std::size_t ImGuiTextAtlasProvider::GetFontCount() const { const ImFontAtlas* atlas = ResolveAtlas(ResolveContext()); return atlas != nullptr ? static_cast(atlas->Fonts.Size) : 0u; } IXCUITextAtlasProvider::FontHandle ImGuiTextAtlasProvider::GetFont(std::size_t index) const { const ImFontAtlas* atlas = ResolveAtlas(ResolveContext()); if (atlas == nullptr || index >= static_cast(atlas->Fonts.Size)) { return {}; } return MakeFontHandle(atlas->Fonts[static_cast(index)]); } IXCUITextAtlasProvider::FontHandle ImGuiTextAtlasProvider::GetDefaultFont() const { return MakeFontHandle(ResolveDefaultFont(ResolveContext())); } bool ImGuiTextAtlasProvider::GetFontInfo(FontHandle fontHandle, FontInfo& outInfo) const { outInfo = {}; ImFontAtlas* atlas = ResolveAtlas(ResolveContext()); ImFont* font = ResolveFontHandle(fontHandle); if (!IsFontOwnedByAtlas(font, atlas)) { return false; } outInfo.handle = fontHandle; outInfo.nominalSize = ResolveNominalFontSize(*font); return true; } bool ImGuiTextAtlasProvider::GetBakedFontInfo( FontHandle fontHandle, float fontSize, BakedFontInfo& outInfo) const { outInfo = {}; ImFontAtlas* atlas = ResolveAtlas(ResolveContext()); ImFontBaked* bakedFont = ResolveBakedFont(fontHandle, atlas, fontSize); if (bakedFont == nullptr) { return false; } outInfo.lineHeight = bakedFont->Size; outInfo.ascent = bakedFont->Ascent; outInfo.descent = bakedFont->Descent; outInfo.rasterizerDensity = bakedFont->RasterizerDensity; return true; } bool ImGuiTextAtlasProvider::FindGlyph( FontHandle fontHandle, float fontSize, std::uint32_t codepoint, GlyphInfo& outInfo) const { outInfo = {}; if (codepoint > IM_UNICODE_CODEPOINT_MAX) { return false; } ImFontAtlas* atlas = ResolveAtlas(ResolveContext()); ImFontBaked* bakedFont = ResolveBakedFont(fontHandle, atlas, fontSize); if (bakedFont == nullptr) { return false; } ImFontGlyph* glyph = bakedFont->FindGlyph(static_cast(codepoint)); if (glyph == nullptr) { return false; } outInfo.requestedCodepoint = codepoint; outInfo.resolvedCodepoint = glyph->Codepoint; outInfo.visible = glyph->Visible != 0; outInfo.colored = glyph->Colored != 0; outInfo.advanceX = glyph->AdvanceX; outInfo.x0 = glyph->X0; outInfo.y0 = glyph->Y0; outInfo.x1 = glyph->X1; outInfo.y1 = glyph->Y1; outInfo.u0 = glyph->U0; outInfo.v0 = glyph->V0; outInfo.u1 = glyph->U1; outInfo.v1 = glyph->V1; return true; } ::ImGuiContext* ImGuiTextAtlasProvider::ResolveContext() const { return m_context != nullptr ? m_context : ImGui::GetCurrentContext(); } } // namespace XCUIBackend } // namespace Editor } // namespace XCEngine