mirror of https://github.com/OpenRCT2/OpenRCT2.git
Refactor large scenery to use ImageId
This commit is contained in:
parent
d62736634f
commit
4288589f11
|
@ -868,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();
|
||||
|
@ -882,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;
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -12,6 +12,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"
|
||||
|
@ -26,171 +27,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;
|
||||
|
@ -198,7 +34,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 } },
|
||||
|
@ -219,19 +55,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;
|
||||
|
||||
|
@ -239,216 +335,64 @@ void PaintLargeScenery(paint_session* session, uint8_t direction, uint16_t heigh
|
|||
if (sceneryEntry == nullptr)
|
||||
return;
|
||||
|
||||
const rct_large_scenery_tile* tile = object->GetTileForSequence(sequenceNum);
|
||||
const auto* tile = object->GetTileForSequence(sequenceNum);
|
||||
if (tile == nullptr)
|
||||
return;
|
||||
|
||||
auto imageId = ImageId(
|
||||
sceneryEntry->image + 4 + (sequenceNum << 2) + direction, tileElement.GetPrimaryColour(),
|
||||
tileElement.GetSecondaryColour());
|
||||
uint32_t imageFlags = 0;
|
||||
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)))
|
||||
{
|
||||
imageId = imageId.WithRemap(FilterPaletteID::Palette46);
|
||||
imageFlags = SPRITE_ID_PALETTE_COLOUR_1(EnumValue(FilterPaletteID::Palette46));
|
||||
}
|
||||
imageTemplate = ImageId().WithRemap(FilterPaletteID::Palette46);
|
||||
isGhost = true;
|
||||
}
|
||||
if (tileElement.IsGhost())
|
||||
else if (tileElement.IsGhost())
|
||||
{
|
||||
session->InteractionType = ViewportInteractionItem::None;
|
||||
imageId = imageId.WithRemap(FilterPaletteID::Palette44);
|
||||
imageFlags = CONSTRUCTION_MARKER;
|
||||
imageTemplate = ImageId().WithRemap(FilterPaletteID::Palette44);
|
||||
isGhost = true;
|
||||
}
|
||||
else if (OpenRCT2::TileInspector::IsElementSelected(reinterpret_cast<const TileElement*>(&tileElement)))
|
||||
{
|
||||
imageId = imageId.WithRemap(FilterPaletteID::Palette44);
|
||||
imageFlags = CONSTRUCTION_MARKER;
|
||||
}
|
||||
|
||||
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, imageId, { 0, 0, height }, bbLength, bbOffset);
|
||||
if (sceneryEntry->scrolling_mode == SCROLLING_MODE_NONE || direction == 1 || direction == 2)
|
||||
{
|
||||
large_scenery_paint_supports(session, direction, height, tileElement, imageFlags, 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, imageFlags, tile);
|
||||
return;
|
||||
}
|
||||
}
|
||||
rct_drawpixelinfo* dpi = &session->DPI;
|
||||
if (dpi->zoom_level > ZoomLevel{ 1 })
|
||||
{
|
||||
large_scenery_paint_supports(session, direction, height, tileElement, imageFlags, tile);
|
||||
return;
|
||||
}
|
||||
// 6B8331:
|
||||
// Draw sign text:
|
||||
int32_t textColour = tileElement.GetSecondaryColour();
|
||||
if (imageFlags)
|
||||
{
|
||||
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, imageFlags, tile);
|
||||
return;
|
||||
}
|
||||
uint8_t sequenceDirection2 = (tileElement.GetSequenceIndex() - 1) & 3;
|
||||
if (sequenceDirection2 != direction)
|
||||
{
|
||||
large_scenery_paint_supports(session, direction, height, tileElement, imageFlags, tile);
|
||||
return;
|
||||
}
|
||||
// Draw scrolling text:
|
||||
uint8_t textColour = tileElement.GetSecondaryColour();
|
||||
if (imageFlags)
|
||||
{
|
||||
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, imageFlags, 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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue