diff --git a/src/addresses.h b/src/addresses.h index cfadc3fea7..974a9c7507 100644 --- a/src/addresses.h +++ b/src/addresses.h @@ -249,6 +249,7 @@ #define RCT2_ADDRESS_NEWS_ITEM_LIST 0x013CA754 #define RCT2_ADDRESS_CURRENT_FONT_SPRITE_BASE 0x013CE950 +#define RCT2_ADDRESS_CURRENT_FONT_FLAGS 0x013CE9A2 #define RCT2_ADDRESS_TILE_MAP_ELEMENT_POINTERS 0x013CE9A4 #define RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT 0x0141E9AC @@ -257,6 +258,8 @@ #define RCT2_ADDRESS_GAME_COMMAND_ERROR_STRING_ID 0x0141E9AE #define RCT2_ADDRESS_CURRENT_ROTATION 0x0141E9E0 +#define RCT2_ADDRESS_COMMON_STRING_FORMAT_BUFFER 0x0141ED68 + #define RCT2_ADDRESS_WATER_RAISE_COST 0x0141F738 #define RCT2_ADDRESS_WATER_LOWER_COST 0x0141F73C @@ -357,6 +360,24 @@ static void RCT2_CALLPROC_X(int address, int _eax, int _ebx, int _ecx, int _edx, #endif } +static void RCT2_CALLPROC_X_EBPSAFE(int address, int _eax, int _ebx, int _ecx, int _edx, int _esi, int _edi, int _ebp) +{ + __asm { + push ebp + push address + mov eax, _eax + mov ebx, _ebx + mov ecx, _ecx + mov edx, _edx + mov esi, _esi + mov edi, _edi + mov ebp, _ebp + call[esp] + add esp, 4 + pop ebp + } +} + static void RCT2_CALLFUNC_X(int address, int *_eax, int *_ebx, int *_ecx, int *_edx, int *_esi, int *_edi, int *_ebp) { #ifdef _MSC_VER diff --git a/src/gfx.c b/src/gfx.c index 0aec70adc5..cfda0c8e05 100644 --- a/src/gfx.c +++ b/src/gfx.c @@ -1,5 +1,5 @@ /***************************************************************************** - * Copyright (c) 2014 Ted John + * Copyright (c) 2014 Ted John, Peter Hill * OpenRCT2, an open source clone of Roller Coaster Tycoon 2. * * This file is part of OpenRCT2. @@ -28,6 +28,7 @@ #include "rct2.h" #include "string_ids.h" #include "window.h" +#include "osinterface.h" typedef struct { uint32 num_entries; @@ -42,6 +43,31 @@ int gLastDrawStringY; uint8 _screenDirtyBlocks[5120]; +//Originally 0x9ABE0C, 12 elements from 0xF3 are the peep top colour, 12 elements from 0xCA are peep trouser colour +uint8 peep_palette[0x100] = { + 0x00, 0xF3, 0xF4, 0xF5, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, + 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, + 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F, + 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, + 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F, + 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F, + 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F, + 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF, + 0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF, + 0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF, + 0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF, + 0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF, + 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF +}; + +//Originally 0x9ABE04 +uint8 text_palette[0x8] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + static void gfx_draw_dirty_blocks(int x, int y, int columns, int rows); /** @@ -254,11 +280,198 @@ void gfx_draw_line(rct_drawpixelinfo *dpi, int x1, int y1, int x2, int y2, int c */ void gfx_fill_rect(rct_drawpixelinfo *dpi, int left, int top, int right, int bottom, int colour) { - RCT2_CALLPROC_X(0x00678AD4, left, right, top, bottom, 0, (int)dpi, colour); + int left_, right_, top_, bottom_; + rct_drawpixelinfo* dpi_; + left_ = left; + right_ = right; + top_ = top; + bottom_ = bottom; + dpi_ = dpi; + + if ((left > right) || (top > bottom) || (dpi->x > right) || (left >= (dpi->x + dpi->width)) || + (bottom < dpi->y) || (top >= (dpi->y + dpi->height))) + return; + + colour |= RCT2_GLOBAL(0x009ABD9C, uint32); + + if (!(colour & 0x1000000)) { + if (!(colour & 0x8000000)) { + left_ = left - dpi->x; + if (left_ < 0) + left_ = 0; + + right_ = right - dpi->x; + right_++; + if (right_ > dpi->width) + right_ = dpi->width; + + right_ -= left_; + + top_ = top - dpi->y; + if (top_ < 0) + top_ = 0; + + bottom_ = bottom - dpi->y; + bottom_++; + + if (bottom_ > dpi->height) + bottom_ = dpi->height; + + bottom_ -= top_; + + if (!(colour & 0x2000000)) { + if (!(colour & 0x4000000)) { + uint8* pixel = (top_ * (dpi->width + dpi->pitch)) + left_ + dpi->bits; + + int length = dpi->width + dpi->pitch - right_; + + for (int i = 0; i < bottom_; ++i) { + memset(pixel, (colour & 0xFF), right_); + pixel += length + right_; + } + } else { + // 00678B8A 00678E38 + char* esi; + esi = (top_ * (dpi->width + dpi->pitch)) + left_ + dpi->bits;; + + int eax, ebp; + eax = colour; + ebp = dpi->width + dpi->pitch - right_; + + RCT2_GLOBAL(0x00EDF810, uint32) = ebp; + RCT2_GLOBAL(0x009ABDB2, uint16) = bottom_; + RCT2_GLOBAL(0x00EDF814, uint32) = right_; + + top_ = (top + dpi->y) & 0xf; + right_ = (right + dpi_->x) &0xf; + + dpi_ = (rct_drawpixelinfo*)esi; + + esi = (char*)(eax >> 0x1C); + esi = (char*)RCT2_GLOBAL(0x0097FEFC,uint32)[esi]; // or possibly uint8)[esi*4] ? + + for (; RCT2_GLOBAL(0x009ABDB2, uint16) > 0; RCT2_GLOBAL(0x009ABDB2, uint16)--) { + // push ebx + // push ecx + ebp = *(esi + top_*2); + + // mov bp, [esi+top_*2]; + int ecx; + ecx = RCT2_GLOBAL(0x00EDF814, uint32); + + for (int i = ecx; i >=0; --i) { + if (!(ebp & (1 << right_))) + dpi_->bits = (char*)(left_ & 0xFF); + + right_++; + right_ = right_ & 0xF; + dpi_++; + } + // pop ecx + // pop ebx + top_++; + top_ = top_ &0xf; + dpi_ += RCT2_GLOBAL(0x00EDF810, uint32); + } + return; + } + + } else { + // 00678B7E 00678C83 + if (dpi->zoom_level < 1) { + // Location in screen buffer? + uint8* pixel = top_ * (dpi->width + dpi->pitch) + left_ + dpi->bits; + + // Find colour in colour table? + uint32 eax = RCT2_ADDRESS(0x0097FCBC, uint32)[(colour & 0xFF)]; + rct_g1_element* g1_element = &(RCT2_ADDRESS(RCT2_ADDRESS_G1_ELEMENTS, rct_g1_element)[eax]); + + int length = (dpi->width + dpi->pitch) - right_; + + // Fill the rectangle with the colours from the colour table + for (int i = 0; i < bottom_; ++i) { + for (int j = 0; j < right_; ++j) { + *pixel = *((uint8*)(&g1_element->offset[*pixel])); + pixel++; + } + pixel += length; + } + } else if (dpi->zoom_level > 1) { + // 00678C8A 00678D57 + right_ = right; + } else if (dpi->zoom_level == 1) { + // 00678C88 00678CEE + right = right; + } + + } + } else { + // 00678B3A 00678EC9 + right_ = right; + } + } else { + // 00678B2E 00678BE5 + // Cross hatching + uint16 pattern = 0; + + left_ = left_ - dpi->x; + if (left_ < 0) { + pattern = pattern ^ left_; + left_ = 0; + } + + right_ = right_ - dpi->x; + right_++; + + if (right_ > dpi->width) + right_ = dpi-> width; + + right_ = right_ - left_; + + top_ = top - dpi->y; + if (top_ < 0) { + pattern = pattern ^ top_; + top_ = 0; + } + + bottom_ = bottom - dpi->y; + bottom_++; + + if (bottom_ > dpi->height) + bottom_ = dpi->height; + + bottom_ -= top_; + + uint8* pixel = (top_ * (dpi->width + dpi->pitch)) + left_ + dpi->bits; + + int length = dpi->width + dpi->pitch - right_; + + uint32 ecx; + for (int i = 0; i < bottom_; ++i) { + ecx = pattern; + // Rotate right + ecx = (ecx >> 1) | (ecx << (sizeof(ecx) * CHAR_BIT - 1)); + ecx = (ecx & 0xFFFF0000) | right_; + // Fill every other pixel with the colour + for (; (ecx & 0xFFFF) > 0; ecx--) { + ecx = ecx ^ 0x80000000; + if ((int)ecx < 0) { + *pixel = colour & 0xFF; + } + pixel++; + } + pattern = pattern ^ 1; + pixel += length; + + } + } + + // RCT2_CALLPROC_X(0x00678AD4, left, right, top, bottom, 0, dpi, colour); } /** - * + * Draw a rectangle, with optional border or fill + * * rct2: 0x006E6F81 * dpi (edi) * left (ax) @@ -266,13 +479,339 @@ void gfx_fill_rect(rct_drawpixelinfo *dpi, int left, int top, int right, int bot * right (bx) * bottom (dx) * colour (ebp) - * _si (si) + * flags (si) */ -void gfx_fill_rect_inset(rct_drawpixelinfo* dpi, short left, short top, short right, short bottom, int colour, short _si) +void gfx_fill_rect_inset(rct_drawpixelinfo* dpi, short left, short top, short right, short bottom, int colour, short flags) { - RCT2_CALLPROC_X(0x006E6F81, left, right, top, bottom, _si, (int)dpi, colour); + uint8 shadow, fill, hilight; + + // Flags + int no_border, no_fill, pressed; + + no_border = 8; + no_fill = 0x10; + pressed = 0x20; + + if (colour & 0x180) { + if (colour & 0x100) { + colour = colour & 0x7F; + } else { + colour = RCT2_ADDRESS(0x009DEDF4,uint8)[colour]; + } + + colour = colour | 0x2000000; //Transparent + + if (flags & no_border) { + gfx_fill_rect(dpi, left, top, bottom, right, colour); + } else if (flags & pressed) { + // Draw outline of box + gfx_fill_rect(dpi, left, top, left, bottom, colour + 1); + gfx_fill_rect(dpi, left, top, right, top, colour + 1); + gfx_fill_rect(dpi, right, top, right, bottom, colour + 2); + gfx_fill_rect(dpi, left, bottom, right, bottom, colour + 2); + + if (!(flags & no_fill)) { + gfx_fill_rect(dpi, left+1, top+1, right-1, bottom-1, colour); + } + } else { + // Draw outline of box + gfx_fill_rect(dpi, left, top, left, bottom, colour + 2); + gfx_fill_rect(dpi, left, top, right, top, colour + 2); + gfx_fill_rect(dpi, right, top, right, bottom, colour + 1); + gfx_fill_rect(dpi, left, bottom, right, bottom, colour + 1); + + if (!(flags & no_fill)) { + gfx_fill_rect(dpi, left+1, top+1, right-1, bottom-1, colour); + } + } + } else { + if (flags & 0x80) { + shadow = RCT2_ADDRESS(0x0141FC46, uint8)[colour * 8]; + fill = RCT2_ADDRESS(0x0141FC48, uint8)[colour * 8]; + hilight = RCT2_ADDRESS(0x0141FC4A, uint8)[colour * 8]; + } else { + shadow = RCT2_ADDRESS(0x0141FC47, uint8)[colour * 8]; + fill = RCT2_ADDRESS(0x0141FC49, uint8)[colour * 8]; + hilight = RCT2_ADDRESS(0x0141FC4B, uint8)[colour * 8]; + } + + if (flags & no_border) { + gfx_fill_rect(dpi, left, top, right, bottom, fill); + } else if (flags & pressed) { + // Draw outline of box + gfx_fill_rect(dpi, left, top, left, bottom, shadow); + gfx_fill_rect(dpi, left + 1, top, right, top, shadow); + gfx_fill_rect(dpi, right, top + 1, right, bottom - 1, hilight); + gfx_fill_rect(dpi, left + 1, bottom, right, bottom, hilight); + + if (!(flags & no_fill)) { + if (!(flags & 0x40)) { + if (flags & 0x04) { + fill = RCT2_ADDRESS(0x0141FC49, uint8)[0]; + } else { + fill = RCT2_ADDRESS(0x0141FC4A, uint8)[colour * 8]; + } + } + gfx_fill_rect(dpi, left+1, top+1, right-1, bottom-1, fill); + } + } else { + // Draw outline of box + gfx_fill_rect(dpi, left, top, left, bottom - 1, hilight); + gfx_fill_rect(dpi, left + 1, top, right - 1, top, hilight); + gfx_fill_rect(dpi, right, top, right, bottom - 1, shadow); + gfx_fill_rect(dpi, left, bottom, right, bottom, shadow); + + if (!(flags & no_fill)) { + if (flags & 0x04) { + fill = RCT2_ADDRESS(0x0141FC49, uint8)[0]; + } + gfx_fill_rect(dpi, left+1, top+1, right-1, bottom-1, fill); + } + } + } } +#define RCT2_Y_RELATED_GLOBAL_1 0x9E3D12 //uint16 +#define RCT2_Y_END_POINT_GLOBAL 0x9ABDAC //sint16 +#define RCT2_Y_START_POINT_GLOBAL 0xEDF808 //sint16 +#define RCT2_X_RELATED_GLOBAL_1 0x9E3D10 //uint16 +#define RCT2_X_END_POINT_GLOBAL 0x9ABDA8 //sint16 +#define RCT2_X_START_POINT_GLOBAL 0xEDF80C //sint16 +#define RCT2_DPI_LINE_LENGTH_GLOBAL 0x9ABDB0 //uint16 width+pitch + +/* +* rct2: 0x67A690 +* copies a sprite onto the buffer. There is no compression used on the sprite +* image. +*/ +void 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){ + uint8 zoom_level = dest_dpi->zoom_level + 1; + //Requires use of palette? + if (image_type & IMAGE_TYPE_USE_PALETTE){ + + //Mix with another image?? and colour adjusted + if (unknown_pointer!= NULL){ //Not tested. I can't actually work out when this code runs. + unknown_pointer += source_pointer - source_image->offset;// RCT2_GLOBAL(0x9E3CE0, uint32); + + for (; height > 0; height -= zoom_level){ + uint8* next_source_pointer = source_pointer + source_image->width*zoom_level; + uint8* next_unknown_pointer = unknown_pointer + source_image->width*zoom_level; + uint8* next_dest_pointer = dest_pointer + dest_dpi->width + dest_dpi->pitch; + + for (int no_pixels = width; no_pixels > 0; no_pixels -= zoom_level, source_pointer+=zoom_level, unknown_pointer+=zoom_level, dest_pointer++){ + uint8 pixel = *source_pointer; + pixel = palette_pointer[pixel]; + pixel &= *unknown_pointer; + if (pixel){ + *dest_pointer = pixel; + } + } + source_pointer = next_source_pointer; + dest_pointer = next_dest_pointer; + unknown_pointer = next_unknown_pointer; + } + return; + } + + //image colour adjusted? + for (; height > 0; height -= zoom_level){ + uint8* next_source_pointer = source_pointer + source_image->width*zoom_level; + uint8* next_dest_pointer = dest_pointer + dest_dpi->width + dest_dpi->pitch; + for (int no_pixels = width; no_pixels > 0; no_pixels -= zoom_level, source_pointer+= zoom_level, dest_pointer++){ + uint8 pixel = *source_pointer; + pixel = palette_pointer[pixel]; + if (pixel){ + *dest_pointer = pixel; + } + } + + source_pointer = next_source_pointer; + dest_pointer = next_dest_pointer; + } + return; + } + + //Mix with background. It only uses source pointer for + //telling if it needs to be drawn not for colour. + if (image_type & IMAGE_TYPE_MIX_BACKGROUND){//Not tested + for (; height > 0; height -= zoom_level){ + uint8* next_source_pointer = source_pointer + source_image->width*zoom_level; + uint8* next_dest_pointer = dest_pointer + dest_dpi->width + dest_dpi->pitch; + + for (int no_pixels = width; no_pixels > 0; no_pixels -= zoom_level, source_pointer += zoom_level, dest_pointer++){ + uint8 pixel = *source_pointer; + if (pixel){ + pixel = *dest_pointer; + pixel = palette_pointer[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_level){ + uint8* next_source_pointer = source_pointer + source_image->width*zoom_level; + uint8* next_dest_pointer = dest_pointer + dest_dpi->width + dest_dpi->pitch; + + for (int no_pixels = width; no_pixels > 0; no_pixels -= zoom_level, dest_pointer++, source_pointer += zoom_level){ + *dest_pointer = *source_pointer; + } + + dest_pointer = next_dest_pointer; + source_pointer = next_source_pointer; + } + return; + } + + if (RCT2_GLOBAL(0x9E3CDC, uint32) != 0){//Not tested. I can't actually work out when this code runs. + unknown_pointer += source_pointer - source_image->offset; + + for (; height > 0; height -= zoom_level){ + uint8* next_source_pointer = source_pointer + source_image->width*zoom_level; + uint8* next_unknown_pointer = unknown_pointer + source_image->width*zoom_level; + uint8* next_dest_pointer = dest_pointer + dest_dpi->width + dest_dpi->pitch; + + for (int no_pixels = width; no_pixels > 0; no_pixels -= zoom_level, dest_pointer++, source_pointer += zoom_level, unknown_pointer += zoom_level){ + uint8 pixel = *source_pointer; + pixel &= *unknown_pointer; + if (pixel){ + *dest_pointer = pixel; + } + } + dest_pointer = next_dest_pointer; + source_pointer = next_source_pointer; + unknown_pointer = next_unknown_pointer; + } + } + + //Basic bitmap with no draw pixels + for (; height > 0; height -= zoom_level){ + uint8* next_source_pointer = source_pointer + source_image->width*zoom_level; + uint8* next_dest_pointer = dest_pointer + dest_dpi->width + dest_dpi->pitch; + + for (int no_pixels = width; no_pixels > 0; no_pixels -= zoom_level, dest_pointer++, source_pointer += zoom_level){ + uint8 pixel = *source_pointer; + if (pixel){ + *dest_pointer = pixel; + } + } + dest_pointer = next_dest_pointer; + source_pointer = next_source_pointer; + } + return; +} + + +/* +* rct2: 0x67AA18 transfers readied images onto buffers +* This function copies the sprite data onto the screen +* I think its only used for bitmaps onto buttons but i am not sure. +* There is still a small bug with this code when it is in the choose park view. +*/ +void gfx_rle_sprite_to_buffer(uint8* source_bits_pointer, uint8* dest_bits_pointer, uint8* palette_pointer, rct_drawpixelinfo *dpi, int image_type, int source_y_start, int height, int source_x_start, int width){ + int zoom_level = dpi->zoom_level + 1; + + uint8* next_source_pointer; + uint8* next_dest_pointer = dest_bits_pointer; + + //For every line in the image + for (int y = source_y_start; y < (height + source_y_start); y += zoom_level){ + + //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. + next_source_pointer = source_bits_pointer + ((uint16*)source_bits_pointer)[y]; + + uint8 last_data_line = 0; + + //For every data section in the line + while (!last_data_line){ + uint8* source_pointer = next_source_pointer; + uint8* dest_pointer = next_dest_pointer; + + int no_pixels = *source_pointer++; + //gap_size is the number of non drawn pixels you require to + //jump over on your destination + uint8 gap_size = *source_pointer++; + //The last bit in no_pixels tells you if you have reached the end of a line + last_data_line = no_pixels & 0x80; + //Clear the last data line bit so we have just the no_pixels + no_pixels &= 0x7f; + //Have our next source pointer point to the next data section + next_source_pointer = source_pointer + no_pixels; + + //Calculates the start point of the image + int x_start = gap_size - source_x_start; + + if (x_start > 0){ + //Since the start is positive + //We need to move the drawing surface to the correct position + dest_pointer += x_start / zoom_level; + } + else{ + //If the start is negative we require to remove part of the image. + //This is done by moving the image pointer to the correct position. + source_pointer -= x_start; + //The no_pixels will be reduced in this operation + no_pixels += x_start; + //If there are no pixels there is nothing to draw this data section + if (no_pixels <= 0) continue; + //Reset the start position to zero as we have taken into account all moves + x_start = 0; + } + + int x_end = x_start + no_pixels; + //If the end position is further out than the whole image + //end position then we need to shorten the line again + if (x_end > width){ + //Shorten the line + no_pixels -= x_end - width; + //If there are no pixels there is nothing to draw. + if (no_pixels <= 0) continue; + } + + //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 (image_type & IMAGE_TYPE_USE_PALETTE){//In the .exe these are all unraveled loops + for (; no_pixels > 0; no_pixels -= zoom_level, source_pointer += zoom_level, dest_pointer++){ + uint8 al = *source_pointer; + uint8 ah = *dest_pointer; + if (image_type & IMAGE_TYPE_MIX_BACKGROUND)//Mix with background and image Not Tested + al = palette_pointer[(al | ((int)ah) << 8) - 0x100]; + else //Adjust colours? + al = palette_pointer[al]; + *dest_pointer = al; + } + } + else if (image_type & IMAGE_TYPE_MIX_BACKGROUND){//In the .exe these are all unraveled loops + //Doesnt use source pointer ??? mix with background only? + //Not Tested + for (; no_pixels > 0; no_pixels -= zoom_level, dest_pointer++){ + uint8 pixel = *dest_pointer; + pixel = palette_pointer[pixel]; + *dest_pointer = pixel; + } + } + else + { + for (; no_pixels > 0; no_pixels -= zoom_level, source_pointer += zoom_level, dest_pointer++){ + *dest_pointer = *source_pointer; + } + } + } + + //Add a line to the drawing surface pointer + next_dest_pointer += (int)dpi->width + (int)dpi->pitch; + } +} + + +void gfx_draw_sprite_palette_set(rct_drawpixelinfo *dpi, int image_id, int x, int y, uint8* palette_pointer, uint8* unknown_pointer); /** * * rct2: 0x0067A28E @@ -282,7 +821,264 @@ void gfx_fill_rect_inset(rct_drawpixelinfo* dpi, short left, short top, short ri */ void gfx_draw_sprite(rct_drawpixelinfo *dpi, int image_id, int x, int y) { - RCT2_CALLPROC_X(0x0067A28E, 0, image_id, x, y, 0, (int)dpi, 0); + + int eax = 0, ebx = image_id, ecx = x, edx = y, esi = 0, edi = (int)dpi, ebp = 0; + int image_type = (image_id & 0xE0000000) >> 28; + int image_sub_type = (image_id & 0x1C000000) >> 26; + uint8* palette_pointer = NULL; + uint8 palette[0x100]; + RCT2_GLOBAL(0x00EDF81C, uint32) = image_id & 0xE0000000; + eax = (image_id >> 26) & 0x7; + + uint8* unknown_pointer = (uint8*)(RCT2_ADDRESS(0x9E3CE4, uint32*)[image_sub_type]); + RCT2_GLOBAL(0x009E3CDC, uint32) = RCT2_GLOBAL(0x009E3CE4 + eax * 4, uint32); + + if (image_type && !(image_type & IMAGE_TYPE_UNKNOWN)) { + + if (!(image_type & IMAGE_TYPE_MIX_BACKGROUND)){ + eax = image_id; + eax >>= 19; + eax &= 0xFF; + unknown_pointer = NULL; + RCT2_GLOBAL(0x009E3CDC, uint32) = 0; + } + else{ + eax = image_id; + eax >>= 19; + eax &= 0x7F; + } + eax = RCT2_GLOBAL(eax * 4 + 0x97FCBC, uint32); + + palette_pointer = ((rct_g1_element*)RCT2_ADDRESS_G1_ELEMENTS)[eax].offset; + RCT2_GLOBAL(0x9ABDA4, uint32) = (uint32)palette_pointer; + } + else if (image_type && !(image_type & IMAGE_TYPE_USE_PALETTE)){ + //Has not been tested + RCT2_GLOBAL(0x9E3CDC, uint32) = 0; + unknown_pointer = NULL; + + eax = image_id; + eax >>= 19; + //push edx/y + eax &= 0x1F; + ebp = RCT2_GLOBAL(ebp * 4 + 0x97FCBC, uint32); + eax = RCT2_GLOBAL(eax * 4 + 0x97FCBC, uint32); + ebp <<= 0x4; + eax <<= 0x4; + ebp = RCT2_GLOBAL(ebp + RCT2_ADDRESS_G1_ELEMENTS, uint32); + eax = RCT2_GLOBAL(eax + RCT2_ADDRESS_G1_ELEMENTS, uint32); + edx = *((uint32*)(eax + 0xF3)); + esi = *((uint32*)(eax + 0xF7)); + RCT2_GLOBAL(0x9ABFFF, uint32) = edx; + RCT2_GLOBAL(0x9AC003, uint32) = esi; + edx = *((uint32*)(ebp + 0xF3)); + esi = *((uint32*)(ebp + 0xF7)); + esi = *((uint32*)(eax + 0xF7)); + + edx = *((uint32*)(eax + 0xFB)); + esi = *((uint32*)(ebp + 0xFB)); + + eax = image_id; + RCT2_GLOBAL(0x9AC007, uint32) = edx; + eax >>= 24; + RCT2_GLOBAL(0x9ABF42, uint32) = esi; + eax &= 0x1F; + + //image_id + RCT2_GLOBAL(0xEDF81C, uint32) |= 0x20000000; + image_id |= IMAGE_TYPE_USE_PALETTE; + + eax = RCT2_GLOBAL(eax * 4 + 0x97FCBC, uint32); + eax <<= 4; + eax = RCT2_GLOBAL(eax + RCT2_ADDRESS_G1_ELEMENTS, uint32); + edx = *((uint32*)(eax + 0xF3)); + esi = *((uint32*)(eax + 0xF7)); + RCT2_GLOBAL(0x9ABFD6, uint32) = edx; + RCT2_GLOBAL(0x9ABFDA, uint32) = esi; + edx = *((uint32*)(eax + 0xFB)); + RCT2_GLOBAL(0x9ABDA4, uint32) = 0x9ABF0C; + palette_pointer = (uint8*)0x9ABF0C; + RCT2_GLOBAL(0x9ABFDE, uint32) = edx; + edx = y; + + } + else if (image_type){ + RCT2_GLOBAL(0x9E3CDC, uint32) = 0; + unknown_pointer = NULL; + //Copy the peep palette into a new palette. + //Not really required but its nice to make a copy + memcpy(palette, peep_palette, 0x100); + + //Top + int top_type = (image_id >> 19) & 0x1f; + uint32 top_offset = RCT2_ADDRESS(0x97FCBC, uint32)[top_type]; + rct_g1_element top_palette = RCT2_ADDRESS(RCT2_ADDRESS_G1_ELEMENTS, rct_g1_element)[top_offset]; + memcpy(palette + 0xF3, top_palette.offset + 0xF3, 12); + + //Trousers + int trouser_type = (image_id >> 24) & 0x1f; + uint32 trouser_offset = RCT2_ADDRESS(0x97FCBC, uint32)[trouser_type]; + rct_g1_element trouser_palette = RCT2_ADDRESS(RCT2_ADDRESS_G1_ELEMENTS, rct_g1_element)[trouser_offset]; + memcpy(palette + 0xCA, trouser_palette.offset + 0xF3, 12); + + //For backwards compatibility until the zooming function is done + RCT2_GLOBAL(0x9ABDA4, uint8*) = palette; + palette_pointer = palette; + } + + gfx_draw_sprite_palette_set(dpi, image_id, x, y, palette_pointer, unknown_pointer); +} + +/* +* 0x67A46E +*/ +void gfx_draw_sprite_palette_set(rct_drawpixelinfo *dpi, int image_id, int x, int y, uint8* palette_pointer, uint8* unknown_pointer){ + int image_element = 0x7FFFF&image_id; + int image_type = (image_id & 0xE0000000) >> 28; + + rct_g1_element* g1_source = &(RCT2_ADDRESS(RCT2_ADDRESS_G1_ELEMENTS, rct_g1_element)[image_element]); + + //Zooming code has been integrated into main code. + /*if (dpi->zoom_level >= 1){ //These have not been tested + //something to do with zooming + if (dpi->zoom_level == 1){ + RCT2_CALLPROC_X(0x0067BD81, 0, (int)g1_source, x, y, 0,(int) dpi, 0); + return; + } + if (dpi->zoom_level == 2){ + RCT2_CALLPROC_X(0x0067DADA, 0, (int)g1_source, x, y, 0, (int)dpi, 0); + return; + } + RCT2_CALLPROC_X(0x0067FAAE, 0, (int)g1_source, x, y, 0, (int)dpi, 0); + return; + }*/ + + //We add on one so that divides will create the correct number of pixels + int zoom_level = dpi->zoom_level + 1; + //This will be the height of the drawn image + int height = g1_source->height / zoom_level; + //This is the start y coordinate on the destination + int dest_start_y = y - dpi->y + g1_source->y_offset; + //This is the start y coordinate on the source + int source_start_y = 0; + + + if (dest_start_y < 0){ + //If the destination y is negative reduce the height of the + //image as we will cut off the bottom + height += dest_start_y; + //If the image is no longer visible nothing to draw + if (height <= 0){ + return; + } + //The source image will start a further up the image + source_start_y -= dest_start_y*zoom_level; + //The destination start is now reset to 0 + dest_start_y = 0; + } + + + int dest_end_y = dest_start_y + height; + + if (dest_end_y > dpi->height){ + //If the destination y is outside of the drawing + //image reduce the height of the image + height -= dest_end_y - dpi->height; + //If the image no longer has anything to draw + if (height <= 0)return; + } + + //This will be the width of the drawn image + int width = g1_source->width / zoom_level; + //This is the source start x coordinate + int source_start_x = 0; + //This is the destination start x coordinate + int dest_start_x = x - dpi->x + g1_source->x_offset; + + if (dest_start_x < 0){ + //If the destination is negative reduce the width + //image will cut off the side + width += dest_start_x; + //If there is no image to draw + if (width <= 0){ + return; + } + //The source start will also need to cut off the side + source_start_x -= dest_start_x*zoom_level; + //Reset the destination to 0 + dest_start_x = 0; + } + + int dest_end_x = dest_start_x + width; + + if (dest_end_x > dpi->width){ + //If the destination x is outside of the drawing area + //reduce the image width. + width -= dest_end_x - dpi->width; + //If there is no image to draw. + if (width <= 0)return; + } + + + uint8* dest_pointer = (uint8*)dpi->bits; + //Move the pointer to the start point of the destination + dest_pointer += (dpi->width + dpi->pitch)*dest_start_y + dest_start_x; + + height *= zoom_level; + width *= zoom_level; + + if (g1_source->flags & G1_FLAG_RLE_COMPRESSION){ + //We have to use a different method to move the source pointer for + //rle encoded sprites so that will be handled within this function + gfx_rle_sprite_to_buffer(g1_source->offset, dest_pointer, palette_pointer, dpi, image_type, source_start_y, height, source_start_x, width); + return; + } + uint8* source_pointer = g1_source->offset; + //Move the pointer to the start point of the source + source_pointer += g1_source->width*source_start_y + source_start_x; + + if (!(g1_source->flags & 0x02)){ + gfx_bmp_sprite_to_buffer(palette_pointer, unknown_pointer, source_pointer, dest_pointer, g1_source, dpi, height, width, image_type); + return; + } + //0x67A60A Not tested + int total_no_pixels = g1_source->width*g1_source->height; + source_pointer = g1_source->offset; + uint8* new_source_pointer_start = malloc(total_no_pixels); + uint8* new_source_pointer = new_source_pointer_start;// 0x9E3D28; + int ebx, 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; + ebx = (uint32)new_source_pointer - eax; + eax = (uint32)source_pointer; + source_pointer = (uint8*)ebx; + ebx = eax; + eax = 0; + memcpy((char*)new_source_pointer, (char*)source_pointer, ecx); + new_source_pointer += ecx; + source_pointer += ecx; + source_pointer = (uint8*)ebx; + } + source_pointer = new_source_pointer_start + g1_source->width*source_start_y + source_start_x; + gfx_bmp_sprite_to_buffer(palette_pointer, unknown_pointer, source_pointer, dest_pointer, g1_source, dpi, height, width, image_type); + free(new_source_pointer_start); + return; } /** @@ -309,8 +1105,7 @@ void gfx_transpose_palette(int pal, unsigned char product) esi += 3; edi += 4; } - - RCT2_CALLPROC_3(0x00405595, int, int, int, 0x01424680, 10, 236); + osinterface_update_palette((char*)0x01424680, 10, 236); } /** @@ -325,7 +1120,22 @@ void gfx_transpose_palette(int pal, unsigned char product) */ void gfx_draw_string_centred(rct_drawpixelinfo *dpi, int format, int x, int y, int colour, void *args) { - RCT2_CALLPROC_X(0x006C1D6C, colour, format, x, y, (int)args, (int)dpi, 0); + char* buffer; + short text_width; + + buffer = RCT2_ADDRESS(RCT2_ADDRESS_COMMON_STRING_FORMAT_BUFFER, char); + format_string(buffer, format, args); + + RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_FONT_SPRITE_BASE, uint16) = 0xE0; + + // Measure text width + text_width = gfx_get_string_width(buffer); + + // Draw the text centred + if (text_width <= 0xFFF) { + x -= text_width / 2; + gfx_draw_string(dpi, buffer, colour, x, y); + } } /** @@ -466,18 +1276,154 @@ void gfx_redraw_screen_rect(short left, short top, short right, short bottom) } /** - * + * Return the width of the string in buffer + * * rct2: 0x006C2321 * buffer (esi) */ -int gfx_get_string_width(char *buffer) +int gfx_get_string_width(char* buffer) { - int eax, ebx, ecx, edx, esi, edi, ebp; + // Current font sprites + uint16* current_font_sprite_base; + // Width of string + int width; + rct_g1_element* g1_element; + + current_font_sprite_base = RCT2_ADDRESS(RCT2_ADDRESS_CURRENT_FONT_SPRITE_BASE, uint16); + width = 0; - esi = (int)buffer; - RCT2_CALLFUNC_X(0x006C2321, &eax, &ebx, &ecx, &edx, &esi, &edi, &ebp); + for (uint8* curr_char = buffer; *curr_char != NULL; curr_char++) { - return ecx & 0xFFFF; + if (*curr_char >= 0x20) { + //Maybe global not address?? + width += RCT2_ADDRESS(0x0141E9E8, uint8)[*current_font_sprite_base + (*curr_char-0x20)]; + continue; + } + switch(*curr_char) { + case 1: + width = *curr_char; + curr_char++; + break; + case 2: + case 3: + case 4: + curr_char++; + break; + case 7: + *current_font_sprite_base = 0x1C0; + break; + case 8: + *current_font_sprite_base = 0x2A0; + break; + case 9: + *current_font_sprite_base = 0x0E0; + break; + case 0x0A: + *current_font_sprite_base = 0; + break; + case 0x17: + g1_element = &(RCT2_ADDRESS(RCT2_ADDRESS_G1_ELEMENTS, rct_g1_element)[*curr_char&0x7FFFF]); + width += g1_element->width; //RCT2_ADDRESS(RCT2_ADDRESS_G1_ELEMENTS + 4, uint16)[(*curr_char & 0x7FFFF) << 4]; + curr_char += 4; + break; + default: + if (*curr_char <= 0x10) { + continue; + } + curr_char += 2; + if (*curr_char <= 0x16) { + continue; + } + curr_char += 2; + break; + } + } + return width; +} + +/** + * Clip the text in buffer to width, add ellipsis and return the new width of the clipped string + * + * rct2: 0x006C2460 + * buffer (esi) + * width (edi) + */ +int gfx_clip_string(char* buffer, int width) +{ + // Location of font sprites + uint16* current_font_sprite_base; + // Width the string has to fit into + int max_width; + // Character to change to ellipsis + char* last_char; + // Width of the string, including ellipsis + int clipped_width; + + if (width < 6) { + *buffer = 0; + return 0; + } + + current_font_sprite_base = RCT2_ADDRESS(RCT2_ADDRESS_CURRENT_FONT_SPRITE_BASE, uint16); + max_width = width - (3 * RCT2_ADDRESS(0x141E9F6, uint8)[*current_font_sprite_base]); + + clipped_width = 0; + last_char = buffer; + + for (uint8* curr_char = buffer; *curr_char != NULL; curr_char++) { + if (*curr_char < 0x20) { + switch(*curr_char) { + case 1: + width = *curr_char; + curr_char++; + continue; + case 2: + case 3: + case 4: + curr_char++; + continue; + case 7: + *current_font_sprite_base = 0x1C0; + break; + case 8: + *current_font_sprite_base = 0x2A0; + break; + case 9: + *current_font_sprite_base = 0x0E0; + break; + case 0x0A: + *current_font_sprite_base = 0; + break; + case 0x17: + clipped_width += RCT2_ADDRESS(RCT2_ADDRESS_G1_ELEMENTS + 4, uint16)[(*curr_char & 0x7FFFF) << 4]; + curr_char += 4; + continue; + default: + if (*curr_char <= 0x10) { + continue; + } + curr_char += 2; + if (*curr_char <= 0x16) { + continue; + } + curr_char += 2; + continue; + } + max_width = width - (3 * RCT2_ADDRESS(0x141E9F6, uint8)[*current_font_sprite_base]); + } + + clipped_width += RCT2_ADDRESS(0x0141E9E8, uint8)[*current_font_sprite_base + (*curr_char-0x20)]; + + if (clipped_width >= width) { + RCT2_GLOBAL(last_char, uint32) = 0x2E2E2E; + clipped_width = width; + return clipped_width; + } + if (clipped_width <= max_width) { + last_char = curr_char; + } + } + return clipped_width; } /** @@ -494,15 +1440,19 @@ int gfx_get_string_width(char *buffer) */ void gfx_draw_string_left_clipped(rct_drawpixelinfo* dpi, int format, void* args, int colour, int x, int y, int width) { - RCT2_CALLPROC_X(0x006C1B83, colour, format, x, y, (int)args, (int)dpi, width); + // RCT2_CALLPROC_X(0x006C1B83, colour, format, x, y, (int)args, (int)dpi, width); - //char* buffer; + char* buffer; - //buffer = (char*)0x0141ED68; - //format_string(buffer, format, args); - //rctmem->current_font_sprite_base = 224; - //clip_text(buffer, width); - //gfx_draw_string(dpi, buffer, colour, x, y); + buffer = RCT2_ADDRESS(RCT2_ADDRESS_COMMON_STRING_FORMAT_BUFFER, char); + format_string(buffer, format, args); + + RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_FONT_SPRITE_BASE, uint16) = 0xE0; + + // Clip text - return value is not needed + gfx_clip_string(buffer, width); + + gfx_draw_string(dpi, buffer, colour, x, y); } /** @@ -519,19 +1469,22 @@ void gfx_draw_string_left_clipped(rct_drawpixelinfo* dpi, int format, void* args */ void gfx_draw_string_centred_clipped(rct_drawpixelinfo *dpi, int format, void *args, int colour, int x, int y, int width) { - RCT2_CALLPROC_X(0x006C1BBA, colour, format, x, y, (int)args, (int)dpi, width); + char* buffer; + short text_width; - //char* buffer; - //short text_width; + buffer = RCT2_ADDRESS(RCT2_ADDRESS_COMMON_STRING_FORMAT_BUFFER, char); + format_string(buffer, format, args); - //buffer = (char*)0x0141ED68; - //format_string(buffer, format, args); - //rctmem->current_font_sprite_base = 224; - //text_width = clip_text(buffer, width); + RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_FONT_SPRITE_BASE, uint16) = 0xE0; - //// Draw the text centred - //x -= (text_width - 1) / 2; - //gfx_draw_string(dpi, buffer, colour, x, y); + // Clip text + text_width = gfx_clip_string(buffer, width); + + // Draw the text centred + if (text_width <= 0xFFF) { + x -= (text_width - 1) / 2; + gfx_draw_string(dpi, buffer, colour, x, y); + } } @@ -550,7 +1503,7 @@ void gfx_draw_string_right(rct_drawpixelinfo* dpi, int format, void* args, int c char* buffer; short text_width; - buffer = (char*)0x0141ED68; + buffer = RCT2_ADDRESS(RCT2_ADDRESS_COMMON_STRING_FORMAT_BUFFER, char); format_string(buffer, format, args); // Measure text width @@ -575,15 +1528,62 @@ void gfx_draw_string_right(rct_drawpixelinfo* dpi, int format, void* args, int c int gfx_draw_string_centred_wrapped(rct_drawpixelinfo *dpi, void *args, int x, int y, int width, int format, int colour) { int eax, ebx, ecx, edx, esi, edi, ebp; + // Location of font sprites + uint16* current_font_sprite_base; + // Location of font flags + uint16 current_font_flags; - eax = colour; - ebx = format; - ecx = x; - edx = y; - esi = (int)args; - edi = (int)dpi; - ebp = width; - RCT2_CALLFUNC_X(0x006C1E53, &eax, &ebx, &ecx, &edx, &esi, &edi, &ebp); + current_font_sprite_base = RCT2_ADDRESS(RCT2_ADDRESS_CURRENT_FONT_SPRITE_BASE, uint16); + *current_font_sprite_base = 0xE0; + + char* buffer = RCT2_ADDRESS(0x009C383D, char); + + gfx_draw_string(dpi, buffer, colour, dpi->x, dpi->y); + + buffer = RCT2_ADDRESS(RCT2_ADDRESS_COMMON_STRING_FORMAT_BUFFER, char); + + format_string(buffer, format, args); + + *current_font_sprite_base = 0xE0; + + esi = buffer; + edi = width; + RCT2_CALLFUNC_X(0x006C21E2, &eax, &ebx, &ecx, &edx, &esi, &edi, &ebp); + ecx &= 0xFFFF; + edi &= 0xFFFF; + + RCT2_GLOBAL(0x00F43938, uint16) = 0x0A; + + if (ebx > 0xE0) { + RCT2_GLOBAL(0x00F43938, uint16) = 6; + if (ebx != 0x1C0) { + RCT2_GLOBAL(0x00F43938, uint16) = 0x12; + } + } + + if (*buffer == 0x0B) { + RCT2_GLOBAL(0x00F43938, uint16) = RCT2_GLOBAL(0x00F43938, uint16) + 1; + } + + ebx = (RCT2_GLOBAL(0x00F43938, uint16) / 2) * edi; + edx = y - ebx; + + RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_FONT_FLAGS, uint16) = 0; + + buffer = RCT2_ADDRESS(RCT2_ADDRESS_COMMON_STRING_FORMAT_BUFFER, char); + + do { + int new_width = gfx_get_string_width(buffer); + new_width /= 2; + gfx_draw_string(dpi, buffer, 0xFE, x - new_width, edx); + + buffer += strlen(buffer) + 1; + + edx += RCT2_GLOBAL(0x00F43938, uint16); + eax = (RCT2_GLOBAL(0x00F43938, uint16) / 2) * edi; + ebx -= eax; + + } while (ebx > 0); return (sint16)(edx & 0xFFFF) - y; } @@ -602,17 +1602,78 @@ int gfx_draw_string_centred_wrapped(rct_drawpixelinfo *dpi, void *args, int x, i int gfx_draw_string_left_wrapped(rct_drawpixelinfo *dpi, void *args, int x, int y, int width, int format, int colour) { int eax, ebx, ecx, edx, esi, edi, ebp; + + // eax = colour; + // ebx = format; + // ecx = x; + // edx = y; + // esi = (int)args; + // edi = (int)dpi; + // ebp = width; + // RCT2_CALLFUNC_X(0x006C2105, &eax, &ebx, &ecx, &edx, &esi, &edi, &ebp); + // return (sint16)(edx & 0xFFFF) - y; - eax = colour; - ebx = format; - ecx = x; - edx = y; - esi = (int)args; - edi = (int)dpi; - ebp = width; - RCT2_CALLFUNC_X(0x006C2105, &eax, &ebx, &ecx, &edx, &esi, &edi, &ebp); + // Location of font sprites + uint16* current_font_sprite_base; + // Location of font flags + uint16 current_font_flags; + + current_font_sprite_base = RCT2_ADDRESS(RCT2_ADDRESS_CURRENT_FONT_SPRITE_BASE, uint16); + *current_font_sprite_base = 0xE0; + + char* buffer = RCT2_ADDRESS(0x009C383D, char); + + gfx_draw_string(dpi, buffer, colour, dpi->x, dpi->y); + + buffer = RCT2_ADDRESS(RCT2_ADDRESS_COMMON_STRING_FORMAT_BUFFER, char); + + format_string(buffer, format, args); + + buffer = RCT2_ADDRESS(RCT2_ADDRESS_COMMON_STRING_FORMAT_BUFFER, char); + + *current_font_sprite_base = 0xE0; + + // Add line breaks? Adds \0 rather than \n + // not working for strings with colour code? + esi = buffer; + edi = width; + RCT2_CALLFUNC_X(0x006C21E2, &eax, &ebx, &ecx, &edx, &esi, &edi, &ebp); + ecx &= 0xFFFF; + edi &= 0xFFFF; + + // Font height? + RCT2_GLOBAL(0x00F43938, uint16) = 0x0A; + + if (ebx > 0xE0) { + RCT2_GLOBAL(0x00F43938, uint16) = 6; + if (ebx != 0x1C0) { + RCT2_GLOBAL(0x00F43938, uint16) = 0x12; + } + } + + // Number of lines? + ebx = (RCT2_GLOBAL(0x00F43938, uint16) / 2) * edi; + + RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_FONT_FLAGS, uint16) = 0; + + buffer = RCT2_ADDRESS(RCT2_ADDRESS_COMMON_STRING_FORMAT_BUFFER, char); + esi = buffer; + + edx = y; + + do { + gfx_draw_string(dpi, buffer, 0xFE, x, edx); + + buffer += strlen(buffer) + 1; + + edx += RCT2_GLOBAL(0x00F43938, uint16); + eax = (RCT2_GLOBAL(0x00F43938, uint16) / 2); + ebx -= eax; + + } while (ebx >= 0); return (sint16)(edx & 0xFFFF) - y; + } /** @@ -629,34 +1690,379 @@ void gfx_draw_string_left(rct_drawpixelinfo *dpi, int format, void *args, int co { char* buffer; - buffer = (char*)0x0141ED68; + buffer = RCT2_ADDRESS(RCT2_ADDRESS_COMMON_STRING_FORMAT_BUFFER, char); format_string(buffer, format, args); RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_FONT_SPRITE_BASE, uint16) = 0xE0; gfx_draw_string(dpi, buffer, colour, x, y); } + +void colour_char(int al, uint16* current_font_flags) { + + int eax; + + rct_g1_element* g1_element = &(RCT2_ADDRESS(RCT2_ADDRESS_G1_ELEMENTS, rct_g1_element)[0x1332]); + eax = ((uint32*)g1_element->offset)[al & 0xFF]; + + if (!(*current_font_flags & 2)) { + eax = eax & 0x0FF0000FF; + } + // Adjust text palette. Store current colour? + RCT2_GLOBAL(0x009ABE05, uint32) = eax; + RCT2_GLOBAL(0x009ABDA4, uint32) = 0x009ABE04; +} + + +void sub_682AC7(int ebp, uint16* current_font_flags) { + + int eax; + + // loc_682AC7 + eax = RCT2_ADDRESS(0x0141FD45, uint8)[ebp * 8]; + if (*current_font_flags & 2) { + eax |= 0x0A0A00; + } + //Adjust text palette. Store current colour? + RCT2_GLOBAL(0x009ABE05, uint32) = eax; + RCT2_GLOBAL(0x009ABDA4, uint32) = 0x009ABE04; + eax = 0; + // jmp loc_682842 + +} + + /** * * rct2: 0x00682702 * dpi (edi) - * format (esi) + * buffer (esi) * colour (al) * x (cx) * y (dx) */ -void gfx_draw_string(rct_drawpixelinfo *dpi, char *format, int colour, int x, int y) +void gfx_draw_string(rct_drawpixelinfo *dpi, char *buffer, int colour, int x, int y) { + //int eax, ebx, ecx, edx, esi, edi, ebp; + //char* find = "FINDMEDRAWSTRING"; + //eax = colour; + //ebx = 0; + //ecx = x; + //edx = y; + //esi = (int)buffer; + //edi = (int)dpi; + //ebp = 0; + //RCT2_CALLFUNC_X(0x00682702, &eax, &ebx, &ecx, &edx, &esi, &edi, &ebp); + + //gLastDrawStringX = ecx; + //gLastDrawStringY = edx; + // int eax, ebx, ecx, edx, esi, edi, ebp; + rct_g1_element* g1_element; - eax = colour; - ebx = 0; - ecx = x; - edx = y; - esi = (int)format; - edi = (int)dpi; - ebp = 0; - RCT2_CALLFUNC_X(0x00682702, &eax, &ebx, &ecx, &edx, &esi, &edi, &ebp); + // Maximum length/height of string + int max_x = x; + int max_y = y; - gLastDrawStringX = ecx; - gLastDrawStringY = edx; + // Store original x, y + RCT2_GLOBAL(0x00EDF840, uint16) = x; + RCT2_GLOBAL(0x00EDF842, uint16) = y; + + // + uint16* current_font_flags = RCT2_ADDRESS(RCT2_ADDRESS_CURRENT_FONT_FLAGS, uint16); + uint16* current_font_sprite_base = RCT2_ADDRESS(RCT2_ADDRESS_CURRENT_FONT_SPRITE_BASE, uint16); + + // Flag for skipping non-printing characters + int skip_char = 0; + + if (colour != 0xFE) { + + if (x >= dpi->x + dpi->width) + return; + + if (x + 0x280 <= dpi->x) + return; + + if (y >= dpi->y + dpi->height) + return; + + if (y + 0x5A <= dpi->y) { + return; + } + + if (colour != 0xFF) { + + // switch_colour: + *current_font_flags = 0; + if (*current_font_sprite_base < 0) { + *current_font_flags |= 4; + if (*current_font_sprite_base != 0xFFFF) { + *current_font_flags |= 8; + } + *current_font_sprite_base = 0xE0; + } + if (colour & (1 << 5)) { + *current_font_flags |= 2; + } + colour &= ~(1 << 5); + + if (!(colour & 0x40)) { + ebp = colour; + if (*current_font_flags & 1) { + if ((y + 0x13 <= dpi->y) || (dpi->y + dpi->height <= y)) { + skip_char = 1; + } else { + skip_char = 0; + } + } else { + sub_682AC7(ebp, current_font_flags); + } + } else { + *current_font_flags |= 1; + colour &= 0x1F; + + if (*current_font_flags & 4) { + if (*current_font_flags & 8) { + eax = RCT2_ADDRESS(0x0141FC48, uint8)[colour * 8]; + eax = eax << 10; + eax = eax | RCT2_ADDRESS(0x0141FC46, uint8)[colour * 8]; + } else { + eax = RCT2_ADDRESS(0x0141FC49, uint8)[colour * 8]; + eax = eax << 10; + eax = eax | RCT2_ADDRESS(0x0141FC47, uint8)[colour * 8]; + } + } else { + eax = RCT2_ADDRESS(0x0141FC4A, uint8)[colour * 8]; + eax = eax << 10; + eax = eax | RCT2_ADDRESS(0x0141FC48, uint8)[colour * 8]; + } + // Adjust text palette. Store current colour? ; + RCT2_GLOBAL(0x009ABE05, uint32) = eax; + RCT2_GLOBAL(0x009ABDA4, uint32) = 0x009ABE04; + eax = 0; + } + } + } + + if ((y + 0x13 <= dpi->y) || (dpi->y + dpi->height <= y)) { + skip_char = 1; + } + + for (uint8 al = *buffer; al > 0; ++buffer, al = *buffer) { + + // Skip to the next printing character + if (skip_char) { + if (al < 0x20) { + // Control codes + skip_char = 0; + } else if (al >= 0x8E && al < 0x9C) { + // Colour codes + al -= 0x8E; + if (*current_font_flags == 1) { + if ((y + 0x13 <= dpi->y) || (dpi->y + dpi->height <= y)) { + skip_char = 1; + } else { + skip_char = 0; + } + continue; + } + colour_char(al, current_font_flags); + continue; + } else { + continue; + } + } + + if ((al >= 0x8E) && (al < 0x9C)){ + // Colour codes + al -= 0x8E; + if (*current_font_flags == 1) { + if ((y + 0x13 <= dpi->y) || (dpi->y + dpi->height <= y)) { + skip_char = 1; + } else { + skip_char = 0; + } + continue; + } + colour_char(al, current_font_flags); + continue; + } else { + if (al < 0x20) { + // Control codes + al -= 0x20; + switch (al) { + case 0x0E5://Start New Line at set y lower + max_x = x;//RCT2_GLOBAL(0x0EDF840, uint16); + max_y += 0x0A; + if (*current_font_sprite_base <= 0x0E) { + break; + } + max_y -= 4; + if (*current_font_sprite_base == 0x1C0) { + break; + } + max_y -= 0xFFF4; + break; + case 0x0E6://Start New Line at set y lower + max_x = x;//RCT2_GLOBAL(0x0EDF840, uint16); + max_y += 5; + if (*current_font_sprite_base <= 0x0E) { + break; + } + max_y -= 2; + if (*current_font_sprite_base == 0x1C0) { + break; + } + max_y -= 0xFFFA;//This does not look correct probably should be an add + break; + case 0x0E1://Start New Line at start+buffer x, same y. (Overwrite?) + al = *buffer; + buffer++; + max_x = x;//RCT2_GLOBAL(0x0EDF840, uint16); + max_x += al; + break; + case 0x0F1: //Start new line at specified x,y + eax = *((uint16*)buffer); + buffer += 2; + max_x = x;//RCT2_GLOBAL(0x0EDF840, uint16); + max_x += (eax & 0xFF); + max_y = y;//RCT2_GLOBAL(0x0EDF842, uint16); + max_y += (eax & 0xFF00) >> 8; + break; + case 0x0E7: + *current_font_sprite_base = 0x1C0; + break; + case 0x0E8: + *current_font_sprite_base = 0x2A0; + break; + case 0x0E9: + *current_font_sprite_base = 0xE0; + break; + case 0x0EA: + *current_font_sprite_base = 0; + break; + case 0x0EB: + *current_font_flags |= 2; + break; + case 0x0EC: + *current_font_flags &= 0x0FFFD; + break; + case 0x0ED: + ebp = RCT2_GLOBAL(0x0141F740, uint8); + if (*current_font_flags & 1) { + if ((y + 0x13 <= dpi->y) || (dpi->y + dpi->height <= y)) { + skip_char = 1; + } else { + skip_char = 0; + } + break; + } + sub_682AC7(ebp, current_font_flags); + break; + case 0x0EE: + ebp = RCT2_GLOBAL(0x0141F741, uint8); + if (*current_font_flags & 1) { + if ((y + 0x13 <= dpi->y) || (dpi->y + dpi->height <= y)) { + skip_char = 1; + } else { + skip_char = 0; + } + break; + } + sub_682AC7(ebp, current_font_flags); + break; + case 0x0EF: + ebp = RCT2_GLOBAL(0x0141F742, uint8); + if (*current_font_flags & 1) { + if ((y + 0x13 <= dpi->y) || (dpi->y + dpi->height <= y)) { + skip_char = 1; + } else { + skip_char = 0; + } + break; + } + sub_682AC7(ebp, current_font_flags); + break; + case 0x0E2: + al = *buffer; + buffer++; + if (*current_font_flags & 1) { + if ((y + 0x13 <= dpi->y) || (dpi->y + dpi->height <= y)) { + skip_char = 1; + break; + } + } + + eax = RCT2_ADDRESS(0x097FCBC, uint32)[al*4]; + g1_element = &(RCT2_ADDRESS(RCT2_ADDRESS_G1_ELEMENTS, rct_g1_element)[eax]); + ebx = g1_element->offset[0xF9] + (1 << 8); + + if (!(*current_font_flags & 2)) { + ebx = ebx & 0xFF; + } + //Adjust the text palette + RCT2_GLOBAL(0x09ABE05, uint16) = ebx; + memcpy((uint8*)0x09ABE07,&(g1_element->offset[0xF7]),2); + //ebx = g1_element->offset[0xF7]; + //RCT2_GLOBAL(0x09ABE07, uint16) = ebx; + memcpy((uint8*)0x09ABE09,&(g1_element->offset[0xFA]),2); + //ebx = g1_element->offset[0xFA]; + //RCT2_GLOBAL(0x09ABE09, uint16) = ebx; + //Set the palette pointer + RCT2_GLOBAL(0x09ABDA4, uint32) = 0x09ABE04; + if ((y + 0x13 <= dpi->y) || (dpi->y + dpi->height <= y)) { + skip_char = 1; + } + break; + case 0x0F7: + buffer += 4; + if (max_x >= dpi->x + dpi->width) { + skip_char = 1; + break; + } + ebx = *(buffer - 4); + eax = ebx & 0x7FFFF; + g1_element = &(RCT2_ADDRESS(RCT2_ADDRESS_G1_ELEMENTS, rct_g1_element)[eax]); + + gfx_draw_sprite(dpi, ebx, max_x, max_y); + + max_x = max_x + g1_element->width; + break; + } + + } else { + al -= 0x20; + if (max_x >= dpi->x + dpi->width) { + skip_char = 1; + } + if (max_x + 0x1A < dpi->x) { + ebx = al; + ebx += *current_font_sprite_base; + max_x = max_x + (RCT2_ADDRESS(0x0141E9E8, uint8)[ebx] & 0xFF); + continue; + } + ebx = al + *current_font_sprite_base; + + ecx = max_x; + + max_x = max_x + (RCT2_ADDRESS(0x0141E9E8, uint8)[ebx] & 0xFF); + + eax = (int)al; + ebx += 0xF15; + + edx = max_y; + esi = (int)buffer; + edi = (int)dpi; + ebp = 0; + + RCT2_GLOBAL(0x00EDF81C, uint32) = 0x20000000; + + gfx_draw_sprite_palette_set(dpi, 0x20000000 | ebx, ecx, edx, RCT2_GLOBAL(0x9ABDA4, uint8*), NULL); + + continue; + } + } + } + + gLastDrawStringX = max_x; + gLastDrawStringY = max_y; } diff --git a/src/gfx.h b/src/gfx.h index b266ea3dc2..a627bffb72 100644 --- a/src/gfx.h +++ b/src/gfx.h @@ -46,6 +46,18 @@ typedef struct { sint16 unused; // 0x0E } rct_g1_element; +enum{ + G1_FLAG_BMP = (1 << 0), //No invisible sections + G1_FLAG_RLE_COMPRESSION = (1<<2), +}; + +enum{ + IMAGE_TYPE_NO_BACKGROUND = 0, + IMAGE_TYPE_USE_PALETTE= (1 << 1), + IMAGE_TYPE_MIX_BACKGROUND = (1<<2), + IMAGE_TYPE_UNKNOWN = (1<<3) +}; + extern int gLastDrawStringX; extern int gLastDrawStringY; diff --git a/src/osinterface.c b/src/osinterface.c index 274c2a5f3a..0843f127c5 100644 --- a/src/osinterface.c +++ b/src/osinterface.c @@ -40,7 +40,7 @@ unsigned int gLastKeyPressed; static void osinterface_create_window(); static void osinterface_close_window(); static void osinterface_resize(int width, int height); -static void osinterface_update_palette(char* colours, int start_index, int num_colours); + static SDL_Window *_window; static SDL_Surface *_surface; @@ -167,7 +167,7 @@ static void osinterface_resize(int width, int height) gfx_invalidate_screen(); } -static void osinterface_update_palette(char* colours, int start_index, int num_colours) +void osinterface_update_palette(char* colours, int start_index, int num_colours) { SDL_Color base[256]; SDL_Surface *surface; @@ -476,4 +476,4 @@ int osinterface_ensure_directory_exists(const char *path) char osinterface_get_path_separator() { return '\\'; -} \ No newline at end of file +} diff --git a/src/osinterface.h b/src/osinterface.h index 59691835c6..4725902362 100644 --- a/src/osinterface.h +++ b/src/osinterface.h @@ -45,6 +45,7 @@ void osinterface_init(); void osinterface_process_messages(); void osinterface_draw(); void osinterface_free(); +void osinterface_update_palette(char* colours, int start_index, int num_colours); int osinterface_open_common_file_dialog(int type, char *title, char *filename, char *filterPattern, char *filterName); void osinterface_show_messagebox(char* message); diff --git a/src/widget.c b/src/widget.c index 3fc27264bd..55f4f1006d 100644 --- a/src/widget.c +++ b/src/widget.c @@ -156,6 +156,8 @@ void widget_draw(rct_drawpixelinfo *dpi, rct_window *w, int widgetIndex) widget_scroll_draw(dpi, w, widgetIndex); break; case WWT_CHECKBOX: + widget_checkbox_draw(dpi, w, widgetIndex); + break; case WWT_24: widget_checkbox_draw(dpi, w, widgetIndex); break; @@ -715,7 +717,7 @@ static void widget_closebox_draw(rct_drawpixelinfo *dpi, rct_window *w, int widg } /** -* + * * rct2: 0x006EBAD9 */ static void widget_checkbox_draw(rct_drawpixelinfo *dpi, rct_window *w, int widgetIndex) @@ -736,14 +738,12 @@ static void widget_checkbox_draw(rct_drawpixelinfo *dpi, rct_window *w, int widg colour = w->colours[widget->colour]; // checkbox - if (widget->type != WWT_24) { - gfx_fill_rect_inset(dpi, l, t, l + 9, b - 1, colour, 0x60); + gfx_fill_rect_inset(dpi, l, t, l + 9, b - 1, colour, 0x60); - // fill it when checkbox is pressed - if (widget_is_pressed(w, widgetIndex)) { - RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_FONT_SPRITE_BASE, uint16) = 224; - gfx_draw_string(dpi, (char*)0x009DED72, colour & 0x7F, l, t); - } + // fill it when checkbox is pressed + if (widget_is_pressed(w, widgetIndex)) { + RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_FONT_SPRITE_BASE, uint16) = 224; + gfx_draw_string(dpi, (char*)0x009DED72, colour & 0x7F, l, t); } // draw the text