From efded3e0d2da12b4db4e4655234e4190d475d4b5 Mon Sep 17 00:00:00 2001 From: Hielke Morsink Date: Mon, 14 May 2018 17:37:31 +0200 Subject: [PATCH] Always paint edges for tiles next to tiles that don't get drawn This also makes it so that when a surface is cut off by the clip height, the neighbour tiles will draw the edges too, making the surface appear as a pit instead of a blank tile. I've renamed some of the variables and added a few comments to make the code easier to understand. I've also left a todo comment for a future improvement - the current call isn't expensive so it won't become a bottleneck in the meantime. --- src/openrct2/paint/tile_element/Surface.cpp | 77 +++++++++++++-------- 1 file changed, 48 insertions(+), 29 deletions(-) diff --git a/src/openrct2/paint/tile_element/Surface.cpp b/src/openrct2/paint/tile_element/Surface.cpp index f6f695fa14..e05db91508 100644 --- a/src/openrct2/paint/tile_element/Surface.cpp +++ b/src/openrct2/paint/tile_element/Surface.cpp @@ -19,6 +19,7 @@ #include "../../OpenRCT2.h" #include "../../Cheats.h" #include "../../config/Config.h" +#include "../../core/Guard.hpp" #include "../../core/Math.hpp" #include "../../core/Util.hpp" #include "../../drawing/Drawing.h" @@ -424,6 +425,7 @@ static constexpr const uint32 dword_97B898[][2] = struct tile_descriptor { + TileCoordsXY tile_coords; const rct_tile_element * tile_element; uint8 terrain; uint8 slope; @@ -612,12 +614,26 @@ static void viewport_surface_smoothen_edge(paint_session * session, enum edge_t } } +static bool tile_is_inside_clip_view(const tile_descriptor& tile) +{ + Guard::ArgumentNotNull(tile.tile_element); + + if (tile.tile_element->base_height > gClipHeight) + return false; + if (tile.tile_coords.x < gClipSelectionA.x || tile.tile_coords.x > gClipSelectionB.x) + return false; + if (tile.tile_coords.y < gClipSelectionA.y || tile.tile_coords.y > gClipSelectionB.y) + return false; + + return true; +} + static void viewport_surface_draw_tile_side_bottom(paint_session * session, enum edge_t edge, uint8 height, uint8 edgeStyle, struct tile_descriptor self, struct tile_descriptor neighbour, bool isWater) { if (!is_csg_loaded() && edgeStyle >= TERRAIN_EDGE_RCT2_COUNT) edgeStyle = TERRAIN_EDGE_ROCK; - sint16 al, ah, cl, ch, dl = 0, dh; + sint16 cornerHeight1, neighbourCornerHeight1, cornerHeight2, neighbourCornerHeight2; LocationXY8 offset = { 0, 0 }; LocationXY8 bounds = { 0, 0 }; @@ -628,11 +644,11 @@ static void viewport_surface_draw_tile_side_bottom(paint_session * session, enum switch (edge) { case EDGE_BOTTOMLEFT: - al = self.corner_heights.left; - cl = self.corner_heights.bottom; + cornerHeight1 = self.corner_heights.left; + cornerHeight2 = self.corner_heights.bottom; - ah = neighbour.corner_heights.top; - ch = neighbour.corner_heights.right; + neighbourCornerHeight1 = neighbour.corner_heights.top; + neighbourCornerHeight2 = neighbour.corner_heights.right; offset.x = 30; bounds.y = 30; @@ -643,11 +659,11 @@ static void viewport_surface_draw_tile_side_bottom(paint_session * session, enum break; case EDGE_BOTTOMRIGHT: - al = self.corner_heights.right; - cl = self.corner_heights.bottom; + cornerHeight1 = self.corner_heights.right; + cornerHeight2 = self.corner_heights.bottom; - ah = neighbour.corner_heights.top; - ch = neighbour.corner_heights.left; + neighbourCornerHeight1 = neighbour.corner_heights.top; + neighbourCornerHeight2 = neighbour.corner_heights.left; offset.y = 30; bounds.x = 30; @@ -661,31 +677,32 @@ static void viewport_surface_draw_tile_side_bottom(paint_session * session, enum return; } - if (isWater) - dl = height; - - if (neighbour.tile_element == nullptr) + // TODO: Check the viewport flag for view clipping instead of calling `tile_is_inside_clip_view(self)` + if (neighbour.tile_element == nullptr || (tile_is_inside_clip_view(self) && !tile_is_inside_clip_view(neighbour))) { - ch = 1; - ah = 1; + // The neigbour tile doesn't exist or isn't drawn - assume minimum height to draw full edges + neighbourCornerHeight2 = MINIMUM_LAND_HEIGHT / 2; + neighbourCornerHeight1 = MINIMUM_LAND_HEIGHT / 2; } else { if (isWater) { - dh = surface_get_water_height(neighbour.tile_element); - if (dl == dh) + uint8 waterHeight = surface_get_water_height(neighbour.tile_element); + if (waterHeight == height) { + // Don't draw the edge when the neighbour's water level is the same return; } - al = dl; - cl = dl; + cornerHeight1 = height; + cornerHeight2 = height; } } - if (al <= ah && cl <= ch) + if (cornerHeight1 <= neighbourCornerHeight1 && cornerHeight2 <= neighbourCornerHeight2) { + // The edge is not visible behind the neighbour's slope return; } @@ -703,18 +720,18 @@ static void viewport_surface_draw_tile_side_bottom(paint_session * session, enum base_image_id += 5; } - uint8 curHeight = Math::Min(ah, ch); - if (ch != ah) + uint8 curHeight = Math::Min(neighbourCornerHeight1, neighbourCornerHeight2); + if (neighbourCornerHeight2 != neighbourCornerHeight1) { // If bottom part of edge isn't straight, add a filler uint32 image_offset = 3; - if (ch >= ah) + if (neighbourCornerHeight2 >= neighbourCornerHeight1) { image_offset = 4; } - if (curHeight != al && curHeight != cl) + if (curHeight != cornerHeight1 && curHeight != cornerHeight2) { uint32 image_id = base_image_id + image_offset; sub_98196C(session, image_id, offset.x, offset.y, bounds.x, bounds.y, 15, curHeight * 16); @@ -722,19 +739,19 @@ static void viewport_surface_draw_tile_side_bottom(paint_session * session, enum } } - ah = cl; + neighbourCornerHeight1 = cornerHeight2; for(uint32 tunnelIndex = 0; tunnelIndex < TUNNEL_MAX_COUNT;) { - if (curHeight >= al || curHeight >= cl) + if (curHeight >= cornerHeight1 || curHeight >= cornerHeight2) { // If top of edge isn't straight, add a filler uint32 image_offset = 1; - if (curHeight >= al) + if (curHeight >= cornerHeight1) { image_offset = 2; - if (curHeight >= cl) + if (curHeight >= cornerHeight2) { return; } @@ -768,7 +785,7 @@ static void viewport_surface_draw_tile_side_bottom(paint_session * session, enum uint8 tunnelHeight = _tunnelHeights[tunnelType][0]; sint16 zOffset = curHeight; - if ((zOffset + tunnelHeight) > ah || (zOffset + tunnelHeight) > al) + if ((zOffset + tunnelHeight) > neighbourCornerHeight1 || (zOffset + tunnelHeight) > cornerHeight1) { tunnelType = byte_97B5B0[tunnelType]; } @@ -1000,6 +1017,7 @@ void surface_paint(paint_session * session, uint8 direction, uint16 height, cons tile_descriptor selfDescriptor = { + { base.x / 32, base.y / 32 }, tileElement, (uint8)terrain_type, surfaceShape, @@ -1041,6 +1059,7 @@ void surface_paint(paint_session * session, uint8 direction, uint16 height, cons const uint8 baseHeight = surfaceElement->base_height / 2; const corner_height& ch = corner_heights[surfaceSlope]; + descriptor.tile_coords = { position.x / 32, position.y / 32 }; descriptor.tile_element = surfaceElement; descriptor.terrain = surface_get_terrain(surfaceElement); descriptor.slope = surfaceSlope;