diff --git a/src/drawing/drawing.h b/src/drawing/drawing.h index d0cf9e729e..cf1e2be650 100644 --- a/src/drawing/drawing.h +++ b/src/drawing/drawing.h @@ -123,6 +123,7 @@ int gfx_load_g1(); int gfx_load_g2(); void gfx_unload_g1(); void gfx_unload_g2(); +rct_g1_element* gfx_get_g1_element(int image_id); void sub_68371D(); void FASTCALL gfx_bmp_sprite_to_buffer(uint8* palette_pointer, uint8* unknown_pointer, uint8* source_pointer, uint8* dest_pointer, rct_g1_element* source_image, rct_drawpixelinfo *dest_dpi, int height, int width, int image_type); void FASTCALL gfx_rle_sprite_to_buffer(const uint8* source_bits_pointer, uint8* dest_bits_pointer, const uint8* palette_pointer, const rct_drawpixelinfo *dpi, int image_type, int source_y_start, int height, int source_x_start, int width); diff --git a/src/drawing/sprite.c b/src/drawing/sprite.c index 177f909535..eadd08a538 100644 --- a/src/drawing/sprite.c +++ b/src/drawing/sprite.c @@ -375,12 +375,7 @@ void FASTCALL gfx_draw_sprite_palette_set(rct_drawpixelinfo *dpi, int image_id, int image_element = image_id & 0x7FFFF; int image_type = (image_id & 0xE0000000) >> 28; - rct_g1_element* g1_source; - if (image_element < SPR_G2_BEGIN) { - g1_source = &g1Elements[image_element]; - } else { - g1_source = &g2.elements[image_element - SPR_G2_BEGIN]; - } + rct_g1_element *g1_source = gfx_get_g1_element(image_element); if ( dpi->zoom_level && (g1_source->flags & (1<<4)) ){ rct_drawpixelinfo zoomed_dpi = { @@ -553,3 +548,11 @@ void FASTCALL gfx_draw_sprite_palette_set(rct_drawpixelinfo *dpi, int image_id, free(new_source_pointer_start); return; } + +rct_g1_element *gfx_get_g1_element(int image_id) { + if (image_id < SPR_G2_BEGIN) { + return &g1Elements[image_id]; + } + + return &g2.elements[image_id - SPR_G2_BEGIN]; +} diff --git a/src/interface/viewport.c b/src/interface/viewport.c index 11e78c37ac..86289ebda3 100644 --- a/src/interface/viewport.c +++ b/src/interface/viewport.c @@ -935,15 +935,8 @@ int sub_98197C(int image_id, sint8 x_offset, sint8 y_offset, sint16 length_x, si ps->image_id = image_id; - rct_g1_element *g1Element; uint32 image_element = image_id & 0x7FFFF; - - if (image_element < SPR_G2_BEGIN) { - g1Element = &g1Elements[image_element]; - } - else { - g1Element = &g2.elements[image_element - SPR_G2_BEGIN]; - } + rct_g1_element *g1Element = gfx_get_g1_element(image_element); rct_xyz16 coord_3d = { .x = x_offset, @@ -2671,12 +2664,283 @@ void store_interaction_info(paint_struct *ps) } /** - * - * rct2: 0x00679074 + * rct2: 0x00679236, 0x00679662, 0x00679B0D, 0x00679FF1 */ -void sub_679074(rct_drawpixelinfo *dpi, int imageId, int x, int y) -{ - RCT2_CALLPROC_X(0x00679074, 0, imageId, x, y, 0, (int)dpi, 0); +static bool sub_679236_679662_679B0D_679FF1(uint32 ebx, rct_g1_element *image, uint8 *esi) { + // Probably used to check for corruption + if (!(image->flags & G1_FLAG_BMP)) { + return false; + } + + if (ebx & 0x20000000) { + uint8 *ebx_palette = RCT2_GLOBAL(0x009ABDA4, uint8*); + + uint8 al = *esi; + uint8 al2 = *(al + ebx_palette); + + return (al2 != 0); + } + + if (ebx & 0x40000000) { + return false; + } + + return (*esi != 0); +} + +/** + * rct2: 0x0067933B, 0x00679788, 0x00679C4A, 0x0067A117 + */ +static bool sub_67933B_679788_679C4A_67A117(uint8 *esi, sint16 x_start_point, sint16 y_start_point, int round) { + const uint8 *ebx = esi + ((uint16 *) esi)[y_start_point]; + + uint8 last_data_line = 0; + while (!last_data_line) { + int no_pixels = *ebx++; + uint8 gap_size = *ebx++; + + 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; + } + } + } + + int 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 (ceil2(no_pixels, round) == 0) continue; + + 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 new_sub_679074(rct_drawpixelinfo *dpi, int imageId, sint16 x, sint16 y) { + rct_g1_element *image = gfx_get_g1_element(imageId & 0x7FFFF); + + if (dpi->zoom_level != 0) { + if (image->flags & 0x20) { + return false; + } + + if (image->flags & 0x10) { + // TODO: SAR in dpi done with `>> 1`, in coordinates with `/ 2` + rct_drawpixelinfo zoomed_dpi = { + .bits = dpi->bits, + .x = dpi->x >> 1, + .y = dpi->y >> 1, + .height = dpi->height, + .width = dpi->width, + .pitch = dpi->pitch, + .zoom_level = dpi->zoom_level - 1 + }; + + return new_sub_679074(&zoomed_dpi, imageId - image->zoomed_offset, x / 2, y / 2); + } + } + + int round = 1 << dpi->zoom_level; + + if (image->flags & G1_FLAG_RLE_COMPRESSION) { + y -= (round - 1); + } + + y += image->y_offset; + sint16 yStartPoint = 0; + sint16 height = image->height; + if (dpi->zoom_level != 0) { + if (height % 2) { + height--; + yStartPoint++; + } + + if (dpi->zoom_level == 2) { + if (height % 4) { + height -= 2; + yStartPoint += 2; + } + } + + if (height == 0) { + return false; + } + } + + y = floor2(y, round); + sint16 yEndPoint = height; + y -= dpi->y; + if (y < 0) { + yEndPoint += y; + if (yEndPoint <= 0) { + return false; + } + + yStartPoint -= y; + y = 0; + } + + y += yEndPoint; + y--; + if (y > 0) { + yEndPoint -= y; + if (yEndPoint <= 0) { + return false; + } + } + + sint16 xStartPoint = 0; + sint16 xEndPoint = image->width; + if (!(image->flags & G1_FLAG_RLE_COMPRESSION)) { + RCT2_GLOBAL(0x009ABDAE, sint16) = 0; + } + + x += image->x_offset; + x = floor2(x, round); + x -= dpi->x; + if (x < 0) { + xEndPoint += x; + if (xEndPoint <= 0) { + return false; + } + + if (!(image->flags & G1_FLAG_RLE_COMPRESSION)) { + RCT2_GLOBAL(0x009ABDAE, sint16) -= x; + } + + xStartPoint -= x; + x = 0; + } + + x += xEndPoint; + x--; + if (x > 0) { + xEndPoint -= x; + if (xEndPoint <= 0) { + return false; + } + + if (!(image->flags & G1_FLAG_RLE_COMPRESSION)) { + RCT2_GLOBAL(0x009ABDAE, sint16) += x; + } + } + + if (image->flags & G1_FLAG_RLE_COMPRESSION) { + return sub_67933B_679788_679C4A_67A117(image->offset, xStartPoint, yStartPoint, round); + } + + uint8 *offset = image->offset + (yStartPoint * image->width) + xStartPoint; + uint32 ebx = RCT2_GLOBAL(0x00EDF81C, uint32); + + if (!(image->flags & 2)) { + return sub_679236_679662_679B0D_679FF1(ebx, image, offset); + } + + // The code below is untested. + int total_no_pixels = image->width * image->height; + uint8 *source_pointer = image->offset; + uint8 *new_source_pointer_start = malloc(total_no_pixels); + uint8 *new_source_pointer = (*&new_source_pointer_start);// 0x9E3D28; + int ebx1, ecx; + while (total_no_pixels > 0) { + sint8 no_pixels = *source_pointer; + if (no_pixels >= 0) { + source_pointer++; + total_no_pixels -= no_pixels; + memcpy((char *) new_source_pointer, (char *) source_pointer, no_pixels); + new_source_pointer += no_pixels; + source_pointer += no_pixels; + continue; + } + ecx = no_pixels; + no_pixels &= 0x7; + ecx >>= 3;//SAR + int eax = ((int) no_pixels) << 8; + ecx = -ecx;//Odd + eax = (eax & 0xFF00) + *(source_pointer + 1); + total_no_pixels -= ecx; + source_pointer += 2; + ebx1 = (uint32) new_source_pointer - eax; + eax = (uint32) source_pointer; + source_pointer = (uint8 *) ebx1; + ebx1 = eax; + eax = 0; + memcpy((char *) new_source_pointer, (char *) source_pointer, ecx); + new_source_pointer += ecx; + source_pointer = (uint8 *) ebx1; + } + + bool output = sub_679236_679662_679B0D_679FF1(ebx, image, new_source_pointer_start + (uint32) offset); + free(new_source_pointer_start); + + return output; +} + +static bool sub_679074(rct_drawpixelinfo *dpi, int imageId, sint16 x, sint16 y) { + sint16 before_x = RCT2_GLOBAL(0x9ABDAE, sint16); + uint8 before_output = RCT2_GLOBAL(0x00141F569, uint8); + + RCT2_CALLPROC_X(0x00679074, 0, imageId, x, y, 0, (int) dpi, 0); + sint16 original_x = RCT2_GLOBAL(0x9ABDAE, sint16); + uint8 original_output = RCT2_GLOBAL(0x00141F569, uint8); + + RCT2_GLOBAL(0x9ABDAE, sint16) = before_x; + RCT2_GLOBAL(0x00141F569, uint8) = before_output; + + bool new_output = new_sub_679074(dpi, imageId, x, y); + sint16 new_x = RCT2_GLOBAL(0x9ABDAE, sint16); + + assert(new_x == original_x); + assert(new_output == original_output); + + return new_output; } /** @@ -2698,7 +2962,7 @@ void sub_679023(rct_drawpixelinfo *dpi, int imageId, int x, int y) } else { RCT2_GLOBAL(0x00EDF81C, uint32) = 0; } - sub_679074(dpi, imageId, x, y); + RCT2_GLOBAL(0x00141F569, uint8) = sub_679074(dpi, imageId, x, y); } /** diff --git a/src/rct2.h b/src/rct2.h index 1a5aa30746..195f8319f8 100644 --- a/src/rct2.h +++ b/src/rct2.h @@ -86,6 +86,9 @@ typedef uint8 colour_t; // Rounds an integer down to the given power of 2. y must be a power of 2. #define floor2(x, y) ((x) & (~((y) - 1))) +// Rounds an integer up to the given power of 2. y must be a power of 2. +#define ceil2(x, y) (((x) + (y) - 1) & (~((y) - 1))) + #ifndef __cplusplus // in C++ you should be using Util::CountOf