diff --git a/src/openrct2/drawing/drawing.h b/src/openrct2/drawing/drawing.h index 07f59bca8f..30318873c7 100644 --- a/src/openrct2/drawing/drawing.h +++ b/src/openrct2/drawing/drawing.h @@ -313,8 +313,10 @@ void gfx_filter_rect(rct_drawpixelinfo *dpi, sint32 left, sint32 top, sint32 rig // sprite bool gfx_load_g1(); bool gfx_load_g2(); +bool gfx_load_csg(); void gfx_unload_g1(); void gfx_unload_g2(); +void gfx_unload_csg(); rct_g1_element* gfx_get_g1_element(sint32 image_id); uint32 gfx_object_allocate_images(const rct_g1_element * images, uint32 count); void gfx_object_free_images(uint32 baseImageId, uint32 count); diff --git a/src/openrct2/drawing/sprite.c b/src/openrct2/drawing/sprite.c index 229dc3726a..b46334b487 100644 --- a/src/openrct2/drawing/sprite.c +++ b/src/openrct2/drawing/sprite.c @@ -14,9 +14,10 @@ *****************************************************************************/ #pragma endregion -#include "../rct2/addresses.h" #include "../common.h" +#include "../config.h" #include "../OpenRCT2.h" +#include "../rct2/addresses.h" #include "../sprites.h" #include "../util/util.h" #include "drawing.h" @@ -24,6 +25,7 @@ void *_g1Buffer = NULL; rct_gx g2; +rct_gx csg; #ifdef NO_RCT2 rct_g1_element *g1Elements = NULL; @@ -121,6 +123,11 @@ void gfx_unload_g2() SafeFree(g2.elements); } +void gfx_unload_csg() +{ + SafeFree(csg.elements); +} + bool gfx_load_g2() { log_verbose("loading g2 graphics"); @@ -159,6 +166,69 @@ bool gfx_load_g2() return false; } +bool gfx_load_csg() +{ + if (str_is_null_or_empty(gConfigGeneral.rct1_path)) { + return false; + } + + bool success = false; + log_verbose("loading csg graphics"); + + char pathHeader[MAX_PATH]; + safe_strcpy(pathHeader, gConfigGeneral.rct1_path, sizeof(pathHeader)); + safe_strcat_path(pathHeader, "Data", sizeof(pathHeader)); + safe_strcat_path(pathHeader, "csg1i.dat", sizeof(pathHeader)); + + char pathData[MAX_PATH]; + safe_strcpy(pathData, gConfigGeneral.rct1_path, sizeof(pathData)); + safe_strcat_path(pathData, "Data", sizeof(pathData)); + safe_strcat_path(pathData, "csg1.1", sizeof(pathData)); + + SDL_RWops * fileHeader = SDL_RWFromFile(pathHeader, "rb"); + SDL_RWops * fileData = SDL_RWFromFile(pathData, "rb"); + if (fileHeader != NULL && fileData != NULL) { + SDL_RWseek(fileHeader, 0, RW_SEEK_END); + SDL_RWseek(fileData, 0, RW_SEEK_END); + size_t fileHeaderSize = SDL_RWtell(fileHeader); + size_t fileDataSize = SDL_RWtell(fileData); + SDL_RWseek(fileHeader, 0, RW_SEEK_SET); + SDL_RWseek(fileData, 0, RW_SEEK_SET); + + csg.header.num_entries = (uint32)(fileHeaderSize / sizeof(rct_g1_element_32bit)); + csg.header.total_size = (uint32)fileDataSize; + + // Read element headers + csg.elements = malloc(csg.header.num_entries * sizeof(rct_g1_element)); + read_and_convert_gxdat(fileHeader, csg.header.num_entries, csg.elements); + + // Read element data + csg.data = malloc(csg.header.total_size); + SDL_RWread(fileData, csg.data, csg.header.total_size, 1); + + // Fix entry data offsets + for (uint32 i = 0; i < csg.header.num_entries; i++) { + csg.elements[i].offset += (uintptr_t)csg.data; + } + + success = true; + } + + if (fileHeader != NULL) { + SDL_RWclose(fileHeader); + } + if (fileData != NULL) { + SDL_RWclose(fileData); + } + + if (success) { + return true; + } else { + log_error("Unable to load csg graphics"); + return false; + } +} + /** * This function looks like it initialises the 0x009E3CE4 array which references sprites used for background / palette mixing or * something. Further investigation is needed. @@ -548,6 +618,8 @@ rct_g1_element *gfx_get_g1_element(sint32 image_id) { if (image_id < SPR_G2_BEGIN) { return &g1Elements[image_id]; } - - return &g2.elements[image_id - SPR_G2_BEGIN]; + if (image_id < SPR_CSG_BEGIN) { + return &g2.elements[image_id - SPR_G2_BEGIN]; + } + return &csg.elements[image_id - SPR_CSG_BEGIN]; } diff --git a/src/openrct2/paint/map_element/surface.c b/src/openrct2/paint/map_element/surface.c index efd72b9d23..eed18a058d 100644 --- a/src/openrct2/paint/map_element/surface.c +++ b/src/openrct2/paint/map_element/surface.c @@ -19,6 +19,7 @@ #include "../../interface/viewport.h" #include "../../peep/staff.h" #include "../../rct2.h" +#include "../../sprites.h" #include "map_element.h" #include "surface.h" @@ -182,18 +183,43 @@ const uint8 byte_97B5B0[] = { 10, 11, 12, 13, 14, 14 }; -const uint32 stru_97B5C0[][5] = { - {1579, 1599, 1589, 1609, 0}, - {1747, 1767, 1757, 1777, 1}, - {1663, 1683, 1673, 1693, 2}, - {1831, 1851, 1841, 1861, 3}, +#define DEFINE_EDGE_SPRITES(base) { \ + (base) + 0, \ + (base) + 20, \ + (base) + 10, \ + (base) + 30, \ +} +#define DEFINE_EDGE_TUNNEL_SPRITES(base) { \ + (base) + 36, \ + (base) + 40, \ + (base) + 44, \ + (base) + 48, \ + (base) + 52, \ + (base) + 56, \ + (base) + 60, \ + (base) + 64, \ + (base) + 68, \ + (base) + 72, \ + (base) + 76, \ + (base) + 80, \ + (base) + 36, \ + (base) + 48, \ + (base) + 60, \ + (base) + 72, \ +} + +static const uint32 _terrainEdgeSpriteIds[][4] = { + DEFINE_EDGE_SPRITES(SPR_EDGE_ROCK_BASE), + DEFINE_EDGE_SPRITES(SPR_EDGE_WOOD_RED_BASE), + DEFINE_EDGE_SPRITES(SPR_EDGE_WOOD_BLACK_BASE), + DEFINE_EDGE_SPRITES(SPR_EDGE_ICE_BASE), }; -const uint32 stru_97B640[][16] = { - {1615, 1619, 1623, 1627, 1631, 1635, 1639, 1643, 1647, 1651, 1655, 1659, 1615, 1627, 1639, 1651}, - {1783, 1787, 1791, 1795, 1799, 1803, 1807, 1811, 1815, 1819, 1823, 1827, 1783, 1795, 1807, 1819}, - {1699, 1703, 1707, 1711, 1715, 1719, 1723, 1727, 1731, 1735, 1739, 1743, 1699, 1711, 1723, 1735}, - {1867, 1871, 1875, 1879, 1883, 1887, 1891, 1895, 1899, 1903, 1907, 1911, 1867, 1879, 1891, 1903}, +static const uint32 _terrainEdgeTunnelSpriteIds[][16] = { + DEFINE_EDGE_TUNNEL_SPRITES(SPR_EDGE_ROCK_BASE), + DEFINE_EDGE_TUNNEL_SPRITES(SPR_EDGE_WOOD_RED_BASE), + DEFINE_EDGE_TUNNEL_SPRITES(SPR_EDGE_WOOD_BLACK_BASE), + DEFINE_EDGE_TUNNEL_SPRITES(SPR_EDGE_ICE_BASE), }; const uint8 byte_97B740[] = { @@ -479,13 +505,13 @@ static void viewport_surface_draw_land_side_top(enum edge_t edge, uint8 height, if (!(gCurrentViewportFlags & VIEWPORT_FLAG_UNDERGROUND_INSIDE)) { uint8 incline = (regs.cl - regs.al) + 1; - uint32 image_id = stru_97B5C0[terrain][3] + (edge == EDGE_TOPLEFT ? 3 : 0) + incline; // var_c; + uint32 image_id = _terrainEdgeSpriteIds[terrain][3] + (edge == EDGE_TOPLEFT ? 3 : 0) + incline; // var_c; sint16 y = (regs.dl - regs.al) * 16; paint_attach_to_previous_ps(image_id, 0, y); return; } - uint32 base_image_id = stru_97B5C0[terrain][1] + (edge == EDGE_TOPLEFT ? 5 : 0); // var_04 + uint32 base_image_id = _terrainEdgeSpriteIds[terrain][1] + (edge == EDGE_TOPLEFT ? 5 : 0); // var_04 const uint8 rotation = get_current_rotation(); uint8 cur_height = min(regs.ch, regs.ah); @@ -580,9 +606,9 @@ static void viewport_surface_draw_land_side_bottom(enum edge_t edge, uint8 heigh return; } - uint32 base_image_id = stru_97B5C0[edgeStyle][0]; + uint32 base_image_id = _terrainEdgeSpriteIds[edgeStyle][0]; if (gCurrentViewportFlags & VIEWPORT_FLAG_UNDERGROUND_INSIDE) { - base_image_id = stru_97B5C0[edgeStyle][1]; + base_image_id = _terrainEdgeSpriteIds[edgeStyle][1]; } if (edge == EDGE_BOTTOMRIGHT) { @@ -661,7 +687,7 @@ static void viewport_surface_draw_land_side_bottom(enum edge_t edge, uint8 heigh } - uint32 image_id = stru_97B640[edgeStyle][tunnelType] + (edge == EDGE_BOTTOMRIGHT ? 2 : 0); + uint32 image_id = _terrainEdgeTunnelSpriteIds[edgeStyle][tunnelType] + (edge == EDGE_BOTTOMRIGHT ? 2 : 0); sub_98197C(image_id, offset.x, offset.y, tunnelBounds.x, tunnelBounds.y, boundBoxLength - 1, zOffset, 0, 0, boundBoxOffsetZ, rotation); @@ -673,7 +699,7 @@ static void viewport_surface_draw_land_side_bottom(enum edge_t edge, uint8 heigh boundBoxLength -= 16; } - image_id = stru_97B640[edgeStyle][tunnelType] + (edge == EDGE_BOTTOMRIGHT ? 2 : 0) + 1; + image_id = _terrainEdgeTunnelSpriteIds[edgeStyle][tunnelType] + (edge == EDGE_BOTTOMRIGHT ? 2 : 0) + 1; sub_98197C(image_id, offset.x, offset.y, tunnelBounds.x, tunnelBounds.y, boundBoxLength - 1, curHeight * 16, tunnelTopBoundBoxOffset.x, tunnelTopBoundBoxOffset.y, boundBoxOffsetZ, rotation); curHeight += stru_97B570[tunnelType][0]; @@ -741,10 +767,10 @@ static void viewport_surface_draw_water_side_top(enum edge_t edge, uint8 height, return; } - uint32 base_image_id = stru_97B5C0[terrain][2]; // var_08 + uint32 base_image_id = _terrainEdgeSpriteIds[terrain][2]; // var_08 if (gCurrentViewportFlags & VIEWPORT_FLAG_UNDERGROUND_INSIDE) { - base_image_id = stru_97B5C0[terrain][1]; // var_04 + base_image_id = _terrainEdgeSpriteIds[terrain][1]; // var_04 } base_image_id += (edge == EDGE_TOPLEFT ? 5 : 0); @@ -852,9 +878,9 @@ static void viewport_surface_draw_water_side_bottom(enum edge_t edge, uint8 heig return; } - uint32 base_image_id = stru_97B5C0[edgeStyle][0]; + uint32 base_image_id = _terrainEdgeSpriteIds[edgeStyle][0]; if (gCurrentViewportFlags & VIEWPORT_FLAG_UNDERGROUND_INSIDE) { - base_image_id = stru_97B5C0[edgeStyle][1]; + base_image_id = _terrainEdgeSpriteIds[edgeStyle][1]; } if (edge == EDGE_BOTTOMRIGHT) { @@ -931,7 +957,7 @@ static void viewport_surface_draw_water_side_bottom(enum edge_t edge, uint8 heig } - uint32 image_id = stru_97B640[edgeStyle][tunnelType] + (edge == EDGE_BOTTOMRIGHT ? 2 : 0); + uint32 image_id = _terrainEdgeTunnelSpriteIds[edgeStyle][tunnelType] + (edge == EDGE_BOTTOMRIGHT ? 2 : 0); sub_98197C(image_id, offset.x, offset.y, tunnelBounds.x, tunnelBounds.y, boundBoxLength - 1, zOffset, 0, 0, boundBoxOffsetZ, rotation); @@ -943,7 +969,7 @@ static void viewport_surface_draw_water_side_bottom(enum edge_t edge, uint8 heig boundBoxLength -= 16; } - image_id = stru_97B640[edgeStyle][tunnelType] + (edge == EDGE_BOTTOMRIGHT ? 2 : 0) + 1; + image_id = _terrainEdgeTunnelSpriteIds[edgeStyle][tunnelType] + (edge == EDGE_BOTTOMRIGHT ? 2 : 0) + 1; sub_98197C(image_id, offset.x, offset.y, tunnelBounds.x, tunnelBounds.y, boundBoxLength - 1, curHeight * 16, tunnelTopBoundBoxOffset.x, tunnelTopBoundBoxOffset.y, boundBoxOffsetZ, rotation); curHeight += stru_97B570[tunnelType][0]; @@ -1177,7 +1203,7 @@ void surface_paint(uint8 direction, uint16 height, rct_map_element * mapElement) } if (gCurrentViewportFlags & VIEWPORT_FLAG_CONSTRUCTION_RIGHTS - && !(mapElement->properties.surface.ownership & OWNERSHIP_OWNED)) { + && !(mapElement->properties.surface.ownership & OWNERSHIP_OWNED)) { if (mapElement->properties.surface.ownership & OWNERSHIP_CONSTRUCTION_RIGHTS_OWNED) { assert(surfaceShape < countof(byte_97B444)); // TODO: SPR_TERRAIN_SELECTION_DOTTED ??? @@ -1236,7 +1262,7 @@ void surface_paint(uint8 direction, uint16 height, rct_map_element * mapElement) local_height += 16; if (waterHeight != local_height - || !(local_surfaceShape & 0x10)) { + || !(local_surfaceShape & 0x10)) { local_height = waterHeight; local_surfaceShape = 0; } else { @@ -1279,10 +1305,10 @@ void surface_paint(uint8 direction, uint16 height, rct_map_element * mapElement) } if (zoomLevel == 0 - && has_surface - && !(gCurrentViewportFlags & VIEWPORT_FLAG_UNDERGROUND_INSIDE) - && !(gCurrentViewportFlags & VIEWPORT_FLAG_HIDE_BASE) - && gConfigGeneral.landscape_smoothing) { + && has_surface + && !(gCurrentViewportFlags & VIEWPORT_FLAG_UNDERGROUND_INSIDE) + && !(gCurrentViewportFlags & VIEWPORT_FLAG_HIDE_BASE) + && gConfigGeneral.landscape_smoothing) { viewport_surface_smoothen_edge(EDGE_TOPLEFT, tileDescriptors[0], tileDescriptors[3]); viewport_surface_smoothen_edge(EDGE_TOPRIGHT, tileDescriptors[0], tileDescriptors[4]); viewport_surface_smoothen_edge(EDGE_BOTTOMLEFT, tileDescriptors[0], tileDescriptors[1]); @@ -1291,8 +1317,8 @@ void surface_paint(uint8 direction, uint16 height, rct_map_element * mapElement) if (gCurrentViewportFlags & VIEWPORT_FLAG_UNDERGROUND_INSIDE - && !(gCurrentViewportFlags & VIEWPORT_FLAG_HIDE_BASE) - && !(gScreenFlags & (SCREEN_FLAGS_TRACK_DESIGNER | SCREEN_FLAGS_TRACK_MANAGER))) { + && !(gCurrentViewportFlags & VIEWPORT_FLAG_HIDE_BASE) + && !(gScreenFlags & (SCREEN_FLAGS_TRACK_DESIGNER | SCREEN_FLAGS_TRACK_MANAGER))) { uint8 image_offset = byte_97B444[surfaceShape]; uint32 base_image = terrain_type; diff --git a/src/openrct2/rct2.c b/src/openrct2/rct2.c index 09693b6ea3..c3e14c80f6 100644 --- a/src/openrct2/rct2.c +++ b/src/openrct2/rct2.c @@ -167,6 +167,7 @@ bool rct2_init() if (!gfx_load_g2()) { return false; } + gfx_load_csg(); font_sprite_initialise_characters(); if (!gOpenRCT2Headless) { diff --git a/src/openrct2/sprites.h b/src/openrct2/sprites.h index fd90623303..e3b0142de6 100644 --- a/src/openrct2/sprites.h +++ b/src/openrct2/sprites.h @@ -23,6 +23,11 @@ enum { SPR_SCROLLING_TEXT_START = 1542, SPR_SCROLLING_TEXT_DEFAULT = 1574, + SPR_EDGE_ROCK_BASE = 1579, + SPR_EDGE_WOOD_RED_BASE = 1747, + SPR_EDGE_WOOD_BLACK_BASE = 1663, + SPR_EDGE_ICE_BASE = 1831, + SPR_PALETTE_1_START = 3100, SPR_PALETTE_1_END = 3110, @@ -746,6 +751,22 @@ enum { SPR_G2_SORT = SPR_G2_BEGIN + 77, SPR_G2_COPY = SPR_G2_BEGIN + 78, SPR_G2_PASTE = SPR_G2_BEGIN + 79, + + // 0x60000, chosen because it's a round hex number + // of the last possible range of image ID values that is large enough to fit all csg1 sprites. + SPR_CSG_BEGIN = 393216, + + SPR_CSG_EDGE_BRICK_BASE = SPR_CSG_BEGIN + 40506, + SPR_CSG_EDGE_IRON_BASE = SPR_CSG_BEGIN + 40590, + SPR_CSG_EDGE_RED_BASE = SPR_CSG_BEGIN + 40926, + SPR_CSG_EDGE_YELLOW_BASE = SPR_CSG_BEGIN + 41030, + SPR_CSG_EDGE_GREY_BASE = SPR_CSG_BEGIN + 41134, + SPR_CSG_EDGE_PURPLE_BASE = SPR_CSG_BEGIN + 41238, + SPR_CSG_EDGE_GREEN_BASE = SPR_CSG_BEGIN + 41342, + SPR_CSG_EDGE_STONE_BROWN_BASE = SPR_CSG_BEGIN + 41446, + SPR_CSG_EDGE_STONE_GREY_BASE = SPR_CSG_BEGIN + 41550, + SPR_CSG_EDGE_SKYSCRAPER_A_BASE = SPR_CSG_BEGIN + 41654, + SPR_CSG_EDGE_SKYSCRAPER_B_BASE = SPR_CSG_BEGIN + 41758, }; #endif