/** * @file test_win_adapt.cpp * @brief Window Adaptation 单元测试 * * 测试窗口适配模式、坐标转换、视口计算等功能。 */ #include "test_framework.h" #include #include #include #include using namespace extra2d; using namespace extra2d::test; namespace { constexpr f32 EPSILON = 0.001f; bool vec2Equal(const Vec2& a, const Vec2& b, f32 eps = EPSILON) { return std::abs(a.x - b.x) < eps && std::abs(a.y - b.y) < eps; } bool rectEqual(const Rect& a, const Rect& b, f32 eps = EPSILON) { return std::abs(a.origin.x - b.origin.x) < eps && std::abs(a.origin.y - b.origin.y) < eps && std::abs(a.size.width - b.size.width) < eps && std::abs(a.size.height - b.size.height) < eps; } } // --------------------------------------------------------------------------- // WinAdapt 基本测试 // --------------------------------------------------------------------------- TEST(WinAdapt, Create) { WinAdapt adapt; WinAdaptCfg cfg = adapt.cfg(); TEST_ASSERT_TRUE(cfg.mode == AdaptMode::Fit); TEST_ASSERT_TRUE(std::abs(cfg.refW - 1280) < EPSILON); TEST_ASSERT_TRUE(std::abs(cfg.refH - 720) < EPSILON); } TEST(WinAdapt, SetConfig) { WinAdapt adapt; WinAdaptCfg cfg; cfg.mode = AdaptMode::Fill; cfg.refW = 1920; cfg.refH = 1080; cfg.autoScale = false; adapt.cfg(cfg); WinAdaptCfg retrieved = adapt.cfg(); TEST_ASSERT_TRUE(retrieved.mode == AdaptMode::Fill); TEST_ASSERT_TRUE(std::abs(retrieved.refW - 1920) < EPSILON); TEST_ASSERT_TRUE(std::abs(retrieved.refH - 1080) < EPSILON); TEST_ASSERT_FALSE(retrieved.autoScale); } TEST(WinAdapt, SetRef) { WinAdapt adapt; adapt.ref(800, 600); Vec2 ref = adapt.ref(); TEST_ASSERT_TRUE(vec2Equal(ref, Vec2(800, 600))); } TEST(WinAdapt, SetWin) { WinAdapt adapt; adapt.ref(1280, 720); adapt.win(1920, 1080); Vec2 win = adapt.win(); TEST_ASSERT_TRUE(vec2Equal(win, Vec2(1920, 1080))); } // --------------------------------------------------------------------------- // Exact 模式测试 // --------------------------------------------------------------------------- TEST(WinAdapt, ExactMode) { WinAdapt adapt; WinAdaptCfg cfg; cfg.mode = AdaptMode::Exact; cfg.refW = 1280; cfg.refH = 720; adapt.cfg(cfg); adapt.win(1920, 1080); Rect vp = adapt.viewport(); TEST_ASSERT_TRUE(rectEqual(vp, Rect(0, 0, 1920, 1080))); TEST_ASSERT_TRUE(std::abs(adapt.scale() - 1.0f) < EPSILON); } // --------------------------------------------------------------------------- // Stretch 模式测试 // --------------------------------------------------------------------------- TEST(WinAdapt, StretchMode) { WinAdapt adapt; WinAdaptCfg cfg; cfg.mode = AdaptMode::Stretch; cfg.refW = 1280; cfg.refH = 720; adapt.cfg(cfg); adapt.win(1920, 1080); Rect vp = adapt.viewport(); TEST_ASSERT_TRUE(rectEqual(vp, Rect(0, 0, 1920, 1080))); Vec2 scale2D = adapt.scale2D(); TEST_ASSERT_TRUE(std::abs(scale2D.x - 1.5f) < EPSILON); TEST_ASSERT_TRUE(std::abs(scale2D.y - 1.5f) < EPSILON); } // --------------------------------------------------------------------------- // Fit 模式测试 // --------------------------------------------------------------------------- TEST(WinAdapt, FitModeSameAspect) { WinAdapt adapt; WinAdaptCfg cfg; cfg.mode = AdaptMode::Fit; cfg.refW = 1280; cfg.refH = 720; adapt.cfg(cfg); adapt.win(1920, 1080); Rect vp = adapt.viewport(); TEST_ASSERT_TRUE(rectEqual(vp, Rect(0, 0, 1920, 1080))); TEST_ASSERT_TRUE(std::abs(adapt.scale() - 1.5f) < EPSILON); } TEST(WinAdapt, FitModeWiderWindow) { WinAdapt adapt; WinAdaptCfg cfg; cfg.mode = AdaptMode::Fit; cfg.refW = 1280; cfg.refH = 720; adapt.cfg(cfg); adapt.win(1920, 800); Rect vp = adapt.viewport(); f32 expectedScale = 800.0f / 720.0f; f32 expectedW = 1280.0f * expectedScale; f32 expectedX = (1920.0f - expectedW) / 2.0f; TEST_ASSERT_TRUE(std::abs(vp.origin.x - expectedX) < EPSILON); TEST_ASSERT_TRUE(std::abs(vp.origin.y) < EPSILON); TEST_ASSERT_TRUE(std::abs(vp.size.width - expectedW) < EPSILON); TEST_ASSERT_TRUE(std::abs(vp.size.height - 800) < EPSILON); TEST_ASSERT_TRUE(std::abs(adapt.scale() - expectedScale) < EPSILON); } TEST(WinAdapt, FitModeTallerWindow) { WinAdapt adapt; WinAdaptCfg cfg; cfg.mode = AdaptMode::Fit; cfg.refW = 1280; cfg.refH = 720; adapt.cfg(cfg); adapt.win(1280, 900); Rect vp = adapt.viewport(); f32 expectedScale = 1280.0f / 1280.0f; f32 expectedH = 720.0f * expectedScale; f32 expectedY = (900.0f - expectedH) / 2.0f; TEST_ASSERT_TRUE(std::abs(vp.origin.x) < EPSILON); TEST_ASSERT_TRUE(std::abs(vp.origin.y - expectedY) < EPSILON); TEST_ASSERT_TRUE(std::abs(vp.size.width - 1280) < EPSILON); TEST_ASSERT_TRUE(std::abs(vp.size.height - expectedH) < EPSILON); } // --------------------------------------------------------------------------- // Fill 模式测试 // --------------------------------------------------------------------------- TEST(WinAdapt, FillModeWiderWindow) { WinAdapt adapt; WinAdaptCfg cfg; cfg.mode = AdaptMode::Fill; cfg.refW = 1280; cfg.refH = 720; adapt.cfg(cfg); adapt.win(1920, 800); Rect vp = adapt.viewport(); f32 expectedScale = 1920.0f / 1280.0f; f32 expectedH = 720.0f * expectedScale; f32 expectedY = (800.0f - expectedH) / 2.0f; TEST_ASSERT_TRUE(std::abs(vp.origin.x) < EPSILON); TEST_ASSERT_TRUE(std::abs(vp.origin.y - expectedY) < EPSILON); TEST_ASSERT_TRUE(std::abs(adapt.scale() - expectedScale) < EPSILON); } TEST(WinAdapt, FillModeTallerWindow) { WinAdapt adapt; WinAdaptCfg cfg; cfg.mode = AdaptMode::Fill; cfg.refW = 1280; cfg.refH = 720; adapt.cfg(cfg); adapt.win(1280, 900); Rect vp = adapt.viewport(); f32 expectedScale = 900.0f / 720.0f; f32 expectedW = 1280.0f * expectedScale; f32 expectedX = (1280.0f - expectedW) / 2.0f; TEST_ASSERT_TRUE(std::abs(vp.origin.x - expectedX) < EPSILON); TEST_ASSERT_TRUE(std::abs(vp.origin.y) < EPSILON); TEST_ASSERT_TRUE(std::abs(adapt.scale() - expectedScale) < EPSILON); } // --------------------------------------------------------------------------- // Center 模式测试 // --------------------------------------------------------------------------- TEST(WinAdapt, CenterMode) { WinAdapt adapt; WinAdaptCfg cfg; cfg.mode = AdaptMode::Center; cfg.refW = 800; cfg.refH = 600; adapt.cfg(cfg); adapt.win(1920, 1080); Rect vp = adapt.viewport(); f32 expectedX = (1920.0f - 800.0f) / 2.0f; f32 expectedY = (1080.0f - 600.0f) / 2.0f; TEST_ASSERT_TRUE(std::abs(vp.origin.x - expectedX) < EPSILON); TEST_ASSERT_TRUE(std::abs(vp.origin.y - expectedY) < EPSILON); TEST_ASSERT_TRUE(std::abs(vp.size.width - 800) < EPSILON); TEST_ASSERT_TRUE(std::abs(vp.size.height - 600) < EPSILON); TEST_ASSERT_TRUE(std::abs(adapt.scale() - 1.0f) < EPSILON); } // --------------------------------------------------------------------------- // 坐标转换测试 // --------------------------------------------------------------------------- TEST(WinAdapt, WinToRef) { WinAdapt adapt; WinAdaptCfg cfg; cfg.mode = AdaptMode::Fit; cfg.refW = 1280; cfg.refH = 720; adapt.cfg(cfg); adapt.win(1920, 1080); Vec2 winPos(960, 540); Vec2 refPos = adapt.winToRef(winPos); TEST_ASSERT_TRUE(vec2Equal(refPos, Vec2(640, 360))); } TEST(WinAdapt, RefToWin) { WinAdapt adapt; WinAdaptCfg cfg; cfg.mode = AdaptMode::Fit; cfg.refW = 1280; cfg.refH = 720; adapt.cfg(cfg); adapt.win(1920, 1080); Vec2 refPos(640, 360); Vec2 winPos = adapt.refToWin(refPos); TEST_ASSERT_TRUE(vec2Equal(winPos, Vec2(960, 540))); } TEST(WinAdapt, WinToRefRoundTrip) { WinAdapt adapt; WinAdaptCfg cfg; cfg.mode = AdaptMode::Fit; cfg.refW = 1280; cfg.refH = 720; adapt.cfg(cfg); adapt.win(1600, 900); Vec2 originalRef(500, 300); Vec2 win = adapt.refToWin(originalRef); Vec2 backToRef = adapt.winToRef(win); TEST_ASSERT_TRUE(vec2Equal(originalRef, backToRef, 0.1f)); } TEST(WinAdapt, ScreenToRef) { WinAdapt adapt; WinAdaptCfg cfg; cfg.mode = AdaptMode::Fit; cfg.refW = 1280; cfg.refH = 720; adapt.cfg(cfg); adapt.win(1920, 1080); Vec2 screenPos(960, 540); Vec2 refPos = adapt.screenToRef(screenPos); TEST_ASSERT_TRUE(vec2Equal(refPos, Vec2(640, 360))); } TEST(WinAdapt, RefToScreen) { WinAdapt adapt; WinAdaptCfg cfg; cfg.mode = AdaptMode::Fit; cfg.refW = 1280; cfg.refH = 720; adapt.cfg(cfg); adapt.win(1920, 1080); Vec2 refPos(640, 360); Vec2 screenPos = adapt.refToScreen(refPos); TEST_ASSERT_TRUE(vec2Equal(screenPos, Vec2(960, 540))); } // --------------------------------------------------------------------------- // 矩阵测试 // --------------------------------------------------------------------------- TEST(WinAdapt, Matrix) { WinAdapt adapt; WinAdaptCfg cfg; cfg.mode = AdaptMode::Fit; cfg.refW = 1280; cfg.refH = 720; adapt.cfg(cfg); adapt.win(1920, 1080); Mat4 m = adapt.matrix(); Vec4 origin(0, 0, 0, 1); Vec4 transformed = m * origin; TEST_ASSERT_TRUE(std::abs(transformed.x) < EPSILON); TEST_ASSERT_TRUE(std::abs(transformed.y) < EPSILON); } // --------------------------------------------------------------------------- // 边界情况测试 // --------------------------------------------------------------------------- TEST(WinAdapt, ZeroWindowSize) { WinAdapt adapt; adapt.ref(1280, 720); adapt.win(0, 0); Rect vp = adapt.viewport(); TEST_ASSERT_TRUE(std::abs(vp.size.width) < EPSILON); TEST_ASSERT_TRUE(std::abs(vp.size.height) < EPSILON); } TEST(WinAdapt, VerySmallWindow) { WinAdapt adapt; WinAdaptCfg cfg; cfg.mode = AdaptMode::Fit; cfg.refW = 1280; cfg.refH = 720; adapt.cfg(cfg); adapt.win(100, 100); Rect vp = adapt.viewport(); TEST_ASSERT_TRUE(vp.size.width > 0); TEST_ASSERT_TRUE(vp.size.height > 0); TEST_ASSERT_TRUE(adapt.scale() > 0); } TEST(WinAdapt, VeryLargeWindow) { WinAdapt adapt; WinAdaptCfg cfg; cfg.mode = AdaptMode::Fit; cfg.refW = 1280; cfg.refH = 720; adapt.cfg(cfg); adapt.win(7680, 4320); Rect vp = adapt.viewport(); TEST_ASSERT_TRUE(vp.size.width > 0); TEST_ASSERT_TRUE(vp.size.height > 0); TEST_ASSERT_TRUE(adapt.scale() > 1.0f); } // --------------------------------------------------------------------------- // 不同宽高比测试 // --------------------------------------------------------------------------- TEST(WinAdapt, AspectRatioPreservation) { WinAdapt adapt; WinAdaptCfg cfg; cfg.mode = AdaptMode::Fit; cfg.refW = 1280; cfg.refH = 720; adapt.cfg(cfg); adapt.win(2560, 1440); Rect vp = adapt.viewport(); f32 refAspect = 1280.0f / 720.0f; f32 vpAspect = vp.size.width / vp.size.height; TEST_ASSERT_TRUE(std::abs(refAspect - vpAspect) < EPSILON); }