From d0b1bfbe87a781ff4d847b924e26ddfe5deb3c6d Mon Sep 17 00:00:00 2001 From: Ted John Date: Sun, 31 May 2020 13:55:47 +0100 Subject: [PATCH] Refactor bitmap drawing, one arg struct --- src/openrct2/CmdlineSprite.cpp | 7 +- src/openrct2/drawing/Drawing.Sprite.BMP.cpp | 179 +++++++++----------- src/openrct2/drawing/Drawing.Sprite.cpp | 4 +- src/openrct2/drawing/Drawing.h | 52 +++++- 4 files changed, 136 insertions(+), 106 deletions(-) diff --git a/src/openrct2/CmdlineSprite.cpp b/src/openrct2/CmdlineSprite.cpp index 2d2c82b037..669d4f9809 100644 --- a/src/openrct2/CmdlineSprite.cpp +++ b/src/openrct2/CmdlineSprite.cpp @@ -227,9 +227,10 @@ static bool sprite_file_export(rct_g1_element* spriteHeader, const char* outPath } else { - gfx_bmp_sprite_to_buffer( - PaletteMap::GetDefault(), spriteHeader->offset, pixels, spriteHeader, &dpi, spriteHeader->height, - spriteHeader->width, ImageId()); + DrawSpriteArgs args( + &dpi, ImageId(), PaletteMap::GetDefault(), *spriteHeader, spriteHeader->width, spriteHeader->height, + spriteHeader->offset, pixels); + gfx_bmp_sprite_to_buffer(args); } auto const pixels8 = dpi.bits; diff --git a/src/openrct2/drawing/Drawing.Sprite.BMP.cpp b/src/openrct2/drawing/Drawing.Sprite.BMP.cpp index 3c11aaa90d..a4abfb9e1d 100644 --- a/src/openrct2/drawing/Drawing.Sprite.BMP.cpp +++ b/src/openrct2/drawing/Drawing.Sprite.BMP.cpp @@ -9,16 +9,19 @@ #include "Drawing.h" -static void FASTCALL gfx_bmp_sprite_to_buffer_magnify( - const PaletteMap& paletteMap, uint8_t* source_pointer, uint8_t* dest_pointer, const rct_g1_element* source_image, - rct_drawpixelinfo* dest_dpi, int32_t height, int32_t width, ImageId imageId) +static void FASTCALL gfx_bmp_sprite_to_buffer_magnify(DrawSpriteArgs& args) { - auto zoom_level = dest_dpi->zoom_level; + auto dpi = args.DPI; + auto zoom_level = dpi->zoom_level; uint8_t zoom_amount = 1 * zoom_level; - uint32_t dest_line_width = (dest_dpi->width / zoom_level) + dest_dpi->pitch; - uint32_t source_line_width = source_image->width * zoom_level; + uint32_t dest_line_width = (dpi->width / zoom_level) + dpi->pitch; + uint32_t source_line_width = args.SourceImage.width * zoom_level; // Basic bitmap with no draw pixels + auto source_pointer = args.SourceBits; + auto dest_pointer = args.DestinationBits; + auto width = args.Width; + auto height = args.Height; for (; height > 0; height -= zoom_amount) { auto next_source_pointer = source_pointer + source_line_width; @@ -37,116 +40,94 @@ static void FASTCALL gfx_bmp_sprite_to_buffer_magnify( } } +template static void FASTCALL gfx_bmp_sprite_to_buffer_x(DrawSpriteArgs& args) +{ + auto src = args.SourceBits; + auto dst = args.DestinationBits; + auto& paletteMap = args.PalMap; + auto width = args.Width; + auto height = args.Height; + auto dpi = args.DPI; + auto zoomLevel = dpi->zoom_level; + size_t srcLineWidth = args.SourceImage.width * zoomLevel; + size_t dstLineWidth = (static_cast(dpi->width) / zoomLevel) + dpi->pitch; + uint8_t zoom = 1 * zoomLevel; + for (; height > 0; height -= zoom) + { + auto nextSrc = src + srcLineWidth; + auto nextDst = dst + dstLineWidth; + for (int32_t widthRemaining = width; widthRemaining > 0; widthRemaining -= zoom, src += zoom, dst++) + { + if constexpr (TBlendOp & BLEND_TRANSPARENT) + { + // Ignore transparent pixels + if (*src == 0) + { + continue; + } + } + + if constexpr (((TBlendOp & BLEND_SRC) != 0) && ((TBlendOp & BLEND_DST) != 0)) + { + *dst = paletteMap.Blend(*src, *dst); + } + else if constexpr ((TBlendOp & BLEND_SRC) != 0) + { + *dst = paletteMap[*src]; + } + else if constexpr ((TBlendOp & BLEND_DST) != 0) + { + *dst = paletteMap[*dst]; + } + else + { + *dst = *src; + } + } + src = nextSrc; + dst = nextDst; + } +} + /** * Copies a sprite onto the buffer. There is no compression used on the sprite * image. * rct2: 0x0067A690 * @param imageId Only flags are used. */ -void FASTCALL gfx_bmp_sprite_to_buffer( - const PaletteMap& paletteMap, uint8_t* source_pointer, uint8_t* dest_pointer, const rct_g1_element* source_image, - rct_drawpixelinfo* dest_dpi, int32_t height, int32_t width, ImageId imageId) +void FASTCALL gfx_bmp_sprite_to_buffer(DrawSpriteArgs& args) { - auto zoom_level = dest_dpi->zoom_level; + auto dpi = args.DPI; + auto zoom_level = dpi->zoom_level; if (zoom_level < 0) { - gfx_bmp_sprite_to_buffer_magnify( - paletteMap, source_pointer, dest_pointer, source_image, dest_dpi, height, width, imageId); + gfx_bmp_sprite_to_buffer_magnify(args); return; } - uint8_t zoom_amount = 1 * zoom_level; - uint32_t dest_line_width = (dest_dpi->width / zoom_level) + dest_dpi->pitch; - uint32_t source_line_width = source_image->width * zoom_level; + auto imageId = args.Image; // Image uses the palette pointer to remap the colours of the image if (imageId.HasPrimary()) { - // Image with remaps - for (; height > 0; height -= zoom_amount) - { - uint8_t* next_source_pointer = source_pointer + source_line_width; - uint8_t* next_dest_pointer = dest_pointer + dest_line_width; - for (int32_t no_pixels = width; no_pixels > 0; - no_pixels -= zoom_amount, source_pointer += zoom_amount, dest_pointer++) - { - uint8_t pixel = *source_pointer; - pixel = paletteMap[pixel]; - if (pixel) - { - *dest_pointer = pixel; - } - } - - source_pointer = next_source_pointer; - dest_pointer = next_dest_pointer; - } - return; + // Copy non-transparent bitmap data but re-colour using the palette map. + gfx_bmp_sprite_to_buffer_x(args); } - - // Image is transparent. It only uses source pointer for - // telling if it needs to be drawn not for colour. Colour provided - // by the palette pointer. - if (imageId.IsBlended()) - { // Not tested - for (; height > 0; height -= zoom_amount) - { - uint8_t* next_source_pointer = source_pointer + source_line_width; - uint8_t* next_dest_pointer = dest_pointer + dest_line_width; - - for (int32_t no_pixels = width; no_pixels > 0; - no_pixels -= zoom_amount, source_pointer += zoom_amount, dest_pointer++) - { - uint8_t pixel = *source_pointer; - if (pixel) - { - pixel = *dest_pointer; - pixel = paletteMap[pixel]; - *dest_pointer = pixel; - } - } - - source_pointer = next_source_pointer; - dest_pointer = next_dest_pointer; - } - return; - } - - // Basic bitmap no fancy stuff - if (!(source_image->flags & G1_FLAG_BMP)) - { // Not tested - for (; height > 0; height -= zoom_amount) - { - uint8_t* next_source_pointer = source_pointer + source_line_width; - uint8_t* next_dest_pointer = dest_pointer + dest_line_width; - - for (int32_t no_pixels = width; no_pixels > 0; - no_pixels -= zoom_amount, dest_pointer++, source_pointer += zoom_amount) - { - *dest_pointer = *source_pointer; - } - - dest_pointer = next_dest_pointer; - source_pointer = next_source_pointer; - } - return; - } - - // Basic bitmap with no draw pixels - for (; height > 0; height -= zoom_amount) + else if (imageId.IsBlended()) { - uint8_t* next_source_pointer = source_pointer + source_line_width; - uint8_t* next_dest_pointer = dest_pointer + dest_line_width; - - for (int32_t no_pixels = width; no_pixels > 0; no_pixels -= zoom_amount, dest_pointer++, source_pointer += zoom_amount) - { - uint8_t pixel = *source_pointer; - if (pixel) - { - *dest_pointer = pixel; - } - } - dest_pointer = next_dest_pointer; - source_pointer = next_source_pointer; + // Image is only a transparency mask. Just colour the pixels using the palette map. + // Used for glass. + gfx_bmp_sprite_to_buffer_x(args); + return; + } + else if (!(args.SourceImage.flags & G1_FLAG_BMP)) + { + // Copy raw bitmap data to target + gfx_bmp_sprite_to_buffer_x(args); + } + else + { + // Copy raw bitmap data to target but exclude transparent pixels + gfx_bmp_sprite_to_buffer_x(args); } } diff --git a/src/openrct2/drawing/Drawing.Sprite.cpp b/src/openrct2/drawing/Drawing.Sprite.cpp index ab3a15fb31..2c6278dcc4 100644 --- a/src/openrct2/drawing/Drawing.Sprite.cpp +++ b/src/openrct2/drawing/Drawing.Sprite.cpp @@ -580,7 +580,9 @@ void FASTCALL gfx_draw_sprite_palette_set_software( { // Move the pointer to the start point of the source auto source_pointer = g1->offset + ((static_cast(g1->width) * source_start_y) + source_start_x); - gfx_bmp_sprite_to_buffer(paletteMap, source_pointer, dest_pointer, g1, dpi, height, width, imageId); + + DrawSpriteArgs args(dpi, imageId, paletteMap, *g1, width, height, source_pointer, dest_pointer); + gfx_bmp_sprite_to_buffer(args); } } diff --git a/src/openrct2/drawing/Drawing.h b/src/openrct2/drawing/Drawing.h index c6735ab4af..48fd5a75f8 100644 --- a/src/openrct2/drawing/Drawing.h +++ b/src/openrct2/drawing/Drawing.h @@ -142,6 +142,28 @@ enum : uint32_t // REMAP_2_PLUS = REMAP 3 }; +using DrawBlendOp = uint8_t; + +constexpr DrawBlendOp BLEND_NONE = 0; + +/** + * Only supported by BITMAP. RLE images always encode transparency via the encoding. + * Pixel value of 0 represents transparent. + */ +constexpr DrawBlendOp BLEND_TRANSPARENT = 1 << 0; + +/** + * Whether to use the pixel value from the source image. + * This is usually only unset for glass images where there the src is only a transparency mask. + */ +constexpr DrawBlendOp BLEND_SRC = 1 << 1; + +/** + * Whether to use the pixel value of the destination image for blending. + * This is used for any image that filters the target image, e.g. glass or water. + */ +constexpr DrawBlendOp BLEND_DST = 2 << 2; + enum { INSET_RECT_FLAG_FILL_GREY = (1 << 2), // 0x04 @@ -492,6 +514,32 @@ public: void Copy(size_t dstIndex, const PaletteMap& src, size_t srcIndex, size_t length); }; +struct DrawSpriteArgs +{ + rct_drawpixelinfo* DPI; + ImageId Image; + const PaletteMap& PalMap; + const rct_g1_element& SourceImage; + int32_t Width; + int32_t Height; + const uint8_t* SourceBits; + uint8_t* DestinationBits; + + DrawSpriteArgs( + rct_drawpixelinfo* dpi, ImageId image, const PaletteMap& palMap, const rct_g1_element& sourceImage, int32_t width, + int32_t height, const uint8_t* sourceBits, uint8_t* destinationBits) + : DPI(dpi) + , Image(image) + , PalMap(palMap) + , SourceImage(sourceImage) + , Width(width) + , Height(height) + , SourceBits(sourceBits) + , DestinationBits(destinationBits) + { + } +}; + #define SPRITE_ID_PALETTE_COLOUR_1(colourId) (IMAGE_TYPE_REMAP | ((colourId) << 19)) #define SPRITE_ID_PALETTE_COLOUR_2(primaryId, secondaryId) \ (IMAGE_TYPE_REMAP_2_PLUS | IMAGE_TYPE_REMAP | (((primaryId) << 19) | ((secondaryId) << 24))) @@ -576,9 +624,7 @@ void gfx_object_free_images(uint32_t baseImageId, uint32_t count); void gfx_object_check_all_images_freed(); size_t ImageListGetUsedCount(); size_t ImageListGetMaximum(); -void FASTCALL gfx_bmp_sprite_to_buffer( - const PaletteMap& paletteMap, uint8_t* source_pointer, uint8_t* dest_pointer, const rct_g1_element* source_image, - rct_drawpixelinfo* dest_dpi, int32_t height, int32_t width, ImageId imageId); +void FASTCALL gfx_bmp_sprite_to_buffer(DrawSpriteArgs& args); void FASTCALL gfx_rle_sprite_to_buffer( const uint8_t* RESTRICT source_bits_pointer, uint8_t* RESTRICT dest_bits_pointer, const PaletteMap& RESTRICT paletteMap, const rct_drawpixelinfo* RESTRICT dpi, ImageId imageId, int32_t source_y_start, int32_t height, int32_t source_x_start,