1
0
mirror of https://github.com/OpenRCT2/OpenRCT2 synced 2025-12-21 06:43:04 +01:00

Refactor RLE minify

This commit is contained in:
Ted John
2020-06-03 01:46:40 +01:00
parent 1645c64e87
commit f16a46b872

View File

@@ -7,8 +7,6 @@
* OpenRCT2 is licensed under the GNU General Public License version 3. * OpenRCT2 is licensed under the GNU General Public License version 3.
*****************************************************************************/ *****************************************************************************/
#pragma warning(disable : 4127) // conditional expression is constant
#include "Drawing.h" #include "Drawing.h"
#include <cstring> #include <cstring>
@@ -156,127 +154,95 @@ template<DrawBlendOp TBlendOp, size_t TZoom> static void FASTCALL DrawRLESpriteM
} }
} }
template<DrawBlendOp TBlendOp, int32_t zoom_level> static void FASTCALL DrawRLESpriteMinify(DrawSpriteArgs& args) template<DrawBlendOp TBlendOp, size_t TZoom> static void FASTCALL DrawRLESpriteMinify(DrawSpriteArgs& args)
{ {
auto dpi = args.DPI; auto dpi = args.DPI;
auto source_bits_pointer = args.SourceImage.offset; auto src0 = args.SourceImage.offset;
auto dest_bits_pointer = args.DestinationBits; auto dst0 = args.DestinationBits;
auto source_x_start = args.SrcX; auto srcX = args.SrcX;
auto source_y_start = args.SrcY; auto srcY = args.SrcY;
auto width = args.Width; auto width = args.Width;
auto height = args.Height; auto height = args.Height;
[[maybe_unused]] auto& paletteMap = args.PalMap; auto& paletteMap = args.PalMap;
auto zoom = 1 << TZoom;
// The distance between two samples in the source image. auto dstLineWidth = (static_cast<size_t>(dpi->width) >> TZoom) + dpi->pitch;
// We draw the image at 1 / (2^zoom_level) scale.
int32_t zoom_amount = 1 << zoom_level;
// Width of one screen line in the dest buffer
int32_t line_width = (dpi->width >> zoom_level) + dpi->pitch;
// Move up to the first line of the image if source_y_start is negative. Why does this even occur? // Move up to the first line of the image if source_y_start is negative. Why does this even occur?
if (source_y_start < 0) if (srcY < 0)
{ {
source_y_start += zoom_amount; srcY += zoom;
height -= zoom_amount; height -= zoom;
dest_bits_pointer += line_width; dst0 += dstLineWidth;
} }
// For every line in the image // For every line in the image
for (int32_t i = 0; i < height; i += zoom_amount) for (int32_t i = 0; i < height; i += zoom)
{ {
int32_t y = source_y_start + i; int32_t y = srcY + i;
// The first part of the source pointer is a list of offsets to different lines // The first part of the source pointer is a list of offsets to different lines
// This will move the pointer to the correct source line. // This will move the pointer to the correct source line.
const uint16_t lineOffset = source_bits_pointer[y * 2] | (source_bits_pointer[y * 2 + 1] << 8); uint16_t lineOffset = src0[y * 2] | (src0[y * 2 + 1] << 8);
const uint8_t* lineData = source_bits_pointer + lineOffset; auto nextRun = src0 + lineOffset;
uint8_t* loop_dest_pointer = dest_bits_pointer + line_width * (i >> zoom_level); auto dstLineStart = dst0 + dstLineWidth * (i >> TZoom);
uint8_t isEndOfLine = 0;
// For every data chunk in the line // For every data chunk in the line
auto isEndOfLine = false;
while (!isEndOfLine) while (!isEndOfLine)
{ {
const uint8_t* copySrc = lineData;
// Read chunk metadata // Read chunk metadata
uint8_t dataSize = *copySrc++; auto src = nextRun;
uint8_t firstPixelX = *copySrc++; auto dataSize = *src++;
auto firstPixelX = *src++;
isEndOfLine = dataSize & 0x80; // If the last bit in dataSize is set, then this is the last line isEndOfLine = (dataSize & 0x80) != 0;
dataSize &= 0x7F; // The rest of the bits are the actual size dataSize &= 0x7F;
// Have our next source pointer point to the next data section // Have our next source pointer point to the next data section
lineData = copySrc + dataSize; nextRun = src + dataSize;
int32_t x_start = firstPixelX - source_x_start; int32_t x = firstPixelX - srcX;
int32_t numPixels = dataSize; int32_t numPixels = dataSize;
if (x > 0)
if (x_start > 0)
{ {
int mod = x_start & (zoom_amount - 1); // x_start modulo zoom_amount // If x is not a multiple of zoom, round it up to a multiple
auto mod = x & (zoom - 1);
// If x_start is not a multiple of zoom_amount, round it up to a multiple
if (mod != 0) if (mod != 0)
{ {
int offset = zoom_amount - mod; auto offset = zoom - mod;
x_start += offset; x += offset;
copySrc += offset; src += offset;
numPixels -= offset; numPixels -= offset;
} }
} }
else if (x_start < 0) else if (x < 0)
{ {
// Clamp x_start to zero if negative // Clamp x to zero if negative
int offset = 0 - x_start; src += -x;
x_start = 0; numPixels += x;
copySrc += offset; x = 0;
numPixels -= offset;
} }
// If the end position is further out than the whole image // If the end position is further out than the whole image
// end position then we need to shorten the line again // end position then we need to shorten the line again
if (x_start + numPixels > width) numPixels = std::min(numPixels, width - x);
numPixels = width - x_start;
uint8_t* copyDest = loop_dest_pointer + (x_start >> zoom_level); auto dst = dstLineStart + (x >> TZoom);
if constexpr ((TBlendOp & BLEND_SRC) == 0 && (TBlendOp & BLEND_DST) == 0 && TZoom == 0)
// Finally after all those checks, copy the image onto the drawing surface
// If the image type is not a basic one we require to mix the pixels
if constexpr ((TBlendOp & BLEND_SRC) != 0) // palette controlled images
{
for (int j = 0; j < numPixels; j += zoom_amount, copySrc += zoom_amount, copyDest++)
{
if ((TBlendOp & BLEND_DST) != 0)
{
*copyDest = paletteMap.Blend(*copySrc, *copyDest);
}
else
{
*copyDest = paletteMap[*copySrc];
}
}
}
else if constexpr ((TBlendOp & BLEND_DST) != 0) // single alpha blended color (used for glass)
{
for (int j = 0; j < numPixels; j += zoom_amount, copyDest++)
{
*copyDest = paletteMap[*copyDest];
}
}
else // standard opaque image
{
if (zoom_level == 0)
{ {
// Since we're sampling each pixel at this zoom level, just do a straight std::memcpy // Since we're sampling each pixel at this zoom level, just do a straight std::memcpy
if (numPixels > 0) if (numPixels > 0)
std::memcpy(copyDest, copySrc, numPixels); {
std::memcpy(dst, src, numPixels);
}
} }
else else
{ {
for (int j = 0; j < numPixels; j += zoom_amount, copySrc += zoom_amount, copyDest++) while (numPixels > 0)
*copyDest = *copySrc; {
BlitPixel<TBlendOp>(src, dst, paletteMap);
numPixels -= zoom;
src += zoom;
dst++;
} }
} }
} }