mirror of
https://github.com/OpenRCT2/OpenRCT2
synced 2026-01-29 17:54:50 +01:00
Rewrite sprite-cursor interaction code (#22239)
This commit is contained in:
@@ -48,11 +48,11 @@
|
||||
|
||||
using namespace OpenRCT2;
|
||||
|
||||
enum : uint32_t
|
||||
enum : uint8_t
|
||||
{
|
||||
IMAGE_TYPE_DEFAULT = 0,
|
||||
IMAGE_TYPE_REMAP = (1 << 29),
|
||||
IMAGE_TYPE_TRANSPARENT = (1 << 30),
|
||||
IMAGE_TYPE_REMAP = (1 << 1),
|
||||
IMAGE_TYPE_TRANSPARENT = (1 << 2),
|
||||
};
|
||||
|
||||
uint8_t gShowGridLinesRefCount;
|
||||
@@ -65,7 +65,6 @@ Viewport* g_music_tracking_viewport;
|
||||
static std::unique_ptr<JobPool> _paintJobs;
|
||||
static std::vector<PaintSession*> _paintColumns;
|
||||
|
||||
static uint32_t _currentImageType;
|
||||
InteractionInfo::InteractionInfo(const PaintStruct* ps)
|
||||
: Loc(ps->MapPos)
|
||||
, Element(ps->Element)
|
||||
@@ -1573,9 +1572,10 @@ static bool PSSpriteTypeIsInFilter(PaintStruct* ps, uint16_t filter)
|
||||
/**
|
||||
* rct2: 0x00679236, 0x00679662, 0x00679B0D, 0x00679FF1
|
||||
*/
|
||||
static bool IsPixelPresentBMP(uint32_t imageType, const G1Element* g1, const uint8_t* index, const PaletteMap& paletteMap)
|
||||
static bool IsPixelPresentBMP(
|
||||
const uint32_t imageType, const G1Element* g1, const int32_t x, const int32_t y, const PaletteMap& paletteMap)
|
||||
{
|
||||
PROFILED_FUNCTION();
|
||||
uint8_t* index = g1->offset + (y * g1->width) + x;
|
||||
|
||||
// Needs investigation as it has no consideration for pure BMP maps.
|
||||
if (!(g1->flags & G1_FLAG_HAS_TRANSPARENCY))
|
||||
@@ -1599,102 +1599,32 @@ static bool IsPixelPresentBMP(uint32_t imageType, const G1Element* g1, const uin
|
||||
/**
|
||||
* rct2: 0x0067933B, 0x00679788, 0x00679C4A, 0x0067A117
|
||||
*/
|
||||
static bool IsPixelPresentRLE(const uint8_t* esi, int32_t x_start_point, int32_t y_start_point, int32_t round)
|
||||
static bool IsPixelPresentRLE(const void* data, const int32_t x, const int32_t y)
|
||||
{
|
||||
PROFILED_FUNCTION();
|
||||
const uint16_t* data16 = static_cast<const uint16_t*>(data);
|
||||
uint16_t startOffset = data16[y];
|
||||
const uint8_t* data8 = static_cast<const uint8_t*>(data) + startOffset;
|
||||
|
||||
uint32_t start_offset = esi[y_start_point * 2] | (esi[y_start_point * 2 + 1] << 8);
|
||||
const uint8_t* ebx = esi + start_offset;
|
||||
|
||||
uint8_t last_data_line = 0;
|
||||
while (!last_data_line)
|
||||
bool lastDataLine = false;
|
||||
while (!lastDataLine)
|
||||
{
|
||||
int32_t no_pixels = *ebx++;
|
||||
uint8_t gap_size = *ebx++;
|
||||
int32_t numPixels = *data8++;
|
||||
uint8_t pixelRunStart = *data8++;
|
||||
lastDataLine = numPixels & 0x80;
|
||||
numPixels &= 0x7F;
|
||||
data8 += numPixels;
|
||||
|
||||
last_data_line = no_pixels & 0x80;
|
||||
|
||||
no_pixels &= 0x7F;
|
||||
|
||||
ebx += no_pixels;
|
||||
|
||||
if (round > 1)
|
||||
{
|
||||
if (gap_size % 2)
|
||||
{
|
||||
gap_size++;
|
||||
no_pixels--;
|
||||
if (no_pixels == 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (round == 4)
|
||||
{
|
||||
if (gap_size % 4)
|
||||
{
|
||||
gap_size += 2;
|
||||
no_pixels -= 2;
|
||||
if (no_pixels <= 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int32_t x_start = gap_size - x_start_point;
|
||||
if (x_start <= 0)
|
||||
{
|
||||
no_pixels += x_start;
|
||||
if (no_pixels <= 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
x_start = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Do nothing?
|
||||
}
|
||||
|
||||
x_start += no_pixels;
|
||||
x_start--;
|
||||
if (x_start > 0)
|
||||
{
|
||||
no_pixels -= x_start;
|
||||
if (no_pixels <= 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (round > 1)
|
||||
{
|
||||
// This matches the original implementation, but allows empty lines to cause false positives on zoom 0
|
||||
if (Ceil2(no_pixels, round) == 0)
|
||||
continue;
|
||||
}
|
||||
|
||||
return true;
|
||||
if (pixelRunStart <= x && x < pixelRunStart + numPixels)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* rct2: 0x00679074
|
||||
*
|
||||
* @param dpi (edi)
|
||||
* @param imageId (ebx)
|
||||
* @param x (cx)
|
||||
* @param y (dx)
|
||||
* @return value originally stored in 0x00141F569
|
||||
*/
|
||||
static bool IsSpriteInteractedWithPaletteSet(
|
||||
DrawPixelInfo& dpi, ImageId imageId, const ScreenCoordsXY& coords, const PaletteMap& paletteMap)
|
||||
DrawPixelInfo& dpi, ImageId imageId, const ScreenCoordsXY& coords, const PaletteMap& paletteMap, const uint8_t imageType)
|
||||
{
|
||||
PROFILED_FUNCTION();
|
||||
|
||||
@@ -1704,6 +1634,10 @@ static bool IsSpriteInteractedWithPaletteSet(
|
||||
return false;
|
||||
}
|
||||
|
||||
ZoomLevel zoomLevel = dpi.zoom_level;
|
||||
ScreenCoordsXY interactionPoint{ dpi.x, dpi.y };
|
||||
ScreenCoordsXY origin = coords;
|
||||
|
||||
if (dpi.zoom_level > ZoomLevel{ 0 })
|
||||
{
|
||||
if (g1->flags & G1_FLAG_NO_ZOOM_DRAW)
|
||||
@@ -1711,124 +1645,39 @@ static bool IsSpriteInteractedWithPaletteSet(
|
||||
return false;
|
||||
}
|
||||
|
||||
if (g1->flags & G1_FLAG_HAS_ZOOM_SPRITE)
|
||||
while (g1->flags & G1_FLAG_HAS_ZOOM_SPRITE && zoomLevel > ZoomLevel{ 0 })
|
||||
{
|
||||
// TODO: SAR in dpi done with `>> 1`, in coordinates with `/ 2`
|
||||
DrawPixelInfo zoomed_dpi = {
|
||||
.bits = dpi.bits,
|
||||
.x = dpi.x >> 1,
|
||||
.y = dpi.y >> 1,
|
||||
.width = dpi.width,
|
||||
.height = dpi.height,
|
||||
.pitch = dpi.pitch,
|
||||
.zoom_level = dpi.zoom_level - 1,
|
||||
};
|
||||
|
||||
auto zoomImageId = imageId.WithIndex(imageId.GetIndex() - g1->zoomed_offset);
|
||||
return IsSpriteInteractedWithPaletteSet(zoomed_dpi, zoomImageId, { coords.x / 2, coords.y / 2 }, paletteMap);
|
||||
}
|
||||
}
|
||||
|
||||
int32_t round = std::max(1, dpi.zoom_level.ApplyTo(1));
|
||||
|
||||
auto origin = coords;
|
||||
if (g1->flags & G1_FLAG_RLE_COMPRESSION)
|
||||
{
|
||||
origin.y -= (round - 1);
|
||||
}
|
||||
|
||||
origin.y += g1->y_offset;
|
||||
int32_t yStartPoint = 0;
|
||||
int32_t height = g1->height;
|
||||
if (dpi.zoom_level != ZoomLevel{ 0 })
|
||||
{
|
||||
if (height % 2)
|
||||
{
|
||||
height--;
|
||||
yStartPoint++;
|
||||
}
|
||||
|
||||
if (dpi.zoom_level == ZoomLevel{ 2 })
|
||||
{
|
||||
if (height % 4)
|
||||
imageId = imageId.WithIndex(imageId.GetIndex() - g1->zoomed_offset);
|
||||
g1 = GfxGetG1Element(imageId);
|
||||
if (g1 == nullptr || g1->flags & G1_FLAG_NO_ZOOM_DRAW)
|
||||
{
|
||||
height -= 2;
|
||||
yStartPoint += 2;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (height == 0)
|
||||
{
|
||||
return false;
|
||||
zoomLevel = zoomLevel - 1;
|
||||
interactionPoint.x >>= 1;
|
||||
interactionPoint.y >>= 1;
|
||||
origin.x >>= 1;
|
||||
origin.y >>= 1;
|
||||
}
|
||||
}
|
||||
|
||||
origin.y = Floor2(origin.y, round);
|
||||
int32_t yEndPoint = height;
|
||||
origin.y -= dpi.y;
|
||||
if (origin.y < 0)
|
||||
{
|
||||
yEndPoint += origin.y;
|
||||
if (yEndPoint <= 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
yStartPoint -= origin.y;
|
||||
origin.y = 0;
|
||||
}
|
||||
|
||||
origin.y += yEndPoint;
|
||||
origin.y--;
|
||||
if (origin.y > 0)
|
||||
{
|
||||
yEndPoint -= origin.y;
|
||||
if (yEndPoint <= 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
int32_t xStartPoint = 0;
|
||||
int32_t xEndPoint = g1->width;
|
||||
|
||||
origin.x += g1->x_offset;
|
||||
origin.x = Floor2(origin.x, round);
|
||||
origin.x -= dpi.x;
|
||||
if (origin.x < 0)
|
||||
{
|
||||
xEndPoint += origin.x;
|
||||
if (xEndPoint <= 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
origin.y += g1->y_offset;
|
||||
interactionPoint -= origin;
|
||||
|
||||
xStartPoint -= origin.x;
|
||||
origin.x = 0;
|
||||
}
|
||||
|
||||
origin.x += xEndPoint;
|
||||
origin.x--;
|
||||
if (origin.x > 0)
|
||||
if (interactionPoint.x < 0 || interactionPoint.y < 0 || interactionPoint.x >= g1->width || interactionPoint.y >= g1->height)
|
||||
{
|
||||
xEndPoint -= origin.x;
|
||||
if (xEndPoint <= 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
if (g1->flags & G1_FLAG_RLE_COMPRESSION)
|
||||
{
|
||||
return IsPixelPresentRLE(g1->offset, xStartPoint, yStartPoint, round);
|
||||
return IsPixelPresentRLE(g1->offset, interactionPoint.x, interactionPoint.y);
|
||||
}
|
||||
|
||||
uint8_t* offset = g1->offset + (yStartPoint * g1->width) + xStartPoint;
|
||||
uint32_t imageType = _currentImageType;
|
||||
|
||||
if (!(g1->flags & G1_FLAG_1))
|
||||
{
|
||||
return IsPixelPresentBMP(imageType, g1, offset, paletteMap);
|
||||
return IsPixelPresentBMP(imageType, g1, interactionPoint.x, interactionPoint.y, paletteMap);
|
||||
}
|
||||
|
||||
Guard::Assert(false, "Invalid image type encountered.");
|
||||
@@ -1845,9 +1694,10 @@ static bool IsSpriteInteractedWith(DrawPixelInfo& dpi, ImageId imageId, const Sc
|
||||
PROFILED_FUNCTION();
|
||||
|
||||
auto paletteMap = PaletteMap::GetDefault();
|
||||
uint8_t imageType;
|
||||
if (imageId.HasPrimary() || imageId.IsRemap())
|
||||
{
|
||||
_currentImageType = IMAGE_TYPE_REMAP;
|
||||
imageType = IMAGE_TYPE_REMAP;
|
||||
uint8_t paletteIndex;
|
||||
if (imageId.HasSecondary())
|
||||
{
|
||||
@@ -1864,9 +1714,9 @@ static bool IsSpriteInteractedWith(DrawPixelInfo& dpi, ImageId imageId, const Sc
|
||||
}
|
||||
else
|
||||
{
|
||||
_currentImageType = IMAGE_TYPE_DEFAULT;
|
||||
imageType = IMAGE_TYPE_DEFAULT;
|
||||
}
|
||||
return IsSpriteInteractedWithPaletteSet(dpi, imageId, coords, paletteMap);
|
||||
return IsSpriteInteractedWithPaletteSet(dpi, imageId, coords, paletteMap, imageType);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user