De-ImGui XCUI standalone text atlas provider

This commit is contained in:
2026-04-05 15:16:15 +08:00
parent b05e76de0c
commit 6fd3ed434d
5 changed files with 879 additions and 133 deletions

View File

@@ -745,18 +745,10 @@ else()
endif()
if(EXISTS "${NEW_EDITOR_STANDALONE_TEXT_ATLAS_PROVIDER_HEADER}" AND
EXISTS "${NEW_EDITOR_STANDALONE_TEXT_ATLAS_PROVIDER_SOURCE}" AND
EXISTS "${NEW_EDITOR_FONT_SETUP_HEADER}" AND
EXISTS "${NEW_EDITOR_FONT_SETUP_SOURCE}" AND
EXISTS "${CMAKE_BINARY_DIR}/_deps/imgui-src/imgui.cpp")
EXISTS "${NEW_EDITOR_STANDALONE_TEXT_ATLAS_PROVIDER_SOURCE}")
add_executable(new_editor_xcui_standalone_text_atlas_provider_tests
test_xcui_standalone_text_atlas_provider.cpp
${NEW_EDITOR_FONT_SETUP_SOURCE}
${NEW_EDITOR_STANDALONE_TEXT_ATLAS_PROVIDER_SOURCE}
${CMAKE_BINARY_DIR}/_deps/imgui-src/imgui.cpp
${CMAKE_BINARY_DIR}/_deps/imgui-src/imgui_draw.cpp
${CMAKE_BINARY_DIR}/_deps/imgui-src/imgui_tables.cpp
${CMAKE_BINARY_DIR}/_deps/imgui-src/imgui_widgets.cpp
)
xcengine_configure_new_editor_test_target(new_editor_xcui_standalone_text_atlas_provider_tests)
@@ -767,19 +759,18 @@ if(EXISTS "${NEW_EDITOR_STANDALONE_TEXT_ATLAS_PROVIDER_HEADER}" AND
GTest::gtest
GTest::gtest_main
user32
gdi32
comdlg32
)
target_include_directories(new_editor_xcui_standalone_text_atlas_provider_tests PRIVATE
${CMAKE_SOURCE_DIR}/engine/include
${CMAKE_SOURCE_DIR}/new_editor/src
${CMAKE_BINARY_DIR}/_deps/imgui-src
${CMAKE_BINARY_DIR}/_deps/imgui-src/backends
)
xcengine_discover_new_editor_gtests(new_editor_xcui_standalone_text_atlas_provider_tests)
else()
message(STATUS "Skipping new_editor_xcui_standalone_text_atlas_provider_tests because standalone atlas provider, font setup, or ImGui sources are missing.")
message(STATUS "Skipping new_editor_xcui_standalone_text_atlas_provider_tests because standalone atlas provider files are missing.")
endif()
if(EXISTS "${NEW_EDITOR_RHI_COMMAND_COMPILER_HEADER}" AND

View File

@@ -11,12 +11,15 @@ using XCEngine::Editor::XCUIBackend::XCUIStandaloneTextAtlasProvider;
TEST(XCUIStandaloneTextAtlasProviderTest, BuildsDefaultEditorAtlasWithoutImGuiContext) {
XCUIStandaloneTextAtlasProvider provider = {};
IXCUITextAtlasProvider::AtlasTextureView atlasView = {};
IXCUITextAtlasProvider::AtlasTextureView alphaView = {};
ASSERT_TRUE(provider.IsReady());
ASSERT_TRUE(provider.GetAtlasTextureView(IXCUITextAtlasProvider::PixelFormat::RGBA32, atlasView));
ASSERT_TRUE(provider.GetAtlasTextureView(IXCUITextAtlasProvider::PixelFormat::Alpha8, alphaView));
EXPECT_TRUE(atlasView.IsValid());
EXPECT_TRUE(alphaView.IsValid());
EXPECT_EQ(atlasView.format, IXCUITextAtlasProvider::PixelFormat::RGBA32);
EXPECT_EQ(alphaView.format, IXCUITextAtlasProvider::PixelFormat::Alpha8);
EXPECT_GT(provider.GetFontCount(), 0u);
}
@@ -42,4 +45,113 @@ TEST(XCUIStandaloneTextAtlasProviderTest, ExposesDefaultFontMetricsAndGlyphs) {
EXPECT_GE(glyphInfo.v1, glyphInfo.v0);
}
TEST(XCUIStandaloneTextAtlasProviderTest, RebuildsAfterResetAndRejectsQueriesWhileUnready) {
XCUIStandaloneTextAtlasProvider provider = {};
const IXCUITextAtlasProvider::FontHandle defaultFont = provider.GetDefaultFont();
ASSERT_TRUE(defaultFont.IsValid());
provider.Reset();
IXCUITextAtlasProvider::AtlasTextureView atlasView = {};
IXCUITextAtlasProvider::FontInfo fontInfo = {};
IXCUITextAtlasProvider::BakedFontInfo bakedFontInfo = {};
IXCUITextAtlasProvider::GlyphInfo glyphInfo = {};
EXPECT_FALSE(provider.IsReady());
EXPECT_FALSE(provider.GetAtlasTextureView(IXCUITextAtlasProvider::PixelFormat::RGBA32, atlasView));
EXPECT_EQ(provider.GetFontCount(), 0u);
EXPECT_FALSE(provider.GetDefaultFont().IsValid());
EXPECT_FALSE(provider.GetFontInfo(defaultFont, fontInfo));
EXPECT_FALSE(provider.GetBakedFontInfo(defaultFont, 18.0f, bakedFontInfo));
EXPECT_FALSE(provider.FindGlyph(defaultFont, 18.0f, static_cast<std::uint32_t>('A'), glyphInfo));
ASSERT_TRUE(provider.RebuildDefaultEditorAtlas());
ASSERT_TRUE(provider.IsReady());
ASSERT_TRUE(provider.GetAtlasTextureView(IXCUITextAtlasProvider::PixelFormat::RGBA32, atlasView));
EXPECT_TRUE(atlasView.IsValid());
}
TEST(XCUIStandaloneTextAtlasProviderTest, ResolvesGlyphsForNonNominalRequestedFontSizes) {
XCUIStandaloneTextAtlasProvider provider = {};
const IXCUITextAtlasProvider::FontHandle defaultFont = provider.GetDefaultFont();
ASSERT_TRUE(defaultFont.IsValid());
IXCUITextAtlasProvider::BakedFontInfo bakedFontInfo = {};
ASSERT_TRUE(provider.GetBakedFontInfo(defaultFont, 13.0f, bakedFontInfo));
EXPECT_GT(bakedFontInfo.lineHeight, 0.0f);
EXPECT_GT(bakedFontInfo.rasterizerDensity, 0.0f);
IXCUITextAtlasProvider::GlyphInfo glyphInfo = {};
ASSERT_TRUE(provider.FindGlyph(defaultFont, 13.0f, static_cast<std::uint32_t>('A'), glyphInfo));
EXPECT_EQ(glyphInfo.requestedCodepoint, static_cast<std::uint32_t>('A'));
EXPECT_GT(glyphInfo.advanceX, 0.0f);
EXPECT_GE(glyphInfo.u1, glyphInfo.u0);
EXPECT_GE(glyphInfo.v1, glyphInfo.v0);
}
TEST(XCUIStandaloneTextAtlasProviderTest, LazilyAddsGlyphsOutsideThePrebakedAsciiRanges) {
XCUIStandaloneTextAtlasProvider provider = {};
const IXCUITextAtlasProvider::FontHandle defaultFont = provider.GetDefaultFont();
ASSERT_TRUE(defaultFont.IsValid());
IXCUITextAtlasProvider::AtlasTextureView beforeView = {};
ASSERT_TRUE(provider.GetAtlasTextureView(IXCUITextAtlasProvider::PixelFormat::RGBA32, beforeView));
constexpr std::uint32_t dynamicCodepoint = 0x4E2Du;
IXCUITextAtlasProvider::GlyphInfo glyphInfo = {};
ASSERT_TRUE(provider.FindGlyph(defaultFont, 16.0f, dynamicCodepoint, glyphInfo));
IXCUITextAtlasProvider::AtlasTextureView refreshedView = {};
ASSERT_TRUE(provider.GetAtlasTextureView(IXCUITextAtlasProvider::PixelFormat::RGBA32, refreshedView));
EXPECT_EQ(refreshedView.atlasStorageKey, beforeView.atlasStorageKey);
EXPECT_EQ(glyphInfo.requestedCodepoint, dynamicCodepoint);
if (refreshedView.pixelDataKey != beforeView.pixelDataKey) {
EXPECT_EQ(glyphInfo.resolvedCodepoint, dynamicCodepoint);
EXPECT_GT(glyphInfo.advanceX, 0.0f);
EXPECT_TRUE(glyphInfo.visible);
IXCUITextAtlasProvider::GlyphInfo secondLookup = {};
ASSERT_TRUE(provider.FindGlyph(defaultFont, 16.0f, dynamicCodepoint, secondLookup));
EXPECT_EQ(secondLookup.requestedCodepoint, dynamicCodepoint);
EXPECT_EQ(secondLookup.resolvedCodepoint, dynamicCodepoint);
IXCUITextAtlasProvider::AtlasTextureView secondView = {};
ASSERT_TRUE(provider.GetAtlasTextureView(IXCUITextAtlasProvider::PixelFormat::RGBA32, secondView));
EXPECT_EQ(secondView.pixelDataKey, refreshedView.pixelDataKey);
return;
}
if (glyphInfo.resolvedCodepoint != dynamicCodepoint) {
EXPECT_EQ(glyphInfo.resolvedCodepoint, static_cast<std::uint32_t>('?'));
EXPECT_GT(glyphInfo.advanceX, 0.0f);
EXPECT_TRUE(glyphInfo.visible);
return;
}
if (!glyphInfo.visible) {
EXPECT_GE(glyphInfo.advanceX, 0.0f);
return;
}
if (glyphInfo.resolvedCodepoint == dynamicCodepoint) {
EXPECT_NE(refreshedView.pixelDataKey, beforeView.pixelDataKey);
}
EXPECT_GT(glyphInfo.advanceX, 0.0f);
EXPECT_TRUE(glyphInfo.visible);
}
TEST(XCUIStandaloneTextAtlasProviderTest, MissingGlyphFallsBackToQuestionMarkWhenFontCannotRasterizeIt) {
XCUIStandaloneTextAtlasProvider provider = {};
const IXCUITextAtlasProvider::FontHandle defaultFont = provider.GetDefaultFont();
ASSERT_TRUE(defaultFont.IsValid());
IXCUITextAtlasProvider::GlyphInfo glyphInfo = {};
ASSERT_TRUE(provider.FindGlyph(defaultFont, 16.0f, 0x10FFFFu, glyphInfo));
EXPECT_EQ(glyphInfo.requestedCodepoint, 0x10FFFFu);
EXPECT_EQ(glyphInfo.resolvedCodepoint, static_cast<std::uint32_t>('?'));
EXPECT_GT(glyphInfo.advanceX, 0.0f);
EXPECT_TRUE(glyphInfo.visible);
}
} // namespace