From d322f579a2f52a544fb1753a3290e992e1104c69 Mon Sep 17 00:00:00 2001 From: Adam Heinermann Date: Mon, 21 Apr 2025 18:50:31 -0700 Subject: [PATCH] feat(region): add SRgnIsPointInRegionf --- storm/Region.cpp | 27 +++++++++++++++++++++++++ storm/Region.hpp | 3 +++ test/Region.cpp | 52 ++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 82 insertions(+) diff --git a/storm/Region.cpp b/storm/Region.cpp index de48c38..1dd0586 100644 --- a/storm/Region.cpp +++ b/storm/Region.cpp @@ -514,3 +514,30 @@ void SRgnGetRectsf(HSRGN handle, uint32_t* numRects, RECTF* buffer) { s_rgntable.Unlock(lockedHandle); } + +int32_t SRgnIsPointInRegionf(HSRGN handle, float x, float y) { + STORM_VALIDATE_BEGIN; + STORM_VALIDATE(handle); + STORM_VALIDATE_END; + + HLOCKEDRGN lockedHandle; + auto rgn = s_rgntable.Lock(handle, &lockedHandle, 0); + if (!rgn) return 0; + + int32_t result = 0; + + SOURCE* sourceArray = rgn->source.Ptr(); + uint32_t sourceRects = rgn->source.Count(); + for (uint32_t i = 0; i < sourceRects; i++) { + if (!(sourceArray[i].flags & SF_PARAMONLY)) { + if (x >= sourceArray[i].rect.left && y >= sourceArray[i].rect.bottom && + x < sourceArray[i].rect.right && y < sourceArray[i].rect.top) { + result = 1; + break; + } + } + } + + s_rgntable.Unlock(lockedHandle); + return result; +} diff --git a/storm/Region.hpp b/storm/Region.hpp index fbcfc2a..cca20a7 100644 --- a/storm/Region.hpp +++ b/storm/Region.hpp @@ -20,4 +20,7 @@ void SRgnGetRectParamsf(HSRGN handle, RECTF* rect, uint32_t* numParams, void** b void SRgnGetRectsf(HSRGN handle, uint32_t* numRects, RECTF* buffer); +int32_t SRgnIsPointInRegionf(HSRGN handle, float x, float y); + + #endif diff --git a/test/Region.cpp b/test/Region.cpp index 449f305..100cf7c 100644 --- a/test/Region.cpp +++ b/test/Region.cpp @@ -245,3 +245,55 @@ TEST_CASE("SRgnGetRectsf", "[region]") { CHECK_THAT(buffer[0], MatchesRect(rct1)); } } + +TEST_CASE("SRgnIsPointInRegionf", "[region]") { + RgnDataTest region; + + SECTION("false if region has no rects") { + auto x = GENERATE(0.0f, 1.0f, INFINITY); + auto y = GENERATE(0.0f, -1.0f, -INFINITY); + + CHECK_FALSE(SRgnIsPointInRegionf(region, x, y)); + } + + SECTION("false if using an invalid region object") { + HSRGN inval = reinterpret_cast(1234); + + CHECK_FALSE(SRgnIsPointInRegionf(inval, 0.0f, 0.0f)); + } + + SECTION("reports if points are inside a region") { + RECTF rct1 = { -10, -10, -1, -1 }; + RECTF rct2 = { 1, 1, 5, 5 }; + SRgnCombineRectf(region, &rct1, nullptr, SRGN_OR); + SRgnCombineRectf(region, &rct2, nullptr, SRGN_OR); + + CHECK_FALSE(SRgnIsPointInRegionf(region, 0.0f, 0.0f)); + CHECK_FALSE(SRgnIsPointInRegionf(region, -11.0f, -5.0f)); + CHECK_FALSE(SRgnIsPointInRegionf(region, 4.0f, 6.0f)); + CHECK_FALSE(SRgnIsPointInRegionf(region, 1.0f, 0.0f)); + CHECK_FALSE(SRgnIsPointInRegionf(region, 0.0f, -1.0f)); + CHECK(SRgnIsPointInRegionf(region, -10.0f, -10.0f)); + CHECK(SRgnIsPointInRegionf(region, -1.1f, -1.1f)); + CHECK(SRgnIsPointInRegionf(region, 3.0f, 2.0f)); + } + + SECTION("ignores param only rects") { + RECTF rect = { -1, -1, 1, 1 }; + SRgnCombineRectf(region, &rect, &rect, SRGN_PARAMONLY); + + CHECK_FALSE(SRgnIsPointInRegionf(region, 0.0f, 0.0f)); + } + + SECTION("excludes upper bounds of rect") { + RECTF rect = { 1, 1, 5, 5 }; + SRgnCombineRectf(region, &rect, nullptr, SRGN_OR); + + CHECK_FALSE(SRgnIsPointInRegionf(region, 5.0f, 5.0f)); + CHECK_FALSE(SRgnIsPointInRegionf(region, 5.0f, 4.0f)); + CHECK_FALSE(SRgnIsPointInRegionf(region, 4.0f, 5.0f)); + CHECK(SRgnIsPointInRegionf(region, 4.9999f, 4.9999f)); + CHECK(SRgnIsPointInRegionf(region, 1.0f, 1.0f)); + CHECK_FALSE(SRgnIsPointInRegionf(region, 0.9999f, 1.0f)); + } +}