mirror of
https://github.com/thunderbrewhq/squall.git
synced 2026-05-04 14:33:50 +00:00
feat: sync with Whoa implementation
This commit is contained in:
parent
12ab8f7721
commit
6928bf3f0c
46 changed files with 2980 additions and 441 deletions
841
storm/Region.cpp
841
storm/Region.cpp
|
|
@ -3,10 +3,21 @@
|
|||
#include "storm/Error.hpp"
|
||||
#include "storm/Hash.hpp"
|
||||
#include "storm/Thread.hpp"
|
||||
|
||||
#include <limits>
|
||||
|
||||
static TSExportTableSyncReuse<RGN, HSRGN, HLOCKEDRGN, CCritSect> s_rgntable;
|
||||
|
||||
void DeleteCombinedRect(TSGrowableArray<RECTF>* combinedArray, uint32_t index);
|
||||
void DeleteRect(RECTF* rect);
|
||||
void DeleteSourceRect(TSGrowableArray<SOURCE>* sourceArray, uint32_t index);
|
||||
int32_t IsNullRect(const RECTF* rect);
|
||||
|
||||
void AddCombinedRect(TSGrowableArray<RECTF>* combinedArray, const RECTF* rect) {
|
||||
RECTF* newRect = combinedArray->New();
|
||||
*newRect = *rect;
|
||||
}
|
||||
|
||||
void AddSourceRect(TSGrowableArray<SOURCE>* sourceArray, const RECTF* rect, void* param, int32_t sequence, uint32_t flags) {
|
||||
auto source = sourceArray->New();
|
||||
|
||||
|
|
@ -17,10 +28,91 @@ void AddSourceRect(TSGrowableArray<SOURCE>* sourceArray, const RECTF* rect, void
|
|||
}
|
||||
|
||||
int32_t CheckForIntersection(const RECTF* sourceRect, const RECTF* targetRect) {
|
||||
#if defined(WHOA_RECT_USES_SCREEN_COORDINATES)
|
||||
return sourceRect->left < targetRect->right
|
||||
&& sourceRect->top < targetRect->bottom
|
||||
&& sourceRect->right > targetRect->left
|
||||
&& sourceRect->bottom > targetRect->top;
|
||||
#else
|
||||
return sourceRect->left < targetRect->right
|
||||
&& sourceRect->bottom < targetRect->top
|
||||
&& sourceRect->right > targetRect->left
|
||||
&& sourceRect->top > targetRect->bottom;
|
||||
#endif
|
||||
}
|
||||
|
||||
void CombineRectangles(TSGrowableArray<RECTF>* combinedArray) {
|
||||
for (uint32_t i = 1; i < combinedArray->Count(); i++) {
|
||||
for (uint32_t j = 0; j < i; j++) {
|
||||
RECTF* rctA = &(*combinedArray)[i];
|
||||
RECTF* rctB = &(*combinedArray)[j];
|
||||
|
||||
if (rctA->left == rctB->left && rctA->right == rctB->right) {
|
||||
if (rctA->bottom == rctB->top || rctB->bottom == rctA->top) {
|
||||
#if defined(WHOA_RECT_USES_SCREEN_COORDINATES)
|
||||
rctA->top = std::min(rctB->top, rctA->top);
|
||||
rctA->bottom = std::max(rctB->bottom, rctA->bottom);
|
||||
#else
|
||||
rctA->bottom = std::min(rctB->bottom, rctA->bottom);
|
||||
rctA->top = std::max(rctB->top, rctA->top);
|
||||
#endif
|
||||
DeleteRect(rctB);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (rctA->left == rctB->right || rctB->left == rctA->right) {
|
||||
if (rctA->bottom == rctB->bottom && rctA->top == rctB->top) {
|
||||
rctA->left = std::min(rctB->left, rctA->left);
|
||||
rctA->right = std::max(rctB->right, rctA->right);
|
||||
DeleteRect(rctB);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (rctA->left == rctB->right || rctB->left == rctA->right) {
|
||||
RECTF newrect[5];
|
||||
|
||||
#if defined(WHOA_RECT_USES_SCREEN_COORDINATES)
|
||||
if (rctA->top < rctB->bottom && rctB->top < rctA->bottom) {
|
||||
newrect[0] = { rctA->left, rctA->top, rctA->right, rctB->top };
|
||||
newrect[1] = { rctB->left, rctB->top, rctB->right, rctA->top };
|
||||
newrect[2] = { rctA->left, rctB->bottom, rctA->right, rctA->bottom };
|
||||
newrect[3] = { rctB->left, rctA->bottom, rctB->right, rctB->bottom };
|
||||
|
||||
newrect[4] = {
|
||||
std::min(rctB->left, rctA->left),
|
||||
std::max(rctB->top, rctA->top),
|
||||
std::max(rctB->right, rctA->right),
|
||||
std::min(rctB->bottom, rctA->bottom)
|
||||
};
|
||||
#else
|
||||
if (rctA->bottom < rctB->top && rctB->bottom < rctA->top) {
|
||||
newrect[0] = { rctA->left, rctA->bottom, rctA->right, rctB->bottom };
|
||||
newrect[1] = { rctB->left, rctB->bottom, rctB->right, rctA->bottom };
|
||||
newrect[2] = { rctA->left, rctB->top, rctA->right, rctA->top };
|
||||
newrect[3] = { rctB->left, rctA->top, rctB->right, rctB->top };
|
||||
|
||||
newrect[4] = {
|
||||
std::min(rctB->left, rctA->left),
|
||||
std::max(rctB->bottom, rctA->bottom),
|
||||
std::max(rctB->right, rctA->right),
|
||||
std::min(rctB->top, rctA->top)
|
||||
};
|
||||
#endif
|
||||
|
||||
for (uint32_t k = 0; k < 5; k++) {
|
||||
if (!IsNullRect(&newrect[k])) {
|
||||
AddCombinedRect(combinedArray, &newrect[k]);
|
||||
}
|
||||
}
|
||||
DeleteCombinedRect(combinedArray, i);
|
||||
DeleteCombinedRect(combinedArray, j);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int32_t CompareRects(const RECTF* rect1, const RECTF* rect2) {
|
||||
|
|
@ -30,6 +122,10 @@ int32_t CompareRects(const RECTF* rect1, const RECTF* rect2) {
|
|||
&& rect1->top == rect2->top;
|
||||
}
|
||||
|
||||
void DeleteCombinedRect(TSGrowableArray<RECTF>* combinedArray, uint32_t index) {
|
||||
DeleteRect(&(*combinedArray)[index]);
|
||||
}
|
||||
|
||||
void DeleteRect(RECTF* rect) {
|
||||
rect->left = std::numeric_limits<float>::max();
|
||||
rect->bottom = std::numeric_limits<float>::max();
|
||||
|
|
@ -37,37 +133,249 @@ void DeleteRect(RECTF* rect) {
|
|||
rect->top = std::numeric_limits<float>::max();
|
||||
}
|
||||
|
||||
void FragmentSourceRectangles(TSGrowableArray<SOURCE>* 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, 0x1 | (previousOverlap ? 0x2 : 0x0));
|
||||
int SortFoundParamsCallback(const void* elem1, const void* elem2) {
|
||||
const FOUNDPARAM* param1 = static_cast<const FOUNDPARAM*>(elem1);
|
||||
const FOUNDPARAM* param2 = static_cast<const FOUNDPARAM*>(elem2);
|
||||
|
||||
return param1->sequence - param2->sequence;
|
||||
}
|
||||
|
||||
void FindSourceParams(RGN* rgnptr, const RECTF* rect) {
|
||||
if (CompareRects(rect, &rgnptr->foundparamsrect)) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto overlapsExisting = previousOverlap;
|
||||
rgnptr->foundparams.SetCount(0);
|
||||
uint32_t sourceRects = rgnptr->source.Count();
|
||||
uint32_t params = 0;
|
||||
|
||||
for (uint32_t i = firstIndex; i < lastIndex; i++) {
|
||||
auto source = &(*sourceArray)[i];
|
||||
|
||||
if (CheckForIntersection(rect, &source->rect)) {
|
||||
if (!CompareRects(rect, &source->rect)) {
|
||||
break;
|
||||
}
|
||||
|
||||
source->flags |= 0x2;
|
||||
overlapsExisting = 1;
|
||||
for (uint32_t i = 0; i < sourceRects; i++) {
|
||||
if (!CheckForIntersection(rect, &rgnptr->source[i].rect)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (i + 1 == lastIndex) {
|
||||
AddSourceRect(sourceArray, rect, param, sequence, 0x1 | (previousOverlap ? 0x2 : 0x0));
|
||||
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<RECTF>* combinedArray, uint32_t firstIndex, uint32_t lastIndex, const RECTF* rect) {
|
||||
uint32_t index;
|
||||
RECTF* checkRect;
|
||||
|
||||
for (index = firstIndex; index < lastIndex; index++) {
|
||||
checkRect = &(*combinedArray)[index];
|
||||
if (CheckForIntersection(rect, checkRect)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (index >= lastIndex) {
|
||||
AddCombinedRect(combinedArray, rect);
|
||||
return;
|
||||
}
|
||||
|
||||
RECTF newrect[4];
|
||||
|
||||
#if defined(WHOA_RECT_USES_SCREEN_COORDINATES)
|
||||
newrect[0] = { rect->left, rect->top, rect->right, checkRect->top };
|
||||
newrect[1] = { rect->left, checkRect->bottom, rect->right, rect->bottom };
|
||||
newrect[2] = {
|
||||
rect->left,
|
||||
std::max(checkRect->top, rect->top),
|
||||
checkRect->left,
|
||||
std::min(checkRect->bottom, rect->bottom)
|
||||
};
|
||||
newrect[3] = {
|
||||
checkRect->right,
|
||||
std::max(checkRect->top, rect->top),
|
||||
rect->right,
|
||||
std::min(checkRect->bottom, rect->bottom)
|
||||
};
|
||||
#else
|
||||
newrect[0] = { rect->left, rect->bottom, rect->right, checkRect->bottom };
|
||||
newrect[1] = { rect->left, checkRect->top, rect->right, rect->top };
|
||||
newrect[2] = {
|
||||
rect->left,
|
||||
std::max(checkRect->bottom, rect->bottom),
|
||||
checkRect->left,
|
||||
std::min(checkRect->top, rect->top)
|
||||
};
|
||||
newrect[3] = {
|
||||
checkRect->right,
|
||||
std::max(checkRect->bottom, rect->bottom),
|
||||
rect->right,
|
||||
std::min(checkRect->top, rect->top)
|
||||
};
|
||||
#endif
|
||||
|
||||
for (uint32_t i = 0; i < 4; i++) {
|
||||
if (!IsNullRect(&newrect[i])) {
|
||||
FragmentCombinedRectangles(combinedArray, index + 1, lastIndex, &newrect[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void FragmentSourceRectangles(TSGrowableArray<SOURCE>* sourceArray, uint32_t firstIndex, uint32_t lastIndex, int32_t previousOverlap, const RECTF* rect, void* param, int32_t sequence) {
|
||||
auto overlapsExisting = previousOverlap;
|
||||
|
||||
for (uint32_t index = firstIndex; index < lastIndex; index++) {
|
||||
RECTF* checkRect = &(*sourceArray)[index].rect;
|
||||
|
||||
if (CheckForIntersection(rect, checkRect)) {
|
||||
if (CompareRects(rect, checkRect)) {
|
||||
(*sourceArray)[index].flags |= SF_OVERLAPS;
|
||||
overlapsExisting = 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
const RECTF* overlapRect[2] = { rect, checkRect };
|
||||
|
||||
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];
|
||||
|
||||
#if defined(WHOA_RECT_USES_SCREEN_COORDINATES)
|
||||
newRect[0] = {
|
||||
overlapRect[minTop]->left,
|
||||
overlapRect[minTop]->top,
|
||||
overlapRect[minTop]->right,
|
||||
overlapRect[maxTop]->top,
|
||||
};
|
||||
|
||||
newRect[1] = {
|
||||
overlapRect[maxBottom]->left,
|
||||
overlapRect[minBottom]->bottom,
|
||||
overlapRect[maxBottom]->right,
|
||||
overlapRect[maxBottom]->bottom,
|
||||
};
|
||||
|
||||
newRect[2] = {
|
||||
overlapRect[minLeft]->left,
|
||||
overlapRect[maxTop]->top,
|
||||
overlapRect[maxLeft]->left,
|
||||
overlapRect[minBottom]->bottom,
|
||||
};
|
||||
|
||||
newRect[3] = {
|
||||
overlapRect[minRight]->right,
|
||||
overlapRect[maxTop]->top,
|
||||
overlapRect[maxRight]->right,
|
||||
overlapRect[minBottom]->bottom,
|
||||
};
|
||||
|
||||
newRect[4] = {
|
||||
overlapRect[maxLeft]->left,
|
||||
overlapRect[maxTop]->top,
|
||||
overlapRect[minRight]->right,
|
||||
overlapRect[minBottom]->bottom,
|
||||
};
|
||||
#else
|
||||
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,
|
||||
};
|
||||
#endif
|
||||
|
||||
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(RECTF* rect) {
|
||||
int32_t IsNullRect(const RECTF* rect) {
|
||||
#if defined(WHOA_RECT_USES_SCREEN_COORDINATES)
|
||||
return rect->left >= rect->right || rect->top >= rect->bottom;
|
||||
#else
|
||||
return rect->left >= rect->right || rect->bottom >= rect->top;
|
||||
#endif
|
||||
}
|
||||
|
||||
void ClearRegion(RGN* rgn) {
|
||||
|
|
@ -92,24 +400,24 @@ void DeleteSourceRect(TSGrowableArray<SOURCE>* sourceArray, uint32_t index) {
|
|||
DeleteRect(&source->rect);
|
||||
source->param = nullptr;
|
||||
source->sequence = -1;
|
||||
source->flags = 0x0;
|
||||
source->flags = SF_NONE;
|
||||
}
|
||||
|
||||
void OptimizeSource(TSGrowableArray<SOURCE>* 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++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -117,81 +425,142 @@ void ProcessBooleanOperation(TSGrowableArray<SOURCE>* sourceArray, int32_t combi
|
|||
for (uint32_t i = 0; i < sourceArray->Count(); i++) {
|
||||
auto source = &(*sourceArray)[i];
|
||||
|
||||
int32_t remove = 0;
|
||||
switch (combineMode) {
|
||||
case 1: {
|
||||
if ((~source->flags >> 1) & 0x1) {
|
||||
DeleteSourceRect(sourceArray, i);
|
||||
}
|
||||
|
||||
case SRGN_AND:
|
||||
remove = !(source->flags & SF_OVERLAPS);
|
||||
break;
|
||||
case SRGN_XOR:
|
||||
remove = source->flags & SF_OVERLAPS;
|
||||
break;
|
||||
case SRGN_DIFF:
|
||||
remove = source->flags & (SF_ADDING | SF_OVERLAPS);
|
||||
break;
|
||||
case SRGN_COPY:
|
||||
remove = source->flags & SF_ADDING;
|
||||
break;
|
||||
}
|
||||
|
||||
case 3: {
|
||||
if (source->flags & 0x2) {
|
||||
DeleteSourceRect(sourceArray, i);
|
||||
}
|
||||
|
||||
break;
|
||||
if (remove) {
|
||||
DeleteSourceRect(sourceArray, i);
|
||||
}
|
||||
|
||||
case 4: {
|
||||
if (source->flags & (0x1 | 0x2)) {
|
||||
DeleteSourceRect(sourceArray, i);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case 5: {
|
||||
if (source->flags & 0x1) {
|
||||
DeleteSourceRect(sourceArray, i);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
source->flags = 0x0;
|
||||
source->flags = SF_NONE;
|
||||
}
|
||||
}
|
||||
|
||||
void SRgnCombineRectf(HSRGN handle, RECTF* rect, void* param, int32_t combineMode) {
|
||||
STORM_ASSERT(handle);
|
||||
STORM_ASSERT(rect);
|
||||
STORM_ASSERT(combineMode >= 1);
|
||||
STORM_ASSERT(combineMode <= 6);
|
||||
int SortRectCallback(const void* elem1, const void* elem2) {
|
||||
const RECTF* rct1 = static_cast<const RECTF*>(elem1);
|
||||
const RECTF* rct2 = static_cast<const RECTF*>(elem2);
|
||||
|
||||
#if defined(WHOA_RECT_USES_SCREEN_COORDINATES)
|
||||
double result = rct1->bottom == rct2->bottom ? rct1->left - rct2->left : rct1->bottom - rct2->bottom;
|
||||
#else
|
||||
double result = rct1->top == rct2->top ? rct1->left - rct2->left : rct1->top - rct2->top;
|
||||
#endif
|
||||
|
||||
if (result > 0.0) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (result < 0.0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ProduceCombinedRectangles(RGN* rgn) {
|
||||
rgn->combined.SetCount(0);
|
||||
|
||||
uint32_t sourcerects = rgn->source.Count();
|
||||
SOURCE* sourcearray = rgn->source.Ptr();
|
||||
for (uint32_t i = 0; i < sourcerects; i++) {
|
||||
if (!(sourcearray[i].flags & SF_PARAMONLY)) {
|
||||
FragmentCombinedRectangles(&rgn->combined, 0, rgn->combined.Count(), &sourcearray[i].rect);
|
||||
}
|
||||
}
|
||||
|
||||
CombineRectangles(&rgn->combined);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
rgn->combined.SetCount(i - 1);
|
||||
}
|
||||
}
|
||||
|
||||
void STORMAPI SRgnCombineRectf(HSRGN handle, const RECTF* rect, void* param, int32_t combineMode) {
|
||||
STORM_VALIDATE_BEGIN;
|
||||
STORM_VALIDATE(handle);
|
||||
STORM_VALIDATE(rect);
|
||||
STORM_VALIDATE(combineMode >= 1);
|
||||
STORM_VALIDATE(combineMode <= 6);
|
||||
STORM_VALIDATE_END_VOID;
|
||||
|
||||
HLOCKEDRGN lockedHandle;
|
||||
auto rgn = s_rgntable.Lock(handle, &lockedHandle, 0);
|
||||
if (!rgn) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (combineMode == SRGN_OR || combineMode == SRGN_PARAMONLY) {
|
||||
if (!IsNullRect(rect)) {
|
||||
rgn->sequence++;
|
||||
AddSourceRect(&rgn->source, rect, param, rgn->sequence, combineMode == SRGN_PARAMONLY ? SF_PARAMONLY : SF_NONE);
|
||||
}
|
||||
} else {
|
||||
if (!IsNullRect(rect)) {
|
||||
rgn->sequence++;
|
||||
FragmentSourceRectangles(&rgn->source, 0, rgn->source.Count(), 0, rect, param, rgn->sequence);
|
||||
}
|
||||
|
||||
ProcessBooleanOperation(&rgn->source, combineMode);
|
||||
OptimizeSource(&rgn->source);
|
||||
}
|
||||
|
||||
InvalidateRegion(rgn);
|
||||
s_rgntable.Unlock(lockedHandle);
|
||||
}
|
||||
|
||||
void STORMAPI SRgnCombineRecti(HSRGN handle, const RECT* rect, void* param, int32_t combineMode) {
|
||||
STORM_VALIDATE_BEGIN;
|
||||
STORM_VALIDATE(rect);
|
||||
STORM_VALIDATE_END_VOID;
|
||||
|
||||
// NOTE: top and bottom get flipped, this is a bug in Storm
|
||||
RECTF rectf = {
|
||||
static_cast<float>(rect->left),
|
||||
static_cast<float>(rect->top),
|
||||
static_cast<float>(rect->right),
|
||||
static_cast<float>(rect->bottom)
|
||||
};
|
||||
SRgnCombineRectf(handle, &rectf, param, combineMode);
|
||||
}
|
||||
|
||||
void STORMAPI SRgnClear(HSRGN handle) {
|
||||
STORM_VALIDATE_BEGIN;
|
||||
STORM_VALIDATE(handle);
|
||||
STORM_VALIDATE_END_VOID;
|
||||
|
||||
HLOCKEDRGN lockedHandle;
|
||||
auto rgn = s_rgntable.Lock(handle, &lockedHandle, 0);
|
||||
|
||||
if (rgn) {
|
||||
if (combineMode == 2 || combineMode == 6) {
|
||||
if (!IsNullRect(rect)) {
|
||||
rgn->sequence++;
|
||||
AddSourceRect(&rgn->source, rect, param, rgn->sequence, combineMode == 6 ? 0x10000 : 0x0);
|
||||
}
|
||||
} else {
|
||||
if (!IsNullRect(rect)) {
|
||||
rgn->sequence++;
|
||||
FragmentSourceRectangles(&rgn->source, 0, rgn->source.Count(), 0, rect, param, rgn->sequence);
|
||||
}
|
||||
|
||||
ProcessBooleanOperation(&rgn->source, combineMode);
|
||||
OptimizeSource(&rgn->source);
|
||||
}
|
||||
|
||||
InvalidateRegion(rgn);
|
||||
ClearRegion(rgn);
|
||||
s_rgntable.Unlock(lockedHandle);
|
||||
}
|
||||
|
||||
s_rgntable.Unlock(lockedHandle);
|
||||
}
|
||||
|
||||
void SRgnCreate(HSRGN* handlePtr, uint32_t reserved) {
|
||||
STORM_ASSERT(handlePtr);
|
||||
STORM_ASSERT(!reserved);
|
||||
void STORMAPI SRgnCreate(HSRGN* handlePtr, uint32_t reserved) {
|
||||
STORM_VALIDATE_BEGIN;
|
||||
STORM_VALIDATE(handlePtr);
|
||||
STORM_VALIDATE(!reserved);
|
||||
STORM_VALIDATE_END_VOID;
|
||||
|
||||
HLOCKEDRGN lockedHandle = nullptr;
|
||||
auto rgn = s_rgntable.NewLock(handlePtr, &lockedHandle);
|
||||
|
|
@ -201,37 +570,81 @@ void SRgnCreate(HSRGN* handlePtr, uint32_t reserved) {
|
|||
s_rgntable.Unlock(lockedHandle);
|
||||
}
|
||||
|
||||
void SRgnDelete(HSRGN handle) {
|
||||
STORM_ASSERT(handle);
|
||||
void STORMAPI SRgnDelete(HSRGN handle) {
|
||||
STORM_VALIDATE_BEGIN;
|
||||
STORM_VALIDATE(handle);
|
||||
STORM_VALIDATE_END_VOID;
|
||||
|
||||
s_rgntable.Delete(handle);
|
||||
}
|
||||
|
||||
void SRgnGetBoundingRectf(HSRGN handle, RECTF* rect) {
|
||||
STORM_ASSERT(handle);
|
||||
STORM_ASSERT(rect);
|
||||
void STORMAPI SRgnDestroy() {
|
||||
s_rgntable.Destroy();
|
||||
}
|
||||
|
||||
rect->left = std::numeric_limits<float>::max();
|
||||
rect->bottom = std::numeric_limits<float>::max();
|
||||
rect->right = std::numeric_limits<float>::min();
|
||||
rect->top = std::numeric_limits<float>::min();
|
||||
void STORMAPI SRgnDuplicate(HSRGN origHandle, HSRGN* handle, uint32_t reserved) {
|
||||
STORM_VALIDATE_BEGIN;
|
||||
STORM_VALIDATE(handle);
|
||||
*handle = nullptr;
|
||||
|
||||
STORM_VALIDATE(origHandle);
|
||||
STORM_VALIDATE(reserved == 0);
|
||||
STORM_VALIDATE_END_VOID;
|
||||
|
||||
HLOCKEDRGN origlockedhandle;
|
||||
auto rgn = s_rgntable.Lock(origHandle, &origlockedhandle, 0);
|
||||
|
||||
if (!rgn) {
|
||||
return;
|
||||
}
|
||||
|
||||
#if defined(WHOA_STORM_C_CRIT_SECT_RECURSIVE)
|
||||
HLOCKEDRGN newlockedhandle;
|
||||
|
||||
auto newrgn = s_rgntable.NewLock(handle, &newlockedhandle);
|
||||
*newrgn = *rgn;
|
||||
s_rgntable.Unlock(newlockedhandle);
|
||||
#else
|
||||
auto newrgn = s_rgntable.New(handle);
|
||||
*newrgn = *rgn;
|
||||
#endif
|
||||
|
||||
s_rgntable.Unlock(origlockedhandle);
|
||||
}
|
||||
|
||||
void STORMAPI SRgnGetBoundingRectf(HSRGN handle, RECTF* rect) {
|
||||
STORM_VALIDATE_BEGIN;
|
||||
STORM_VALIDATE(handle);
|
||||
STORM_VALIDATE(rect);
|
||||
STORM_VALIDATE_END_VOID;
|
||||
|
||||
*rect = {
|
||||
std::numeric_limits<float>::max(),
|
||||
std::numeric_limits<float>::max(),
|
||||
std::numeric_limits<float>::min(),
|
||||
std::numeric_limits<float>::min(),
|
||||
};
|
||||
|
||||
HLOCKEDRGN lockedHandle;
|
||||
auto rgn = s_rgntable.Lock(handle, &lockedHandle, 0);
|
||||
|
||||
if (!rgn) {
|
||||
s_rgntable.Unlock(lockedHandle);
|
||||
return;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < rgn->source.Count(); i++) {
|
||||
auto source = &rgn->source[i];
|
||||
|
||||
if (!(source->flags & 0x10000)) {
|
||||
if (!(source->flags & SF_PARAMONLY)) {
|
||||
rect->left = std::min(source->rect.left, rect->left);
|
||||
rect->bottom = std::min(source->rect.bottom, rect->bottom);
|
||||
rect->right = std::max(source->rect.right, rect->right);
|
||||
|
||||
#if defined(WHOA_RECT_USES_SCREEN_COORDINATES)
|
||||
rect->top = std::min(source->rect.top, rect->top);
|
||||
rect->bottom = std::max(source->rect.bottom, rect->bottom);
|
||||
#else
|
||||
rect->bottom = std::min(source->rect.bottom, rect->bottom);
|
||||
rect->top = std::max(source->rect.top, rect->top);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -244,3 +657,239 @@ void SRgnGetBoundingRectf(HSRGN handle, RECTF* rect) {
|
|||
rect->top = 0.0f;
|
||||
}
|
||||
}
|
||||
|
||||
void STORMAPI SRgnGetBoundingRecti(HSRGN handle, RECT* rect) {
|
||||
STORM_VALIDATE_BEGIN;
|
||||
STORM_VALIDATE(rect);
|
||||
STORM_VALIDATE_END_VOID;
|
||||
|
||||
RECTF rectf;
|
||||
SRgnGetBoundingRectf(handle, &rectf);
|
||||
|
||||
rect->left = static_cast<int32_t>(rectf.left);
|
||||
rect->right = static_cast<int32_t>(rectf.right);
|
||||
#if defined(WHOA_RECT_USES_SCREEN_COORDINATES)
|
||||
rect->top = static_cast<int32_t>(rectf.top);
|
||||
rect->bottom = static_cast<int32_t>(rectf.bottom);
|
||||
#else
|
||||
// NOTE: top and bottom get flipped, this is a bug in Storm
|
||||
rect->top = static_cast<int32_t>(rectf.bottom);
|
||||
rect->bottom = static_cast<int32_t>(rectf.top);
|
||||
#endif
|
||||
}
|
||||
|
||||
void STORMAPI SRgnGetRectParamsf(HSRGN handle, const RECTF* rect, uint32_t* numParams, void** buffer) {
|
||||
STORM_VALIDATE_BEGIN;
|
||||
STORM_VALIDATE(handle);
|
||||
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 STORMAPI SRgnGetRectParamsi(HSRGN handle, const RECT* rect, uint32_t* numParams, void** buffer) {
|
||||
STORM_VALIDATE_BEGIN;
|
||||
STORM_VALIDATE(rect);
|
||||
STORM_VALIDATE_END_VOID;
|
||||
|
||||
// NOTE: top and bottom get flipped, this is a bug in Storm
|
||||
RECTF rectf = {
|
||||
static_cast<float>(rect->left),
|
||||
static_cast<float>(rect->top),
|
||||
static_cast<float>(rect->right),
|
||||
static_cast<float>(rect->bottom)
|
||||
};
|
||||
SRgnGetRectParamsf(handle, &rectf, numParams, buffer);
|
||||
}
|
||||
|
||||
void STORMAPI 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;
|
||||
return;
|
||||
}
|
||||
|
||||
if (rgn->dirty) {
|
||||
ProduceCombinedRectangles(rgn);
|
||||
rgn->dirty = 0;
|
||||
}
|
||||
|
||||
if (buffer) {
|
||||
*numRects = std::min(*numRects, rgn->combined.Count());
|
||||
memcpy(buffer, rgn->combined.Ptr(), sizeof(rgn->combined.Ptr()[0]) * *numRects);
|
||||
}
|
||||
else {
|
||||
*numRects = rgn->combined.Count();
|
||||
}
|
||||
|
||||
s_rgntable.Unlock(lockedHandle);
|
||||
}
|
||||
|
||||
void STORMAPI SRgnGetRectsi(HSRGN handle, uint32_t* numRects, RECT* buffer) {
|
||||
RECTF* bufferf = reinterpret_cast<RECTF*>(buffer);
|
||||
SRgnGetRectsf(handle, numRects, bufferf);
|
||||
if (buffer) {
|
||||
for (uint32_t i = 0; i < *numRects; i++) {
|
||||
#if defined(WHOA_RECT_USES_SCREEN_COORDINATES)
|
||||
buffer[i].top = static_cast<int32_t>(bufferf[i].top);
|
||||
buffer[i].bottom = static_cast<int32_t>(bufferf[i].bottom);
|
||||
#else
|
||||
float bottom = bufferf[i].bottom;
|
||||
float top = bufferf[i].top;
|
||||
|
||||
buffer[i].bottom = static_cast<int32_t>(bottom);
|
||||
buffer[i].top = static_cast<int32_t>(top);
|
||||
#endif
|
||||
buffer[i].left = static_cast<int32_t>(bufferf[i].left);
|
||||
buffer[i].right = static_cast<int32_t>(bufferf[i].right);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int32_t STORMAPI 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 defined(WHOA_RECT_USES_SCREEN_COORDINATES)
|
||||
if (x >= sourceArray[i].rect.left && y >= sourceArray[i].rect.top &&
|
||||
x < sourceArray[i].rect.right && y < sourceArray[i].rect.bottom) {
|
||||
#else
|
||||
if (x >= sourceArray[i].rect.left && y >= sourceArray[i].rect.bottom &&
|
||||
x < sourceArray[i].rect.right && y < sourceArray[i].rect.top) {
|
||||
#endif
|
||||
result = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
s_rgntable.Unlock(lockedHandle);
|
||||
return result;
|
||||
}
|
||||
|
||||
int32_t STORMAPI SRgnIsPointInRegioni(HSRGN handle, int32_t x, int32_t y) {
|
||||
return SRgnIsPointInRegionf(handle, static_cast<float>(x), static_cast<float>(y));
|
||||
}
|
||||
|
||||
int32_t STORMAPI SRgnIsRectInRegionf(HSRGN handle, const RECTF* rect) {
|
||||
STORM_VALIDATE_BEGIN;
|
||||
STORM_VALIDATE(handle);
|
||||
STORM_VALIDATE(rect);
|
||||
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 (CheckForIntersection(rect, &sourceArray[i].rect)) {
|
||||
result = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
s_rgntable.Unlock(lockedHandle);
|
||||
return result;
|
||||
}
|
||||
|
||||
int32_t STORMAPI SRgnIsRectInRegioni(HSRGN handle, const RECT* rect) {
|
||||
STORM_VALIDATE_BEGIN;
|
||||
STORM_VALIDATE(rect);
|
||||
STORM_VALIDATE_END;
|
||||
|
||||
// NOTE: top and bottom get flipped, this is a bug in Storm
|
||||
RECTF rectf = {
|
||||
static_cast<float>(rect->left),
|
||||
static_cast<float>(rect->top),
|
||||
static_cast<float>(rect->right),
|
||||
static_cast<float>(rect->bottom)
|
||||
};
|
||||
return SRgnIsRectInRegionf(handle, &rectf);
|
||||
}
|
||||
|
||||
void STORMAPI SRgnOffsetf(HSRGN handle, float xoffset, float yoffset) {
|
||||
STORM_VALIDATE_BEGIN;
|
||||
STORM_VALIDATE(handle);
|
||||
STORM_VALIDATE_END_VOID;
|
||||
|
||||
HLOCKEDRGN lockedHandle;
|
||||
auto rgn = s_rgntable.Lock(handle, &lockedHandle, 0);
|
||||
if (!rgn) {
|
||||
return;
|
||||
}
|
||||
|
||||
SOURCE* sourceArray = rgn->source.Ptr();
|
||||
uint32_t sourceRects = rgn->source.Count();
|
||||
for (uint32_t i = 0; i < sourceRects; i++) {
|
||||
sourceArray[i].rect.left += xoffset;
|
||||
sourceArray[i].rect.bottom += yoffset;
|
||||
sourceArray[i].rect.right += xoffset;
|
||||
sourceArray[i].rect.top += yoffset;
|
||||
}
|
||||
InvalidateRegion(rgn);
|
||||
|
||||
s_rgntable.Unlock(lockedHandle);
|
||||
}
|
||||
|
||||
void STORMAPI SRgnOffseti(HSRGN handle, int32_t xoffset, int32_t yoffset) {
|
||||
SRgnOffsetf(handle, static_cast<float>(xoffset), static_cast<float>(yoffset));
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue