diff --git a/storm/Region.cpp b/storm/Region.cpp index 3bab710..de48c38 100644 --- a/storm/Region.cpp +++ b/storm/Region.cpp @@ -106,6 +106,45 @@ void DeleteRect(RECTF* rect) { rect->top = std::numeric_limits::max(); } +int SortFoundParamsCallback(const void* elem1, const void* elem2) { + const FOUNDPARAM* param1 = static_cast(elem1); + const FOUNDPARAM* param2 = static_cast(elem2); + + return param1->sequence - param2->sequence; +} + +void FindSourceParams(RGN* rgnptr, const RECTF* rect) { + if (CompareRects(rect, &rgnptr->foundparamsrect)) return; + + rgnptr->foundparams.SetCount(0); + uint32_t sourceRects = rgnptr->source.Count(); + uint32_t params = 0; + + for (uint32_t i = 0; i < sourceRects; i++) { + if (!CheckForIntersection(rect, &rgnptr->source[i].rect)) continue; + + int32_t sequence = rgnptr->source[i].sequence; + int32_t found = 0; + + for (uint32_t j = 0; j < params; j++) { + if (rgnptr->foundparams[j].sequence == sequence) { + found = 1; + break; + } + } + + if (!found) { + FOUNDPARAM* newParam = rgnptr->foundparams.New(); + newParam->param = rgnptr->source[i].param; + newParam->sequence = sequence; + params++; + } + } + + std::qsort(rgnptr->foundparams.Ptr(), rgnptr->foundparams.Count(), sizeof(FOUNDPARAM), SortFoundParamsCallback); + rgnptr->foundparamsrect = *rect; +} + void FragmentCombinedRectangles(TSGrowableArray* combinedArray, uint32_t firstIndex, uint32_t lastIndex, const RECTF* rect) { uint32_t index; RECTF* checkRect; @@ -249,8 +288,8 @@ void ProcessBooleanOperation(TSGrowableArray* sourceArray, int32_t combi } int SortRectCallback(const void* elem1, const void* elem2) { - RECTF* rct1 = (RECTF*)elem1; - RECTF* rct2 = (RECTF*)elem2; + const RECTF* rct1 = static_cast(elem1); + const RECTF* rct2 = static_cast(elem2); double result = rct1->top == rct2->top ? rct1->left - rct2->left : rct1->top - rct2->top; @@ -272,7 +311,7 @@ void ProduceCombinedRectangles(RGN* rgn) { CombineRectangles(&rgn->combined); - std::qsort(rgn->combined.Ptr(), rgn->combined.Count(), sizeof(rgn->combined.Ptr()[0]), SortRectCallback); + std::qsort(rgn->combined.Ptr(), rgn->combined.Count(), sizeof(RECTF), SortRectCallback); for (uint32_t i = rgn->combined.Count(); i > 0; i = rgn->combined.Count()) { if (!IsNullRect(&rgn->combined[i-1])) break; @@ -347,17 +386,17 @@ void SRgnDelete(HSRGN handle) { s_rgntable.Delete(handle); } -void SRgnDuplicate(HSRGN orighandle, HSRGN *handle, uint32_t reserved) { +void SRgnDuplicate(HSRGN origHandle, HSRGN* handle, uint32_t reserved) { STORM_VALIDATE_BEGIN; STORM_VALIDATE(handle); *handle = nullptr; - STORM_VALIDATE(orighandle); + STORM_VALIDATE(origHandle); STORM_VALIDATE(reserved == 0); STORM_VALIDATE_END_VOID; HLOCKEDRGN origlockedhandle; - auto rgn = s_rgntable.Lock(orighandle, &origlockedhandle, 0); + auto rgn = s_rgntable.Lock(origHandle, &origlockedhandle, 0); if (rgn) { HLOCKEDRGN newlockedhandle; @@ -406,16 +445,57 @@ void SRgnGetBoundingRectf(HSRGN handle, RECTF* rect) { } } -void SRgnGetRectsf(HSRGN handle, uint32_t* numrects, RECTF* buffer) { +void SRgnGetRectParamsf(HSRGN handle, RECTF* rect, uint32_t* numParams, void** buffer) { STORM_VALIDATE_BEGIN; STORM_VALIDATE(handle); - STORM_VALIDATE(numrects); + STORM_VALIDATE(rect); + STORM_VALIDATE(numParams); + STORM_VALIDATE_END_VOID; + + if (IsNullRect(rect)) { + *numParams = 0; + return; + } + + HLOCKEDRGN lockedHandle; + auto rgn = s_rgntable.Lock(handle, &lockedHandle, 0); + if (!rgn) { + *numParams = 0; + return; + } + + if (rgn->dirty) { + ProduceCombinedRectangles(rgn); + rgn->dirty = 0; + } + + FindSourceParams(rgn, rect); + + if (buffer) { + *numParams = std::min(*numParams, rgn->foundparams.Count()); + FOUNDPARAM* foundArray = rgn->foundparams.Ptr(); + + for (uint32_t i = 0; i < *numParams; i++) { + buffer[i] = foundArray[i].param; + } + } + else { + *numParams = rgn->foundparams.Count(); + } + + s_rgntable.Unlock(lockedHandle); +} + +void SRgnGetRectsf(HSRGN handle, uint32_t* numRects, RECTF* buffer) { + STORM_VALIDATE_BEGIN; + STORM_VALIDATE(handle); + STORM_VALIDATE(numRects); STORM_VALIDATE_END_VOID; HLOCKEDRGN lockedHandle; auto rgn = s_rgntable.Lock(handle, &lockedHandle, 0); if (!rgn) { - *numrects = 0; + *numRects = 0; return; } @@ -425,11 +505,11 @@ void SRgnGetRectsf(HSRGN handle, uint32_t* numrects, RECTF* buffer) { } if (buffer) { - *numrects = std::min(*numrects, rgn->combined.Count()); - memcpy(buffer, rgn->combined.Ptr(), sizeof(rgn->combined.Ptr()[0]) * *numrects); + *numRects = std::min(*numRects, rgn->combined.Count()); + memcpy(buffer, rgn->combined.Ptr(), sizeof(rgn->combined.Ptr()[0]) * *numRects); } else { - *numrects = rgn->combined.Count(); + *numRects = rgn->combined.Count(); } s_rgntable.Unlock(lockedHandle); diff --git a/storm/Region.hpp b/storm/Region.hpp index 1f4fea5..fbcfc2a 100644 --- a/storm/Region.hpp +++ b/storm/Region.hpp @@ -12,10 +12,12 @@ void SRgnCreate(HSRGN* handlePtr, uint32_t reserved = 0); void SRgnDelete(HSRGN handle); -void SRgnDuplicate(HSRGN orighandle, HSRGN *handle, uint32_t reserved = 0); +void SRgnDuplicate(HSRGN origHandle, HSRGN* handle, uint32_t reserved = 0); void SRgnGetBoundingRectf(HSRGN handle, RECTF* rect); -void SRgnGetRectsf(HSRGN handle, uint32_t* numrects, RECTF* buffer); +void SRgnGetRectParamsf(HSRGN handle, RECTF* rect, uint32_t* numParams, void** buffer); + +void SRgnGetRectsf(HSRGN handle, uint32_t* numRects, RECTF* buffer); #endif diff --git a/test/Region.cpp b/test/Region.cpp index b39410e..449f305 100644 --- a/test/Region.cpp +++ b/test/Region.cpp @@ -143,6 +143,54 @@ TEST_CASE("SRgnDuplicate", "[region]") { } } +TEST_CASE("SRgnGetRectParamsf", "[region]") { + RgnDataTest region; + + SECTION("retrieves empty list if nothing put in") { + uint32_t numParams = 1; + void* buffer[1]; + + RECTF rect = { 0, 0, 1, 1 }; + SRgnGetRectParamsf(region, &rect, &numParams, buffer); + + CHECK(numParams == 0); + } + + SECTION("retrieves 0 when using an invalid region object") { + HSRGN inval = reinterpret_cast(1234); + + uint32_t numParams = 1; + RECTF rect = { 0, 0, 1, 1 }; + SRgnGetRectParamsf(inval, &rect, &numParams, nullptr); + + CHECK(numParams == 0); + } + + SECTION("retrieves only overlapping params") { + RECTF rect1 = { 0, 0, 1, 1 }; + RECTF rect2 = { 2, 2, 4, 4 }; + RECTF rect3 = { 2.5, 2.5, 5, 5 }; + RECTF queryRect = { 3, 3, 5, 5 }; + int param1 = 5; + int param2 = 10; + int param3 = 11; + + SRgnCombineRectf(region, &rect1, ¶m1, SRGN_PARAMONLY); + SRgnCombineRectf(region, &rect2, ¶m2, SRGN_PARAMONLY); + SRgnCombineRectf(region, &rect3, ¶m3, SRGN_PARAMONLY); + + uint32_t numParams = 0; + SRgnGetRectParamsf(region, &queryRect, &numParams, nullptr); + REQUIRE(numParams == 2); + + void* buffer[2]; + SRgnGetRectParamsf(region, &queryRect, &numParams, buffer); + CHECK(numParams == 2); + CHECK(buffer[0] == ¶m2); + CHECK(buffer[1] == ¶m3); + } +} + TEST_CASE("SRgnGetRectsf", "[region]") { RgnDataTest region; @@ -155,6 +203,15 @@ TEST_CASE("SRgnGetRectsf", "[region]") { CHECK(numrects == 0); } + SECTION("retrieves 0 when using an invalid region object") { + HSRGN inval = reinterpret_cast(1234); + + uint32_t numrects = 1; + SRgnGetRectsf(inval, &numrects, nullptr); + + CHECK(numrects == 0); + } + SECTION("retrieves all rects that were put in") { RECTF rct1 = { 5, 5, 10, 10 }; RECTF rct2 = { 0, 0, 1, 1 };