Merge pull request #16151 from IntelOrca/refactor/imageid-painting

Refactor most map paint routines to use ImageId
This commit is contained in:
Michael Steenbeek 2021-12-12 11:43:31 +01:00 committed by GitHub
commit b4f256be87
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
25 changed files with 1765 additions and 1897 deletions

View File

@ -1474,9 +1474,9 @@ static bool is_pixel_present_rle(const uint8_t* esi, int32_t x_start_point, int3
* @return value originally stored in 0x00141F569
*/
static bool is_sprite_interacted_with_palette_set(
rct_drawpixelinfo* dpi, int32_t imageId, const ScreenCoordsXY& coords, const PaletteMap& paletteMap)
rct_drawpixelinfo* dpi, ImageId imageId, const ScreenCoordsXY& coords, const PaletteMap& paletteMap)
{
const rct_g1_element* g1 = gfx_get_g1_element(imageId & 0x7FFFF);
const rct_g1_element* g1 = gfx_get_g1_element(imageId);
if (g1 == nullptr)
{
return false;
@ -1502,8 +1502,8 @@ static bool is_sprite_interacted_with_palette_set(
/* .zoom_level = */ dpi->zoom_level - 1,
};
return is_sprite_interacted_with_palette_set(
&zoomed_dpi, imageId - g1->zoomed_offset, { coords.x / 2, coords.y / 2 }, paletteMap);
auto zoomImageId = imageId.WithIndex(imageId.GetIndex() - g1->zoomed_offset);
return is_sprite_interacted_with_palette_set(&zoomed_dpi, zoomImageId, { coords.x / 2, coords.y / 2 }, paletteMap);
}
}
@ -1618,19 +1618,22 @@ static bool is_sprite_interacted_with_palette_set(
* rct2: 0x00679023
*/
static bool is_sprite_interacted_with(rct_drawpixelinfo* dpi, int32_t imageId, const ScreenCoordsXY& coords)
static bool is_sprite_interacted_with(rct_drawpixelinfo* dpi, ImageId imageId, const ScreenCoordsXY& coords)
{
auto paletteMap = PaletteMap::GetDefault();
imageId &= ~IMAGE_TYPE_TRANSPARENT;
if (imageId & IMAGE_TYPE_REMAP)
if (imageId.HasPrimary() || imageId.IsRemap())
{
_currentImageType = IMAGE_TYPE_REMAP;
int32_t index = (imageId >> 19) & 0x7F;
if (imageId & IMAGE_TYPE_REMAP_2_PLUS)
uint8_t paletteIndex;
if (imageId.HasSecondary())
{
index &= 0x1F;
paletteIndex = imageId.GetPrimary();
}
if (auto pm = GetPaletteMapForColour(index); pm.has_value())
else
{
paletteIndex = imageId.GetRemap();
}
if (auto pm = GetPaletteMapForColour(paletteIndex); pm.has_value())
{
paletteMap = pm.value();
}
@ -1659,7 +1662,8 @@ InteractionInfo set_interaction_info_from_paint_session(paint_session* session,
while (next_ps != nullptr)
{
ps = next_ps;
if (is_sprite_interacted_with(dpi, ps->image_id, { ps->x, ps->y }))
auto imageId = ImageId::FromUInt32(ps->image_id, ps->tertiary_colour);
if (is_sprite_interacted_with(dpi, imageId, { ps->x, ps->y }))
{
if (PSSpriteTypeIsInFilter(ps, filter))
{
@ -1671,7 +1675,8 @@ InteractionInfo set_interaction_info_from_paint_session(paint_session* session,
for (attached_paint_struct* attached_ps = ps->attached_ps; attached_ps != nullptr; attached_ps = attached_ps->next)
{
if (is_sprite_interacted_with(dpi, attached_ps->image_id, { (attached_ps->x + ps->x), (attached_ps->y + ps->y) }))
auto imageId = ImageId::FromUInt32(attached_ps->image_id, attached_ps->tertiary_colour);
if (is_sprite_interacted_with(dpi, imageId, { (attached_ps->x + ps->x), (attached_ps->y + ps->y) }))
{
if (PSSpriteTypeIsInFilter(ps, filter))
{

View File

@ -65,3 +65,20 @@ void EntranceObject::ReadJson(IReadObjectContext* context, json_t& root)
PopulateTablesFromJson(context, root);
}
ImageIndex EntranceObject::GetImage(uint8_t sequence, Direction direction) const
{
if (sequence > 2)
return ImageIndexUndefined;
return _legacyType.image_id + ((direction & 3) * 3) + sequence;
}
uint8_t EntranceObject::GetScrollingMode() const
{
return _legacyType.scrolling_mode;
}
uint8_t EntranceObject::GetTextHeight() const
{
return _legacyType.text_height;
}

View File

@ -10,6 +10,7 @@
#pragma once
#include "../world/Entrance.h"
#include "../world/Location.hpp"
#include "Object.h"
class EntranceObject final : public Object
@ -29,4 +30,8 @@ public:
void Unload() override;
void DrawPreview(rct_drawpixelinfo* dpi, int32_t width, int32_t height) const override;
ImageIndex GetImage(uint8_t sequence, Direction direction) const;
uint8_t GetScrollingMode() const;
uint8_t GetTextHeight() const;
};

View File

@ -41,8 +41,8 @@ void StationObject::Unload()
gfx_object_free_images(BaseImageId, GetImageTable().GetCount());
NameStringId = 0;
BaseImageId = 0;
ShelterImageId = 0;
BaseImageId = ImageIndexUndefined;
ShelterImageId = ImageIndexUndefined;
}
void StationObject::DrawPreview(rct_drawpixelinfo* dpi, int32_t width, int32_t height) const

View File

@ -9,6 +9,7 @@
#pragma once
#include "../drawing/ImageId.hpp"
#include "Object.h"
namespace STATION_OBJECT_FLAGS
@ -24,8 +25,8 @@ class StationObject final : public Object
{
public:
rct_string_id NameStringId{};
uint32_t BaseImageId{};
uint32_t ShelterImageId{};
ImageIndex BaseImageId = ImageIndexUndefined;
ImageIndex ShelterImageId = ImageIndexUndefined;
uint32_t Flags{};
int32_t Height{};
uint8_t ScrollingMode{};

View File

@ -177,6 +177,7 @@ static paint_struct* CreateNormalPaintStruct(
}
ps->image_id = image_id.ToUInt32();
ps->tertiary_colour = image_id.GetTertiary();
ps->x = imagePos.x;
ps->y = imagePos.y;
ps->bounds.x_end = rotBoundBoxSize.x + rotBoundBoxOffset.x + session->SpritePosition.x;
@ -867,12 +868,12 @@ paint_struct* PaintAddImageAsChild(
* @param y (cx)
* @return (!CF) success
*/
bool PaintAttachToPreviousAttach(paint_session* session, uint32_t image_id, int32_t x, int32_t y)
bool PaintAttachToPreviousAttach(paint_session* session, ImageId imageId, int32_t x, int32_t y)
{
auto* previousAttachedPS = session->LastAttachedPS;
if (previousAttachedPS == nullptr)
{
return PaintAttachToPreviousPS(session, image_id, x, y);
return PaintAttachToPreviousPS(session, imageId, x, y);
}
auto* ps = session->AllocateAttachedPaintEntry();
@ -881,7 +882,8 @@ bool PaintAttachToPreviousAttach(paint_session* session, uint32_t image_id, int3
return false;
}
ps->image_id = image_id;
ps->image_id = imageId.ToUInt32();
ps->tertiary_colour = imageId.GetTertiary();
ps->x = x;
ps->y = y;
ps->flags = 0;
@ -920,6 +922,7 @@ bool PaintAttachToPreviousPS(paint_session* session, ImageId image_id, int32_t x
}
ps->image_id = image_id.ToUInt32();
ps->tertiary_colour = image_id.GetTertiary();
ps->x = x;
ps->y = y;
ps->flags = 0;

View File

@ -331,7 +331,7 @@ paint_struct* PaintAddImageAsParentRotated(
void paint_util_push_tunnel_rotated(paint_session* session, uint8_t direction, uint16_t height, uint8_t type);
bool PaintAttachToPreviousAttach(paint_session* session, uint32_t image_id, int32_t x, int32_t y);
bool PaintAttachToPreviousAttach(paint_session* session, ImageId imageId, int32_t x, int32_t y);
bool PaintAttachToPreviousPS(paint_session* session, ImageId image_id, int32_t x, int32_t y);
bool PaintAttachToPreviousPS(paint_session* session, uint32_t image_id, int32_t x, int32_t y);
void PaintFloatingMoneyEffect(

View File

@ -1169,7 +1169,7 @@ bool metal_b_supports_paint_setup(
* @return Whether supports were drawn
*/
bool path_a_supports_paint_setup(
paint_session* session, int32_t supportType, int32_t special, int32_t height, uint32_t imageColourFlags,
paint_session* session, int32_t supportType, int32_t special, int32_t height, ImageId imageTemplate,
const FootpathPaintInfo& pathPaintInfo, bool* underground)
{
if (underground != nullptr)
@ -1204,7 +1204,7 @@ bool path_a_supports_paint_setup(
{
// save dx2
PaintAddImageAsParent(
session, (pathPaintInfo.BridgeImageId + 48) | imageColourFlags, { 0, 0, baseHeight - 2 }, { 32, 32, 0 });
session, imageTemplate.WithIndex(pathPaintInfo.BridgeImageId + 48), { 0, 0, baseHeight - 2 }, { 32, 32, 0 });
hasSupports = true;
}
else if (session->Support.slope & 0x10)
@ -1221,11 +1221,11 @@ bool path_a_supports_paint_setup(
+ pathPaintInfo.BridgeImageId;
PaintAddImageAsParent(
session, imageId | imageColourFlags, { 0, 0, baseHeight }, { 32, 32, 11 }, { 0, 0, baseHeight + 2 });
session, imageTemplate.WithIndex(imageId), { 0, 0, baseHeight }, { 32, 32, 11 }, { 0, 0, baseHeight + 2 });
baseHeight += 16;
PaintAddImageAsParent(
session, (imageId + 4) | imageColourFlags, { 0, 0, baseHeight }, { 32, 32, 11 }, { 0, 0, baseHeight + 2 });
session, imageTemplate.WithIndex(imageId + 4), { 0, 0, baseHeight }, { 32, 32, 11 }, { 0, 0, baseHeight + 2 });
baseHeight += 16;
hasSupports = true;
@ -1243,7 +1243,8 @@ bool path_a_supports_paint_setup(
uint32_t ebx = (supportType * 24) + word_97B3C4[session->Support.slope & TILE_ELEMENT_SURFACE_SLOPE_MASK]
+ pathPaintInfo.BridgeImageId;
PaintAddImageAsParent(session, ebx | imageColourFlags, { 0, 0, baseHeight }, { 32, 32, 11 }, { 0, 0, baseHeight + 2 });
PaintAddImageAsParent(
session, imageTemplate.WithIndex(ebx), { 0, 0, baseHeight }, { 32, 32, 11 }, { 0, 0, baseHeight + 2 });
hasSupports = true;
baseHeight += 16;
@ -1256,7 +1257,7 @@ bool path_a_supports_paint_setup(
uint32_t imageId = (supportType * 24) + pathPaintInfo.BridgeImageId + 23;
PaintAddImageAsParent(
session, imageId | imageColourFlags, { 0, 0, baseHeight }, { 32, 32, ((heightSteps == 1) ? 7 : 12) });
session, imageTemplate.WithIndex(imageId), { 0, 0, baseHeight }, { 32, 32, ((heightSteps == 1) ? 7 : 12) });
heightSteps -= 1;
baseHeight += 16;
hasSupports = true;
@ -1266,7 +1267,7 @@ bool path_a_supports_paint_setup(
uint32_t imageId = (supportType * 24) + pathPaintInfo.BridgeImageId + 22;
PaintAddImageAsParent(
session, imageId | imageColourFlags, { 0, 0, baseHeight }, { 32, 32, ((heightSteps == 2) ? 23 : 28) });
session, imageTemplate.WithIndex(imageId), { 0, 0, baseHeight }, { 32, 32, ((heightSteps == 2) ? 23 : 28) });
heightSteps -= 2;
baseHeight += 32;
hasSupports = true;
@ -1277,7 +1278,7 @@ bool path_a_supports_paint_setup(
{
uint16_t specialIndex = (special - 1) & 0xFFFF;
uint32_t imageId = pathPaintInfo.BridgeImageId + 55 + specialIndex;
ImageIndex imageIndex = pathPaintInfo.BridgeImageId + 55 + specialIndex;
const unk_supports_desc& supportsDesc = byte_98D8D4[specialIndex];
const unk_supports_desc_bound_box& boundBox = supportsDesc.bounding_box;
@ -1285,14 +1286,14 @@ bool path_a_supports_paint_setup(
if (supportsDesc.var_6 == 0 || session->WoodenSupportsPrependTo == nullptr)
{
PaintAddImageAsParent(
session, imageId | imageColourFlags, { 0, 0, baseHeight }, boundBox.length,
session, imageTemplate.WithIndex(imageIndex), { 0, 0, baseHeight }, boundBox.length,
{ boundBox.offset.x, boundBox.offset.y, baseHeight + boundBox.offset.z });
hasSupports = true;
}
else
{
paint_struct* paintStruct = PaintAddImageAsOrphan(
session, ImageId::FromUInt32(imageId | imageColourFlags), { 0, 0, baseHeight }, boundBox.length,
session, imageTemplate.WithIndex(imageIndex), { 0, 0, baseHeight }, boundBox.length,
{ boundBox.offset.x, boundBox.offset.y, baseHeight + boundBox.offset.z });
hasSupports = true;
if (paintStruct != nullptr)
@ -1321,7 +1322,7 @@ bool path_a_supports_paint_setup(
* @return Whether supports were drawn
*/
bool path_b_supports_paint_setup(
paint_session* session, int32_t segment, int32_t special, int32_t height, uint32_t imageColourFlags,
paint_session* session, int32_t segment, int32_t special, int32_t height, ImageId imageTemplate,
const FootpathPaintInfo& pathPaintInfo)
{
support_height* supportSegments = session->SupportSegments;
@ -1354,7 +1355,7 @@ bool path_b_supports_paint_setup(
baseHeight = supportSegments[segment].height;
PaintAddImageAsParent(
session, (pathPaintInfo.BridgeImageId + 37 + imageOffset) | imageColourFlags,
session, imageTemplate.WithIndex(pathPaintInfo.BridgeImageId + 37 + imageOffset),
{ SupportBoundBoxes[segment].x, SupportBoundBoxes[segment].y, baseHeight }, { 0, 0, 5 });
baseHeight += 6;
}
@ -1373,7 +1374,7 @@ bool path_b_supports_paint_setup(
if (heightDiff > 0)
{
PaintAddImageAsParent(
session, (pathPaintInfo.BridgeImageId + 20 + (heightDiff - 1)) | imageColourFlags,
session, imageTemplate.WithIndex(pathPaintInfo.BridgeImageId + 20 + (heightDiff - 1)),
{ SupportBoundBoxes[segment], baseHeight }, { 0, 0, heightDiff - 1 });
}
@ -1406,7 +1407,7 @@ bool path_b_supports_paint_setup(
}
PaintAddImageAsParent(
session, (pathPaintInfo.BridgeImageId + 20 + (z - 1)) | imageColourFlags,
session, imageTemplate.WithIndex(pathPaintInfo.BridgeImageId + 20 + (z - 1)),
{ SupportBoundBoxes[segment], baseHeight }, { 0, 0, (z - 1) });
baseHeight += z;
@ -1417,14 +1418,14 @@ bool path_b_supports_paint_setup(
break;
}
uint32_t imageId = pathPaintInfo.BridgeImageId + 20 + (z - 1);
ImageIndex imageIndex = pathPaintInfo.BridgeImageId + 20 + (z - 1);
if (z == 16)
{
imageId += 1;
imageIndex += 1;
}
PaintAddImageAsParent(
session, imageId | imageColourFlags, { SupportBoundBoxes[segment], baseHeight }, { 0, 0, (z - 1) });
session, imageTemplate.WithIndex(imageIndex), { SupportBoundBoxes[segment], baseHeight }, { 0, 0, (z - 1) });
baseHeight += z;
}
@ -1451,9 +1452,9 @@ bool path_b_supports_paint_setup(
break;
}
uint32_t imageId = pathPaintInfo.BridgeImageId + 20 + (z - 1);
ImageIndex imageIndex = pathPaintInfo.BridgeImageId + 20 + (z - 1);
PaintAddImageAsParent(
session, imageId | imageColourFlags, { SupportBoundBoxes[segment], baseHeight }, { 0, 0, 0 },
session, imageTemplate.WithIndex(imageIndex), { SupportBoundBoxes[segment], baseHeight }, { 0, 0, 0 },
{ SupportBoundBoxes[segment], baseHeight });
baseHeight += z;

View File

@ -10,6 +10,7 @@
#pragma once
#include "../common.h"
#include "../drawing/ImageId.hpp"
#include "../world/Footpath.h"
struct FootpathPaintInfo;
@ -25,10 +26,10 @@ bool metal_a_supports_paint_setup(
bool metal_b_supports_paint_setup(
paint_session* session, uint8_t supportType, uint8_t segment, int32_t special, int32_t height, uint32_t imageColourFlags);
bool path_a_supports_paint_setup(
paint_session* session, int32_t supportType, int32_t special, int32_t height, uint32_t imageColourFlags,
paint_session* session, int32_t supportType, int32_t special, int32_t height, ImageId imageTemplate,
const FootpathPaintInfo& pathPaintInfo, bool* underground);
bool path_b_supports_paint_setup(
paint_session* session, int32_t supportType, int32_t special, int32_t height, uint32_t imageColourFlags,
paint_session* session, int32_t supportType, int32_t special, int32_t height, ImageId imageTemplate,
const FootpathPaintInfo& pathPaintInfo);
// There are 13 types of metal supports. A graphic showing all of them is available here:

View File

@ -19,7 +19,6 @@
#include "../Paint.h"
#include "Paint.TileElement.h"
/** rct2: 0x0098D884 */
// BannerBoundBoxes[rotation][0] is for the pole in the back
// BannerBoundBoxes[rotation][1] is for the pole and the banner in the front
constexpr CoordsXY BannerBoundBoxes[][2] = {
@ -29,20 +28,45 @@ constexpr CoordsXY BannerBoundBoxes[][2] = {
{ { 2, 1 }, { 29, 1 } },
};
/**
*
* rct2: 0x006B9CC4
*/
void PaintBanner(paint_session* session, uint8_t direction, int32_t height, const BannerElement& bannerElement)
static void PaintBannerScrollingText(
paint_session* session, const BannerSceneryEntry& bannerEntry, Banner& banner, const BannerElement& bannerElement,
Direction direction, int32_t height, const CoordsXYZ& bbOffset)
{
rct_drawpixelinfo* dpi = &session->DPI;
session->InteractionType = ViewportInteractionItem::Banner;
if (dpi->zoom_level > ZoomLevel{ 1 } || gTrackDesignSaveMode || (session->ViewFlags & VIEWPORT_FLAG_HIGHLIGHT_PATH_ISSUES))
// If text on hidden direction or ghost
direction = direction_reverse(direction) - 1;
if (direction >= 2 || (bannerElement.IsGhost()))
return;
height -= 16;
auto scrollingMode = bannerEntry.scrolling_mode + (direction & 3);
if (scrollingMode >= MAX_SCROLLING_TEXT_MODES)
{
return;
}
auto ft = Formatter();
banner.FormatTextTo(ft, true);
char text[256];
if (gConfigGeneral.upper_case_banners)
{
format_string_to_upper(text, sizeof(text), STR_BANNER_TEXT_FORMAT, ft.Data());
}
else
{
format_string(text, sizeof(text), STR_BANNER_TEXT_FORMAT, ft.Data());
}
auto stringWidth = gfx_get_string_width(text, FontSpriteBase::TINY);
auto scroll = (gCurrentTicks / 2) % stringWidth;
auto imageId = scrolling_text_setup(session, STR_BANNER_TEXT_FORMAT, ft, scroll, scrollingMode, COLOUR_BLACK);
PaintAddImageAsChild(session, imageId, { 0, 0, height + 22 }, { 1, 1, 21 }, bbOffset);
}
void PaintBanner(paint_session* session, uint8_t direction, int32_t height, const BannerElement& bannerElement)
{
if (session->DPI.zoom_level > ZoomLevel{ 1 } || gTrackDesignSaveMode
|| (session->ViewFlags & VIEWPORT_FLAG_HIGHLIGHT_PATH_ISSUES))
return;
auto banner = bannerElement.GetBanner();
if (banner == nullptr)
@ -56,65 +80,35 @@ void PaintBanner(paint_session* session, uint8_t direction, int32_t height, cons
return;
}
session->InteractionType = ViewportInteractionItem::Banner;
height -= 16;
direction += bannerElement.GetPosition();
direction &= 3;
CoordsXYZ boundBoxOffset = CoordsXYZ(BannerBoundBoxes[direction][0], height + 2);
uint32_t base_id = (direction << 1) + bannerEntry->image;
uint32_t image_id = base_id;
if (bannerElement.IsGhost()) // if being placed
ImageId imageTemplate;
if (bannerElement.IsGhost())
{
session->InteractionType = ViewportInteractionItem::None;
image_id |= CONSTRUCTION_MARKER;
imageTemplate = ImageId().WithRemap(FilterPaletteID::Palette44);
}
else if (OpenRCT2::TileInspector::IsElementSelected(reinterpret_cast<const TileElement*>(&bannerElement)))
{
image_id |= CONSTRUCTION_MARKER;
imageTemplate = ImageId().WithRemap(FilterPaletteID::Palette44);
}
else
{
image_id |= (banner->colour << 19) | IMAGE_TYPE_REMAP;
imageTemplate = ImageId().WithPrimary(banner->colour);
}
PaintAddImageAsParent(session, image_id, { 0, 0, height }, { 1, 1, 0x15 }, boundBoxOffset);
boundBoxOffset.x = BannerBoundBoxes[direction][1].x;
boundBoxOffset.y = BannerBoundBoxes[direction][1].y;
auto imageIndex = (direction << 1) + bannerEntry->image;
auto imageId = imageTemplate.WithIndex(imageIndex);
auto bbOffset = CoordsXYZ(BannerBoundBoxes[direction][0], height + 2);
PaintAddImageAsParent(session, imageId, { 0, 0, height }, { 1, 1, 21 }, bbOffset);
image_id++;
PaintAddImageAsParent(session, image_id, { 0, 0, height }, { 1, 1, 0x15 }, boundBoxOffset);
bbOffset = CoordsXYZ(BannerBoundBoxes[direction][1], height + 2);
PaintAddImageAsParent(session, imageId.WithIndexOffset(1), { 0, 0, height }, { 1, 1, 21 }, bbOffset);
// Opposite direction
direction = direction_reverse(direction);
direction--;
// If text not showing / ghost
if (direction >= 2 || (bannerElement.IsGhost()))
return;
uint16_t scrollingMode = bannerEntry->scrolling_mode;
if (scrollingMode >= MAX_SCROLLING_TEXT_MODES)
{
return;
}
scrollingMode += direction;
auto ft = Formatter();
banner->FormatTextTo(ft, /*addColour*/ true);
if (gConfigGeneral.upper_case_banners)
{
format_string_to_upper(gCommonStringFormatBuffer, sizeof(gCommonStringFormatBuffer), STR_BANNER_TEXT_FORMAT, ft.Data());
}
else
{
format_string(gCommonStringFormatBuffer, sizeof(gCommonStringFormatBuffer), STR_BANNER_TEXT_FORMAT, ft.Data());
}
uint16_t string_width = gfx_get_string_width(gCommonStringFormatBuffer, FontSpriteBase::TINY);
uint16_t scroll = (gCurrentTicks / 2) % string_width;
auto scrollIndex = scrolling_text_setup(session, STR_BANNER_TEXT_FORMAT, ft, scroll, scrollingMode, COLOUR_BLACK);
PaintAddImageAsChild(
session, scrollIndex, 0, 0, 1, 1, 0x15, height + 22, boundBoxOffset.x, boundBoxOffset.y, boundBoxOffset.z);
PaintBannerScrollingText(session, *bannerEntry, *banner, bannerElement, direction, height, bbOffset);
}

View File

@ -14,6 +14,8 @@
#include "../../drawing/LightFX.h"
#include "../../interface/Viewport.h"
#include "../../localisation/Localisation.h"
#include "../../object/EntranceObject.h"
#include "../../object/ObjectManager.h"
#include "../../object/StationObject.h"
#include "../../ride/RideData.h"
#include "../../ride/TrackDesign.h"
@ -26,30 +28,61 @@
#include "../Supports.h"
#include "Paint.TileElement.h"
/**
*
* rct2: 0x0066508C, 0x00665540
*/
static void ride_entrance_exit_paint(
paint_session* session, uint8_t direction, int32_t height, const EntranceElement& tile_element)
{
uint8_t is_exit = tile_element.GetEntranceType() == ENTRANCE_TYPE_RIDE_EXIT;
using namespace OpenRCT2;
if (gTrackDesignSaveMode || (session->ViewFlags & VIEWPORT_FLAG_HIGHLIGHT_PATH_ISSUES))
static void PaintRideEntranceExitScrollingText(
paint_session* session, const EntranceElement& entranceEl, const StationObject& stationObj, Direction direction,
int32_t height)
{
if (stationObj.ScrollingMode == SCROLLING_MODE_NONE)
return;
if (entranceEl.GetEntranceType() == ENTRANCE_TYPE_RIDE_EXIT)
return;
auto ride = get_ride(entranceEl.GetRideIndex());
if (ride == nullptr)
return;
auto ft = Formatter();
ft.Add<rct_string_id>(STR_RIDE_ENTRANCE_NAME);
if (ride->status == RideStatus::Open && !(ride->lifecycle_flags & RIDE_LIFECYCLE_BROKEN_DOWN))
{
if (tile_element.GetRideIndex() != gTrackDesignSaveRideIndex)
return;
ride->FormatNameTo(ft);
}
else
{
ft.Add<rct_string_id>(STR_RIDE_ENTRANCE_CLOSED);
}
char text[256];
if (gConfigGeneral.upper_case_banners)
{
format_string_to_upper(text, sizeof(text), STR_BANNER_TEXT_FORMAT, ft.Data());
}
else
{
format_string(text, sizeof(text), STR_BANNER_TEXT_FORMAT, ft.Data());
}
auto stringWidth = gfx_get_string_width(text, FontSpriteBase::TINY);
auto scroll = stringWidth > 0 ? (gCurrentTicks / 2) % stringWidth : 0;
PaintAddImageAsChild(
session, scrolling_text_setup(session, STR_BANNER_TEXT_FORMAT, ft, scroll, stationObj.ScrollingMode, COLOUR_BLACK), 0,
0, 28, 28, 51, height + stationObj.Height, 2, 2, height + stationObj.Height);
}
static void PaintRideEntranceExitLightEffects(paint_session* session, int32_t height, const EntranceElement& entranceEl)
{
#ifdef __ENABLE_LIGHTFX__
if (lightfx_is_available())
{
if (!is_exit)
if (entranceEl.GetEntranceType() == ENTRANCE_TYPE_RIDE_ENTRANCE)
{
lightfx_add_3d_light_magic_from_drawing_tile(session->MapPosition, 0, 0, height + 45, LightType::Lantern3);
}
switch (tile_element.GetDirection())
switch (entranceEl.GetDirection())
{
case 0:
lightfx_add_3d_light_magic_from_drawing_tile(session->MapPosition, 16, 0, height + 16, LightType::Lantern2);
@ -66,8 +99,18 @@ static void ride_entrance_exit_paint(
}
}
#endif
}
auto ride = get_ride(tile_element.GetRideIndex());
static void PaintRideEntranceExit(paint_session* session, uint8_t direction, int32_t height, const EntranceElement& entranceEl)
{
auto rideIndex = entranceEl.GetRideIndex();
if ((gTrackDesignSaveMode || (session->ViewFlags & VIEWPORT_FLAG_HIGHLIGHT_PATH_ISSUES))
&& (rideIndex != gTrackDesignSaveRideIndex))
{
return;
}
auto ride = get_ride(rideIndex);
if (ride == nullptr)
{
return;
@ -79,44 +122,28 @@ static void ride_entrance_exit_paint(
return;
}
uint8_t colour_1, colour_2;
uint32_t transparant_image_id = 0, image_id = 0;
if (stationObj->Flags & STATION_OBJECT_FLAGS::IS_TRANSPARENT)
session->InteractionType = ViewportInteractionItem::Ride;
PaintRideEntranceExitLightEffects(session, height, entranceEl);
auto hasGlass = (stationObj->Flags & STATION_OBJECT_FLAGS::IS_TRANSPARENT) != 0;
auto colourPrimary = ride->track_colour[0].main;
auto colourSecondary = ride->track_colour[0].additional;
auto imageTemplate = ImageId(0, colourPrimary, colourSecondary);
ImageId glassImageTemplate;
if (hasGlass)
{
colour_1 = EnumValue(GlassPaletteIds[ride->track_colour[0].main]);
transparant_image_id = (colour_1 << 19) | IMAGE_TYPE_TRANSPARENT;
glassImageTemplate = ImageId().WithTransparancy(colourPrimary);
}
colour_1 = ride->track_colour[0].main;
colour_2 = ride->track_colour[0].additional;
image_id = (colour_1 << 19) | (colour_2 << 24) | IMAGE_TYPE_REMAP | IMAGE_TYPE_REMAP_2_PLUS;
session->InteractionType = ViewportInteractionItem::Ride;
uint32_t entranceImageId = 0;
if (tile_element.IsGhost())
if (entranceEl.IsGhost())
{
session->InteractionType = ViewportInteractionItem::None;
image_id = CONSTRUCTION_MARKER;
entranceImageId = image_id;
if (transparant_image_id)
transparant_image_id = image_id;
imageTemplate = ImageId().WithRemap(FilterPaletteID::Palette44);
}
else if (OpenRCT2::TileInspector::IsElementSelected(reinterpret_cast<const TileElement*>(&tile_element)))
else if (OpenRCT2::TileInspector::IsElementSelected(reinterpret_cast<const TileElement*>(&entranceEl)))
{
image_id = CONSTRUCTION_MARKER;
entranceImageId = image_id;
if (transparant_image_id)
transparant_image_id = image_id;
}
if (is_exit)
{
image_id |= stationObj->BaseImageId + direction + 8;
}
else
{
image_id |= stationObj->BaseImageId + direction;
imageTemplate = ImageId().WithRemap(FilterPaletteID::Palette44);
}
// Format modified to stop repeated code
@ -124,250 +151,206 @@ static void ride_entrance_exit_paint(
// Each entrance is split into 2 images for drawing
// Certain entrance styles have another 2 images to draw for coloured windows
int8_t ah = is_exit ? 0x23 : 0x33;
int16_t lengthY = (direction & 1) ? 28 : 2;
int16_t lengthX = (direction & 1) ? 2 : 28;
PaintAddImageAsParent(session, image_id, { 0, 0, height }, { lengthX, lengthY, ah }, { 2, 2, height });
if (transparant_image_id)
{
if (is_exit)
{
transparant_image_id |= stationObj->BaseImageId + direction + 24;
}
else
{
transparant_image_id |= stationObj->BaseImageId + direction + 16;
}
PaintAddImageAsChild(session, transparant_image_id, 0, 0, lengthX, lengthY, ah, height, 2, 2, height);
}
image_id += 4;
auto isExit = entranceEl.GetEntranceType() == ENTRANCE_TYPE_RIDE_EXIT;
auto lengthY = (direction & 1) ? 28 : 2;
auto lengthX = (direction & 1) ? 2 : 28;
auto lengthZ = isExit ? 35 : 51;
// Back
ImageIndex imageIndex = isExit ? stationObj->BaseImageId + direction + 8 : stationObj->BaseImageId + direction;
ImageIndex glassImageIndex = isExit ? stationObj->BaseImageId + direction + 24 : stationObj->BaseImageId + direction + 16;
PaintAddImageAsParent(
session, image_id, { 0, 0, height }, { lengthX, lengthY, ah },
session, imageTemplate.WithIndex(imageIndex), { 0, 0, height }, { lengthX, lengthY, lengthZ }, { 2, 2, height });
if (hasGlass)
{
PaintAddImageAsChild(
session, glassImageTemplate.WithIndex(glassImageIndex), { 0, 0, height }, { lengthX, lengthY, lengthZ },
{ 2, 2, height });
}
// Front
imageIndex += 4;
PaintAddImageAsParent(
session, imageTemplate.WithIndex(imageIndex), { 0, 0, height }, { lengthX, lengthY, lengthZ },
{ (direction & 1) ? 28 : 2, (direction & 1) ? 2 : 28, height });
if (transparant_image_id)
if (hasGlass)
{
transparant_image_id += 4;
glassImageIndex += 4;
PaintAddImageAsChild(
session, transparant_image_id, 0, 0, lengthX, lengthY, ah, height, (direction & 1) ? 28 : 2,
(direction & 1) ? 2 : 28, height);
session, glassImageTemplate.WithIndex(glassImageIndex), { 0, 0, height }, { lengthX, lengthY, lengthZ },
{ (direction & 1) ? 28 : 2, (direction & 1) ? 2 : 28, height });
}
if (direction & 1)
paint_util_push_tunnel_rotated(session, direction, height, TUNNEL_SQUARE_FLAT);
if (!entranceEl.IsGhost())
PaintRideEntranceExitScrollingText(session, entranceEl, *stationObj, direction, height);
auto supportsImageTemplate = imageTemplate;
if (!entranceEl.IsGhost())
{
paint_util_push_tunnel_right(session, height, TUNNEL_SQUARE_FLAT);
}
else
{
paint_util_push_tunnel_left(session, height, TUNNEL_SQUARE_FLAT);
supportsImageTemplate = ImageId().WithPrimary(COLOUR_SATURATED_BROWN);
}
wooden_a_supports_paint_setup(session, direction & 1, 0, height, supportsImageTemplate.ToUInt32());
if (!is_exit && !(tile_element.IsGhost()) && tile_element.GetRideIndex() != RIDE_ID_NULL
&& stationObj->ScrollingMode != SCROLLING_MODE_NONE)
{
auto ft = Formatter();
ft.Add<rct_string_id>(STR_RIDE_ENTRANCE_NAME);
if (ride->status == RideStatus::Open && !(ride->lifecycle_flags & RIDE_LIFECYCLE_BROKEN_DOWN))
{
ride->FormatNameTo(ft);
}
else
{
ft.Add<rct_string_id>(STR_RIDE_ENTRANCE_CLOSED);
}
utf8 entrance_string[256];
if (gConfigGeneral.upper_case_banners)
{
format_string_to_upper(entrance_string, sizeof(entrance_string), STR_BANNER_TEXT_FORMAT, ft.Data());
}
else
{
format_string(entrance_string, sizeof(entrance_string), STR_BANNER_TEXT_FORMAT, ft.Data());
}
uint16_t stringWidth = gfx_get_string_width(entrance_string, FontSpriteBase::TINY);
uint16_t scroll = stringWidth > 0 ? (gCurrentTicks / 2) % stringWidth : 0;
PaintAddImageAsChild(
session, scrolling_text_setup(session, STR_BANNER_TEXT_FORMAT, ft, scroll, stationObj->ScrollingMode, COLOUR_BLACK),
0, 0, 0x1C, 0x1C, 0x33, height + stationObj->Height, 2, 2, height + stationObj->Height);
}
image_id = entranceImageId;
if (image_id == 0)
{
image_id = SPRITE_ID_PALETTE_COLOUR_1(COLOUR_SATURATED_BROWN);
}
wooden_a_supports_paint_setup(session, direction & 1, 0, height, image_id);
height += isExit ? 40 : 56;
paint_util_set_segment_support_height(session, SEGMENTS_ALL, 0xFFFF, 0);
height += is_exit ? 40 : 56;
paint_util_set_general_support_height(session, height, 0x20);
}
/**
*
* rct2: 0x006658ED
*/
static void park_entrance_paint(paint_session* session, uint8_t direction, int32_t height, const EntranceElement& tile_element)
static void PaintParkEntranceScrollingText(
paint_session* session, const EntranceObject& entrance, Direction direction, int32_t height)
{
if (gTrackDesignSaveMode || (session->ViewFlags & VIEWPORT_FLAG_HIGHLIGHT_PATH_ISSUES))
if ((direction + 1) & (1 << 1))
return;
auto scrollingMode = entrance.GetScrollingMode();
if (scrollingMode == SCROLLING_MODE_NONE)
return;
auto ft = Formatter();
if (gParkFlags & PARK_FLAGS_PARK_OPEN)
{
const auto& park = OpenRCT2::GetContext()->GetGameState()->GetPark();
auto name = park.Name.c_str();
ft.Add<rct_string_id>(STR_STRING);
ft.Add<const char*>(name);
}
else
{
ft.Add<rct_string_id>(STR_BANNER_TEXT_CLOSED);
ft.Add<uint32_t>(0);
}
char text[256];
if (gConfigGeneral.upper_case_banners)
{
format_string_to_upper(text, sizeof(text), STR_BANNER_TEXT_FORMAT, ft.Data());
}
else
{
format_string(text, sizeof(text), STR_BANNER_TEXT_FORMAT, ft.Data());
}
auto stringWidth = gfx_get_string_width(text, FontSpriteBase::TINY);
auto scroll = stringWidth > 0 ? (gCurrentTicks / 2) % stringWidth : 0;
auto imageIndex = scrolling_text_setup(
session, STR_BANNER_TEXT_FORMAT, ft, scroll, scrollingMode + direction / 2, COLOUR_BLACK);
auto textHeight = height + entrance.GetTextHeight();
PaintAddImageAsChild(session, ImageId(imageIndex), { 0, 0, textHeight }, { 28, 28, 47 }, { 2, 2, textHeight });
}
static void PaintParkEntranceLightEffects(paint_session* session)
{
#ifdef __ENABLE_LIGHTFX__
if (lightfx_is_available())
{
lightfx_add_3d_light_magic_from_drawing_tile(session->MapPosition, 0, 0, 155, LightType::Lantern3);
}
#endif
}
static void PaintParkEntrance(paint_session* session, uint8_t direction, int32_t height, const EntranceElement& entranceEl)
{
if (gTrackDesignSaveMode || (session->ViewFlags & VIEWPORT_FLAG_HIGHLIGHT_PATH_ISSUES))
return;
PaintParkEntranceLightEffects(session);
session->InteractionType = ViewportInteractionItem::ParkEntrance;
uint32_t image_id, ghost_id = 0;
if (tile_element.IsGhost())
ImageId imageTemplate;
if (entranceEl.IsGhost())
{
session->InteractionType = ViewportInteractionItem::None;
ghost_id = CONSTRUCTION_MARKER;
imageTemplate = ImageId().WithRemap(FilterPaletteID::Palette44);
}
else if (OpenRCT2::TileInspector::IsElementSelected(reinterpret_cast<const TileElement*>(&tile_element)))
else if (OpenRCT2::TileInspector::IsElementSelected(reinterpret_cast<const TileElement*>(&entranceEl)))
{
ghost_id = CONSTRUCTION_MARKER;
imageTemplate = ImageId().WithRemap(FilterPaletteID::Palette44);
}
// Index to which part of the entrance
// Middle, left, right
uint8_t part_index = tile_element.GetSequenceIndex();
const PathSurfaceDescriptor* surfaceDescriptor = nullptr;
// The left and right of the park entrance often have this set to 127.
// So only attempt to get the footpath type if we're dealing with the middle bit of the entrance.
if (part_index == 0)
auto& objManager = GetContext()->GetObjectManager();
auto entrance = reinterpret_cast<EntranceObject*>(objManager.GetLoadedObject(ObjectType::ParkEntrance, 0));
auto sequence = entranceEl.GetSequenceIndex();
switch (sequence)
{
surfaceDescriptor = tile_element.GetPathSurfaceDescriptor();
}
rct_entrance_type* entrance;
uint8_t di = ((direction / 2 + part_index / 2) & 1) ? 0x1A : 0x20;
switch (part_index)
{
case 0:
case EntranceSequence::Centre:
{
// Footpath
auto surfaceDescriptor = entranceEl.GetPathSurfaceDescriptor();
if (surfaceDescriptor != nullptr)
{
image_id = (surfaceDescriptor->Image + 5 * (1 + (direction & 1))) | ghost_id;
PaintAddImageAsParent(session, image_id, { 0, 0, height }, { 32, 0x1C, 0 }, { 0, 2, height });
auto imageIndex = (surfaceDescriptor->Image + 5 * (1 + (direction & 1)));
PaintAddImageAsParent(
session, imageTemplate.WithIndex(imageIndex), { 0, 0, height }, { 32, 28, 0 }, { 0, 2, height });
}
entrance = static_cast<rct_entrance_type*>(object_entry_get_chunk(ObjectType::ParkEntrance, 0));
if (entrance == nullptr)
// Entrance
if (entrance != nullptr)
{
return;
}
image_id = (entrance->image_id + direction * 3) | ghost_id;
PaintAddImageAsParent(session, image_id, { 0, 0, height }, { 0x1C, 0x1C, 0x2F }, { 2, 2, height + 32 });
auto imageIndex = entrance->GetImage(sequence, direction);
PaintAddImageAsParent(
session, imageTemplate.WithIndex(imageIndex), { 0, 0, height }, { 28, 28, 47 }, { 2, 2, height + 32 });
if ((direction + 1) & (1 << 1))
break;
if (ghost_id != 0)
break;
{
auto ft = Formatter();
if (gParkFlags & PARK_FLAGS_PARK_OPEN)
{
const auto& park = OpenRCT2::GetContext()->GetGameState()->GetPark();
auto name = park.Name.c_str();
ft.Add<rct_string_id>(STR_STRING);
ft.Add<const char*>(name);
}
else
{
ft.Add<rct_string_id>(STR_BANNER_TEXT_CLOSED);
ft.Add<uint32_t>(0);
}
utf8 park_name[256];
if (gConfigGeneral.upper_case_banners)
{
format_string_to_upper(park_name, sizeof(park_name), STR_BANNER_TEXT_FORMAT, ft.Data());
}
else
{
format_string(park_name, sizeof(park_name), STR_BANNER_TEXT_FORMAT, ft.Data());
}
uint16_t stringWidth = gfx_get_string_width(park_name, FontSpriteBase::TINY);
uint16_t scroll = stringWidth > 0 ? (gCurrentTicks / 2) % stringWidth : 0;
if (entrance->scrolling_mode == SCROLLING_MODE_NONE)
break;
int32_t stsetup = scrolling_text_setup(
session, STR_BANNER_TEXT_FORMAT, ft, scroll, entrance->scrolling_mode + direction / 2, COLOUR_BLACK);
int32_t text_height = height + entrance->text_height;
PaintAddImageAsChild(session, stsetup, 0, 0, 0x1C, 0x1C, 0x2F, text_height, 2, 2, text_height);
if (!entranceEl.IsGhost())
PaintParkEntranceScrollingText(session, *entrance, direction, height);
}
break;
case 1:
case 2:
entrance = static_cast<rct_entrance_type*>(object_entry_get_chunk(ObjectType::ParkEntrance, 0));
if (entrance == nullptr)
}
case EntranceSequence::Left:
case EntranceSequence::Right:
if (entrance != nullptr)
{
return;
auto imageIndex = entrance->GetImage(sequence, direction);
auto y = ((direction / 2 + sequence / 2) & 1) ? 26 : 32;
PaintAddImageAsParent(
session, imageTemplate.WithIndex(imageIndex), { 0, 0, height }, { 26, y, 79 }, { 3, 3, height });
}
image_id = (entrance->image_id + part_index + direction * 3) | ghost_id;
PaintAddImageAsParent(session, image_id, { 0, 0, height }, { 0x1A, di, 0x4F }, { 3, 3, height });
break;
}
image_id = ghost_id;
if (image_id == 0)
auto supportsImageTemplate = imageTemplate;
if (!entranceEl.IsGhost())
{
image_id = SPRITE_ID_PALETTE_COLOUR_1(COLOUR_SATURATED_BROWN);
supportsImageTemplate = ImageId().WithPrimary(COLOUR_SATURATED_BROWN);
}
wooden_a_supports_paint_setup(session, direction & 1, 0, height, image_id);
wooden_a_supports_paint_setup(session, direction & 1, 0, height, supportsImageTemplate.ToUInt32());
paint_util_set_segment_support_height(session, SEGMENTS_ALL, 0xFFFF, 0);
paint_util_set_general_support_height(session, height + 80, 0x20);
}
/**
*
* rct2: 0x00664FD4
*/
static void PaintHeightMarkers(paint_session* session, const EntranceElement& entranceEl, int32_t height)
{
if (PaintShouldShowHeightMarkers(session, VIEWPORT_FLAG_PATH_HEIGHTS))
{
if (entranceEl.GetDirections() & 0xF)
{
auto heightMarkerBaseZ = entranceEl.GetBaseZ() + 3;
ImageIndex baseImageIndex = SPR_HEIGHT_MARKER_BASE;
baseImageIndex += heightMarkerBaseZ / 16;
baseImageIndex += get_height_marker_offset();
baseImageIndex -= gMapBaseZ;
auto imageId = ImageId(baseImageIndex, COLOUR_GREY);
PaintAddImageAsParent(session, imageId, { 16, 16, height }, { 1, 1, 0 }, { 31, 31, heightMarkerBaseZ + 64 });
}
}
}
void PaintEntrance(paint_session* session, uint8_t direction, int32_t height, const EntranceElement& entranceElement)
{
session->InteractionType = ViewportInteractionItem::Label;
if (PaintShouldShowHeightMarkers(session, VIEWPORT_FLAG_PATH_HEIGHTS))
{
if (entranceElement.GetDirections() & 0xF)
{
int32_t z = entranceElement.GetBaseZ() + 3;
uint32_t image_id = 0x20101689 + get_height_marker_offset() + (z / 16);
image_id -= gMapBaseZ;
PaintAddImageAsParent(session, image_id, { 16, 16, height }, { 1, 1, 0 }, { 31, 31, z + 64 });
}
}
PaintHeightMarkers(session, entranceElement, height);
switch (entranceElement.GetEntranceType())
{
case ENTRANCE_TYPE_RIDE_ENTRANCE:
case ENTRANCE_TYPE_RIDE_EXIT:
ride_entrance_exit_paint(session, direction, height, entranceElement);
PaintRideEntranceExit(session, direction, height, entranceElement);
break;
case ENTRANCE_TYPE_PARK_ENTRANCE:
park_entrance_paint(session, direction, height, entranceElement);
PaintParkEntrance(session, direction, height, entranceElement);
break;
}
}

View File

@ -10,6 +10,7 @@
#include "../../Game.h"
#include "../../config/Config.h"
#include "../../core/Numerics.hpp"
#include "../../core/String.hpp"
#include "../../interface/Viewport.h"
#include "../../localisation/Localisation.h"
#include "../../object/LargeSceneryObject.h"
@ -25,171 +26,6 @@
#include "../Supports.h"
#include "Paint.TileElement.h"
#include <iterator>
// 6B8172:
static void large_scenery_paint_supports(
paint_session* session, uint8_t direction, uint16_t height, const LargeSceneryElement& tileElement, uint32_t dword_F4387C,
const rct_large_scenery_tile* tile)
{
if (tile->flags & LARGE_SCENERY_TILE_FLAG_NO_SUPPORTS)
{
return;
}
int32_t ax = 0;
int32_t supportHeight = height;
if (supportHeight & 0xF)
{
supportHeight &= 0xFFFFFFF0;
ax = 49;
}
int32_t supportImageColourFlags = IMAGE_TYPE_REMAP;
if (dword_F4387C)
{
supportImageColourFlags = dword_F4387C;
}
wooden_b_supports_paint_setup(session, (direction & 1), ax, supportHeight, supportImageColourFlags);
int32_t clearanceHeight = ceil2(tileElement.GetClearanceZ() + 15, 16);
if (tile->flags & LARGE_SCENERY_TILE_FLAG_ALLOW_SUPPORTS_ABOVE)
{
paint_util_set_segment_support_height(session, SEGMENTS_ALL, clearanceHeight, 0x20);
}
else
{
paint_util_set_segment_support_height(session, SEGMENTS_ALL, 0xFFFF, 0);
}
paint_util_set_general_support_height(session, clearanceHeight, 0x20);
}
static rct_large_scenery_text_glyph* large_scenery_sign_get_glyph(LargeSceneryText* text, uint32_t codepoint)
{
if (codepoint >= std::size(text->glyphs))
{
return &text->glyphs[static_cast<size_t>('?')];
}
return &text->glyphs[codepoint];
}
static int32_t large_scenery_sign_text_width(const utf8* str, LargeSceneryText* text)
{
int32_t width = 0;
uint32_t codepoint;
while ((codepoint = utf8_get_next(str, &str)) != 0)
{
width += large_scenery_sign_get_glyph(text, codepoint)->width;
}
return width;
}
static int32_t large_scenery_sign_text_height(const utf8* str, LargeSceneryText* text)
{
int32_t height = 0;
uint32_t codepoint;
while ((codepoint = utf8_get_next(str, &str)) != 0)
{
height += large_scenery_sign_get_glyph(text, codepoint)->height;
}
return height;
}
static void large_scenery_sign_fit_text(const utf8* str, LargeSceneryText* text, bool height, utf8* fitStr, size_t bufLen)
{
utf8* fitStrEnd = fitStr;
safe_strcpy(fitStr, str, bufLen);
int32_t w = 0;
uint32_t codepoint;
while (w <= text->max_width && (codepoint = utf8_get_next(fitStrEnd, const_cast<const utf8**>(&fitStrEnd))) != 0)
{
if (height)
{
w += large_scenery_sign_get_glyph(text, codepoint)->height;
}
else
{
w += large_scenery_sign_get_glyph(text, codepoint)->width;
}
}
*fitStrEnd = 0;
}
static int32_t div_to_minus_infinity(int32_t a, int32_t b)
{
return (a / b) - (a % b < 0);
}
static void large_scenery_sign_paint_line(
paint_session* session, const utf8* str, LargeSceneryText* text, int32_t textImage, int32_t textColour, uint8_t direction,
int32_t y_offset)
{
utf8 fitStr[32];
large_scenery_sign_fit_text(str, text, false, fitStr, sizeof(fitStr));
int32_t width = large_scenery_sign_text_width(fitStr, text);
int32_t x_offset = text->offset[(direction & 1)].x;
int32_t acc = y_offset * ((direction & 1) ? -1 : 1);
if (!(text->flags & LARGE_SCENERY_TEXT_FLAG_VERTICAL))
{
// sign is horizontal, centre text:
x_offset -= (width / 2);
acc -= (width / 2);
}
uint32_t codepoint;
const utf8* fitStrPtr = fitStr;
while ((codepoint = utf8_get_next(fitStrPtr, &fitStrPtr)) != 0)
{
int32_t glyph_offset = large_scenery_sign_get_glyph(text, codepoint)->image_offset;
uint8_t glyph_type = direction & 1;
if (text->flags & LARGE_SCENERY_TEXT_FLAG_VERTICAL)
{ // vertical sign
glyph_offset *= 2;
}
else
{
glyph_offset *= 4;
// set slightly different glyph on horizontal sign, which was rendered 1/2 pixel lower to deal with aliasing:
if (direction & 1)
{
if (!(acc & 1))
{
glyph_type += 2;
}
}
else
{
if ((acc & 1))
{
glyph_type += 2;
}
}
}
int32_t image_id = (textImage + glyph_offset + glyph_type) | textColour;
if (direction == 3)
{
PaintAttachToPreviousPS(session, image_id, x_offset, -div_to_minus_infinity(acc, 2));
}
else
{
if (text->flags & LARGE_SCENERY_TEXT_FLAG_VERTICAL)
{
PaintAttachToPreviousPS(session, image_id, x_offset, div_to_minus_infinity(acc, 2));
}
else
{
PaintAttachToPreviousAttach(session, image_id, x_offset, div_to_minus_infinity(acc, 2));
}
}
x_offset += large_scenery_sign_get_glyph(text, codepoint)->width;
acc += large_scenery_sign_get_glyph(text, codepoint)->width;
}
}
struct boundbox
{
CoordsXY offset;
@ -197,7 +33,7 @@ struct boundbox
};
// clang-format off
static constexpr const boundbox s98E3C4[] = {
static constexpr const boundbox LargeSceneryBoundBoxes[] = {
{ { 3, 3 }, { 26, 26 } },
{ { 17, 17 }, { 12, 12 } },
{ { 17, 3 }, { 12, 12 } },
@ -218,19 +54,279 @@ static constexpr const boundbox s98E3C4[] = {
};
// clang-format on
/*
*
* rct2: 0x006B7F0C
*/
static void PaintLargeScenerySupports(
paint_session* session, uint8_t direction, uint16_t height, const LargeSceneryElement& tileElement, ImageId imageTemplate,
const rct_large_scenery_tile& tile)
{
if (tile.flags & LARGE_SCENERY_TILE_FLAG_NO_SUPPORTS)
return;
auto special = 0;
auto supportHeight = height;
if (supportHeight & 0xF)
{
supportHeight &= ~0xF;
special = 49;
}
wooden_b_supports_paint_setup(session, (direction & 1), special, supportHeight, imageTemplate.ToUInt32());
int32_t clearanceHeight = ceil2(tileElement.GetClearanceZ() + 15, 16);
if (tile.flags & LARGE_SCENERY_TILE_FLAG_ALLOW_SUPPORTS_ABOVE)
{
paint_util_set_segment_support_height(session, SEGMENTS_ALL, clearanceHeight, 0x20);
}
else
{
paint_util_set_segment_support_height(session, SEGMENTS_ALL, 0xFFFF, 0);
}
paint_util_set_general_support_height(session, clearanceHeight, 0x20);
}
static std::string_view LargeSceneryCalculateDisplayText(const LargeSceneryText& text, std::string_view s, bool height)
{
size_t totalSize = 0;
CodepointView view(s);
auto it = view.begin();
while (it != view.end() && totalSize <= text.max_width)
{
auto glyph = text.GetGlyph(*it, ' ');
totalSize += height ? glyph.height : glyph.width;
it++;
}
auto totalLength = it.GetIndex();
return s.substr(0, totalLength);
}
static int32_t DivToMinusInfinity(int32_t a, int32_t b)
{
return (a / b) - (a % b < 0);
}
static void PaintLargeScenery3DTextLine(
paint_session* session, const LargeSceneryEntry& sceneryEntry, const LargeSceneryText& text, std::string_view line,
ImageId imageTemplate, Direction direction, int32_t offsetY)
{
line = LargeSceneryCalculateDisplayText(text, line, false);
auto width = text.MeasureWidth(line);
auto offsetX = text.offset[(direction & 1)].x;
auto acc = offsetY * ((direction & 1) ? -1 : 1);
if (!(text.flags & LARGE_SCENERY_TEXT_FLAG_VERTICAL))
{
// sign is horizontal, centre text:
offsetX -= (width / 2);
acc -= (width / 2);
}
for (auto codepoint : CodepointView(line))
{
auto glyph = text.GetGlyph(codepoint, ' ');
auto glyphOffset = glyph.image_offset;
auto glyphType = direction & 1;
if (text.flags & LARGE_SCENERY_TEXT_FLAG_VERTICAL)
{
glyphOffset *= 2;
}
else
{
glyphOffset *= 4;
// set slightly different glyph on horizontal sign, which was rendered 1/2 pixel lower to deal with aliasing:
if (direction & 1)
{
if (!(acc & 1))
{
glyphType += 2;
}
}
else
{
if ((acc & 1))
{
glyphType += 2;
}
}
}
auto imageIndex = sceneryEntry.text_image + glyphOffset + glyphType;
auto imageId = imageTemplate.WithIndex(imageIndex);
if (direction == 3)
{
PaintAttachToPreviousPS(session, imageId, offsetX, -DivToMinusInfinity(acc, 2));
}
else if (text.flags & LARGE_SCENERY_TEXT_FLAG_VERTICAL)
{
PaintAttachToPreviousPS(session, imageId, offsetX, DivToMinusInfinity(acc, 2));
}
else
{
PaintAttachToPreviousAttach(session, imageId, offsetX, DivToMinusInfinity(acc, 2));
}
offsetX += glyph.width;
acc += glyph.width;
}
}
static bool Is3DTextSingleLine(const LargeSceneryText& text, std::string_view s)
{
if (text.flags & LARGE_SCENERY_TEXT_FLAG_TWO_LINE)
{
auto width = text.MeasureWidth(s);
return width <= text.max_width;
}
return true;
}
static void PaintLargeScenery3DText(
paint_session* session, const LargeSceneryEntry& sceneryEntry, const rct_large_scenery_tile& tile,
const LargeSceneryElement& tileElement, uint8_t direction, uint16_t height, bool isGhost)
{
if (sceneryEntry.tiles[1].x_offset != -1)
{
auto sequenceDirection = (tileElement.GetSequenceIndex() - 1) & 3;
if (sequenceDirection != direction)
{
return;
}
}
if (session->DPI.zoom_level > ZoomLevel{ 1 })
return;
auto banner = tileElement.GetBanner();
if (banner == nullptr)
return;
const auto* text = sceneryEntry.text;
if (text == nullptr)
return;
auto textColour = isGhost ? static_cast<colour_t>(COLOUR_GREY) : tileElement.GetSecondaryColour();
auto imageTemplate = ImageId().WithPrimary(textColour);
char signString[256];
auto ft = Formatter();
banner->FormatTextTo(ft);
format_string(signString, sizeof(signString), STR_STRINGID, ft.Data());
auto offsetY = text->offset[(direction & 1)].y * 2;
if (text->flags & LARGE_SCENERY_TEXT_FLAG_VERTICAL)
{
// Vertical sign
offsetY++;
auto displayText = LargeSceneryCalculateDisplayText(*text, signString, true);
auto displayTextHeight = text->MeasureHeight(displayText);
for (auto codepoint : CodepointView(displayText))
{
char line[8]{};
utf8_write_codepoint(line, codepoint);
PaintLargeScenery3DTextLine(
session, sceneryEntry, *text, line, imageTemplate, direction, offsetY - displayTextHeight);
auto glyph = text->GetGlyph(codepoint, ' ');
offsetY += glyph.height * 2;
}
}
else
{
// Horizontal sign
offsetY -= (direction & 1);
if (Is3DTextSingleLine(*text, signString))
{
PaintLargeScenery3DTextLine(session, sceneryEntry, *text, signString, imageTemplate, direction, offsetY);
}
else
{
auto lineHeight = text->GetGlyph('A')->height + 1;
offsetY -= lineHeight;
// Split the string into two lines at best position
auto current = std::string_view(signString);
std::string_view next;
for (int32_t lineIndex = 0; lineIndex < 2; lineIndex++)
{
std::string_view best;
CodepointView view(current);
auto lineWidth = 0;
auto it = view.begin();
while (it != view.end() && lineWidth < text->max_width)
{
// Trim any leading spaces
auto codepoint = *it;
if (codepoint != ' ' || lineWidth != 0)
{
// Determine if this is a good place to split
if (codepoint == ' ' || codepoint == '\n')
{
auto index = it.GetIndex();
best = current.substr(0, index);
next = current.substr(index + 1);
if (codepoint == '\n')
break;
}
auto glyph = text->GetGlyph(*it, ' ');
lineWidth += glyph.width;
}
it++;
}
if (best.empty())
{
// No good split found, or reached end of string
auto index = it.GetIndex();
best = current.substr(0, index);
next = current.substr(index);
}
PaintLargeScenery3DTextLine(session, sceneryEntry, *text, best, imageTemplate, direction, offsetY);
current = next;
offsetY += lineHeight * 2;
}
}
}
}
static void PaintLargeSceneryScrollingText(
paint_session* session, const LargeSceneryEntry& sceneryEntry, const LargeSceneryElement& tileElement, uint8_t direction,
uint16_t height, const CoordsXYZ& bbOffset, bool isGhost)
{
auto textColour = isGhost ? static_cast<colour_t>(COLOUR_GREY) : tileElement.GetSecondaryColour();
auto textPaletteIndex = direction == 0 ? ColourMapA[textColour].mid_dark : ColourMapA[textColour].light;
auto banner = tileElement.GetBanner();
if (banner == nullptr)
return;
auto ft = Formatter();
banner->FormatTextTo(ft);
char text[256];
if (gConfigGeneral.upper_case_banners)
{
format_string_to_upper(text, sizeof(text), STR_SCROLLING_SIGN_TEXT, ft.Data());
}
else
{
format_string(text, sizeof(text), STR_SCROLLING_SIGN_TEXT, ft.Data());
}
auto scrollMode = sceneryEntry.scrolling_mode + ((direction + 1) & 3);
auto stringWidth = gfx_get_string_width(text, FontSpriteBase::TINY);
auto scroll = stringWidth > 0 ? (gCurrentTicks / 2) % stringWidth : 0;
auto imageId = scrolling_text_setup(session, STR_SCROLLING_SIGN_TEXT, ft, scroll, scrollMode, textPaletteIndex);
PaintAddImageAsChild(session, imageId, { 0, 0, height + 25 }, { 1, 1, 21 }, bbOffset);
}
void PaintLargeScenery(paint_session* session, uint8_t direction, uint16_t height, const LargeSceneryElement& tileElement)
{
if (session->ViewFlags & VIEWPORT_FLAG_HIGHLIGHT_PATH_ISSUES)
{
return;
}
session->InteractionType = ViewportInteractionItem::LargeScenery;
const uint32_t sequenceNum = tileElement.GetSequenceIndex();
const LargeSceneryObject* object = tileElement.GetObject();
auto sequenceNum = tileElement.GetSequenceIndex();
const auto* object = tileElement.GetObject();
if (object == nullptr)
return;
@ -238,218 +334,64 @@ void PaintLargeScenery(paint_session* session, uint8_t direction, uint16_t heigh
if (sceneryEntry == nullptr)
return;
uint32_t image_id = (sequenceNum << 2) + sceneryEntry->image + 4 + direction;
const rct_large_scenery_tile* tile = object->GetTileForSequence(sequenceNum);
const auto* tile = object->GetTileForSequence(sequenceNum);
if (tile == nullptr)
return;
uint32_t dword_F4387C = 0;
image_id |= SPRITE_ID_PALETTE_COLOUR_2(tileElement.GetPrimaryColour(), tileElement.GetSecondaryColour());
if (gTrackDesignSaveMode)
session->InteractionType = ViewportInteractionItem::LargeScenery;
auto isGhost = false;
ImageId imageTemplate;
if (gTrackDesignSaveMode && !track_design_save_contains_tile_element(reinterpret_cast<const TileElement*>(&tileElement)))
{
if (!track_design_save_contains_tile_element(reinterpret_cast<const TileElement*>(&tileElement)))
{
image_id &= 0x7FFFF;
dword_F4387C = SPRITE_ID_PALETTE_COLOUR_1(EnumValue(FilterPaletteID::Palette46));
image_id |= dword_F4387C;
}
imageTemplate = ImageId().WithRemap(FilterPaletteID::Palette46);
isGhost = true;
}
if (tileElement.IsGhost())
else if (tileElement.IsGhost())
{
session->InteractionType = ViewportInteractionItem::None;
image_id &= 0x7FFFF;
dword_F4387C = CONSTRUCTION_MARKER;
image_id |= dword_F4387C;
imageTemplate = ImageId().WithRemap(FilterPaletteID::Palette44);
isGhost = true;
}
else if (OpenRCT2::TileInspector::IsElementSelected(reinterpret_cast<const TileElement*>(&tileElement)))
{
image_id &= 0x7FFFF;
dword_F4387C = CONSTRUCTION_MARKER;
image_id |= dword_F4387C;
}
int32_t boxlengthZ = tile->z_clearance;
if (boxlengthZ > 0x80)
{
boxlengthZ = 0x80;
}
boxlengthZ -= 3;
uint16_t edi = tile->flags;
int32_t esi = 16;
if (edi & 0xF00)
{
edi &= 0xF000;
edi = Numerics::rol16(edi, direction);
esi = (edi & 0xF) | (edi >> 12);
}
const CoordsXYZ bbOffset = { s98E3C4[esi].offset, height };
const CoordsXYZ bbLength = { s98E3C4[esi].length, boxlengthZ };
PaintAddImageAsParent(session, image_id, { 0, 0, height }, bbLength, bbOffset);
if (sceneryEntry->scrolling_mode == SCROLLING_MODE_NONE || direction == 1 || direction == 2)
{
large_scenery_paint_supports(session, direction, height, tileElement, dword_F4387C, tile);
return;
}
if (sceneryEntry->flags & LARGE_SCENERY_FLAG_3D_TEXT)
{
if (sceneryEntry->tiles[1].x_offset != static_cast<int16_t>(static_cast<uint16_t>(0xFFFF)))
{
int32_t sequenceDirection = (tileElement.GetSequenceIndex() - 1) & 3;
if (sequenceDirection != direction)
{
large_scenery_paint_supports(session, direction, height, tileElement, dword_F4387C, tile);
return;
}
}
rct_drawpixelinfo* dpi = &session->DPI;
if (dpi->zoom_level > ZoomLevel{ 1 })
{
large_scenery_paint_supports(session, direction, height, tileElement, dword_F4387C, tile);
return;
}
// 6B8331:
// Draw sign text:
int32_t textColour = tileElement.GetSecondaryColour();
if (dword_F4387C)
{
textColour = COLOUR_GREY;
}
textColour = (textColour << 19) | IMAGE_TYPE_REMAP;
auto banner = tileElement.GetBanner();
if (banner != nullptr)
{
auto ft = Formatter();
banner->FormatTextTo(ft);
utf8 signString[256];
format_string(signString, sizeof(signString), STR_STRINGID, ft.Data());
LargeSceneryText* text = sceneryEntry->text;
int32_t y_offset = (text->offset[(direction & 1)].y * 2);
if (text->flags & LARGE_SCENERY_TEXT_FLAG_VERTICAL)
{
// Draw vertical sign:
y_offset += 1;
utf8 fitStr[32];
large_scenery_sign_fit_text(signString, text, true, fitStr, sizeof(fitStr));
safe_strcpy(fitStr, fitStr, sizeof(fitStr));
const utf8* fitStrPtr = fitStr;
int32_t height2 = large_scenery_sign_text_height(fitStr, text);
uint32_t codepoint;
while ((codepoint = utf8_get_next(fitStrPtr, &fitStrPtr)) != 0)
{
utf8 str[5] = { 0 };
utf8_write_codepoint(str, codepoint);
large_scenery_sign_paint_line(
session, str, sceneryEntry->text, sceneryEntry->text_image, textColour, direction, y_offset - height2);
y_offset += large_scenery_sign_get_glyph(text, codepoint)->height * 2;
}
}
else
{
y_offset -= (direction & 1);
if (text->flags & LARGE_SCENERY_TEXT_FLAG_TWO_LINE)
{
// Draw two-line sign:
int32_t width = large_scenery_sign_text_width(signString, text);
if (width > text->max_width)
{
y_offset -= large_scenery_sign_get_glyph(text, 'A')->height + 1;
utf8* src = signString;
for (int32_t i = 0; i < 2; i++)
{
utf8 str1[64] = { 0 };
utf8* dst = str1;
utf8* srcold = src;
utf8* spacesrc = nullptr;
utf8* spacedst = nullptr;
int32_t w = 0;
uint32_t codepoint = utf8_get_next(src, const_cast<const utf8**>(&src));
do
{
w += large_scenery_sign_get_glyph(text, codepoint)->width;
if (codepoint == ' ')
{
spacesrc = src;
spacedst = dst;
}
} while (w <= text->max_width && (dst = utf8_write_codepoint(dst, codepoint)) != nullptr
&& (srcold = src) != nullptr
&& (codepoint = utf8_get_next(src, const_cast<const utf8**>(&src))) != '\0');
src = srcold;
if (spacesrc && codepoint)
{
*spacedst = 0;
src = spacesrc;
}
large_scenery_sign_paint_line(
session, str1, sceneryEntry->text, sceneryEntry->text_image, textColour, direction, y_offset);
y_offset += (large_scenery_sign_get_glyph(text, 'A')->height + 1) * 2;
}
}
else
{
large_scenery_sign_paint_line(
session, signString, sceneryEntry->text, sceneryEntry->text_image, textColour, direction, y_offset);
}
}
else
{
// Draw one-line sign:
large_scenery_sign_paint_line(
session, signString, sceneryEntry->text, sceneryEntry->text_image, textColour, direction, y_offset);
}
}
}
return;
}
rct_drawpixelinfo* dpi = &session->DPI;
if (dpi->zoom_level > ZoomLevel{ 0 })
{
large_scenery_paint_supports(session, direction, height, tileElement, dword_F4387C, tile);
return;
}
uint8_t sequenceDirection2 = (tileElement.GetSequenceIndex() - 1) & 3;
if (sequenceDirection2 != direction)
{
large_scenery_paint_supports(session, direction, height, tileElement, dword_F4387C, tile);
return;
}
// Draw scrolling text:
uint8_t textColour = tileElement.GetSecondaryColour();
if (dword_F4387C)
{
textColour = COLOUR_GREY;
}
if (direction == 0)
{
textColour = ColourMapA[textColour].mid_dark;
imageTemplate = ImageId().WithRemap(FilterPaletteID::Palette44);
isGhost = true;
}
else
{
textColour = ColourMapA[textColour].light;
imageTemplate = ImageId(0, tileElement.GetPrimaryColour(), tileElement.GetSecondaryColour());
}
// 6B809A:
uint16_t scrollMode = sceneryEntry->scrolling_mode + ((direction + 1) & 0x3);
auto banner = tileElement.GetBanner();
if (banner != nullptr)
auto boxlengthZ = std::min<uint8_t>(tile->z_clearance, 128) - 3;
auto flags = tile->flags;
auto bbIndex = 16;
if (flags & 0xF00)
{
auto ft = Formatter();
banner->FormatTextTo(ft);
utf8 signString[256];
if (gConfigGeneral.upper_case_banners)
{
format_string_to_upper(signString, sizeof(signString), STR_SCROLLING_SIGN_TEXT, ft.Data());
}
else
{
format_string(signString, sizeof(signString), STR_SCROLLING_SIGN_TEXT, ft.Data());
}
uint16_t stringWidth = gfx_get_string_width(signString, FontSpriteBase::TINY);
uint16_t scroll = stringWidth > 0 ? (gCurrentTicks / 2) % stringWidth : 0;
PaintAddImageAsChild(
session, scrolling_text_setup(session, STR_SCROLLING_SIGN_TEXT, ft, scroll, scrollMode, textColour), 0, 0, 1, 1, 21,
height + 25, bbOffset.x, bbOffset.y, bbOffset.z);
flags &= 0xF000;
flags = Numerics::rol16(flags, direction);
bbIndex = (flags & 0xF) | (flags >> 12);
}
const CoordsXYZ bbOffset = { LargeSceneryBoundBoxes[bbIndex].offset, height };
const CoordsXYZ bbLength = { LargeSceneryBoundBoxes[bbIndex].length, boxlengthZ };
large_scenery_paint_supports(session, direction, height, tileElement, dword_F4387C, tile);
auto imageIndex = sceneryEntry->image + 4 + (sequenceNum << 2) + direction;
PaintAddImageAsParent(session, imageTemplate.WithIndex(imageIndex), { 0, 0, height }, bbLength, bbOffset);
if (sceneryEntry->scrolling_mode != SCROLLING_MODE_NONE && direction != 1 && direction != 2)
{
if (sceneryEntry->flags & LARGE_SCENERY_FLAG_3D_TEXT)
{
PaintLargeScenery3DText(session, *sceneryEntry, *tile, tileElement, direction, height, isGhost);
}
else if (session->DPI.zoom_level <= ZoomLevel{ 0 })
{
auto sequenceDirection2 = (tileElement.GetSequenceIndex() - 1) & 3;
if (sequenceDirection2 == direction)
{
PaintLargeSceneryScrollingText(session, *sceneryEntry, tileElement, direction, height, bbOffset, isGhost);
}
}
}
PaintLargeScenerySupports(session, direction, height, tileElement, isGhost ? imageTemplate : ImageId(), *tile);
}

File diff suppressed because it is too large Load Diff

View File

@ -28,6 +28,77 @@ static constexpr const CoordsXY lengths[] = {
{ 26, 12 },
};
static void PaintSmallScenerySupports(
paint_session* session, const SmallSceneryEntry& sceneryEntry, const SmallSceneryElement& sceneryElement,
Direction direction, int32_t height, ImageId imageTemplate)
{
if (!sceneryElement.NeedsSupports())
return;
if (sceneryEntry.HasFlag(SMALL_SCENERY_FLAG_NO_SUPPORTS))
return;
auto special = 0;
auto supportHeight = height;
if (supportHeight & 0xF)
{
supportHeight &= ~0xF;
special = 49;
}
auto supportImageTemplate = ImageId().WithRemap(0);
if (sceneryEntry.HasFlag(SMALL_SCENERY_FLAG_PAINT_SUPPORTS))
{
supportImageTemplate = ImageId().WithPrimary(sceneryElement.GetPrimaryColour());
}
if (imageTemplate.IsRemap())
{
supportImageTemplate = imageTemplate;
}
auto supportType = (direction & 1) ? 1 : 0;
wooden_b_supports_paint_setup(session, supportType, special, supportHeight, supportImageTemplate.ToUInt32());
}
static void SetSupportHeights(
paint_session* session, const SmallSceneryEntry& sceneryEntry, const SmallSceneryElement& sceneryElement, int32_t height)
{
height += sceneryEntry.height;
paint_util_set_general_support_height(session, ceil2(height, 8), 0x20);
if (sceneryEntry.HasFlag(SMALL_SCENERY_FLAG_BUILD_DIRECTLY_ONTOP))
{
if (sceneryEntry.HasFlag(SMALL_SCENERY_FLAG_FULL_TILE))
{
paint_util_set_segment_support_height(session, SEGMENT_C4, height, 0x20);
if (sceneryEntry.HasFlag(SMALL_SCENERY_FLAG_VOFFSET_CENTRE))
{
paint_util_set_segment_support_height(session, SEGMENTS_ALL & ~SEGMENT_C4, height, 0x20);
}
}
else if (sceneryEntry.HasFlag(SMALL_SCENERY_FLAG_VOFFSET_CENTRE))
{
auto direction = (sceneryElement.GetSceneryQuadrant() + session->CurrentRotation) % 4;
paint_util_set_segment_support_height(
session, paint_util_rotate_segments(SEGMENT_B4 | SEGMENT_C8 | SEGMENT_CC, direction), height, 0x20);
}
}
else if (sceneryEntry.HasFlag(SMALL_SCENERY_FLAG27 | SMALL_SCENERY_FLAG_FULL_TILE))
{
paint_util_set_segment_support_height(session, SEGMENT_C4, 0xFFFF, 0);
if (sceneryEntry.HasFlag(SMALL_SCENERY_FLAG_VOFFSET_CENTRE))
{
paint_util_set_segment_support_height(session, SEGMENTS_ALL & ~SEGMENT_C4, 0xFFFF, 0);
}
}
else if (sceneryEntry.HasFlag(SMALL_SCENERY_FLAG_VOFFSET_CENTRE))
{
auto direction = (sceneryElement.GetSceneryQuadrant() + session->CurrentRotation) % 4;
paint_util_set_segment_support_height(
session, paint_util_rotate_segments(SEGMENT_B4 | SEGMENT_C8 | SEGMENT_CC, direction), 0xFFFF, 0);
}
}
/**
*
* rct2: 0x006DFF47
@ -38,197 +109,149 @@ void PaintSmallScenery(paint_session* session, uint8_t direction, int32_t height
{
return;
}
session->InteractionType = ViewportInteractionItem::Scenery;
CoordsXYZ boxlength;
CoordsXYZ boxoffset;
boxoffset.x = 0;
boxoffset.y = 0;
boxoffset.z = height;
uint32_t marker = 0;
const int32_t rotation = session->CurrentRotation;
if (gTrackDesignSaveMode)
{
if (!track_design_save_contains_tile_element(reinterpret_cast<const TileElement*>(&sceneryElement)))
{
marker = SPRITE_ID_PALETTE_COLOUR_1(EnumValue(FilterPaletteID::Palette46));
}
}
if (sceneryElement.IsGhost())
{
session->InteractionType = ViewportInteractionItem::None;
marker = CONSTRUCTION_MARKER;
}
else if (OpenRCT2::TileInspector::IsElementSelected(reinterpret_cast<const TileElement*>(&sceneryElement)))
{
marker = CONSTRUCTION_MARKER;
}
auto* sceneryEntry = sceneryElement.GetEntry();
if (sceneryEntry == nullptr)
{
return;
}
int32_t baseImageid = sceneryEntry->image + direction;
boxlength.x = 2;
boxlength.y = 2;
int8_t x_offset = 0;
int8_t y_offset = 0;
session->InteractionType = ViewportInteractionItem::Scenery;
CoordsXYZ boxLength;
CoordsXYZ boxOffset{ 0, 0, height };
ImageId imageTemplate;
if (gTrackDesignSaveMode)
{
if (!track_design_save_contains_tile_element(reinterpret_cast<const TileElement*>(&sceneryElement)))
{
imageTemplate = ImageId().WithRemap(FilterPaletteID::Palette46);
}
}
if (sceneryElement.IsGhost())
{
session->InteractionType = ViewportInteractionItem::None;
imageTemplate = ImageId().WithRemap(FilterPaletteID::Palette44);
}
else if (OpenRCT2::TileInspector::IsElementSelected(reinterpret_cast<const TileElement*>(&sceneryElement)))
{
imageTemplate = ImageId().WithRemap(FilterPaletteID::Palette44);
}
boxLength.x = 2;
boxLength.y = 2;
CoordsXYZ offset = { 0, 0, height };
if (sceneryEntry->HasFlag(SMALL_SCENERY_FLAG_FULL_TILE))
{
if (sceneryEntry->HasFlag(SMALL_SCENERY_FLAG_HALF_SPACE))
{
// 6DFFE3:
static constexpr const CoordsXY scenery_half_tile_offsets[] = {
static constexpr const CoordsXY sceneryHalfTileOffsets[] = {
{ 3, 3 },
{ 3, 17 },
{ 17, 3 },
{ 3, 3 },
};
boxoffset.x = scenery_half_tile_offsets[direction].x;
boxoffset.y = scenery_half_tile_offsets[direction].y;
boxlength.x = lengths[direction].x;
boxlength.y = lengths[direction].y;
x_offset = 3;
y_offset = 3;
boxOffset.x = sceneryHalfTileOffsets[direction].x;
boxOffset.y = sceneryHalfTileOffsets[direction].y;
boxLength.x = lengths[direction].x;
boxLength.y = lengths[direction].y;
offset.x = 3;
offset.y = 3;
}
else
{
x_offset = 15;
y_offset = 15;
offset.x = 15;
offset.y = 15;
if (sceneryEntry->HasFlag(SMALL_SCENERY_FLAG_VOFFSET_CENTRE))
{
x_offset = 3;
y_offset = 3;
boxlength.x = 26;
boxlength.y = 26;
offset.x = 3;
offset.y = 3;
boxLength.x = 26;
boxLength.y = 26;
if (sceneryEntry->HasFlag(SMALL_SCENERY_FLAG_NO_WALLS))
{
x_offset = 1;
y_offset = 1;
boxlength.x = 30;
boxlength.y = 30;
offset.x = 1;
offset.y = 1;
boxLength.x = 30;
boxLength.y = 30;
}
}
boxoffset.x = x_offset;
boxoffset.y = y_offset;
boxOffset.x = offset.x;
boxOffset.y = offset.y;
}
}
else
{
// 6DFFC2:
uint8_t quadrant = (sceneryElement.GetSceneryQuadrant() + rotation) & 3;
x_offset = SceneryQuadrantOffsets[quadrant].x;
y_offset = SceneryQuadrantOffsets[quadrant].y;
boxoffset.x = x_offset;
boxoffset.y = y_offset;
uint8_t quadrant = (sceneryElement.GetSceneryQuadrant() + session->CurrentRotation) & 3;
offset.x = SceneryQuadrantOffsets[quadrant].x;
offset.y = SceneryQuadrantOffsets[quadrant].y;
boxOffset.x = offset.x;
boxOffset.y = offset.y;
}
// 6E007F:
boxlength.z = sceneryEntry->height - 4;
if (boxlength.z > 128 || boxlength.z < 0)
boxLength.z = sceneryEntry->height - 4;
if (boxLength.z > 128 || boxLength.z < 0)
{
boxlength.z = 128;
boxLength.z = 128;
}
boxLength.z--;
ImageIndex baseImageIndex = sceneryEntry->image + direction;
if (sceneryEntry->HasFlag(SMALL_SCENERY_FLAG_CAN_WITHER))
{
if (sceneryElement.GetAge() >= SCENERY_WITHER_AGE_THRESHOLD_1)
{
baseImageid += 4;
baseImageIndex += 4;
}
if (sceneryElement.GetAge() >= SCENERY_WITHER_AGE_THRESHOLD_2)
{
baseImageid += 4;
baseImageIndex += 4;
}
}
if (sceneryEntry->HasFlag(SMALL_SCENERY_FLAG_HAS_PRIMARY_COLOUR))
{
if (sceneryEntry->HasFlag(SMALL_SCENERY_FLAG_HAS_SECONDARY_COLOUR))
{
baseImageid |= SPRITE_ID_PALETTE_COLOUR_2(sceneryElement.GetPrimaryColour(), sceneryElement.GetSecondaryColour());
}
else
{
baseImageid |= SPRITE_ID_PALETTE_COLOUR_1(sceneryElement.GetPrimaryColour());
}
}
if (marker != 0)
{
baseImageid = (baseImageid & 0x7FFFF) | marker;
}
if (!(sceneryEntry->HasFlag(SMALL_SCENERY_FLAG_VISIBLE_WHEN_ZOOMED)))
{
PaintAddImageAsParent(
session, baseImageid, { x_offset, y_offset, height }, { boxlength.x, boxlength.y, boxlength.z - 1 }, boxoffset);
auto imageId = imageTemplate.WithIndex(baseImageIndex);
if (!imageTemplate.IsRemap() && sceneryEntry->HasFlag(SMALL_SCENERY_FLAG_HAS_PRIMARY_COLOUR))
{
imageId = imageId.WithPrimary(sceneryElement.GetPrimaryColour());
if (sceneryEntry->HasFlag(SMALL_SCENERY_FLAG_HAS_SECONDARY_COLOUR))
{
imageId = imageId.WithSecondary(sceneryElement.GetSecondaryColour());
}
}
PaintAddImageAsParent(session, imageId, offset, boxLength, boxOffset);
}
if (sceneryEntry->HasFlag(SMALL_SCENERY_FLAG_HAS_GLASS))
if (sceneryEntry->HasFlag(SMALL_SCENERY_FLAG_HAS_GLASS) && !imageTemplate.IsRemap())
{
if (marker == 0)
{
// Draw translucent overlay:
// TODO: Name palette entries
int32_t image_id = (baseImageid & 0x7FFFF) + (EnumValue(GlassPaletteIds[sceneryElement.GetPrimaryColour()]) << 19)
+ 0x40000004;
PaintAddImageAsChild(
session, image_id, x_offset, y_offset, boxlength.x, boxlength.y, boxlength.z - 1, height, boxoffset.x,
boxoffset.y, boxoffset.z);
}
auto imageId = ImageId(baseImageIndex + 4).WithTransparancy(sceneryElement.GetPrimaryColour());
PaintAddImageAsChild(session, imageId, offset, boxLength, boxOffset);
}
if (sceneryEntry->HasFlag(SMALL_SCENERY_FLAG_ANIMATED))
{
rct_drawpixelinfo* dpi = &session->DPI;
if ((sceneryEntry->HasFlag(SMALL_SCENERY_FLAG_VISIBLE_WHEN_ZOOMED)) || (dpi->zoom_level <= ZoomLevel{ 1 }))
if (sceneryEntry->HasFlag(SMALL_SCENERY_FLAG_VISIBLE_WHEN_ZOOMED) || (session->DPI.zoom_level <= ZoomLevel{ 1 }))
{
// 6E01A9:
if (sceneryEntry->HasFlag(SMALL_SCENERY_FLAG_FOUNTAIN_SPRAY_1))
{
// 6E0512:
int32_t image_id = ((gCurrentTicks / 2) & 0xF) + sceneryEntry->image + 4;
if (marker != 0)
{
image_id = (image_id & 0x7FFFF) | marker;
}
PaintAddImageAsChild(
session, image_id, x_offset, y_offset, boxlength.x, boxlength.y, boxlength.z - 1, height, boxoffset.x,
boxoffset.y, boxoffset.z);
auto imageIndex = sceneryEntry->image + 4 + ((gCurrentTicks / 2) & 0xF);
auto imageId = imageTemplate.WithIndex(imageIndex);
PaintAddImageAsChild(session, imageId, offset, boxLength, boxOffset);
}
else if (sceneryEntry->HasFlag(SMALL_SCENERY_FLAG_FOUNTAIN_SPRAY_4))
{
// 6E043B:
int32_t image_id = ((gCurrentTicks / 2) & 0xF) + sceneryEntry->image + 8;
if (marker != 0)
{
image_id = (image_id & 0x7FFFF) | marker;
}
PaintAddImageAsChild(
session, image_id, x_offset, y_offset, boxlength.x, boxlength.y, boxlength.z - 1, height, boxoffset.x,
boxoffset.y, boxoffset.z);
auto imageIndex = sceneryEntry->image + 8 + ((gCurrentTicks / 2) & 0xF);
PaintAddImageAsChild(session, imageTemplate.WithIndex(imageIndex), offset, boxLength, boxOffset);
image_id = direction + sceneryEntry->image + 4;
if (marker != 0)
{
image_id = (image_id & 0x7FFFF) | marker;
}
PaintAddImageAsChild(
session, image_id, x_offset, y_offset, boxlength.x, boxlength.y, boxlength.z - 1, height, boxoffset.x,
boxoffset.y, boxoffset.z);
imageIndex = direction + sceneryEntry->image + 4;
PaintAddImageAsChild(session, imageTemplate.WithIndex(imageIndex), offset, boxLength, boxOffset);
image_id = ((gCurrentTicks / 2) & 0xF) + sceneryEntry->image + 24;
if (marker != 0)
{
image_id = (image_id & 0x7FFFF) | marker;
}
PaintAddImageAsChild(
session, image_id, x_offset, y_offset, boxlength.x, boxlength.y, boxlength.z - 1, height, boxoffset.x,
boxoffset.y, boxoffset.z);
imageIndex = sceneryEntry->image + 24 + ((gCurrentTicks / 2) & 0xF);
PaintAddImageAsChild(session, imageTemplate.WithIndex(imageIndex), offset, boxLength, boxOffset);
}
else if (sceneryEntry->HasFlag(SMALL_SCENERY_FLAG_IS_CLOCK))
{
// 6E035C:
int32_t minuteImageOffset = ((gRealTimeOfDay.minute + 6) * 17) / 256;
int32_t timeImageBase = gRealTimeOfDay.hour;
auto minuteImageOffset = ((gRealTimeOfDay.minute + 6) * 17) / 256;
auto timeImageBase = gRealTimeOfDay.hour;
while (timeImageBase >= 12)
{
timeImageBase -= 12;
@ -238,177 +261,75 @@ void PaintSmallScenery(paint_session* session, uint8_t direction, int32_t height
{
timeImageBase -= 48;
}
int32_t image_id = timeImageBase + (direction * 12);
if (image_id >= 48)
auto imageIndex = timeImageBase + (direction * 12);
if (imageIndex >= 48)
{
image_id -= 48;
imageIndex -= 48;
}
image_id = image_id + sceneryEntry->image + 68;
if (marker != 0)
{
image_id = (image_id & 0x7FFFF) | marker;
}
PaintAddImageAsChild(
session, image_id, x_offset, y_offset, boxlength.x, boxlength.y, boxlength.z - 1, height, boxoffset.x,
boxoffset.y, boxoffset.z);
imageIndex = sceneryEntry->image + 68 + imageIndex;
PaintAddImageAsChild(session, imageTemplate.WithIndex(imageIndex), offset, boxLength, boxOffset);
image_id = gRealTimeOfDay.minute + (direction * 15);
if (image_id >= 60)
imageIndex = gRealTimeOfDay.minute + (direction * 15);
if (imageIndex >= 60)
{
image_id -= 60;
imageIndex -= 60;
}
image_id = image_id + sceneryEntry->image + 8;
if (marker != 0)
{
image_id = (image_id & 0x7FFFF) | marker;
}
PaintAddImageAsChild(
session, image_id, x_offset, y_offset, boxlength.x, boxlength.y, boxlength.z - 1, height, boxoffset.x,
boxoffset.y, boxoffset.z);
imageIndex = sceneryEntry->image + 8 + imageIndex;
PaintAddImageAsChild(session, imageTemplate.WithIndex(imageIndex), offset, boxLength, boxOffset);
}
else if (sceneryEntry->HasFlag(SMALL_SCENERY_FLAG_SWAMP_GOO))
{
// 6E02F6:
int32_t image_id = gCurrentTicks;
image_id += session->SpritePosition.x / 4;
image_id += session->SpritePosition.y / 4;
image_id = (image_id / 4) & 15;
image_id += sceneryEntry->image;
if (marker != 0)
{
image_id = (image_id & 0x7FFFF) | marker;
}
PaintAddImageAsChild(
session, image_id, x_offset, y_offset, boxlength.x, boxlength.y, boxlength.z - 1, height, boxoffset.x,
boxoffset.y, boxoffset.z);
auto imageIndex = gCurrentTicks;
imageIndex += session->SpritePosition.x / 4;
imageIndex += session->SpritePosition.y / 4;
imageIndex = sceneryEntry->image + ((imageIndex / 4) % 16);
PaintAddImageAsChild(session, imageTemplate.WithIndex(imageIndex), offset, boxLength, boxOffset);
}
else if (sceneryEntry->HasFlag(SMALL_SCENERY_FLAG_HAS_FRAME_OFFSETS))
{
int32_t frame = gCurrentTicks;
auto delay = sceneryEntry->animation_delay & 0xFF;
auto frame = gCurrentTicks;
if (!(sceneryEntry->HasFlag(SMALL_SCENERY_FLAG_COG)))
{
// 6E01F8:
frame += ((session->SpritePosition.x / 4) + (session->SpritePosition.y / 4));
frame += sceneryElement.GetSceneryQuadrant() << 2;
}
// 6E0222:
uint16_t delay = sceneryEntry->animation_delay & 0xFF;
frame >>= delay;
frame &= sceneryEntry->animation_mask;
int32_t image_id = 0;
frame = (frame >> delay) & sceneryEntry->animation_mask;
auto imageIndex = 0;
if (frame < sceneryEntry->num_frames)
{
image_id = sceneryEntry->frame_offsets[frame];
imageIndex = sceneryEntry->frame_offsets[frame];
}
image_id = (image_id * 4) + direction + sceneryEntry->image;
imageIndex = (imageIndex * 4) + direction + sceneryEntry->image;
if (sceneryEntry->HasFlag(SMALL_SCENERY_FLAG_VISIBLE_WHEN_ZOOMED | SMALL_SCENERY_FLAG17))
{
image_id += 4;
imageIndex += 4;
}
if (sceneryEntry->HasFlag(SMALL_SCENERY_FLAG_HAS_PRIMARY_COLOUR))
auto imageId = imageTemplate.WithIndex(imageIndex);
if (!imageTemplate.IsRemap() && sceneryEntry->HasFlag(SMALL_SCENERY_FLAG_HAS_PRIMARY_COLOUR))
{
imageId = ImageId(imageIndex).WithPrimary(sceneryElement.GetPrimaryColour());
if (sceneryEntry->HasFlag(SMALL_SCENERY_FLAG_HAS_SECONDARY_COLOUR))
{
image_id |= SPRITE_ID_PALETTE_COLOUR_2(
sceneryElement.GetPrimaryColour(), sceneryElement.GetSecondaryColour());
}
else
{
image_id |= SPRITE_ID_PALETTE_COLOUR_1(sceneryElement.GetPrimaryColour());
imageId = imageId.WithSecondary(sceneryElement.GetSecondaryColour());
}
}
if (marker != 0)
{
image_id = (image_id & 0x7FFFF) | marker;
}
if (sceneryEntry->HasFlag(SMALL_SCENERY_FLAG_VISIBLE_WHEN_ZOOMED))
{
PaintAddImageAsParent(
session, image_id, { x_offset, y_offset, height }, { boxlength.x, boxlength.y, boxlength.z - 1 },
boxoffset);
PaintAddImageAsParent(session, imageId, offset, boxLength, boxOffset);
}
else
{
PaintAddImageAsChild(
session, image_id, x_offset, y_offset, boxlength.x, boxlength.y, boxlength.z - 1, height, boxoffset.x,
boxoffset.y, boxoffset.z);
PaintAddImageAsChild(session, imageId, offset, boxLength, boxOffset);
}
}
}
}
// 6E0556: Draw supports:
if (sceneryElement.NeedsSupports())
{
if (!(sceneryEntry->HasFlag(SMALL_SCENERY_FLAG_NO_SUPPORTS)))
{
int32_t ax = 0;
int32_t supportHeight = height;
if (supportHeight & 0xF)
{
supportHeight &= 0xFFFFFFF0;
ax = 49;
}
uint32_t supportImageColourFlags = IMAGE_TYPE_REMAP;
if (sceneryEntry->HasFlag(SMALL_SCENERY_FLAG_PAINT_SUPPORTS))
{
supportImageColourFlags = SPRITE_ID_PALETTE_COLOUR_1(sceneryElement.GetPrimaryColour());
}
if (marker != 0)
{
supportImageColourFlags = marker;
}
if (direction & 1)
{
wooden_b_supports_paint_setup(session, 1, ax, supportHeight, supportImageColourFlags);
}
else
{
wooden_b_supports_paint_setup(session, 0, ax, supportHeight, supportImageColourFlags);
}
}
}
// 6E05D1:
height += sceneryEntry->height;
paint_util_set_general_support_height(session, ceil2(height, 8), 0x20);
// 6E05FF:
if (sceneryEntry->HasFlag(SMALL_SCENERY_FLAG_BUILD_DIRECTLY_ONTOP))
{
if (sceneryEntry->HasFlag(SMALL_SCENERY_FLAG_FULL_TILE))
{
// 6E0825:
paint_util_set_segment_support_height(session, SEGMENT_C4, height, 0x20);
if (sceneryEntry->HasFlag(SMALL_SCENERY_FLAG_VOFFSET_CENTRE))
{
paint_util_set_segment_support_height(session, SEGMENTS_ALL & ~SEGMENT_C4, height, 0x20);
}
return;
}
if (sceneryEntry->HasFlag(SMALL_SCENERY_FLAG_VOFFSET_CENTRE))
{
// 6E075C:
direction = (sceneryElement.GetSceneryQuadrant() + rotation) % 4;
paint_util_set_segment_support_height(
session, paint_util_rotate_segments(SEGMENT_B4 | SEGMENT_C8 | SEGMENT_CC, direction), height, 0x20);
return;
}
return;
}
if (sceneryEntry->HasFlag(SMALL_SCENERY_FLAG27 | SMALL_SCENERY_FLAG_FULL_TILE))
{
paint_util_set_segment_support_height(session, SEGMENT_C4, 0xFFFF, 0);
if (sceneryEntry->HasFlag(SMALL_SCENERY_FLAG_VOFFSET_CENTRE))
{
paint_util_set_segment_support_height(session, SEGMENTS_ALL & ~SEGMENT_C4, 0xFFFF, 0);
}
return;
}
if (sceneryEntry->HasFlag(SMALL_SCENERY_FLAG_VOFFSET_CENTRE))
{
direction = (sceneryElement.GetSceneryQuadrant() + rotation) % 4;
paint_util_set_segment_support_height(
session, paint_util_rotate_segments(SEGMENT_B4 | SEGMENT_C8 | SEGMENT_CC, direction), 0xFFFF, 0);
return;
}
PaintSmallScenerySupports(session, *sceneryEntry, sceneryElement, direction, height, imageTemplate);
SetSupportHeights(session, *sceneryEntry, sceneryElement, height);
}

View File

@ -313,34 +313,34 @@ static const TerrainSurfaceObject* get_surface_object(size_t index)
return result;
}
static uint32_t get_surface_image(
static ImageId get_surface_image(
const paint_session* session, ObjectEntryIndex index, int32_t offset, uint8_t rotation, int32_t grassLength, bool grid,
bool underground)
{
auto image = static_cast<uint32_t>(SPR_NONE);
ImageId image;
auto obj = get_surface_object(index);
if (obj != nullptr)
{
image = obj->GetImageId(
{ session->MapPosition.x >> 5, session->MapPosition.y >> 5 }, grassLength, rotation, offset, grid, underground);
image = ImageId(obj->GetImageId(
{ session->MapPosition.x >> 5, session->MapPosition.y >> 5 }, grassLength, rotation, offset, grid, underground));
if (obj->Colour != 255)
{
image |= SPRITE_ID_PALETTE_COLOUR_1(obj->Colour);
image = image.WithPrimary(obj->Colour);
}
}
return image;
}
static uint32_t get_surface_pattern(uint8_t index, int32_t offset)
static ImageId get_surface_pattern(uint8_t index, int32_t offset)
{
auto image = static_cast<uint32_t>(SPR_NONE);
ImageId image;
auto obj = get_surface_object(index);
if (obj != nullptr)
{
image = obj->PatternBaseImageId + offset;
image = ImageId(obj->PatternBaseImageId + offset);
if (obj->Colour != 255)
{
image |= SPRITE_ID_PALETTE_COLOUR_1(obj->Colour);
image = image.WithPrimary(obj->Colour);
}
}
return image;
@ -366,20 +366,20 @@ static bool surface_should_smooth(uint8_t index)
return false;
}
static uint32_t get_edge_image_with_offset(uint8_t index, uint32_t offset)
static ImageId get_edge_image_with_offset(uint8_t index, uint32_t offset)
{
uint32_t result = 0;
ImageId result;
auto& objMgr = OpenRCT2::GetContext()->GetObjectManager();
auto obj = objMgr.GetLoadedObject(ObjectType::TerrainEdge, index);
if (obj != nullptr)
{
auto tobj = static_cast<TerrainEdgeObject*>(obj);
return tobj->BaseImageId + offset;
result = ImageId(tobj->BaseImageId + offset);
}
return result;
}
static uint32_t get_edge_image(uint8_t index, uint8_t type)
static ImageId get_edge_image(uint8_t index, uint8_t type)
{
static constexpr uint32_t offsets[] = {
0,
@ -388,7 +388,7 @@ static uint32_t get_edge_image(uint8_t index, uint8_t type)
30,
};
uint32_t result = 0;
ImageId result;
if (type < std::size(offsets))
{
result = get_edge_image_with_offset(index, offsets[type]);
@ -396,7 +396,7 @@ static uint32_t get_edge_image(uint8_t index, uint8_t type)
return result;
}
static uint32_t get_tunnel_image(ObjectEntryIndex index, uint8_t type)
static ImageId get_tunnel_image(ObjectEntryIndex index, uint8_t type, edge_t edge)
{
static constexpr uint32_t offsets[TUNNEL_TYPE_COUNT] = { 36, 40, 44, 48, 52, 56, 60, 64, 68, 72, 76, 80,
36, 48, 60, 72, 76, 80, 84, 88, 92, 96, 100 };
@ -413,10 +413,10 @@ static uint32_t get_tunnel_image(ObjectEntryIndex index, uint8_t type)
if (!hasDoors && type >= REGULAR_TUNNEL_TYPE_COUNT && type < std::size(offsets))
type = TUNNEL_0;
uint32_t result = 0;
ImageId result;
if (type < std::size(offsets))
{
result = get_edge_image_with_offset(index, offsets[type]);
result = get_edge_image_with_offset(index, offsets[type]).WithIndexOffset(edge == EDGE_BOTTOMRIGHT ? 2 : 0);
}
return result;
}
@ -529,7 +529,7 @@ static void viewport_surface_smoothen_edge(
{
attached_paint_struct* out = session->LastAttachedPS;
// set content and enable masking
out->colour_image_id = get_surface_pattern(neighbour.terrain, cl);
out->colour_image_id = get_surface_pattern(neighbour.terrain, cl).ToUInt32();
out->flags |= PAINT_STRUCT_FLAG_IS_MASKED;
}
}
@ -629,15 +629,15 @@ static void viewport_surface_draw_tile_side_bottom(
return;
}
uint32_t base_image_id = get_edge_image(edgeStyle, 0);
auto baseImageId = get_edge_image(edgeStyle, 0);
if (session->ViewFlags & VIEWPORT_FLAG_UNDERGROUND_INSIDE)
{
base_image_id = get_edge_image(edgeStyle, 1);
baseImageId = get_edge_image(edgeStyle, 1);
}
if (edge == EDGE_BOTTOMRIGHT)
{
base_image_id += 5;
baseImageId = baseImageId.WithIndexOffset(5);
}
uint8_t curHeight = std::min(neighbourCornerHeight1, neighbourCornerHeight2);
@ -653,8 +653,8 @@ static void viewport_surface_draw_tile_side_bottom(
if (curHeight != cornerHeight1 && curHeight != cornerHeight2)
{
uint32_t image_id = base_image_id + image_offset;
PaintAddImageAsParent(session, image_id, { offset, curHeight * COORDS_Z_PER_TINY_Z }, { bounds, 15 });
auto imageId = baseImageId.WithIndexOffset(image_offset);
PaintAddImageAsParent(session, imageId, { offset, curHeight * COORDS_Z_PER_TINY_Z }, { bounds, 15 });
curHeight++;
}
}
@ -677,8 +677,8 @@ static void viewport_surface_draw_tile_side_bottom(
}
}
const uint32_t image_id = base_image_id + image_offset;
PaintAddImageAsParent(session, image_id, { offset, curHeight * COORDS_Z_PER_TINY_Z }, { bounds, 15 });
auto imageId = baseImageId.WithIndexOffset(image_offset);
PaintAddImageAsParent(session, imageId, { offset, curHeight * COORDS_Z_PER_TINY_Z }, { bounds, 15 });
return;
}
@ -693,7 +693,7 @@ static void viewport_surface_draw_tile_side_bottom(
if (isWater || curHeight != tunnelArray[tunnelIndex].height)
{
PaintAddImageAsParent(session, base_image_id, { offset, curHeight * COORDS_Z_PER_TINY_Z }, { bounds, 15 });
PaintAddImageAsParent(session, baseImageId, { offset, curHeight * COORDS_Z_PER_TINY_Z }, { bounds, 15 });
curHeight++;
continue;
@ -720,9 +720,9 @@ static void viewport_surface_draw_tile_side_bottom(
boundBoxLength -= 16;
}
uint32_t image_id = get_tunnel_image(edgeStyle, tunnelType) + (edge == EDGE_BOTTOMRIGHT ? 2 : 0);
auto imageId = get_tunnel_image(edgeStyle, tunnelType, edge);
PaintAddImageAsParent(
session, image_id, { offset, zOffset }, { tunnelBounds.x, tunnelBounds.y, boundBoxLength - 1 },
session, imageId, { offset, zOffset }, { tunnelBounds.x, tunnelBounds.y, boundBoxLength - 1 },
{ 0, 0, boundBoxOffsetZ });
boundBoxOffsetZ = curHeight * COORDS_Z_PER_TINY_Z;
@ -734,9 +734,9 @@ static void viewport_surface_draw_tile_side_bottom(
boundBoxLength -= 16;
}
image_id = get_tunnel_image(edgeStyle, tunnelType) + (edge == EDGE_BOTTOMRIGHT ? 2 : 0) + 1;
imageId = get_tunnel_image(edgeStyle, tunnelType, edge).WithIndexOffset(1);
PaintAddImageAsParent(
session, image_id, { offset, curHeight * COORDS_Z_PER_TINY_Z },
session, imageId, { offset, curHeight * COORDS_Z_PER_TINY_Z },
{ tunnelBounds.x, tunnelBounds.y, boundBoxLength - 1 },
{ tunnelTopBoundBoxOffset.x, tunnelTopBoundBoxOffset.y, boundBoxOffsetZ });
@ -831,28 +831,27 @@ static void viewport_surface_draw_tile_side_top(
return;
}
uint32_t base_image_id;
ImageId baseImageId;
if (isWater)
{
base_image_id = get_edge_image(terrain, 2); // var_08
baseImageId = get_edge_image(terrain, 2); // var_08
if (session->ViewFlags & VIEWPORT_FLAG_UNDERGROUND_INSIDE)
{
base_image_id = get_edge_image(terrain, 1); // var_04
baseImageId = get_edge_image(terrain, 1); // var_04
}
base_image_id += (edge == EDGE_TOPLEFT ? 5 : 0);
baseImageId = baseImageId.WithIndexOffset(edge == EDGE_TOPLEFT ? 5 : 0);
}
else
{
if (!(session->ViewFlags & VIEWPORT_FLAG_UNDERGROUND_INSIDE))
{
const uint8_t incline = (cornerHeight2 - cornerHeight1) + 1;
const uint32_t image_id = get_edge_image(terrain, 3) + (edge == EDGE_TOPLEFT ? 3 : 0) + incline; // var_c;
const auto imageId = get_edge_image(terrain, 3).WithIndexOffset((edge == EDGE_TOPLEFT ? 3 : 0) + incline);
const int16_t y = (height - cornerHeight1) * COORDS_Z_PER_TINY_Z;
PaintAttachToPreviousPS(session, image_id, 0, y);
PaintAttachToPreviousPS(session, imageId, 0, y);
return;
}
base_image_id = get_edge_image(terrain, 1) + (edge == EDGE_TOPLEFT ? 5 : 0); // var_04
baseImageId = get_edge_image(terrain, 1).WithIndexOffset(edge == EDGE_TOPLEFT ? 5 : 0);
}
uint8_t cur_height = std::min(neighbourCornerHeight2, neighbourCornerHeight1);
@ -867,9 +866,9 @@ static void viewport_surface_draw_tile_side_top(
if (cur_height != cornerHeight1 && cur_height != cornerHeight2)
{
const uint32_t image_id = base_image_id + image_offset;
auto imageId = baseImageId.WithIndexOffset(image_offset);
PaintAddImageAsParent(
session, image_id, { offset.x, offset.y, cur_height * COORDS_Z_PER_TINY_Z }, { bounds.x, bounds.y, 15 });
session, imageId, { offset.x, offset.y, cur_height * COORDS_Z_PER_TINY_Z }, { bounds.x, bounds.y, 15 });
cur_height++;
}
}
@ -884,7 +883,7 @@ static void viewport_surface_draw_tile_side_top(
while (cur_height < cornerHeight1 && cur_height < neighbourCornerHeight1)
{
PaintAddImageAsParent(session, base_image_id, { offset, cur_height * COORDS_Z_PER_TINY_Z }, { bounds, 15 });
PaintAddImageAsParent(session, baseImageId, { offset, cur_height * COORDS_Z_PER_TINY_Z }, { bounds, 15 });
cur_height++;
}
@ -899,8 +898,8 @@ static void viewport_surface_draw_tile_side_top(
}
}
const uint32_t image_id = base_image_id + image_offset;
PaintAddImageAsParent(session, image_id, { offset, cur_height * COORDS_Z_PER_TINY_Z }, { bounds, 15 });
auto imageId = baseImageId.WithIndexOffset(image_offset);
PaintAddImageAsParent(session, imageId, { offset, cur_height * COORDS_Z_PER_TINY_Z }, { bounds, 15 });
}
/**
@ -1058,20 +1057,23 @@ void PaintSurface(paint_session* session, uint8_t direction, uint16_t height, co
assert(surfaceShape < std::size(byte_97B444));
const uint8_t image_offset = byte_97B444[surfaceShape];
auto imageId = get_surface_image(session, terrain_type, image_offset, rotation, grassLength, showGridlines, false);
ImageId imageId;
if (gScreenFlags & (SCREEN_FLAGS_TRACK_DESIGNER | SCREEN_FLAGS_TRACK_MANAGER))
{
imageId = SPR_TERRAIN_TRACK_DESIGNER;
imageId = ImageId(SPR_TERRAIN_TRACK_DESIGNER);
}
else
{
imageId = get_surface_image(session, terrain_type, image_offset, rotation, grassLength, showGridlines, false);
}
if (session->ViewFlags & (VIEWPORT_FLAG_UNDERGROUND_INSIDE | VIEWPORT_FLAG_HIDE_BASE))
{
imageId &= 0xDC07FFFF; // remove colour
imageId |= 0x41880000;
imageId = imageId.WithRemap(FilterPaletteID::PaletteDarken1).WithBlended(true);
}
if (OpenRCT2::TileInspector::IsElementSelected(elementPtr))
{
imageId |= CONSTRUCTION_MARKER;
imageId = imageId.WithRemap(FilterPaletteID::Palette44);
}
PaintAddImageAsParent(session, imageId, { 0, 0, height }, { 32, 32, -1 });
@ -1265,8 +1267,8 @@ void PaintSurface(paint_session* session, uint8_t direction, uint16_t height, co
&& !(gScreenFlags & (SCREEN_FLAGS_TRACK_DESIGNER | SCREEN_FLAGS_TRACK_MANAGER)))
{
const uint8_t image_offset = byte_97B444[surfaceShape];
const uint32_t image_id = get_surface_image(session, terrain_type, image_offset, rotation, 1, false, true);
PaintAttachToPreviousPS(session, image_id, 0, 0);
auto imageId = get_surface_image(session, terrain_type, image_offset, rotation, 1, false, true);
PaintAttachToPreviousPS(session, imageId, 0, 0);
}
if (!(session->ViewFlags & VIEWPORT_FLAG_HIDE_VERTICAL))

View File

@ -77,7 +77,6 @@ enum
SPR_TERRAIN_SELECTION_QUARTER = 3081,
SPR_WATER_MASK = 5048,
SPR_WATER_OVERLAY = 5053,
SPR_HEIGHT_MARKER_BASE = 5769,
SPR_TERRAIN_BOUNDARY_FENCES_1 = 22872,
SPR_TERRAIN_BOUNDARY_FENCES_2 = 22873,

View File

@ -24,275 +24,189 @@
#include "../Paint.h"
#include "Paint.TileElement.h"
static constexpr const uint8_t byte_9A406C[] = {
static constexpr const uint8_t DirectionToDoorImageOffset0[] = {
2, 2, 22, 26, 30, 34, 34, 34, 34, 34, 30, 26, 22, 2, 6, 2, 2, 2, 6, 10, 14, 18, 18, 18, 18, 18, 14, 10, 6, 2, 22, 2,
};
static constexpr const uint8_t byte_9A408C[] = {
static constexpr const uint8_t DirectionToDoorImageOffset1[] = {
0, 0, 4, 8, 12, 16, 16, 16, 16, 16, 12, 8, 4, 0, 20, 0, 0, 0, 20, 24, 28, 32, 32, 32, 32, 32, 28, 24, 20, 0, 4, 0,
};
static constexpr const uint8_t byte_9A40AC[] = {
static constexpr const uint8_t DirectionToDoorImageOffset2[] = {
2, 2, 6, 10, 14, 18, 18, 18, 18, 18, 14, 10, 6, 2, 22, 2, 2, 2, 22, 26, 30, 34, 34, 34, 34, 34, 30, 26, 22, 2, 6, 2,
};
static constexpr const uint8_t byte_9A40CC[] = {
static constexpr const uint8_t DirectionToDoorImageOffset3[] = {
0, 0, 20, 24, 28, 32, 32, 32, 32, 32, 28, 24, 20, 0, 4, 0, 0, 0, 4, 8, 12, 16, 16, 16, 16, 16, 12, 8, 4, 0, 20, 0,
};
static constexpr const uint8_t* DirectionToDoorImageOffset[] = { DirectionToDoorImageOffset0, DirectionToDoorImageOffset1,
DirectionToDoorImageOffset2, DirectionToDoorImageOffset3 };
static void PaintWallDoor(
paint_session* session, uint32_t imageId, WallSceneryEntry* wallEntry, uint32_t imageColourFlags, uint32_t tertiaryColour,
uint32_t dword_141F710, CoordsXYZ offset, CoordsXYZ boundsR1, CoordsXYZ boundsR1_, CoordsXYZ boundsR2, CoordsXYZ boundsR2_,
CoordsXYZ boundsL1, CoordsXYZ boundsL1_)
paint_session* session, const WallSceneryEntry& wallEntry, ImageId imageId, CoordsXYZ offset, CoordsXYZ bbLengthR1,
CoordsXYZ bbOffsetR1, CoordsXYZ bbLengthR2, CoordsXYZ bbOffsetR2, CoordsXYZ bbLengthL, CoordsXYZ bbOffsetL)
{
if (wallEntry->flags & WALL_SCENERY_HAS_PRIMARY_COLOUR)
auto newImageId0 = imageId;
auto newImageId1 = imageId.WithIndexOffset(1);
if (wallEntry.flags & WALL_SCENERY_IS_DOUBLE_SIDED)
{
imageId |= imageColourFlags;
}
if (dword_141F710 != 0)
{
imageId = (imageId & 0x7FFFF) | dword_141F710;
}
if (wallEntry->flags & WALL_SCENERY_IS_DOUBLE_SIDED)
{
paint_struct* ps;
ps = PaintAddImageAsParent(session, imageId, offset, boundsR1, boundsR1_);
if (ps != nullptr)
{
ps->tertiary_colour = tertiaryColour;
}
ps = PaintAddImageAsParent(session, imageId + 1, offset, boundsR2, boundsR2_);
if (ps != nullptr)
{
ps->tertiary_colour = tertiaryColour;
}
PaintAddImageAsParent(session, newImageId0, offset, bbLengthR1, bbOffsetR1);
PaintAddImageAsParent(session, newImageId1, offset, bbLengthR2, bbOffsetR2);
}
else
{
paint_struct* ps;
PaintAddImageAsParent(session, newImageId0, offset, bbLengthL, bbOffsetL);
PaintAddImageAsChild(session, newImageId1, offset, bbLengthL, bbOffsetL);
}
}
ps = PaintAddImageAsParent(session, imageId, offset, boundsL1, boundsL1_);
if (ps != nullptr)
static void PaintWallDoor(
paint_session* session, const WallSceneryEntry& wallEntry, const WallElement& wallElement, ImageId imageTemplate,
Direction direction, int32_t height)
{
auto bbHeight = wallEntry.height * 8 - 2;
auto animationFrame = wallElement.GetAnimationFrame();
// Add the direction as well
if (wallElement.AnimationIsBackwards())
animationFrame |= (1 << 4);
auto imageId = wallEntry.image + DirectionToDoorImageOffset[direction & 3][animationFrame];
switch (direction)
{
case 0:
{
ps->tertiary_colour = tertiaryColour;
CoordsXYZ bbLengthR1 = { 1, 3, bbHeight - 5 };
CoordsXYZ bbOffsetR1 = { 1, 1, height + 1 };
CoordsXYZ bbLengthR2 = { 1, 28, 3 };
CoordsXYZ bbOffsetR2 = { 1, 1, height + bbHeight - 9 };
CoordsXYZ bbLengthL = { 1, 28, bbHeight };
CoordsXYZ bbOffsetL = { 1, 1, height + 1 };
CoordsXYZ offset = { 0, 0, height };
PaintWallDoor(
session, wallEntry, imageTemplate.WithIndex(imageId), offset, bbLengthR1, bbOffsetR1, bbLengthR2, bbOffsetR2,
bbLengthL, bbOffsetL);
break;
}
ps = PaintAddImageAsChild(
session, imageId + 1, static_cast<int8_t>(offset.x), static_cast<int8_t>(offset.y), boundsL1.x, boundsL1.y,
static_cast<int8_t>(boundsL1.z), offset.z, boundsL1_.x, boundsL1_.y, boundsL1_.z);
if (ps != nullptr)
case 1:
{
ps->tertiary_colour = tertiaryColour;
CoordsXYZ bbLengthR1 = { 3, 3, bbHeight - 5 };
CoordsXYZ bbOffsetR1 = { 1, 30, height + 1 };
CoordsXYZ bbLengthR2 = { 29, 3, 2 };
CoordsXYZ bbOffsetR2 = { 1, 30, height + bbHeight - 8 };
CoordsXYZ bbLengthL = { 29, 1, bbHeight };
CoordsXYZ bbOffsetL = { 2, 30, height + 1 };
CoordsXYZ offset = { 1, 31, height };
PaintWallDoor(
session, wallEntry, imageTemplate.WithIndex(imageId), offset, bbLengthR1, bbOffsetR1, bbLengthR2, bbOffsetR2,
bbLengthL, bbOffsetL);
break;
}
case 2:
{
CoordsXYZ bbLengthR1 = { 3, 3, bbHeight - 5 };
CoordsXYZ bbOffsetR1 = { 30, 1, height + 1 };
CoordsXYZ bbLengthR2 = { 3, 29, 2 };
CoordsXYZ bbOffsetR2 = { 30, 1, height + bbHeight - 8 };
CoordsXYZ bbLengthL = { 1, 29, bbHeight };
CoordsXYZ bbOffsetL = { 30, 2, height + 1 };
CoordsXYZ offset = { 31, 0, height };
PaintWallDoor(
session, wallEntry, imageTemplate.WithIndex(imageId), offset, bbLengthR1, bbOffsetR1, bbLengthR2, bbOffsetR2,
bbLengthL, bbOffsetL);
break;
}
case 3:
{
CoordsXYZ bbLengthR1 = { 3, 1, bbHeight - 5 };
CoordsXYZ bbOffsetR1 = { 1, 1, height + 1 };
CoordsXYZ bbLengthR2 = { 28, 1, 3 };
CoordsXYZ bbOffsetR2 = { 1, 1, height + bbHeight - 9 };
CoordsXYZ bbLengthL = { 28, 1, bbHeight };
CoordsXYZ bbOffsetL = { 1, 1, height + 1 };
CoordsXYZ offset = { 2, 1, height };
PaintWallDoor(
session, wallEntry, imageTemplate.WithIndex(imageId), offset, bbLengthR1, bbOffsetR1, bbLengthR2, bbOffsetR2,
bbLengthL, bbOffsetL);
break;
}
}
}
static void PaintWallWall(
paint_session* session, uint32_t frameNum, const WallSceneryEntry* wallEntry, uint32_t dword_141F710,
uint32_t imageColourFlags, uint32_t dword_141F718, uint32_t tertiaryColour, uint32_t imageOffset, CoordsXYZ offset,
CoordsXYZ bounds, CoordsXYZ boundsOffset)
paint_session* session, const WallSceneryEntry& wallEntry, ImageId imageTemplate, uint32_t imageOffset, CoordsXYZ offset,
CoordsXYZ bounds, CoordsXYZ boundsOffset, bool isGhost)
{
uint32_t baseImageId = wallEntry->image + imageOffset + frameNum;
uint32_t imageId = baseImageId;
if (wallEntry->flags & WALL_SCENERY_HAS_GLASS)
auto frameNum = (wallEntry.flags2 & WALL_SCENERY_2_ANIMATED) ? (gCurrentTicks & 7) * 2 : 0;
auto imageIndex = wallEntry.image + imageOffset + frameNum;
PaintAddImageAsParent(session, imageTemplate.WithIndex(imageIndex), offset, bounds, boundsOffset);
if ((wallEntry.flags & WALL_SCENERY_HAS_GLASS) && !isGhost)
{
if (wallEntry->flags & WALL_SCENERY_HAS_PRIMARY_COLOUR)
{
imageId |= imageColourFlags;
}
auto glassImageId = ImageId(imageIndex + 6).WithTransparancy(imageTemplate.GetPrimary());
PaintAddImageAsChild(session, glassImageId, offset, bounds, boundsOffset);
}
}
if (dword_141F710 != 0)
{
imageId = (imageId & 0x7FFFF) | dword_141F710;
}
static void PaintWallScrollingText(
paint_session* session, const WallSceneryEntry& wallEntry, const WallElement& wallElement, Direction direction,
int32_t height, const CoordsXYZ& boundsOffset, bool isGhost)
{
if (direction != 0 && direction != 3)
return;
PaintAddImageAsParent(session, imageId, offset, bounds, boundsOffset);
if (dword_141F710 == 0)
{
imageId = baseImageId + dword_141F718;
PaintAddImageAsChild(
session, imageId, static_cast<int8_t>(offset.x), static_cast<int8_t>(offset.y), bounds.x, bounds.y,
static_cast<int8_t>(bounds.z), offset.z, boundsOffset.x, boundsOffset.y, boundsOffset.z);
}
auto scrollingMode = wallEntry.scrolling_mode;
if (scrollingMode == SCROLLING_MODE_NONE)
return;
scrollingMode = wallEntry.scrolling_mode + ((direction + 1) & 3);
if (scrollingMode >= MAX_SCROLLING_TEXT_MODES)
return;
auto banner = wallElement.GetBanner();
if (banner == nullptr)
return;
auto textColour = isGhost ? static_cast<colour_t>(COLOUR_GREY) : wallElement.GetSecondaryColour();
auto textPaletteIndex = direction == 0 ? ColourMapA[textColour].mid_dark : ColourMapA[textColour].light;
auto ft = Formatter();
banner->FormatTextTo(ft);
char signString[256];
if (gConfigGeneral.upper_case_banners)
{
format_string_to_upper(signString, sizeof(signString), STR_SCROLLING_SIGN_TEXT, ft.Data());
}
else
{
if (wallEntry->flags & WALL_SCENERY_HAS_PRIMARY_COLOUR)
{
imageId |= imageColourFlags;
}
if (dword_141F710 != 0)
{
imageId = (imageId & 0x7FFFF) | dword_141F710;
}
paint_struct* paint = PaintAddImageAsParent(session, imageId, offset, bounds, boundsOffset);
if (paint != nullptr)
{
paint->tertiary_colour = tertiaryColour;
}
format_string(signString, sizeof(signString), STR_SCROLLING_SIGN_TEXT, ft.Data());
}
auto stringWidth = gfx_get_string_width(signString, FontSpriteBase::TINY);
auto scroll = stringWidth > 0 ? (gCurrentTicks / 2) % stringWidth : 0;
auto imageId = scrolling_text_setup(session, STR_SCROLLING_SIGN_TEXT, ft, scroll, scrollingMode, textPaletteIndex);
PaintAddImageAsChild(session, imageId, { 0, 0, height + 8 }, { 1, 1, 13 }, boundsOffset);
}
/**
* rct2: 0x006E44B0
* @param direction (cl)
* @param height (dx)
* @param tile_element (esi)
*/
void PaintWall(paint_session* session, uint8_t direction, int32_t height, const WallElement& wallElement)
static void PaintWallWall(
paint_session* session, const WallSceneryEntry& wallEntry, const WallElement& wallElement, ImageId imageTemplate,
Direction direction, int32_t height, bool isGhost)
{
session->InteractionType = ViewportInteractionItem::Wall;
auto* wallEntry = wallElement.GetEntry();
if (wallEntry == nullptr)
{
return;
}
uint32_t frameNum = 0;
if (wallEntry->flags2 & WALL_SCENERY_2_ANIMATED)
{
frameNum = (gCurrentTicks & 7) * 2;
}
int32_t primaryColour = wallElement.GetPrimaryColour();
uint32_t imageColourFlags = SPRITE_ID_PALETTE_COLOUR_1(primaryColour);
uint32_t dword_141F718 = imageColourFlags + 0x23800006;
if (wallEntry->flags & WALL_SCENERY_HAS_SECONDARY_COLOUR)
{
uint8_t secondaryColour = wallElement.GetSecondaryColour();
imageColourFlags |= secondaryColour << 24 | IMAGE_TYPE_REMAP_2_PLUS;
}
uint32_t tertiaryColour = 0;
if (wallEntry->flags & WALL_SCENERY_HAS_TERNARY_COLOUR)
{
tertiaryColour = wallElement.GetTertiaryColour();
imageColourFlags &= 0x0DFFFFFFF;
}
paint_util_set_general_support_height(session, 8 * wallElement.clearance_height, 0x20);
uint32_t dword_141F710 = 0;
if (gTrackDesignSaveMode || (session->ViewFlags & VIEWPORT_FLAG_HIGHLIGHT_PATH_ISSUES))
{
if (!track_design_save_contains_tile_element(reinterpret_cast<const TileElement*>(&wallElement)))
{
dword_141F710 = SPRITE_ID_PALETTE_COLOUR_1(EnumValue(FilterPaletteID::Palette46));
}
}
if (wallElement.IsGhost())
{
session->InteractionType = ViewportInteractionItem::None;
dword_141F710 = CONSTRUCTION_MARKER;
}
else if (OpenRCT2::TileInspector::IsElementSelected(reinterpret_cast<const TileElement*>(&wallElement)))
{
dword_141F710 = CONSTRUCTION_MARKER;
}
// Save tile_element
uint8_t ah = wallEntry->height * 8 - 2;
if (wallEntry->flags & WALL_SCENERY_IS_DOOR)
{
CoordsXYZ offset;
CoordsXYZ boundsR1, boundsR1_, boundsR2, boundsR2_, boundsL1, boundsL1_;
uint8_t animationFrame = wallElement.GetAnimationFrame();
// Add the direction as well
if (wallElement.AnimationIsBackwards())
animationFrame |= (1 << 4);
uint32_t imageId;
switch (direction)
{
case 0:
imageId = wallEntry->image + byte_9A406C[animationFrame];
boundsR1 = { 1, 3, static_cast<int16_t>(ah - 5) };
boundsR1_ = { 1, 1, static_cast<int16_t>(height + 1) };
boundsR2 = { 1, 28, 3 };
boundsR2_ = { 1, 1, static_cast<int16_t>(height + ah - 9) };
boundsL1 = { 1, 28, ah };
boundsL1_ = { 1, 1, static_cast<int16_t>(height + 1) };
offset = { 0, 0, static_cast<int16_t>(height) };
PaintWallDoor(
session, imageId, wallEntry, imageColourFlags, tertiaryColour, dword_141F710, offset, boundsR1, boundsR1_,
boundsR2, boundsR2_, boundsL1, boundsL1_);
break;
case 1:
imageId = wallEntry->image + byte_9A408C[animationFrame];
boundsR1 = { 3, 3, static_cast<int16_t>(ah - 5) };
boundsR1_ = { 1, 30, static_cast<int16_t>(height + 1) };
boundsR2 = { 29, 3, 2 };
boundsR2_ = { 1, 30, static_cast<int16_t>(height + ah - 8) };
boundsL1 = { 29, 1, ah };
boundsL1_ = { 2, 30, static_cast<int16_t>(height + 1) };
offset = { 1, 31, static_cast<int16_t>(height) };
PaintWallDoor(
session, imageId, wallEntry, imageColourFlags, tertiaryColour, dword_141F710, offset, boundsR1, boundsR1_,
boundsR2, boundsR2_, boundsL1, boundsL1_);
break;
case 2:
imageId = wallEntry->image + byte_9A40AC[animationFrame];
boundsR1 = { 3, 3, static_cast<int16_t>(ah - 5) };
boundsR1_ = { 30, 1, static_cast<int16_t>(height + 1) };
boundsR2 = { 3, 29, 2 };
boundsR2_ = { 30, 1, static_cast<int16_t>(height + ah - 8) };
boundsL1 = { 1, 29, ah };
boundsL1_ = { 30, 2, static_cast<int16_t>(height + 1) };
offset = { 31, 0, static_cast<int16_t>(height) };
PaintWallDoor(
session, imageId, wallEntry, imageColourFlags, tertiaryColour, dword_141F710, offset, boundsR1, boundsR1_,
boundsR2, boundsR2_, boundsL1, boundsL1_);
break;
case 3:
imageId = wallEntry->image + byte_9A40CC[animationFrame];
boundsR1 = { 3, 1, static_cast<int16_t>(ah - 5) };
boundsR1_ = { 1, 1, static_cast<int16_t>(height + 1) };
boundsR2 = { 28, 1, 3 };
boundsR2_ = { 1, 1, static_cast<int16_t>(height + ah - 9) };
boundsL1 = { 28, 1, ah };
boundsL1_ = { 1, 1, static_cast<int16_t>(height + 1) };
offset = { 2, 1, static_cast<int16_t>(height) };
PaintWallDoor(
session, imageId, wallEntry, imageColourFlags, tertiaryColour, dword_141F710, offset, boundsR1, boundsR1_,
boundsR2, boundsR2_, boundsL1, boundsL1_);
break;
}
return;
}
uint32_t imageOffset = 0;
CoordsXYZ offset = { 0, 0, 0 }, bounds = { 0, 0, 0 }, boundsOffset = { 0, 0, 0 };
uint8_t bbHeight = wallEntry.height * 8 - 2;
ImageIndex imageOffset = 0;
CoordsXYZ offset, bounds, boundsOffset;
switch (direction)
{
case 0:
@ -309,9 +223,9 @@ void PaintWall(paint_session* session, uint8_t direction, int32_t height, const
imageOffset = 1;
}
offset = { 0, 0, static_cast<int16_t>(height) };
bounds = { 1, 28, ah };
boundsOffset = { 1, 1, static_cast<int16_t>(height + 1) };
offset = { 0, 0, height };
bounds = { 1, 28, bbHeight };
boundsOffset = { 1, 1, height + 1 };
break;
case 1:
@ -328,24 +242,24 @@ void PaintWall(paint_session* session, uint8_t direction, int32_t height, const
imageOffset = 0;
}
if (wallEntry->flags & WALL_SCENERY_HAS_GLASS)
if (wallEntry.flags & WALL_SCENERY_HAS_GLASS)
{
if (wallEntry->flags & WALL_SCENERY_IS_DOUBLE_SIDED)
if (wallEntry.flags & WALL_SCENERY_IS_DOUBLE_SIDED)
{
imageOffset += 12;
}
}
else
{
if (wallEntry->flags & WALL_SCENERY_IS_DOUBLE_SIDED)
if (wallEntry.flags & WALL_SCENERY_IS_DOUBLE_SIDED)
{
imageOffset += 6;
}
}
offset = { 1, 31, static_cast<int16_t>(height) };
bounds = { 29, 1, ah };
boundsOffset = { 2, 30, static_cast<int16_t>(height + 1) };
offset = { 1, 31, height };
bounds = { 29, 1, bbHeight };
boundsOffset = { 2, 30, height + 1 };
break;
case 2:
@ -362,14 +276,14 @@ void PaintWall(paint_session* session, uint8_t direction, int32_t height, const
imageOffset = 1;
}
if (wallEntry->flags & WALL_SCENERY_IS_DOUBLE_SIDED)
if (wallEntry.flags & WALL_SCENERY_IS_DOUBLE_SIDED)
{
imageOffset += 6;
}
offset = { 31, 0, static_cast<int16_t>(height) };
bounds = { 1, 29, ah };
boundsOffset = { 30, 2, static_cast<int16_t>(height + 1) };
offset = { 31, 0, height };
bounds = { 1, 29, bbHeight };
boundsOffset = { 30, 2, height + 1 };
break;
case 3:
@ -386,66 +300,70 @@ void PaintWall(paint_session* session, uint8_t direction, int32_t height, const
imageOffset = 0;
}
offset = { 2, 1, static_cast<int16_t>(height) };
bounds = { 28, 1, ah };
boundsOffset = { 1, 1, static_cast<int16_t>(height + 1) };
offset = { 2, 1, height };
bounds = { 28, 1, bbHeight };
boundsOffset = { 1, 1, height + 1 };
break;
}
PaintWallWall(
session, frameNum, wallEntry, dword_141F710, imageColourFlags, dword_141F718, tertiaryColour, imageOffset, offset,
bounds, boundsOffset);
PaintWallWall(session, wallEntry, imageTemplate, imageOffset, offset, bounds, boundsOffset, isGhost);
PaintWallScrollingText(session, wallEntry, wallElement, direction, height, boundsOffset, isGhost);
}
if (wallEntry->scrolling_mode == SCROLLING_MODE_NONE)
void PaintWall(paint_session* session, uint8_t direction, int32_t height, const WallElement& wallElement)
{
auto* wallEntry = wallElement.GetEntry();
if (wallEntry == nullptr)
{
return;
}
if (direction != 0 && direction != 3)
session->InteractionType = ViewportInteractionItem::Wall;
ImageId imageTemplate;
if (wallEntry->flags & WALL_SCENERY_HAS_PRIMARY_COLOUR)
{
return;
imageTemplate = imageTemplate.WithPrimary(wallElement.GetPrimaryColour());
}
if (wallEntry->flags & WALL_SCENERY_HAS_SECONDARY_COLOUR)
{
imageTemplate = imageTemplate.WithSecondary(wallElement.GetSecondaryColour());
}
if (wallEntry->flags & WALL_SCENERY_HAS_TERNARY_COLOUR)
{
imageTemplate = imageTemplate.WithTertiary(wallElement.GetTertiaryColour());
}
auto secondaryColour = wallElement.GetSecondaryColour();
if (dword_141F710 != 0)
paint_util_set_general_support_height(session, 8 * wallElement.clearance_height, 0x20);
auto isGhost = false;
if (gTrackDesignSaveMode || (session->ViewFlags & VIEWPORT_FLAG_HIGHLIGHT_PATH_ISSUES))
{
secondaryColour = COLOUR_GREY;
if (!track_design_save_contains_tile_element(reinterpret_cast<const TileElement*>(&wallElement)))
{
imageTemplate = ImageId().WithRemap(FilterPaletteID::Palette46);
isGhost = true;
}
}
if (direction == 0)
if (wallElement.IsGhost())
{
secondaryColour = ColourMapA[secondaryColour].mid_dark;
session->InteractionType = ViewportInteractionItem::None;
imageTemplate = ImageId().WithRemap(FilterPaletteID::Palette44);
isGhost = true;
}
else if (OpenRCT2::TileInspector::IsElementSelected(reinterpret_cast<const TileElement*>(&wallElement)))
{
imageTemplate = ImageId().WithRemap(FilterPaletteID::Palette44);
isGhost = true;
}
if (wallEntry->flags & WALL_SCENERY_IS_DOOR)
{
PaintWallDoor(session, *wallEntry, wallElement, imageTemplate, direction, height);
}
else
{
secondaryColour = ColourMapA[secondaryColour].light;
}
uint16_t scrollingMode = wallEntry->scrolling_mode + ((direction + 1) & 0x3);
if (scrollingMode >= MAX_SCROLLING_TEXT_MODES)
{
return;
}
auto banner = wallElement.GetBanner();
if (banner != nullptr)
{
auto ft = Formatter();
banner->FormatTextTo(ft);
utf8 signString[256];
if (gConfigGeneral.upper_case_banners)
{
format_string_to_upper(signString, sizeof(signString), STR_SCROLLING_SIGN_TEXT, ft.Data());
}
else
{
format_string(signString, sizeof(signString), STR_SCROLLING_SIGN_TEXT, ft.Data());
}
uint16_t stringWidth = gfx_get_string_width(signString, FontSpriteBase::TINY);
uint16_t scroll = stringWidth > 0 ? (gCurrentTicks / 2) % stringWidth : 0;
PaintAddImageAsChild(
session, scrolling_text_setup(session, STR_SCROLLING_SIGN_TEXT, ft, scroll, scrollingMode, secondaryColour), 0, 0,
1, 1, 13, height + 8, boundsOffset.x, boundsOffset.y, boundsOffset.z);
PaintWallWall(session, *wallEntry, wallElement, imageTemplate, direction, height, isGhost);
}
}

View File

@ -796,23 +796,16 @@ bool track_paint_util_draw_station_covers_2(
return false;
}
auto baseImageIndex = stationObject->ShelterImageId;
if (baseImageIndex == ImageIndexUndefined)
return false;
static constexpr const int16_t heights[][2] = {
{ 22, 0 },
{ 30, 0 },
{ 46, 0 },
};
uint32_t imageId;
uint32_t baseImageId = stationObject->ShelterImageId;
if (stationObject->Flags & STATION_OBJECT_FLAGS::HAS_SECONDARY_COLOUR)
{
baseImageId |= IMAGE_TYPE_REMAP_2_PLUS;
}
if (stationObject->Flags & STATION_OBJECT_FLAGS::IS_TRANSPARENT)
{
baseImageId |= IMAGE_TYPE_TRANSPARENT;
}
int32_t imageOffset = 0;
CoordsXYZ bounds, boundsOffset;
CoordsXYZ offset = CoordsXYZ(0, 0, height);
@ -840,38 +833,21 @@ bool track_paint_util_draw_station_covers_2(
break;
}
if (session->TrackColours[SCHEME_MISC] != IMAGE_TYPE_REMAP)
{
baseImageId &= 0x7FFFF;
}
if (baseImageId <= 0x20)
{
return false;
}
if (stationVariant == STATION_VARIANT_TALL)
{
imageOffset += SPR_STATION_COVER_OFFSET_TALL;
}
if (baseImageId & IMAGE_TYPE_TRANSPARENT)
{
imageId = (baseImageId & ~IMAGE_TYPE_TRANSPARENT) + imageOffset;
PaintAddImageAsParent(session, imageId, offset, bounds, boundsOffset);
uint32_t edi = session->TrackColours[SCHEME_TRACK] & (0b11111 << 19);
// weird jump
imageId = (baseImageId | edi) + ((1 << 23) | (1 << 24) | (1 << 25)) + imageOffset + 12;
PaintAddImageAsChild(
session, imageId, static_cast<int8_t>(offset.x), static_cast<int8_t>(offset.y), bounds.x, bounds.y,
static_cast<int8_t>(bounds.z), offset.z, boundsOffset.x, boundsOffset.y, boundsOffset.z);
return true;
}
imageId = (baseImageId + imageOffset) | session->TrackColours[SCHEME_TRACK];
auto imageTemplate = ImageId::FromUInt32(session->TrackColours[SCHEME_TRACK]);
auto imageId = imageTemplate.WithIndex(baseImageIndex + imageOffset);
PaintAddImageAsParent(session, imageId, offset, bounds, boundsOffset);
// Glass
if (session->TrackColours[SCHEME_MISC] == IMAGE_TYPE_REMAP && (stationObject->Flags & STATION_OBJECT_FLAGS::IS_TRANSPARENT))
{
imageId = ImageId(baseImageIndex + imageOffset + 12).WithTransparancy(imageTemplate.GetPrimary());
PaintAddImageAsChild(session, imageId, offset, bounds, boundsOffset);
}
return true;
}

View File

@ -929,69 +929,72 @@ const vehicle_boundbox VehicleBoundboxes[16][224] = {
}
};
static void PaintVehicleRiders(
paint_session* session, const Vehicle* vehicle, const rct_ride_entry_vehicle* vehicleEntry, uint32_t baseImageId, int32_t z,
const vehicle_boundbox& bb)
{
baseImageId += vehicleEntry->no_vehicle_images;
for (auto i = 0; i < 8; i++)
{
if (vehicle->num_peeps > (i * 2) && vehicleEntry->no_seating_rows > i)
{
auto offsetImageId = baseImageId;
if (i == 0 && (vehicleEntry->flags & VEHICLE_ENTRY_FLAG_RIDER_ANIMATION))
{
offsetImageId += (vehicleEntry->no_vehicle_images * vehicle->animation_frame);
}
auto peepColour0 = vehicle->peep_tshirt_colours[i * 2];
auto peepColour1 = vehicle->peep_tshirt_colours[(i * 2) + 1];
auto imageId = ImageId(offsetImageId, peepColour0, peepColour1);
if (vehicle->IsGhost())
{
imageId = ImageId(offsetImageId).WithRemap(FilterPaletteID::Palette44);
}
PaintAddImageAsChild(
session, imageId, { 0, 0, z }, { bb.length_x, bb.length_y, bb.length_z },
{ bb.offset_x, bb.offset_y, bb.offset_z + z });
baseImageId += vehicleEntry->no_vehicle_images;
}
}
}
// 6D5214
static void vehicle_sprite_paint(
paint_session* session, const Vehicle* vehicle, int32_t ebx, int32_t ecx, int32_t z,
const rct_ride_entry_vehicle* vehicleEntry)
{
int32_t baseImage_id = ebx;
if (vehicleEntry->draw_order >= std::size(VehicleBoundboxes))
{
return;
}
vehicle_boundbox bb = VehicleBoundboxes[vehicleEntry->draw_order][ecx];
const auto& bb = VehicleBoundboxes[vehicleEntry->draw_order][ecx];
auto baseImageId = static_cast<uint32_t>(ebx);
if (vehicleEntry->flags & VEHICLE_ENTRY_FLAG_SPINNING_ADDITIONAL_FRAMES)
{
baseImage_id += (vehicle->spin_sprite / 8) & 31;
baseImageId += (vehicle->spin_sprite / 8) & 31;
}
if (vehicleEntry->flags & VEHICLE_ENTRY_FLAG_VEHICLE_ANIMATION)
{
baseImage_id += vehicle->animation_frame;
baseImageId += vehicle->animation_frame;
}
int32_t image_id = baseImage_id | (vehicle->colours.body_colour << 19) | (vehicle->colours.trim_colour << 24)
| IMAGE_TYPE_REMAP_2_PLUS;
auto imageId = ImageId(baseImageId, vehicle->colours.body_colour, vehicle->colours.trim_colour, vehicle->colours_extended);
if (vehicle->IsGhost())
{
image_id &= 0x7FFFF;
image_id |= CONSTRUCTION_MARKER;
imageId = ImageId(baseImageId).WithRemap(FilterPaletteID::Palette44);
}
paint_struct* ps = PaintAddImageAsParent(
session, image_id, { 0, 0, z }, { bb.length_x, bb.length_y, bb.length_z },
PaintAddImageAsParent(
session, imageId, { 0, 0, z }, { bb.length_x, bb.length_y, bb.length_z },
{ bb.offset_x, bb.offset_y, bb.offset_z + z });
if (ps != nullptr)
{
ps->tertiary_colour = vehicle->colours_extended;
}
rct_drawpixelinfo* dpi = &session->DPI;
auto* dpi = &session->DPI;
if (dpi->zoom_level < ZoomLevel{ 2 } && vehicle->num_peeps > 0 && vehicleEntry->no_seating_rows > 0)
{
baseImage_id += vehicleEntry->no_vehicle_images;
for (int32_t i = 0; i < 8; i++)
{
if (vehicle->num_peeps > (i * 2) && vehicleEntry->no_seating_rows > i)
{
image_id = baseImage_id
| SPRITE_ID_PALETTE_COLOUR_2(
vehicle->peep_tshirt_colours[i * 2], vehicle->peep_tshirt_colours[(i * 2) + 1]);
if (i == 0 && vehicleEntry->flags & VEHICLE_ENTRY_FLAG_RIDER_ANIMATION)
{
image_id += (vehicleEntry->no_vehicle_images * vehicle->animation_frame);
}
if (vehicle->IsGhost())
{
image_id &= 0x7FFFF;
image_id |= CONSTRUCTION_MARKER;
}
PaintAddImageAsChild(
session, image_id, 0, 0, bb.length_x, bb.length_y, bb.length_z, z, bb.offset_x, bb.offset_y,
bb.offset_z + z);
baseImage_id += vehicleEntry->no_vehicle_images;
}
}
PaintVehicleRiders(session, vehicle, vehicleEntry, baseImageId, z, bb);
}
vehicle_visual_splash_effect(session, z, vehicle, vehicleEntry);
}

View File

@ -25,6 +25,38 @@ enum
SPR_OBSERVATION_TOWER_SEGMENT_TOP = 14988,
};
static uint32_t GetObservationTowerVehicleBaseImageId(
const Vehicle* vehicle, const rct_ride_entry_vehicle* vehicleEntry, int32_t imageDirection)
{
uint32_t result = (vehicle->restraints_position / 64);
if (vehicle->restraints_position >= 64)
{
auto directionOffset = imageDirection / 8;
if ((directionOffset == 0) || (directionOffset == 3))
{
result = vehicleEntry->base_image_id + 8;
}
else
{
result *= 2;
result += vehicleEntry->base_image_id;
if (directionOffset == 1)
{
result += 28;
}
else
{
result += 22;
}
}
}
else
{
result = (vehicle->animation_frame * 2) + vehicleEntry->base_image_id + 8;
}
return result;
}
/**
*
* rct2: 0x006D6258
@ -33,53 +65,19 @@ void vehicle_visual_observation_tower(
paint_session* session, int32_t x, int32_t imageDirection, int32_t y, int32_t z, const Vehicle* vehicle,
const rct_ride_entry_vehicle* vehicleEntry)
{
int32_t image_id;
int32_t baseImage_id = (vehicle->restraints_position / 64);
if (vehicle->restraints_position >= 64)
{
auto directionOffset = imageDirection / 8;
if ((directionOffset == 0) || (directionOffset == 3))
{
baseImage_id = vehicleEntry->base_image_id + 8;
}
else
{
baseImage_id *= 2;
baseImage_id += vehicleEntry->base_image_id;
if (directionOffset == 1)
{
baseImage_id += 28;
}
else
{
baseImage_id += 22;
}
}
}
else
{
baseImage_id = (vehicle->animation_frame * 2) + vehicleEntry->base_image_id + 8;
}
image_id = baseImage_id | SPRITE_ID_PALETTE_COLOUR_3(vehicle->colours.body_colour, vehicle->colours.trim_colour);
auto baseImageId = GetObservationTowerVehicleBaseImageId(vehicle, vehicleEntry, imageDirection);
auto imageId0 = ImageId(
baseImageId + 0, vehicle->colours.body_colour, vehicle->colours.trim_colour, vehicle->colours_extended);
auto imageId1 = ImageId(
baseImageId + 1, vehicle->colours.body_colour, vehicle->colours.trim_colour, vehicle->colours_extended);
if (vehicle->IsGhost())
{
image_id = (image_id & 0x7FFFF) | CONSTRUCTION_MARKER;
}
paint_struct* ps = PaintAddImageAsParent(session, image_id, { 0, 0, z }, { 2, 2, 41 }, { -11, -11, z + 1 });
if (ps != nullptr)
{
ps->tertiary_colour = vehicle->colours_extended;
}
image_id++;
ps = PaintAddImageAsParent(session, image_id, { 0, 0, z }, { 16, 16, 41 }, { -5, -5, z + 1 });
if (ps != nullptr)
{
ps->tertiary_colour = vehicle->colours_extended;
imageId0 = ImageId(baseImageId + 0).WithRemap(FilterPaletteID::Palette44);
imageId1 = ImageId(baseImageId + 1).WithRemap(FilterPaletteID::Palette44);
}
PaintAddImageAsParent(session, imageId0, { 0, 0, z }, { 2, 2, 41 }, { -11, -11, z + 1 });
PaintAddImageAsParent(session, imageId1, { 0, 0, z }, { 16, 16, 41 }, { -5, -5, z + 1 });
assert(vehicleEntry->effect_visual == 1);
}

View File

@ -16,7 +16,37 @@
#include "../Vehicle.h"
#include "../VehiclePaint.h"
#ifndef NO_VEHICLES
static uint32_t SubmarineVehicleGetBaseImageId(
const Vehicle* vehicle, const rct_ride_entry_vehicle* vehicleEntry, int32_t imageDirection)
{
uint32_t result = imageDirection;
if (vehicle->restraints_position >= 64)
{
if ((vehicleEntry->sprite_flags & VEHICLE_SPRITE_FLAG_RESTRAINT_ANIMATION) && !(imageDirection & 3))
{
result /= 8;
result += ((vehicle->restraints_position - 64) / 64) * 4;
result *= vehicleEntry->base_num_frames;
result += vehicleEntry->restraint_image_id;
}
}
else
{
if (vehicleEntry->flags & VEHICLE_ENTRY_FLAG_USE_16_ROTATION_FRAMES)
{
result /= 2;
}
if (vehicleEntry->sprite_flags & VEHICLE_SPRITE_FLAG_USE_4_ROTATION_FRAMES)
{
result /= 8;
}
result *= vehicleEntry->base_num_frames;
result += vehicleEntry->base_image_id;
result += vehicle->SwingSprite;
}
return result;
}
/**
*
* rct2: 0x006D44D5
@ -25,61 +55,25 @@ void vehicle_visual_submarine(
paint_session* session, int32_t x, int32_t imageDirection, int32_t y, int32_t z, const Vehicle* vehicle,
const rct_ride_entry_vehicle* vehicleEntry)
{
auto imageFlags = SPRITE_ID_PALETTE_COLOUR_3(vehicle->colours.body_colour, vehicle->colours.trim_colour);
auto baseImageId = SubmarineVehicleGetBaseImageId(vehicle, vehicleEntry, imageDirection);
auto imageId0 = ImageId(
baseImageId + 0, vehicle->colours.body_colour, vehicle->colours.trim_colour, vehicle->colours_extended);
auto imageId1 = ImageId(
baseImageId + 1, vehicle->colours.body_colour, vehicle->colours.trim_colour, vehicle->colours_extended);
if (vehicle->IsGhost())
{
imageFlags = CONSTRUCTION_MARKER;
imageId0 = ImageId(baseImageId + 0).WithRemap(FilterPaletteID::Palette44);
imageId1 = ImageId(baseImageId + 1).WithRemap(FilterPaletteID::Palette44);
}
int32_t baseImage_id = imageDirection;
int32_t image_id;
if (vehicle->restraints_position >= 64)
{
if ((vehicleEntry->sprite_flags & VEHICLE_SPRITE_FLAG_RESTRAINT_ANIMATION) && !(imageDirection & 3))
{
baseImage_id /= 8;
baseImage_id += ((vehicle->restraints_position - 64) / 64) * 4;
baseImage_id *= vehicleEntry->base_num_frames;
baseImage_id += vehicleEntry->restraint_image_id;
}
}
else
{
if (vehicleEntry->flags & VEHICLE_ENTRY_FLAG_USE_16_ROTATION_FRAMES)
{
baseImage_id /= 2;
}
if (vehicleEntry->sprite_flags & VEHICLE_SPRITE_FLAG_USE_4_ROTATION_FRAMES)
{
baseImage_id /= 8;
}
baseImage_id *= vehicleEntry->base_num_frames;
baseImage_id += vehicleEntry->base_image_id;
baseImage_id += vehicle->SwingSprite;
}
vehicle_boundbox bb = VehicleBoundboxes[vehicleEntry->draw_order][imageDirection / 2];
image_id = baseImage_id | imageFlags;
paint_struct* ps = PaintAddImageAsParent(
session, image_id, { 0, 0, z }, { bb.length_x, bb.length_y, bb.length_z },
const auto& bb = VehicleBoundboxes[vehicleEntry->draw_order][imageDirection / 2];
PaintAddImageAsParent(
session, imageId0, { 0, 0, z }, { bb.length_x, bb.length_y, bb.length_z },
{ bb.offset_x, bb.offset_y, bb.offset_z + z });
if (ps != nullptr)
{
ps->tertiary_colour = vehicle->colours_extended;
}
image_id = (baseImage_id + 1) | imageFlags;
ps = PaintAddImageAsParent(
session, image_id, { 0, 0, z }, { bb.length_x, bb.length_y, 2 }, { bb.offset_x, bb.offset_y, bb.offset_z + z - 10 });
if (ps != nullptr)
{
ps->tertiary_colour = vehicle->colours_extended;
}
PaintAddImageAsParent(
session, imageId1, { 0, 0, z }, { bb.length_x, bb.length_y, 2 }, { bb.offset_x, bb.offset_y, bb.offset_z + z - 10 });
assert(vehicleEntry->effect_visual == 1);
}
#endif
static void submarine_ride_paint_track_station(
paint_session* session, const Ride* ride, uint8_t trackSequence, uint8_t direction, int32_t height,

View File

@ -28,6 +28,9 @@ enum
SPR_EDGE_WOOD_BLACK_BASE = 1663,
SPR_EDGE_ICE_BASE = 1831,
SPR_TERRAIN_STAFF = 2618,
SPR_TERRAIN_STAFF_SLOPED = 2619,
SPR_TERRAIN_SELECTION_SQUARE_SIMPLE = 2624, // Used for showing peep spawn
SPR_TERRAIN_SELECTION_SQUARE = 2625, // Used to show land owned by park
SPR_TERRAIN_SELECTION_DOTTED = 2644, // Used to show construction rights owned by park
@ -531,6 +534,8 @@ enum
SPR_CONSTRUCTION_FOOTPATH_LAND = 5639,
SPR_CONSTRUCTION_FOOTPATH_BRIDGE = 5640,
SPR_HEIGHT_MARKER_BASE = 5769,
SPR_6410 = 6410,
SPR_PEEP_PICKUP_COUNT = 12,

View File

@ -34,6 +34,13 @@ enum
ENTRANCE_ELEMENT_FLAGS2_LEGACY_PATH_ENTRY = (1 << 0),
};
namespace EntranceSequence
{
constexpr const uint8_t Centre = 0;
constexpr const uint8_t Left = 1;
constexpr const uint8_t Right = 2;
}; // namespace EntranceSequence
constexpr const uint8_t ParkEntranceHeight = 12 * COORDS_Z_STEP;
constexpr const uint8_t RideEntranceHeight = 7 * COORDS_Z_STEP;
constexpr const uint8_t RideExitHeight = 5 * COORDS_Z_STEP;

View File

@ -19,6 +19,7 @@
#include "../actions/SmallSceneryRemoveAction.h"
#include "../actions/WallRemoveAction.h"
#include "../common.h"
#include "../core/String.hpp"
#include "../entity/Fountain.h"
#include "../localisation/Localisation.h"
#include "../network/network.h"
@ -64,6 +65,61 @@ const CoordsXY SceneryQuadrantOffsets[] = {
{ 23, 7 },
};
LargeSceneryText::LargeSceneryText(const rct_large_scenery_text& original)
{
for (size_t i = 0; i < std::size(original.offset); i++)
{
offset[i].x = original.offset[i].x;
offset[i].y = original.offset[i].y;
}
max_width = original.max_width;
flags = original.flags;
num_images = original.num_images;
for (size_t i = 0; i < std::size(original.glyphs); i++)
{
glyphs[i] = original.glyphs[i];
}
}
const rct_large_scenery_text_glyph* LargeSceneryText::GetGlyph(char32_t codepoint) const
{
if (codepoint >= std::size(glyphs))
{
return nullptr;
}
return &glyphs[codepoint];
}
const rct_large_scenery_text_glyph& LargeSceneryText::GetGlyph(char32_t codepoint, char32_t defaultCodepoint) const
{
auto glyph = GetGlyph(codepoint);
if (glyph == nullptr)
{
glyph = GetGlyph(defaultCodepoint);
}
return *glyph;
}
int32_t LargeSceneryText::MeasureWidth(std::string_view text) const
{
auto result = 0;
for (auto codepoint : CodepointView(text))
{
result += GetGlyph(codepoint, ' ').width;
}
return result;
}
int32_t LargeSceneryText::MeasureHeight(std::string_view text) const
{
auto result = 0;
for (auto codepoint : CodepointView(text))
{
result += GetGlyph(codepoint, ' ').height;
}
return result;
}
void scenery_update_tile(const CoordsXY& sceneryPos)
{
TileElement* tileElement;

View File

@ -15,6 +15,7 @@
#include "TileElement.h"
#include <limits>
#include <string_view>
#define SCENERY_WITHER_AGE_THRESHOLD_1 0x28
#define SCENERY_WITHER_AGE_THRESHOLD_2 0x37
@ -178,22 +179,11 @@ struct LargeSceneryText
rct_large_scenery_text_glyph glyphs[256];
LargeSceneryText() = default;
explicit LargeSceneryText(const rct_large_scenery_text& original)
{
for (size_t i = 0; i < std::size(original.offset); i++)
{
offset[i].x = original.offset[i].x;
offset[i].y = original.offset[i].y;
}
max_width = original.max_width;
flags = original.flags;
num_images = original.num_images;
for (size_t i = 0; i < std::size(original.glyphs); i++)
{
glyphs[i] = original.glyphs[i];
}
}
explicit LargeSceneryText(const rct_large_scenery_text& original);
const rct_large_scenery_text_glyph* GetGlyph(char32_t codepoint) const;
const rct_large_scenery_text_glyph& GetGlyph(char32_t codepoint, char32_t defaultCodepoint) const;
int32_t MeasureWidth(std::string_view text) const;
int32_t MeasureHeight(std::string_view text) const;
};
struct rct_scenery_group_entry