Implement arrangeStructs (#686)

Heavily based on OpenRCT2 equivalent
This commit is contained in:
Duncan 2021-01-03 07:44:02 +00:00 committed by GitHub
parent e06e013c6b
commit 1e0901f920
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 195 additions and 4 deletions

View File

@ -170,10 +170,194 @@ namespace OpenLoco::Paint
}
}
template<uint8_t>
static bool checkBoundingBox(const PaintStructBoundBox& initialBBox, const PaintStructBoundBox& currentBBox)
{
return false;
}
template<>
bool checkBoundingBox<0>(const PaintStructBoundBox& initialBBox, const PaintStructBoundBox& currentBBox)
{
if (initialBBox.zEnd >= currentBBox.z && initialBBox.yEnd >= currentBBox.y && initialBBox.xEnd >= currentBBox.x
&& !(initialBBox.z < currentBBox.zEnd && initialBBox.y < currentBBox.yEnd && initialBBox.x < currentBBox.xEnd))
{
return true;
}
return false;
}
template<>
bool checkBoundingBox<1>(const PaintStructBoundBox& initialBBox, const PaintStructBoundBox& currentBBox)
{
if (initialBBox.zEnd >= currentBBox.z && initialBBox.yEnd >= currentBBox.y && initialBBox.xEnd < currentBBox.x
&& !(initialBBox.z < currentBBox.zEnd && initialBBox.y < currentBBox.yEnd && initialBBox.x >= currentBBox.xEnd))
{
return true;
}
return false;
}
template<>
bool checkBoundingBox<2>(const PaintStructBoundBox& initialBBox, const PaintStructBoundBox& currentBBox)
{
if (initialBBox.zEnd >= currentBBox.z && initialBBox.yEnd < currentBBox.y && initialBBox.xEnd < currentBBox.x
&& !(initialBBox.z < currentBBox.zEnd && initialBBox.y >= currentBBox.yEnd && initialBBox.x >= currentBBox.xEnd))
{
return true;
}
return false;
}
template<>
bool checkBoundingBox<3>(const PaintStructBoundBox& initialBBox, const PaintStructBoundBox& currentBBox)
{
if (initialBBox.zEnd >= currentBBox.z && initialBBox.yEnd < currentBBox.y && initialBBox.xEnd >= currentBBox.x
&& !(initialBBox.z < currentBBox.zEnd && initialBBox.y >= currentBBox.yEnd && initialBBox.x < currentBBox.xEnd))
{
return true;
}
return false;
}
template<uint8_t _TRotation>
static PaintStruct* arrangeStructsHelperRotation(PaintStruct* psNext, const uint16_t quadrantIndex, const uint8_t flag)
{
PaintStruct* ps = nullptr;
do
{
ps = psNext;
psNext = psNext->nextQuadrantPS;
if (psNext == nullptr)
return ps;
} while (quadrantIndex > psNext->quadrantIndex);
// Cache the last visited node so we don't have to walk the whole list again
auto* psCache = ps;
auto* psTemp = ps;
do
{
ps = ps->nextQuadrantPS;
if (ps == nullptr)
break;
if (ps->quadrantIndex > quadrantIndex + 1)
{
ps->quadrantFlags = QuadrantFlags::bigger;
}
else if (ps->quadrantIndex == quadrantIndex + 1)
{
ps->quadrantFlags = QuadrantFlags::next | QuadrantFlags::identical;
}
else if (ps->quadrantIndex == quadrantIndex)
{
ps->quadrantFlags = flag | QuadrantFlags::identical;
}
} while (ps->quadrantIndex <= quadrantIndex + 1);
ps = psTemp;
while (true)
{
while (true)
{
psNext = ps->nextQuadrantPS;
if (psNext == nullptr)
return psCache;
if (psNext->quadrantFlags & QuadrantFlags::bigger)
return psCache;
if (psNext->quadrantFlags & QuadrantFlags::identical)
break;
ps = psNext;
}
psNext->quadrantFlags &= ~QuadrantFlags::identical;
psTemp = ps;
const PaintStructBoundBox& initialBBox = psNext->bounds;
while (true)
{
ps = psNext;
psNext = psNext->nextQuadrantPS;
if (psNext == nullptr)
break;
if (psNext->quadrantFlags & QuadrantFlags::bigger)
break;
if (!(psNext->quadrantFlags & QuadrantFlags::next))
continue;
const PaintStructBoundBox& currentBBox = psNext->bounds;
const bool compareResult = checkBoundingBox<_TRotation>(initialBBox, currentBBox);
if (compareResult)
{
ps->nextQuadrantPS = psNext->nextQuadrantPS;
PaintStruct* ps_temp2 = psTemp->nextQuadrantPS;
psTemp->nextQuadrantPS = psNext;
psNext->nextQuadrantPS = ps_temp2;
psNext = ps;
}
}
ps = psTemp;
}
}
static PaintStruct* arrangeStructsHelper(PaintStruct* psNext, uint16_t quadrantIndex, uint8_t flag, uint8_t rotation)
{
switch (rotation)
{
case 0:
return arrangeStructsHelperRotation<0>(psNext, quadrantIndex, flag);
case 1:
return arrangeStructsHelperRotation<1>(psNext, quadrantIndex, flag);
case 2:
return arrangeStructsHelperRotation<2>(psNext, quadrantIndex, flag);
case 3:
return arrangeStructsHelperRotation<3>(psNext, quadrantIndex, flag);
}
return nullptr;
}
// 0x0045E7B5
void PaintSession::arrangeStructs()
{
call(0x0045E7B5);
_paintHead = _nextFreePaintStruct;
_nextFreePaintStruct++;
PaintStruct* ps = &(*_paintHead)->basic;
ps->nextQuadrantPS = nullptr;
uint32_t quadrantIndex = _quadrantBackIndex;
if (quadrantIndex == std::numeric_limits<uint32_t>::max())
{
return;
}
do
{
PaintStruct* psNext = _quadrants[quadrantIndex];
if (psNext != nullptr)
{
ps->nextQuadrantPS = psNext;
do
{
ps = psNext;
psNext = psNext->nextQuadrantPS;
} while (psNext != nullptr);
}
} while (++quadrantIndex <= _quadrantFrontIndex);
PaintStruct* psCache = arrangeStructsHelper(
&(*_paintHead)->basic, _quadrantBackIndex & 0xFFFF, QuadrantFlags::next, currentRotation);
quadrantIndex = _quadrantBackIndex;
while (++quadrantIndex < _quadrantFrontIndex)
{
psCache = arrangeStructsHelper(psCache, quadrantIndex & 0xFFFF, 0, currentRotation);
}
}
// 0x0045ED91

View File

@ -68,6 +68,13 @@ namespace OpenLoco::Paint
uint16_t zEnd; // 0x12
};
namespace QuadrantFlags
{
constexpr uint8_t identical = (1 << 0);
constexpr uint8_t bigger = (1 << 7);
constexpr uint8_t next = (1 << 1);
};
struct PaintStruct
{
uint32_t imageId; // 0x00
@ -80,9 +87,9 @@ namespace OpenLoco::Paint
PaintStructBoundBox bounds; // 0x08
int16_t x; // 0x14
int16_t y; // 0x16
uint16_t quadrantIndex;
uint16_t quadrantIndex; // 0x18
uint8_t flags;
uint8_t quadrantFlags;
uint8_t quadrantFlags; // 0x1B
AttachedPaintStruct* attachedPS; // 0x1C
PaintStruct* children;
PaintStruct* nextQuadrantPS; // 0x24
@ -135,6 +142,7 @@ namespace OpenLoco::Paint
inline static Interop::loco_global<uint32_t, 0x00E400C4> _quadrantFrontIndex;
inline static Interop::loco_global<const void*, 0x00E4F0B4> _currentlyDrawnItem;
inline static Interop::loco_global<PaintEntry*, 0x00E0C404> _endOfPaintStructArray;
inline static Interop::loco_global<PaintEntry*, 0x00E0C408> _paintHead;
inline static Interop::loco_global<PaintEntry*, 0x00E0C40C> _nextFreePaintStruct;
inline static Interop::loco_global<coord_t, 0x00E3F090> _spritePositionX;
inline static Interop::loco_global<coord_t, 0x00E3F096> _spritePositionY;
@ -147,7 +155,6 @@ namespace OpenLoco::Paint
uint8_t currentRotation; // new field set from 0x00E3F0B8 but split out into this struct as seperate item
// From OpenRCT2 equivalent fields not found yet or new
//PaintStruct paintHead; // new field
//uint32_t viewFlags; // new field might not be needed tbc
//AttachedPaintStruct* unkF1AD2C; // no equivalent
//support_height supportSegments[9];