From 8d86943c945453fad7382728d62f096eb013bdba Mon Sep 17 00:00:00 2001 From: Adam Heinermann Date: Tue, 22 Apr 2025 17:31:02 -0700 Subject: [PATCH] feat(region): write several tests and finish SRgn functionality --- storm/Region.cpp | 117 +++++++++++++--- storm/region/RGN.hpp | 2 +- test/Region.cpp | 323 ++++++++++++++++++++++++++++++++++++++++--- 3 files changed, 401 insertions(+), 41 deletions(-) diff --git a/storm/Region.cpp b/storm/Region.cpp index 49f67b1..c3a5b25 100644 --- a/storm/Region.cpp +++ b/storm/Region.cpp @@ -11,6 +11,7 @@ static TSExportTableSyncReuse s_rgntable; void DeleteCombinedRect(TSGrowableArray* combinedArray, uint32_t index); void DeleteRect(RECTF* rect); +void DeleteSourceRect(TSGrowableArray* sourceArray, uint32_t index); int32_t IsNullRect(const RECTF* rect); @@ -184,32 +185,104 @@ void FragmentCombinedRectangles(TSGrowableArray* combinedArray, uint32_t } void FragmentSourceRectangles(TSGrowableArray* sourceArray, uint32_t firstIndex, uint32_t lastIndex, int32_t previousOverlap, const RECTF* rect, void* param, int32_t sequence) { - if (firstIndex >= lastIndex) { - AddSourceRect(sourceArray, rect, param, sequence, SF_ADDING | (previousOverlap ? SF_OVERLAPS : SF_NONE)); - return; - } - auto overlapsExisting = previousOverlap; - for (uint32_t i = firstIndex; i < lastIndex; i++) { - auto source = &(*sourceArray)[i]; + for (uint32_t index = firstIndex; index < lastIndex; index++) { + RECTF* checkRect = &(*sourceArray)[index].rect; - if (CheckForIntersection(rect, &source->rect)) { - if (!CompareRects(rect, &source->rect)) { - break; + if (CheckForIntersection(rect, checkRect)) { + if (CompareRects(rect, checkRect)) { + (*sourceArray)[index].flags |= SF_OVERLAPS; + overlapsExisting = 1; + continue; } - source->flags |= SF_OVERLAPS; - overlapsExisting = 1; - } + const RECTF* overlapRect[2] = { rect, checkRect }; - if (i + 1 == lastIndex) { - AddSourceRect(sourceArray, rect, param, sequence, SF_ADDING | (previousOverlap ? SF_OVERLAPS : SF_NONE)); + uint32_t minLeft = rect->left > checkRect->left ? 1 : 0; + uint32_t maxLeft = checkRect->left > rect->left ? 1 : 0; + uint32_t minBottom = rect->bottom > checkRect->bottom ? 1 : 0; + uint32_t maxBottom = checkRect->bottom > rect->bottom ? 1 : 0; + uint32_t minRight = rect->right > checkRect->right ? 1 : 0; + uint32_t maxRight = checkRect->right > rect->right ? 1 : 0; + uint32_t minTop = rect->top > checkRect->top ? 1 : 0; + uint32_t maxTop = checkRect->top > rect->top ? 1 : 0; + + RECTF newRect[5]; + + newRect[0] = { + overlapRect[minBottom]->left, + overlapRect[minBottom]->bottom, + overlapRect[minBottom]->right, + overlapRect[maxBottom]->bottom, + }; + + newRect[1] = { + overlapRect[maxTop]->left, + overlapRect[minTop]->top, + overlapRect[maxTop]->right, + overlapRect[maxTop]->top, + }; + + newRect[2] = { + overlapRect[minLeft]->left, + overlapRect[maxBottom]->bottom, + overlapRect[maxLeft]->left, + overlapRect[minTop]->top, + }; + + newRect[3] = { + overlapRect[minRight]->right, + overlapRect[maxBottom]->bottom, + overlapRect[maxRight]->right, + overlapRect[minTop]->top, + }; + + newRect[4] = { + overlapRect[maxLeft]->left, + overlapRect[maxBottom]->bottom, + overlapRect[minRight]->right, + overlapRect[minTop]->top, + }; + + int32_t overlaps[5][2]; + for (uint32_t j = 0; j < 5; j++) { + if (IsNullRect(&newRect[j])) { + overlaps[j][1] = 0; + overlaps[j][0] = 0; + } + else { + for (uint32_t k = 0; k < 2; k++) { + overlaps[j][k] = CheckForIntersection(&newRect[j], overlapRect[k]); + } + } + } + + for (uint32_t j = 0; j < 5; j++) { + if (overlaps[j][0]) { + FragmentSourceRectangles( + sourceArray, + index + 1, + lastIndex, + overlapsExisting || overlaps[j][1], + &newRect[j], + param, + sequence); + } + + if (overlaps[j][1]) { + uint32_t newFlags = (*sourceArray)[index].flags & ~SF_TEMPMASK; + newFlags |= overlaps[j][0] ? SF_OVERLAPS : SF_NONE; + + AddSourceRect(sourceArray, &newRect[j], (*sourceArray)[index].param, (*sourceArray)[index].sequence, newFlags); + } + } + DeleteSourceRect(sourceArray, index); return; } } - // TODO + AddSourceRect(sourceArray, rect, param, sequence, SF_ADDING | (overlapsExisting ? SF_OVERLAPS : SF_NONE)); } int32_t IsNullRect(const RECTF* rect) { @@ -242,20 +315,20 @@ void DeleteSourceRect(TSGrowableArray* sourceArray, uint32_t index) { } void OptimizeSource(TSGrowableArray* sourceArray) { - for (uint32_t i = 0; i < sourceArray->Count(); i++) { - auto source = &(*sourceArray)[i]; + for (uint32_t index = 0; index < sourceArray->Count(); ) { + auto source = &(*sourceArray)[index]; if (IsNullRect(&source->rect)) { // Set current (null) element to last element auto last = &(*sourceArray)[sourceArray->Count() - 1]; - (*sourceArray)[i] = *last; - - // Decrement index by 1 to force null check on copied last element on next tick - i--; + (*sourceArray)[index] = *last; // Shrink by 1 (to account for the removal of the null element) sourceArray->SetCount(sourceArray->Count() - 1); } + else { + index++; + } } } diff --git a/storm/region/RGN.hpp b/storm/region/RGN.hpp index 74fb4f9..b02d973 100644 --- a/storm/region/RGN.hpp +++ b/storm/region/RGN.hpp @@ -7,7 +7,7 @@ #include // region flgs -#define SF_NONE 0x00 +#define SF_NONE 0x00000000 #define SF_ADDING 0x00000001 #define SF_OVERLAPS 0x00000002 #define SF_TEMPMASK 0x00000003 diff --git a/test/Region.cpp b/test/Region.cpp index 495ce18..46c73cc 100644 --- a/test/Region.cpp +++ b/test/Region.cpp @@ -1,10 +1,13 @@ #include "RegionTest.hpp" +// Note: diagrams are y inverted when building for WoW, +// still conveys understanding. + TEST_CASE("SRgnClear", "[region]") { RgnDataTest region; SECTION("operates on an empty object") { - uint32_t numrects = 0; + uint32_t numrects = 1; SRgnClear(region); @@ -12,6 +15,11 @@ TEST_CASE("SRgnClear", "[region]") { CHECK(numrects == 0); } + SECTION("runs on an invalid pointer") { + HSRGN inval = reinterpret_cast(1234); + CHECK_NOTHROW(SRgnClear(inval)); + } + SECTION("clears rects out of a region object") { uint32_t numrects = 0; @@ -26,6 +34,23 @@ TEST_CASE("SRgnClear", "[region]") { SRgnGetRectsf(region, &numrects, nullptr); CHECK(numrects == 0); } + + SECTION("clears params out of a region object") { + uint32_t numParams = 1; + void* params[1]; + + RECTF baseRect = { 0.0f, 0.0f, 1.0f, 1.0f }; + SRgnCombineRectf(region, &baseRect, nullptr, SRGN_OR); + SRgnCombineRectf(region, &baseRect, &baseRect, SRGN_PARAMONLY); + + SRgnGetRectParamsf(region, &baseRect, &numParams, params); + CHECK(numParams == 1); + + SRgnClear(region); + + SRgnGetRectParamsf(region, &baseRect, &numParams, params); + CHECK(numParams == 0); + } } TEST_CASE("SRgnCreate", "[region]") { @@ -41,9 +66,10 @@ TEST_CASE("SRgnCreate", "[region]") { TEST_CASE("SRgnCombineRectf", "[region]") { RgnDataTest region; + RECTF baseRect = { 0.0f, 0.0f, 1.0f, 1.0f }; + RECTF testRect = { 0.5f, 0.6f, 1.8f, 1.4f }; SECTION("combines the region with a single given rect 1") { - RECTF baseRect = { 0.0f, 0.0f, 1.0f, 1.0f }; SRgnCombineRectf(region, &baseRect, nullptr, SRGN_OR); RECTF boundingRect = { 0.0f, 0.0f, 0.0f, 0.0f }; @@ -53,7 +79,6 @@ TEST_CASE("SRgnCombineRectf", "[region]") { } SECTION("combines the region with multiple given rects 1") { - RECTF baseRect = { 0.0f, 0.0f, 1.0f, 1.0f }; SRgnCombineRectf(region, &baseRect, nullptr, SRGN_OR); RECTF newRect = { 0.0f, 0.0f, 0.0f, 0.0f }; @@ -66,7 +91,6 @@ TEST_CASE("SRgnCombineRectf", "[region]") { } SECTION("combines the region with multiple given rects 2") { - RECTF baseRect = { 0.0f, 0.0f, 1.0f, 1.0f }; SRgnCombineRectf(region, &baseRect, nullptr, SRGN_OR); RECTF newRect = { 0.0f, 0.0f, 1.0f, 1.0f }; @@ -79,7 +103,6 @@ TEST_CASE("SRgnCombineRectf", "[region]") { } SECTION("combines the region with multiple given rects 3") { - RECTF baseRect = { 0.0f, 0.0f, 1.0f, 1.0f }; SRgnCombineRectf(region, &baseRect, nullptr, SRGN_OR); RECTF newRect = { 0.0f, 1.0f, 1.0f, 1.0f }; @@ -90,6 +113,202 @@ TEST_CASE("SRgnCombineRectf", "[region]") { CHECK_THAT(boundingRect, MatchesRect({ 0.0f, 0.0f, 1.0f, 1.0f })); } + + SECTION("OR operation combines rects") { + SRgnCombineRectf(region, &baseRect, nullptr, SRGN_OR); + SRgnCombineRectf(region, &testRect, nullptr, SRGN_OR); + + uint32_t numRects = 4; + RECTF buffer[4]; + SRgnGetRectsf(region, &numRects, buffer); + + // ┌─────────┐ + // │ 0 │ + // │┈┈┈┈┌────┼──────┐ + // │ 1 │ + // └────┼────┘┈┈┈┈┈┈│ + // │ 2 │ + // └───────────┘ + CHECK(numRects == 3); + CHECK_THAT(buffer[0], MatchesRect({ 0.0f, 0.0f, 1.0f, 0.6f })); + CHECK_THAT(buffer[1], MatchesRect({ 0.0f, 0.6f, 1.8f, 1.0f })); + CHECK_THAT(buffer[2], MatchesRect({ 0.5f, 1.0f, 1.8f, 1.4f })); + } + + SECTION("AND operation intersects rects") { + SRgnCombineRectf(region, &baseRect, nullptr, SRGN_OR); + SRgnCombineRectf(region, &testRect, nullptr, SRGN_AND); + + uint32_t numRects = 2; + RECTF buffer[2]; + SRgnGetRectsf(region, &numRects, buffer); + + // ┌─────────┐ + // │╳╳╳╳╳╳╳╳╳│ + // │╳╳╳╳┌────┼──────┐ + // │╳╳╳╳│ 0 │╳╳╳╳╳╳│ + // └────┼────┘╳╳╳╳╳╳│ + // │╳╳╳╳╳╳╳╳╳╳╳│ + // └───────────┘ + CHECK(numRects == 1); + CHECK_THAT(buffer[0], MatchesRect({ 0.5f, 0.6f, 1.0f, 1.0f })); + } + + SECTION("XOR operation takes exclusive differences of rects") { + SRgnCombineRectf(region, &baseRect, nullptr, SRGN_OR); + SRgnCombineRectf(region, &testRect, nullptr, SRGN_XOR); + + uint32_t numRects = 5; + RECTF buffer[5]; + SRgnGetRectsf(region, &numRects, buffer); + + // ┌─────────┐ + // │ 0 │ + // │┈┈┈┈┌────┼──────┐ + // │ 1 │╳╳╳╳│ 2 │ + // └────┼────┘┈┈┈┈┈┈│ + // │ 3 │ + // └───────────┘ + CHECK(numRects == 4); + CHECK_THAT(buffer[0], MatchesRect({ 0.0f, 0.0f, 1.0f, 0.6f })); + CHECK_THAT(buffer[1], MatchesRect({ 0.0f, 0.6f, 0.5f, 1.0f })); + CHECK_THAT(buffer[2], MatchesRect({ 1.0f, 0.6f, 1.8f, 1.0f })); + CHECK_THAT(buffer[3], MatchesRect({ 0.5f, 1.0f, 1.8f, 1.4f })); + } + + SECTION("DIFF operation removes parts of rects") { + SRgnCombineRectf(region, &baseRect, nullptr, SRGN_OR); + SRgnCombineRectf(region, &testRect, nullptr, SRGN_DIFF); + + uint32_t numRects = 5; + RECTF buffer[5]; + SRgnGetRectsf(region, &numRects, buffer); + + // ┌─────────┐ + // │ 0 │ + // │┈┈┈┈┌────┼──────┐ + // │ 1 │╳╳╳╳│╳╳╳╳╳╳│ + // └────┼────┘╳╳╳╳╳╳│ + // │╳╳╳╳╳╳╳╳╳╳╳│ + // └───────────┘ + CHECK(numRects == 2); + CHECK_THAT(buffer[0], MatchesRect({ 0.0f, 0.0f, 1.0f, 0.6f })); + CHECK_THAT(buffer[1], MatchesRect({ 0.0f, 0.6f, 0.5f, 1.0f })); + } + + SECTION("COPY operation splits intersecting rects") { + SRgnCombineRectf(region, &baseRect, nullptr, SRGN_OR); + SRgnCombineRectf(region, &testRect, nullptr, SRGN_COPY); + + uint32_t numRects = 5; + RECTF buffer[5]; + SRgnGetRectsf(region, &numRects, buffer); + + // ┌─────────┐ + // │ 0 │ + // │┈┈┈┈┌────┼──────┐ + // │ 1 │╳╳╳╳╳╳│ + // └────┼────┘╳╳╳╳╳╳│ + // │╳╳╳╳╳╳╳╳╳╳╳│ + // └───────────┘ + CHECK(numRects == 2); + CHECK_THAT(buffer[0], MatchesRect({ 0.0f, 0.0f, 1.0f, 0.6f })); + CHECK_THAT(buffer[1], MatchesRect({ 0.0f, 0.6f, 1.0f, 1.0f })); + } + + SECTION("COPY operation splits intersecting rects 2") { + SRgnCombineRectf(region, &baseRect, nullptr, SRGN_OR); + RECTF testRect2 = { 0.4f, 0.4f, 0.6f, 0.6f }; + SRgnCombineRectf(region, &testRect2, nullptr, SRGN_COPY); + + uint32_t numRects = 5; + RECTF buffer[5]; + SRgnGetRectsf(region, &numRects, buffer); + + // ┌─────────┐ + // │ 0 │ + // │┈┈┈┌┈┐┈┈┈│ + // │┈┈┈└┈┘┈1┈│ + // │ 2 │ + // └─────────┘ + CHECK(numRects == 3); + CHECK_THAT(buffer[0], MatchesRect({ 0.0f, 0.0f, 1.0f, 0.4f })); + CHECK_THAT(buffer[1], MatchesRect({ 0.0f, 0.4f, 1.0f, 0.6f })); + CHECK_THAT(buffer[2], MatchesRect({ 0.0f, 0.6f, 1.0f, 1.0f })); + } + + SECTION("operation doesn't work when operating rect width or height is <= 0") { + int32_t combineMode = GENERATE(SRGN_OR, SRGN_XOR, SRGN_DIFF, SRGN_COPY, SRGN_PARAMONLY); + RECTF testRects = GENERATE( + RECTF{ 0.5f, 0.0f, 0.5f, 1.0f }, + RECTF{ 0.0f, 0.5f, 1.0f, 0.5f }, + RECTF{ 1.0f, 0.0f, 0.5f, 1.0f }, + RECTF{ 0.0f, 1.0f, 1.0f, 0.5f } + ); + + INFO("CombineMode = " << combineMode); + INFO("testRects = " << testRects); + + SRgnCombineRectf(region, &baseRect, nullptr, SRGN_OR); + + uint32_t numRects = 5; + RECTF buffer[5]; + + SRgnCombineRectf(region, &testRects, &testRects, combineMode); + + SRgnGetRectsf(region, &numRects, buffer); + CHECK(numRects == 1); + CHECK_THAT(buffer[0], MatchesRect(baseRect)); + + uint32_t numParams = 1; + SRgnGetRectParamsf(region, &testRects, &numParams, nullptr); + CHECK(numParams == 0); + + SRgnGetRectParamsf(region, &baseRect, &numParams, nullptr); + CHECK(numParams == 1); + } + + SECTION("AND kills all rects when rect width or height is <= 0") { + int32_t combineMode = SRGN_AND; + RECTF testRects = GENERATE( + RECTF{ 0.5f, 0.0f, 0.5f, 1.0f }, + RECTF{ 0.0f, 0.5f, 1.0f, 0.5f }, + RECTF{ 1.0f, 0.0f, 0.5f, 1.0f }, + RECTF{ 0.0f, 1.0f, 1.0f, 0.5f } + ); + + INFO("CombineMode = " << combineMode); + INFO("testRects = " << testRects); + + SRgnCombineRectf(region, &baseRect, nullptr, SRGN_OR); + + uint32_t numRects = 5; + RECTF buffer[5]; + + SRgnCombineRectf(region, &testRects, &testRects, combineMode); + + SRgnGetRectsf(region, &numRects, buffer); + CHECK(numRects == 0); + + uint32_t numParams = 1; + SRgnGetRectParamsf(region, &testRects, &numParams, nullptr); + CHECK(numParams == 0); + + SRgnGetRectParamsf(region, &baseRect, &numParams, nullptr); + CHECK(numParams == 0); + } + + SECTION("PARAM operation doesn't influence rects") { + SRgnCombineRectf(region, &baseRect, nullptr, SRGN_OR); + SRgnCombineRectf(region, &testRect, nullptr, SRGN_PARAMONLY); + + uint32_t numRects = 5; + RECTF buffer[5]; + SRgnGetRectsf(region, &numRects, buffer); + + CHECK(numRects == 1); + CHECK_THAT(buffer[0], MatchesRect(baseRect)); + } } TEST_CASE("SRgnDelete", "[region]") { @@ -114,9 +333,9 @@ TEST_CASE("SRgnDelete", "[region]") { TEST_CASE("SRgnDuplicate", "[region]") { RgnDataTest region; + RECTF baseRect = { -1.0f, 1.0f, 1.0f, 2.0f }; SECTION("creates an independent copy of a region") { - RECTF baseRect = { -1.0f, 1.0f, 1.0f, 2.0f }; SRgnCombineRectf(region, &baseRect, nullptr, SRGN_OR); HSRGN newrgn = nullptr; @@ -133,6 +352,28 @@ TEST_CASE("SRgnDuplicate", "[region]") { CHECK_THAT(buffer[0], MatchesRect(baseRect)); } + SECTION("copies parms") { + SRgnCombineRectf(region, &baseRect, &baseRect, SRGN_PARAMONLY); + + uint32_t numParams = 2; + void* buffer[2]; + SRgnGetRectParamsf(region, &baseRect, &numParams, buffer); + + CHECK(numParams == 1); + CHECK(buffer[0] == &baseRect); + + HSRGN newrgn = nullptr; + SRgnDuplicate(region, &newrgn); + + REQUIRE(newrgn != nullptr); + SRgnClear(region); + + SRgnGetRectParamsf(newrgn, &baseRect, &numParams, buffer); + + CHECK(numParams == 1); + CHECK(buffer[0] == &baseRect); + } + SECTION("sets handle to null when using an invalid region object") { HSRGN inval = reinterpret_cast(1234); @@ -244,6 +485,52 @@ TEST_CASE("SRgnGetRectsf", "[region]") { CHECK_THAT(buffer[0], MatchesRect(rct1)); } + + SECTION("retrieves rects in order of top value") { + RECTF rects[4] = { + { 0, 0, 1, 1 }, + { 4, -2, 5, 5 }, + { -2, 2, -1, 3 }, + { 2, -2, 3, -1 }, + }; + + for (int i = 0; i < 4; i++) { + SRgnCombineRectf(region, &rects[i], nullptr, SRGN_OR); + } + + uint32_t numrects = 5; + RECTF buffer[5]; + SRgnGetRectsf(region, &numrects, buffer); + + CHECK(numrects == 4); + CHECK_THAT(buffer[0], MatchesRect(rects[3])); + CHECK_THAT(buffer[1], MatchesRect(rects[0])); + CHECK_THAT(buffer[2], MatchesRect(rects[2])); + CHECK_THAT(buffer[3], MatchesRect(rects[1])); + } + + SECTION("retrieves rects in order of left value when tops are equal") { + RECTF rects[4] = { + { 0, 0, 1, 1 }, + { 4, 0.5, 5, 1 }, + { -2, -2, -1, 1 }, + { 2, -1, 3, 1 }, + }; + + for (int i = 0; i < 4; i++) { + SRgnCombineRectf(region, &rects[i], nullptr, SRGN_OR); + } + + uint32_t numrects = 5; + RECTF buffer[5]; + SRgnGetRectsf(region, &numrects, buffer); + + CHECK(numrects == 4); + CHECK_THAT(buffer[0], MatchesRect(rects[2])); + CHECK_THAT(buffer[1], MatchesRect(rects[0])); + CHECK_THAT(buffer[2], MatchesRect(rects[3])); + CHECK_THAT(buffer[3], MatchesRect(rects[1])); + } } TEST_CASE("SRgnIsPointInRegionf", "[region]") { @@ -311,7 +598,7 @@ TEST_CASE("SRgnIsRectInRegionf", "[region]") { CHECK_FALSE(SRgnIsRectInRegionf(inval, &rect)); } - SECTION("reports if rects overlap a region") { + SECTION("true if rects overlap a region") { RECTF checkRects[] = { { 0.5f, 0.5f, 0.5f, 0.5f }, { 0.00001f, 0.00001f, 0.999999f, 0.999999f }, @@ -331,7 +618,7 @@ TEST_CASE("SRgnIsRectInRegionf", "[region]") { CHECK(SRgnIsRectInRegionf(region, &checkRects[4])); } - SECTION("reports if rects are outside a region") { + SECTION("false if rects are outside a region") { RECTF checkRects[] = { { 2.0f, 2.0f, 2.0f, 2.0f }, { 1.0f, 1.0f, 2.0f, 2.0f }, @@ -379,8 +666,8 @@ TEST_CASE("SRgnOffsetf", "[region]") { SECTION("shifts rects by given amount") { RECTF rects[] = { - { 0.0f, 0.0f, 100.0f, 100.0f }, - { -200.0f, -200.0f, -100.0f, -100.0f } + { -200.0f, -200.0f, -100.0f, -100.0f }, + { 0.0f, 0.0f, 100.0f, 100.0f } }; SRgnCombineRectf(region, &rects[0], nullptr, SRGN_OR); @@ -398,8 +685,8 @@ TEST_CASE("SRgnOffsetf", "[region]") { SECTION("shifts rects back to their original positions with opposite amounts") { RECTF rects[] = { - { 0.0f, 0.0f, 100.0f, 100.0f }, - { -200.0f, -200.0f, -100.0f, -100.0f } + { -200.0f, -200.0f, -100.0f, -100.0f }, + { 0.0f, 0.0f, 100.0f, 100.0f } }; SRgnCombineRectf(region, &rects[0], nullptr, SRGN_OR); @@ -413,14 +700,14 @@ TEST_CASE("SRgnOffsetf", "[region]") { RECTF buffer[2]; SRgnGetRectsf(region, &numRects, buffer); - CHECK_THAT(buffer[0], MatchesRect(rects[1])); - CHECK_THAT(buffer[1], MatchesRect(rects[0])); + CHECK_THAT(buffer[0], MatchesRect(rects[0])); + CHECK_THAT(buffer[1], MatchesRect(rects[1])); } SECTION("doesn't shift anything with 0") { RECTF rects[] = { - { 0.0f, 0.0f, 100.0f, 100.0f }, - { -200.0f, -200.0f, -100.0f, -100.0f } + { -200.0f, -200.0f, -100.0f, -100.0f }, + { 0.0f, 0.0f, 100.0f, 100.0f } }; SRgnCombineRectf(region, &rects[0], nullptr, SRGN_OR); @@ -432,7 +719,7 @@ TEST_CASE("SRgnOffsetf", "[region]") { RECTF buffer[2]; SRgnGetRectsf(region, &numRects, buffer); - CHECK_THAT(buffer[0], MatchesRect(rects[1])); - CHECK_THAT(buffer[1], MatchesRect(rects[0])); + CHECK_THAT(buffer[0], MatchesRect(rects[0])); + CHECK_THAT(buffer[1], MatchesRect(rects[1])); } }