2016-05-01 17:01:40 +02:00
|
|
|
/*****************************************************************************
|
2020-07-21 15:04:34 +02:00
|
|
|
* Copyright (c) 2014-2020 OpenRCT2 developers
|
2016-05-05 20:29:49 +02:00
|
|
|
*
|
2018-06-15 14:07:34 +02:00
|
|
|
* For a complete list of all authors, please refer to contributors.md
|
|
|
|
* Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2
|
2016-05-05 20:29:49 +02:00
|
|
|
*
|
2018-06-15 14:07:34 +02:00
|
|
|
* OpenRCT2 is licensed under the GNU General Public License version 3.
|
2016-05-05 20:29:49 +02:00
|
|
|
*****************************************************************************/
|
2016-05-01 17:01:40 +02:00
|
|
|
|
2018-06-22 23:03:53 +02:00
|
|
|
#include "Paint.TileElement.h"
|
|
|
|
|
|
|
|
#include "../../Game.h"
|
|
|
|
#include "../../Input.h"
|
2017-12-14 10:34:12 +01:00
|
|
|
#include "../../config/Config.h"
|
2018-01-05 22:17:33 +01:00
|
|
|
#include "../../drawing/Drawing.h"
|
2018-01-06 00:45:53 +01:00
|
|
|
#include "../../interface/Viewport.h"
|
2018-01-06 18:32:25 +01:00
|
|
|
#include "../../localisation/Localisation.h"
|
2018-01-10 00:00:09 +01:00
|
|
|
#include "../../ride/RideData.h"
|
2017-10-16 12:02:23 +02:00
|
|
|
#include "../../ride/TrackData.h"
|
2018-01-10 00:00:09 +01:00
|
|
|
#include "../../ride/TrackPaint.h"
|
2018-06-22 23:03:53 +02:00
|
|
|
#include "../../sprites.h"
|
2017-12-14 10:34:12 +01:00
|
|
|
#include "../../world/Banner.h"
|
|
|
|
#include "../../world/Entrance.h"
|
2018-01-11 10:59:26 +01:00
|
|
|
#include "../../world/Footpath.h"
|
|
|
|
#include "../../world/Scenery.h"
|
2018-06-22 23:03:53 +02:00
|
|
|
#include "../../world/Sprite.h"
|
2018-05-01 16:33:16 +02:00
|
|
|
#include "../../world/Surface.h"
|
2017-12-14 10:34:12 +01:00
|
|
|
#include "../Paint.h"
|
|
|
|
#include "../Supports.h"
|
2018-01-06 20:29:44 +01:00
|
|
|
#include "../VirtualFloor.h"
|
2018-06-01 00:16:53 +02:00
|
|
|
#include "Paint.Surface.h"
|
2017-12-14 10:34:12 +01:00
|
|
|
|
2018-08-12 13:50:40 +02:00
|
|
|
#include <algorithm>
|
|
|
|
|
2017-01-17 23:57:53 +01:00
|
|
|
#ifdef __TESTPAINT__
|
2018-06-20 17:28:51 +02:00
|
|
|
uint16_t testPaintVerticalTunnelHeight;
|
2017-01-17 23:57:53 +01:00
|
|
|
#endif
|
|
|
|
|
2018-06-22 23:03:53 +02:00
|
|
|
static void blank_tiles_paint(paint_session* session, int32_t x, int32_t y);
|
|
|
|
static void sub_68B3FB(paint_session* session, int32_t x, int32_t y);
|
2016-05-01 17:01:40 +02:00
|
|
|
|
2018-07-21 11:50:45 +02:00
|
|
|
const int32_t SEGMENTS_ALL = SEGMENT_B4 | SEGMENT_B8 | SEGMENT_BC | SEGMENT_C0 | SEGMENT_C4 | SEGMENT_C8 | SEGMENT_CC
|
|
|
|
| SEGMENT_D0 | SEGMENT_D4;
|
2016-05-17 23:04:37 +02:00
|
|
|
|
2016-05-01 17:01:40 +02:00
|
|
|
/**
|
|
|
|
*
|
|
|
|
* rct2: 0x0068B35F
|
|
|
|
*/
|
2018-06-22 23:03:53 +02:00
|
|
|
void tile_element_paint_setup(paint_session* session, int32_t x, int32_t y)
|
2016-05-01 17:01:40 +02:00
|
|
|
{
|
2018-06-22 23:03:53 +02:00
|
|
|
if (x < gMapSizeUnits && y < gMapSizeUnits && x >= 32 && y >= 32)
|
|
|
|
{
|
2017-09-03 02:56:56 +02:00
|
|
|
paint_util_set_segment_support_height(session, SEGMENTS_ALL, 0xFFFF, 0);
|
|
|
|
paint_util_force_set_general_support_height(session, -1, 0);
|
2017-09-02 21:25:03 +02:00
|
|
|
session->Unk141E9DB = 0;
|
2018-01-29 20:25:56 +01:00
|
|
|
session->WaterHeight = 0xFFFF;
|
2017-06-06 23:24:18 +02:00
|
|
|
|
2017-09-02 23:15:09 +02:00
|
|
|
sub_68B3FB(session, x, y);
|
2018-06-22 23:03:53 +02:00
|
|
|
}
|
2019-05-30 14:34:20 +02:00
|
|
|
else if (!(session->ViewFlags & VIEWPORT_FLAG_TRANSPARENT_BACKGROUND))
|
2018-06-22 23:03:53 +02:00
|
|
|
{
|
2017-09-02 23:15:09 +02:00
|
|
|
blank_tiles_paint(session, x, y);
|
2017-06-06 23:24:18 +02:00
|
|
|
}
|
2016-05-01 17:01:40 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
*
|
|
|
|
* rct2: 0x0068B2B7
|
|
|
|
*/
|
2020-02-13 10:25:42 +01:00
|
|
|
void sub_68B2B7(paint_session* session, const CoordsXY& mapCoords)
|
2016-05-01 17:01:40 +02:00
|
|
|
{
|
2019-11-17 17:32:19 +01:00
|
|
|
if (mapCoords.x < gMapSizeUnits && mapCoords.y < gMapSizeUnits && mapCoords.x >= 32 && mapCoords.y >= 32)
|
2018-06-22 23:03:53 +02:00
|
|
|
{
|
2017-09-03 02:56:56 +02:00
|
|
|
paint_util_set_segment_support_height(session, SEGMENTS_ALL, 0xFFFF, 0);
|
|
|
|
paint_util_force_set_general_support_height(session, -1, 0);
|
2018-01-29 20:25:56 +01:00
|
|
|
session->WaterHeight = 0xFFFF;
|
2017-09-02 23:15:09 +02:00
|
|
|
session->Unk141E9DB = G141E9DB_FLAG_2;
|
2017-06-06 23:24:18 +02:00
|
|
|
|
2019-11-17 17:32:19 +01:00
|
|
|
sub_68B3FB(session, mapCoords.x, mapCoords.y);
|
2018-06-22 23:03:53 +02:00
|
|
|
}
|
2019-05-30 14:34:20 +02:00
|
|
|
else if (!(session->ViewFlags & VIEWPORT_FLAG_TRANSPARENT_BACKGROUND))
|
2018-06-22 23:03:53 +02:00
|
|
|
{
|
2019-11-17 17:32:19 +01:00
|
|
|
blank_tiles_paint(session, mapCoords.x, mapCoords.y);
|
2017-06-06 23:24:18 +02:00
|
|
|
}
|
2016-05-01 17:01:40 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
*
|
|
|
|
* rct2: 0x0068B60E
|
|
|
|
*/
|
2018-06-22 23:03:53 +02:00
|
|
|
static void blank_tiles_paint(paint_session* session, int32_t x, int32_t y)
|
2016-05-01 17:01:40 +02:00
|
|
|
{
|
2018-06-20 17:28:51 +02:00
|
|
|
int32_t dx = 0;
|
2018-02-12 23:25:46 +01:00
|
|
|
switch (session->CurrentRotation)
|
|
|
|
{
|
2018-06-22 23:03:53 +02:00
|
|
|
case 0:
|
|
|
|
dx = x + y;
|
|
|
|
break;
|
|
|
|
case 1:
|
|
|
|
x += 32;
|
|
|
|
dx = y - x;
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
x += 32;
|
|
|
|
y += 32;
|
|
|
|
dx = -(x + y);
|
|
|
|
break;
|
|
|
|
case 3:
|
|
|
|
y += 32;
|
|
|
|
dx = x - y;
|
|
|
|
break;
|
2017-06-06 23:24:18 +02:00
|
|
|
}
|
|
|
|
dx /= 2;
|
|
|
|
dx -= 16;
|
2018-06-20 17:28:51 +02:00
|
|
|
int32_t bx = dx + 32;
|
2017-09-02 23:15:09 +02:00
|
|
|
|
2018-12-18 16:40:28 +01:00
|
|
|
rct_drawpixelinfo* dpi = &session->DPI;
|
2018-06-22 23:03:53 +02:00
|
|
|
if (bx <= dpi->y)
|
|
|
|
return;
|
2017-06-06 23:24:18 +02:00
|
|
|
dx -= 20;
|
|
|
|
dx -= dpi->height;
|
2018-06-22 23:03:53 +02:00
|
|
|
if (dx >= dpi->y)
|
|
|
|
return;
|
2017-09-02 23:15:09 +02:00
|
|
|
|
|
|
|
session->SpritePosition.x = x;
|
|
|
|
session->SpritePosition.y = y;
|
2020-12-29 19:09:15 +01:00
|
|
|
session->InteractionType = ViewportInteractionItem::None;
|
2020-10-23 08:54:32 +02:00
|
|
|
PaintAddImageAsParent(session, SPR_BLANK_TILE, 0, 0, 32, 32, -1, 16);
|
2016-05-01 17:01:40 +02:00
|
|
|
}
|
|
|
|
|
2016-05-23 11:29:11 +02:00
|
|
|
bool gShowSupportSegmentHeights = false;
|
|
|
|
|
2016-05-01 17:01:40 +02:00
|
|
|
/**
|
|
|
|
*
|
|
|
|
* rct2: 0x0068B3FB
|
|
|
|
*/
|
2018-06-22 23:03:53 +02:00
|
|
|
static void sub_68B3FB(paint_session* session, int32_t x, int32_t y)
|
2016-05-01 17:01:40 +02:00
|
|
|
{
|
2018-12-18 16:40:28 +01:00
|
|
|
rct_drawpixelinfo* dpi = &session->DPI;
|
2016-09-07 13:26:53 +02:00
|
|
|
|
2018-12-05 19:29:51 +01:00
|
|
|
if ((session->ViewFlags & VIEWPORT_FLAG_CLIP_VIEW))
|
2018-05-08 01:25:05 +02:00
|
|
|
{
|
2020-03-07 21:07:18 +01:00
|
|
|
if (x < gClipSelectionA.x || x > gClipSelectionB.x)
|
2018-05-08 01:25:05 +02:00
|
|
|
return;
|
2020-03-07 21:07:18 +01:00
|
|
|
if (y < gClipSelectionA.y || y > gClipSelectionB.y)
|
2018-05-08 01:25:05 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2017-09-02 23:15:09 +02:00
|
|
|
session->LeftTunnelCount = 0;
|
|
|
|
session->RightTunnelCount = 0;
|
2018-06-22 23:03:53 +02:00
|
|
|
session->LeftTunnels[0] = { 0xFF, 0xFF };
|
|
|
|
session->RightTunnels[0] = { 0xFF, 0xFF };
|
2017-09-02 23:15:09 +02:00
|
|
|
session->VerticalTunnelHeight = 0xFF;
|
|
|
|
session->MapPosition.x = x;
|
|
|
|
session->MapPosition.y = y;
|
2017-06-06 23:24:18 +02:00
|
|
|
|
2020-02-13 10:56:46 +01:00
|
|
|
TileElement* tile_element = map_get_first_element_at(session->MapPosition);
|
2019-10-09 16:02:21 +02:00
|
|
|
if (tile_element == nullptr)
|
|
|
|
return;
|
2018-06-22 23:03:53 +02:00
|
|
|
uint8_t rotation = session->CurrentRotation;
|
2017-06-06 23:24:18 +02:00
|
|
|
|
2017-10-06 19:21:58 +02:00
|
|
|
bool partOfVirtualFloor = false;
|
|
|
|
#ifndef __TESTPAINT__
|
2020-08-28 02:06:39 +02:00
|
|
|
if (gConfigGeneral.virtual_floor_style != VirtualFloorStyles::Off)
|
2018-01-10 15:05:05 +01:00
|
|
|
{
|
2020-02-18 22:42:38 +01:00
|
|
|
partOfVirtualFloor = virtual_floor_tile_is_floor(session->MapPosition);
|
2018-01-10 15:05:05 +01:00
|
|
|
}
|
2017-10-06 19:21:58 +02:00
|
|
|
#endif // __TESTPAINT__
|
|
|
|
|
2018-06-20 17:28:51 +02:00
|
|
|
int32_t dx = 0;
|
2018-06-22 23:03:53 +02:00
|
|
|
switch (rotation)
|
|
|
|
{
|
|
|
|
case 0:
|
|
|
|
dx = x + y;
|
|
|
|
break;
|
|
|
|
case 1:
|
|
|
|
x += 32;
|
|
|
|
dx = y - x;
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
x += 32;
|
|
|
|
y += 32;
|
|
|
|
dx = -(x + y);
|
|
|
|
break;
|
|
|
|
case 3:
|
|
|
|
y += 32;
|
|
|
|
dx = x - y;
|
|
|
|
break;
|
2017-06-06 23:24:18 +02:00
|
|
|
}
|
|
|
|
dx >>= 1;
|
|
|
|
// Display little yellow arrow when building footpaths?
|
2018-06-22 23:03:53 +02:00
|
|
|
if ((gMapSelectFlags & MAP_SELECT_FLAG_ENABLE_ARROW) && session->MapPosition.x == gMapSelectArrowPosition.x
|
|
|
|
&& session->MapPosition.y == gMapSelectArrowPosition.y)
|
|
|
|
{
|
|
|
|
uint8_t arrowRotation = (rotation + (gMapSelectArrowDirection & 3)) & 3;
|
|
|
|
|
|
|
|
uint32_t imageId = arrowRotation + (gMapSelectArrowDirection & 0xFC) + 0x20900C27;
|
2018-06-20 17:28:51 +02:00
|
|
|
int32_t arrowZ = gMapSelectArrowPosition.z;
|
2017-06-06 23:24:18 +02:00
|
|
|
|
2017-09-02 23:15:09 +02:00
|
|
|
session->SpritePosition.x = x;
|
|
|
|
session->SpritePosition.y = y;
|
2020-12-29 19:09:15 +01:00
|
|
|
session->InteractionType = ViewportInteractionItem::None;
|
2017-06-06 23:24:18 +02:00
|
|
|
|
2020-10-22 19:18:30 +02:00
|
|
|
PaintAddImageAsParent(session, imageId, 0, 0, 32, 32, -1, arrowZ, 0, 0, arrowZ + 18);
|
2017-06-06 23:24:18 +02:00
|
|
|
}
|
2018-06-20 17:28:51 +02:00
|
|
|
int32_t bx = dx + 52;
|
2017-06-06 23:24:18 +02:00
|
|
|
|
|
|
|
if (bx <= dpi->y)
|
|
|
|
return;
|
|
|
|
|
2018-11-01 13:53:50 +01:00
|
|
|
const TileElement* element = tile_element; // push tile_element
|
2017-06-06 23:24:18 +02:00
|
|
|
|
2018-06-20 17:28:51 +02:00
|
|
|
uint16_t max_height = 0;
|
2018-06-22 23:03:53 +02:00
|
|
|
do
|
|
|
|
{
|
2020-04-22 17:09:29 +02:00
|
|
|
max_height = std::max(max_height, static_cast<uint16_t>(element->GetClearanceZ()));
|
2018-05-24 11:44:53 +02:00
|
|
|
} while (!(element++)->IsLastForTile());
|
2017-06-06 23:24:18 +02:00
|
|
|
|
|
|
|
element--;
|
|
|
|
|
2018-09-15 10:56:35 +02:00
|
|
|
if (element->GetType() == TILE_ELEMENT_TYPE_SURFACE && (element->AsSurface()->GetWaterHeight() > 0))
|
2017-07-27 17:15:56 +02:00
|
|
|
{
|
2020-01-19 16:12:48 +01:00
|
|
|
max_height = element->AsSurface()->GetWaterHeight();
|
2017-06-06 23:24:18 +02:00
|
|
|
}
|
|
|
|
|
2017-10-06 21:36:45 +02:00
|
|
|
#ifndef __TESTPAINT__
|
2017-10-06 19:21:58 +02:00
|
|
|
if (partOfVirtualFloor)
|
|
|
|
{
|
|
|
|
// We must pretend this tile is at least as tall as the virtual floor
|
2018-03-04 17:44:42 +01:00
|
|
|
max_height = std::max(max_height, virtual_floor_get_height());
|
2017-10-06 19:21:58 +02:00
|
|
|
}
|
2017-10-06 21:36:45 +02:00
|
|
|
#endif // __TESTPAINT__
|
2017-10-06 19:21:58 +02:00
|
|
|
|
2017-06-06 23:24:18 +02:00
|
|
|
dx -= max_height + 32;
|
|
|
|
|
2018-06-22 23:03:53 +02:00
|
|
|
element = tile_element; // pop tile_element
|
2017-06-06 23:24:18 +02:00
|
|
|
dx -= dpi->height;
|
|
|
|
if (dx >= dpi->y)
|
|
|
|
return;
|
|
|
|
|
2017-09-02 23:15:09 +02:00
|
|
|
session->SpritePosition.x = x;
|
|
|
|
session->SpritePosition.y = y;
|
|
|
|
session->DidPassSurface = false;
|
2019-12-31 09:33:27 +01:00
|
|
|
int32_t previousBaseZ = 0;
|
2018-06-22 23:03:53 +02:00
|
|
|
do
|
|
|
|
{
|
2017-10-31 12:57:40 +01:00
|
|
|
// Only paint tile_elements below the clip height.
|
2020-03-16 21:47:38 +01:00
|
|
|
if ((session->ViewFlags & VIEWPORT_FLAG_CLIP_VIEW) && (tile_element->GetBaseZ() > gClipHeight * COORDS_Z_STEP))
|
2018-03-27 22:00:58 +02:00
|
|
|
continue;
|
2017-06-06 23:24:18 +02:00
|
|
|
|
2019-08-26 12:25:57 +02:00
|
|
|
Direction direction = tile_element->GetDirectionWithOffset(rotation);
|
2019-12-31 09:33:27 +01:00
|
|
|
int32_t baseZ = tile_element->GetBaseZ();
|
2017-06-06 23:24:18 +02:00
|
|
|
|
2019-12-31 09:33:27 +01:00
|
|
|
// If we are on a new baseZ level, look through elements on the
|
|
|
|
// same baseZ and store any types might be relevant to others
|
|
|
|
if (baseZ != previousBaseZ)
|
2017-10-11 18:13:01 +02:00
|
|
|
{
|
2019-12-31 09:33:27 +01:00
|
|
|
previousBaseZ = baseZ;
|
2018-01-04 06:58:44 +01:00
|
|
|
session->PathElementOnSameHeight = nullptr;
|
|
|
|
session->TrackElementOnSameHeight = nullptr;
|
2018-11-01 13:53:50 +01:00
|
|
|
TileElement* tile_element_sub_iterator = tile_element;
|
2018-05-24 11:44:53 +02:00
|
|
|
while (!(tile_element_sub_iterator++)->IsLastForTile())
|
2017-10-11 18:13:01 +02:00
|
|
|
{
|
2019-12-27 15:26:40 +01:00
|
|
|
if (tile_element_sub_iterator->GetBaseZ() != tile_element->GetBaseZ())
|
2017-10-11 18:13:01 +02:00
|
|
|
{
|
|
|
|
break;
|
|
|
|
}
|
2018-05-02 19:27:04 +02:00
|
|
|
switch (tile_element_sub_iterator->GetType())
|
2017-10-11 18:13:01 +02:00
|
|
|
{
|
2018-06-22 23:03:53 +02:00
|
|
|
case TILE_ELEMENT_TYPE_PATH:
|
|
|
|
session->PathElementOnSameHeight = tile_element_sub_iterator;
|
|
|
|
break;
|
|
|
|
case TILE_ELEMENT_TYPE_TRACK:
|
|
|
|
session->TrackElementOnSameHeight = tile_element_sub_iterator;
|
|
|
|
break;
|
|
|
|
case TILE_ELEMENT_TYPE_CORRUPT:
|
|
|
|
// To preserve regular behaviour, make an element hidden by
|
|
|
|
// corruption also invisible to this method.
|
|
|
|
if (tile_element->IsLastForTile())
|
|
|
|
{
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
tile_element_sub_iterator++;
|
2017-10-11 18:13:01 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-10-31 00:19:14 +01:00
|
|
|
CoordsXY mapPosition = session->MapPosition;
|
2017-10-31 12:57:40 +01:00
|
|
|
session->CurrentlyDrawnItem = tile_element;
|
2017-06-06 23:24:18 +02:00
|
|
|
// Setup the painting of for example: the underground, signs, rides, scenery, etc.
|
2018-05-02 19:27:04 +02:00
|
|
|
switch (tile_element->GetType())
|
2017-06-06 23:24:18 +02:00
|
|
|
{
|
2018-06-22 23:03:53 +02:00
|
|
|
case TILE_ELEMENT_TYPE_SURFACE:
|
2019-12-31 09:33:27 +01:00
|
|
|
surface_paint(session, direction, baseZ, tile_element);
|
2018-06-22 23:03:53 +02:00
|
|
|
break;
|
|
|
|
case TILE_ELEMENT_TYPE_PATH:
|
2019-12-31 09:33:27 +01:00
|
|
|
path_paint(session, baseZ, tile_element);
|
2018-06-22 23:03:53 +02:00
|
|
|
break;
|
|
|
|
case TILE_ELEMENT_TYPE_TRACK:
|
2019-12-31 09:33:27 +01:00
|
|
|
track_paint(session, direction, baseZ, tile_element);
|
2018-06-22 23:03:53 +02:00
|
|
|
break;
|
|
|
|
case TILE_ELEMENT_TYPE_SMALL_SCENERY:
|
2019-12-31 09:33:27 +01:00
|
|
|
scenery_paint(session, direction, baseZ, tile_element);
|
2018-06-22 23:03:53 +02:00
|
|
|
break;
|
|
|
|
case TILE_ELEMENT_TYPE_ENTRANCE:
|
2019-12-31 09:33:27 +01:00
|
|
|
entrance_paint(session, direction, baseZ, tile_element);
|
2018-06-22 23:03:53 +02:00
|
|
|
break;
|
|
|
|
case TILE_ELEMENT_TYPE_WALL:
|
2019-12-31 09:33:27 +01:00
|
|
|
fence_paint(session, direction, baseZ, tile_element);
|
2018-06-22 23:03:53 +02:00
|
|
|
break;
|
|
|
|
case TILE_ELEMENT_TYPE_LARGE_SCENERY:
|
2019-12-31 09:33:27 +01:00
|
|
|
large_scenery_paint(session, direction, baseZ, tile_element);
|
2018-06-22 23:03:53 +02:00
|
|
|
break;
|
|
|
|
case TILE_ELEMENT_TYPE_BANNER:
|
2019-12-31 09:33:27 +01:00
|
|
|
banner_paint(session, direction, baseZ, tile_element);
|
2018-06-22 23:03:53 +02:00
|
|
|
break;
|
|
|
|
// A corrupt element inserted by OpenRCT2 itself, which skips the drawing of the next element only.
|
|
|
|
case TILE_ELEMENT_TYPE_CORRUPT:
|
|
|
|
if (tile_element->IsLastForTile())
|
|
|
|
return;
|
|
|
|
tile_element++;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
// An undefined map element is most likely a corrupt element inserted by 8 cars' MOM feature to skip drawing of
|
|
|
|
// all elements after it.
|
2017-06-06 23:24:18 +02:00
|
|
|
return;
|
|
|
|
}
|
2019-10-31 00:19:14 +01:00
|
|
|
session->MapPosition = mapPosition;
|
2018-05-24 11:44:53 +02:00
|
|
|
} while (!(tile_element++)->IsLastForTile());
|
2017-06-06 23:24:18 +02:00
|
|
|
|
2017-10-06 21:36:45 +02:00
|
|
|
#ifndef __TESTPAINT__
|
2020-08-28 02:06:39 +02:00
|
|
|
if (gConfigGeneral.virtual_floor_style != VirtualFloorStyles::Off && partOfVirtualFloor)
|
2017-10-06 19:21:58 +02:00
|
|
|
{
|
|
|
|
virtual_floor_paint(session);
|
|
|
|
}
|
2017-10-06 21:36:45 +02:00
|
|
|
#endif // __TESTPAINT__
|
2017-09-28 21:48:53 +02:00
|
|
|
|
2018-06-22 23:03:53 +02:00
|
|
|
if (!gShowSupportSegmentHeights)
|
|
|
|
{
|
2017-06-06 23:24:18 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2018-06-22 23:03:53 +02:00
|
|
|
if ((tile_element - 1)->GetType() == TILE_ELEMENT_TYPE_SURFACE)
|
|
|
|
{
|
2017-06-06 23:24:18 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2018-06-20 17:28:51 +02:00
|
|
|
static constexpr const int32_t segmentPositions[][3] = {
|
2018-06-22 23:03:53 +02:00
|
|
|
{ 0, 6, 2 },
|
|
|
|
{ 5, 4, 8 },
|
|
|
|
{ 1, 7, 3 },
|
2017-06-06 23:24:18 +02:00
|
|
|
};
|
|
|
|
|
2018-06-22 23:03:53 +02:00
|
|
|
for (int32_t sy = 0; sy < 3; sy++)
|
|
|
|
{
|
|
|
|
for (int32_t sx = 0; sx < 3; sx++)
|
|
|
|
{
|
2018-06-20 17:28:51 +02:00
|
|
|
uint16_t segmentHeight = session->SupportSegments[segmentPositions[sy][sx]].height;
|
|
|
|
int32_t imageColourFlats = 0b101111 << 19 | IMAGE_TYPE_TRANSPARENT;
|
2018-06-22 23:03:53 +02:00
|
|
|
if (segmentHeight == 0xFFFF)
|
|
|
|
{
|
2017-09-02 23:15:09 +02:00
|
|
|
segmentHeight = session->Support.height;
|
2017-06-06 23:24:18 +02:00
|
|
|
// white: 0b101101
|
2017-07-20 20:56:29 +02:00
|
|
|
imageColourFlats = 0b111011 << 19 | IMAGE_TYPE_TRANSPARENT;
|
2017-06-06 23:24:18 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// Only draw supports below the clipping height.
|
2018-12-05 19:29:51 +01:00
|
|
|
if ((session->ViewFlags & VIEWPORT_FLAG_CLIP_VIEW) && (segmentHeight > gClipHeight))
|
2018-06-22 23:03:53 +02:00
|
|
|
continue;
|
2017-06-06 23:24:18 +02:00
|
|
|
|
2018-06-20 17:28:51 +02:00
|
|
|
int32_t xOffset = sy * 10;
|
|
|
|
int32_t yOffset = -22 + sx * 10;
|
2020-10-22 19:18:30 +02:00
|
|
|
paint_struct* ps = PaintAddImageAsParent(
|
2018-07-21 13:51:54 +02:00
|
|
|
session, 5504 | imageColourFlats, xOffset, yOffset, 10, 10, 1, segmentHeight, xOffset + 1, yOffset + 16,
|
2018-02-12 22:59:17 +01:00
|
|
|
segmentHeight);
|
2018-06-22 23:03:53 +02:00
|
|
|
if (ps != nullptr)
|
|
|
|
{
|
2017-06-06 23:24:18 +02:00
|
|
|
ps->flags &= PAINT_STRUCT_FLAG_IS_MASKED;
|
|
|
|
ps->colour_image_id = COLOUR_BORDEAUX_RED;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2016-05-01 17:01:40 +02:00
|
|
|
}
|
2016-05-17 19:10:25 +02:00
|
|
|
|
2018-06-22 23:03:53 +02:00
|
|
|
void paint_util_push_tunnel_left(paint_session* session, uint16_t height, uint8_t type)
|
2016-05-17 19:10:25 +02:00
|
|
|
{
|
2018-06-22 23:03:53 +02:00
|
|
|
session->LeftTunnels[session->LeftTunnelCount] = { static_cast<uint8_t>((height / 16)), type };
|
|
|
|
if (session->LeftTunnelCount < TUNNEL_MAX_COUNT - 1)
|
|
|
|
{
|
|
|
|
session->LeftTunnels[session->LeftTunnelCount + 1] = { 0xFF, 0xFF };
|
2017-09-03 02:51:59 +02:00
|
|
|
session->LeftTunnelCount++;
|
2017-07-09 22:48:21 +02:00
|
|
|
}
|
2016-05-17 19:10:25 +02:00
|
|
|
}
|
|
|
|
|
2018-06-22 23:03:53 +02:00
|
|
|
void paint_util_push_tunnel_right(paint_session* session, uint16_t height, uint8_t type)
|
2016-05-17 19:10:25 +02:00
|
|
|
{
|
2018-06-22 23:03:53 +02:00
|
|
|
session->RightTunnels[session->RightTunnelCount] = { static_cast<uint8_t>((height / 16)), type };
|
|
|
|
if (session->RightTunnelCount < TUNNEL_MAX_COUNT - 1)
|
|
|
|
{
|
|
|
|
session->RightTunnels[session->RightTunnelCount + 1] = { 0xFF, 0xFF };
|
2017-09-03 02:51:59 +02:00
|
|
|
session->RightTunnelCount++;
|
2017-07-09 22:48:21 +02:00
|
|
|
}
|
2016-05-17 19:10:25 +02:00
|
|
|
}
|
|
|
|
|
2018-06-22 23:03:53 +02:00
|
|
|
void paint_util_set_vertical_tunnel(paint_session* session, uint16_t height)
|
2016-09-09 18:16:40 +02:00
|
|
|
{
|
2017-01-17 23:57:53 +01:00
|
|
|
#ifdef __TESTPAINT__
|
2017-06-06 23:24:18 +02:00
|
|
|
testPaintVerticalTunnelHeight = height;
|
2017-01-17 23:57:53 +01:00
|
|
|
#endif
|
2017-09-03 02:51:59 +02:00
|
|
|
session->VerticalTunnelHeight = height / 16;
|
2016-09-09 18:16:40 +02:00
|
|
|
}
|
|
|
|
|
2018-06-22 23:03:53 +02:00
|
|
|
void paint_util_set_general_support_height(paint_session* session, int16_t height, uint8_t slope)
|
2016-05-17 19:10:25 +02:00
|
|
|
{
|
2018-06-22 23:03:53 +02:00
|
|
|
if (session->Support.height >= height)
|
|
|
|
{
|
2017-06-06 23:24:18 +02:00
|
|
|
return;
|
|
|
|
}
|
2016-05-17 19:10:25 +02:00
|
|
|
|
2017-09-03 02:56:56 +02:00
|
|
|
paint_util_force_set_general_support_height(session, height, slope);
|
2016-05-17 19:10:25 +02:00
|
|
|
}
|
|
|
|
|
2018-06-22 23:03:53 +02:00
|
|
|
void paint_util_force_set_general_support_height(paint_session* session, int16_t height, uint8_t slope)
|
2016-05-17 19:10:25 +02:00
|
|
|
{
|
2017-09-03 02:56:56 +02:00
|
|
|
session->Support.height = height;
|
|
|
|
session->Support.slope = slope;
|
2016-05-17 19:10:25 +02:00
|
|
|
}
|
|
|
|
|
2018-07-21 11:50:45 +02:00
|
|
|
const uint16_t segment_offsets[9] = { SEGMENT_B4, SEGMENT_B8, SEGMENT_BC, SEGMENT_C0, SEGMENT_C4,
|
|
|
|
SEGMENT_C8, SEGMENT_CC, SEGMENT_D0, SEGMENT_D4 };
|
2018-06-22 23:03:53 +02:00
|
|
|
|
|
|
|
void paint_util_set_segment_support_height(paint_session* session, int32_t segments, uint16_t height, uint8_t slope)
|
2016-05-17 19:10:25 +02:00
|
|
|
{
|
2018-06-22 23:03:53 +02:00
|
|
|
support_height* supportSegments = session->SupportSegments;
|
|
|
|
for (int32_t s = 0; s < 9; s++)
|
|
|
|
{
|
|
|
|
if (segments & segment_offsets[s])
|
|
|
|
{
|
2017-09-01 13:31:49 +02:00
|
|
|
supportSegments[s].height = height;
|
2018-06-22 23:03:53 +02:00
|
|
|
if (height != 0xFFFF)
|
|
|
|
{
|
2017-09-01 13:31:49 +02:00
|
|
|
supportSegments[s].slope = slope;
|
2017-06-06 23:24:18 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2016-05-18 00:44:44 +02:00
|
|
|
}
|
|
|
|
|
2018-06-20 17:28:51 +02:00
|
|
|
uint16_t paint_util_rotate_segments(uint16_t segments, uint8_t rotation)
|
2016-05-18 00:44:44 +02:00
|
|
|
{
|
2018-06-20 17:28:51 +02:00
|
|
|
uint8_t temp = segments & 0xFF;
|
2017-06-06 23:24:18 +02:00
|
|
|
temp = rol8(temp, rotation * 2);
|
2016-05-18 00:44:44 +02:00
|
|
|
|
2017-06-06 23:24:18 +02:00
|
|
|
return (segments & 0xFF00) | temp;
|
2016-05-18 00:44:44 +02:00
|
|
|
}
|
2020-09-06 09:56:41 +02:00
|
|
|
|
|
|
|
bool PaintShouldShowHeightMarkers(const paint_session* session, const uint32_t viewportFlag)
|
|
|
|
{
|
|
|
|
auto dpi = &session->DPI;
|
|
|
|
return (session->ViewFlags & viewportFlag) && (dpi->zoom_level <= 0);
|
|
|
|
}
|