mirror of
https://github.com/OpenRCT2/OpenRCT2
synced 2026-01-16 19:43:06 +01:00
279 lines
7.6 KiB
C
279 lines
7.6 KiB
C
#include "../addresses.h"
|
|
#include "../config.h"
|
|
#include "../localisation/localisation.h"
|
|
#include "drawing.h"
|
|
|
|
/* size: 0xA12 */
|
|
typedef struct {
|
|
rct_string_id string_id; // 0x00
|
|
uint32 string_args_0; // 0x02
|
|
uint32 string_args_1; // 0x06
|
|
uint16 position; // 0x0A
|
|
uint16 mode; // 0x0C
|
|
uint32 id; // 0x0E
|
|
uint8 bitmap[64 * 8 * 5]; // 0x12
|
|
} rct_draw_scroll_text;
|
|
|
|
rct_draw_scroll_text *gDrawScrollTextList = RCT2_ADDRESS(RCT2_ADDRESS_DRAW_SCROLL_LIST, rct_draw_scroll_text);
|
|
uint8 *gCharacterBitmaps = RCT2_ADDRESS(RCT2_ADDRESS_CHARACTER_BITMAP, uint8);
|
|
|
|
void scrolling_text_set_bitmap_for_sprite(utf8 *text, int scroll, uint8 *bitmap, sint16 *scrollPositionOffsets);
|
|
void scrolling_text_set_bitmap_for_ttf(utf8 *text, int scroll, uint8 *bitmap, sint16 *scrollPositionOffsets);
|
|
|
|
void scrolling_text_initialise_bitmaps()
|
|
{
|
|
uint8 drawingSurface[64];
|
|
rct_drawpixelinfo dpi = {
|
|
.bits = (char*)&drawingSurface,
|
|
.x = 0,
|
|
.y = 0,
|
|
.width = 8,
|
|
.height = 8,
|
|
.pitch = 0,
|
|
.zoom_level = 0
|
|
};
|
|
|
|
|
|
for (int i = 0; i < 224; i++) {
|
|
memset(drawingSurface, 0, sizeof(drawingSurface));
|
|
gfx_draw_sprite(&dpi, i + 0x10D5, -1, 0, 0);
|
|
|
|
for (int x = 0; x < 8; x++) {
|
|
uint8 val = 0;
|
|
for (int y = 0; y < 8; y++) {
|
|
val >>= 1;
|
|
if (dpi.bits[x + y * 8] == 1) {
|
|
val |= 0x80;
|
|
}
|
|
}
|
|
gCharacterBitmaps[i * 8 + x] = val;
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
static uint8 *font_sprite_get_codepoint_bitmap(int codepoint)
|
|
{
|
|
return &gCharacterBitmaps[font_sprite_get_codepoint_offset(codepoint) * 8];
|
|
}
|
|
|
|
|
|
static int scrolling_text_get_matching_or_oldest(rct_string_id stringId, uint16 scroll, uint16 scrollingMode)
|
|
{
|
|
uint32 oldestId = 0xFFFFFFFF;
|
|
int scrollIndex = -1;
|
|
rct_draw_scroll_text* oldestScroll = NULL;
|
|
for (int i = 0; i < 32; i++) {
|
|
rct_draw_scroll_text *scrollText = &gDrawScrollTextList[i];
|
|
if (oldestId >= scrollText->id) {
|
|
oldestId = scrollText->id;
|
|
scrollIndex = i;
|
|
oldestScroll = scrollText;
|
|
}
|
|
|
|
// If exact match return the matching index
|
|
if (
|
|
scrollText->string_id == stringId &&
|
|
scrollText->string_args_0 == RCT2_GLOBAL(RCT2_ADDRESS_COMMON_FORMAT_ARGS, uint32) &&
|
|
scrollText->string_args_1 == RCT2_GLOBAL(0x13CE956, uint32) &&
|
|
scrollText->position == scroll &&
|
|
scrollText->mode == scrollingMode
|
|
) {
|
|
scrollText->id = RCT2_GLOBAL(RCT2_ADDRESS_DRAW_SCROLL_NEXT_ID, uint32);
|
|
return i + 0x606;
|
|
}
|
|
}
|
|
return scrollIndex;
|
|
}
|
|
|
|
static uint8 scrolling_text_get_colour(uint32 character)
|
|
{
|
|
int edi = character & 0x7F;
|
|
int offset = 0;
|
|
if (character >= 0x80) offset = 2;
|
|
return RCT2_ADDRESS(0x0141FC47, uint8)[offset + (edi * 8)];
|
|
}
|
|
|
|
static void scrolling_text_format(utf8 *dst, rct_draw_scroll_text *scrollText)
|
|
{
|
|
if (gConfigGeneral.upper_case_banners) {
|
|
format_string_to_upper(dst, scrollText->string_id, &scrollText->string_args_0);
|
|
} else {
|
|
format_string(dst, scrollText->string_id, &scrollText->string_args_0);
|
|
}
|
|
}
|
|
|
|
/**
|
|
*
|
|
* rct2: 0x006C42D9
|
|
* @param stringId (ax)
|
|
* @param scroll (cx)
|
|
* @param scrollingMode (bp)
|
|
* @returns ebx
|
|
*/
|
|
int scrolling_text_setup(rct_string_id stringId, uint16 scroll, uint16 scrollingMode)
|
|
{
|
|
rct_drawpixelinfo* dpi = RCT2_GLOBAL(0x140E9A8, rct_drawpixelinfo*);
|
|
|
|
if (dpi->zoom_level != 0) return 0x626;
|
|
|
|
RCT2_GLOBAL(RCT2_ADDRESS_DRAW_SCROLL_NEXT_ID, uint32)++;
|
|
|
|
int scrollIndex = scrolling_text_get_matching_or_oldest(stringId, scroll, scrollingMode);
|
|
if (scrollIndex >= 0x606) return scrollIndex;
|
|
|
|
// Setup scrolling text
|
|
rct_draw_scroll_text* scrollText = &gDrawScrollTextList[scrollIndex];
|
|
scrollText->string_id = stringId;
|
|
scrollText->string_args_0 = RCT2_GLOBAL(RCT2_ADDRESS_COMMON_FORMAT_ARGS + 0, uint32);
|
|
scrollText->string_args_1 = RCT2_GLOBAL(RCT2_ADDRESS_COMMON_FORMAT_ARGS + 4, uint32);
|
|
scrollText->position = scroll;
|
|
scrollText->mode = scrollingMode;
|
|
scrollText->id = RCT2_GLOBAL(RCT2_ADDRESS_DRAW_SCROLL_NEXT_ID, uint32);
|
|
|
|
// Create the string to draw
|
|
utf8 scrollString[256];
|
|
scrolling_text_format(scrollString, scrollText);
|
|
|
|
sint16* scrollingModePositions = RCT2_ADDRESS(RCT2_ADDRESS_SCROLLING_MODE_POSITIONS, uint16*)[scrollingMode];
|
|
|
|
memset(scrollText->bitmap, 0, 320 * 8);
|
|
if (gUseTrueTypeFont) {
|
|
scrolling_text_set_bitmap_for_ttf(scrollString, scroll, scrollText->bitmap, scrollingModePositions);
|
|
} else {
|
|
scrolling_text_set_bitmap_for_sprite(scrollString, scroll, scrollText->bitmap, scrollingModePositions);
|
|
}
|
|
|
|
return scrollIndex + 0x606;
|
|
}
|
|
|
|
void scrolling_text_set_bitmap_for_sprite(utf8 *text, int scroll, uint8 *bitmap, sint16 *scrollPositionOffsets)
|
|
{
|
|
uint8 characterColour = scrolling_text_get_colour(RCT2_GLOBAL(0x013CE959, uint8));
|
|
|
|
utf8 *ch = text;
|
|
while (true) {
|
|
uint32 codepoint = utf8_get_next(ch, &ch);
|
|
|
|
// If at the end of the string loop back to the start
|
|
if (codepoint == 0) {
|
|
ch = text;
|
|
continue;
|
|
}
|
|
|
|
// Set any change in colour
|
|
if (codepoint <= FORMAT_COLOUR_CODE_END && codepoint >= FORMAT_COLOUR_CODE_START){
|
|
codepoint -= FORMAT_COLOUR_CODE_START;
|
|
characterColour = RCT2_GLOBAL(0x009FF048, uint8*)[codepoint * 4];
|
|
continue;
|
|
}
|
|
|
|
// If another type of control character ignore
|
|
if (codepoint < 32) continue;
|
|
|
|
int characterWidth = font_sprite_get_codepoint_width(FONT_SPRITE_BASE_TINY, codepoint);
|
|
uint8 *characterBitmap = font_sprite_get_codepoint_bitmap(codepoint);
|
|
for (; characterWidth != 0; characterWidth--, characterBitmap++) {
|
|
// Skip any none displayed columns
|
|
if (scroll != 0) {
|
|
scroll--;
|
|
continue;
|
|
}
|
|
|
|
sint16 scrollPosition = *scrollPositionOffsets;
|
|
if (scrollPosition == -1) return;
|
|
if (scrollPosition > -1) {
|
|
uint8 *dst = &bitmap[scrollPosition];
|
|
for (uint8 char_bitmap = *characterBitmap; char_bitmap != 0; char_bitmap >>= 1){
|
|
if (char_bitmap & 1) *dst = characterColour;
|
|
|
|
// Jump to next row
|
|
dst += 64;
|
|
}
|
|
}
|
|
scrollPositionOffsets++;
|
|
}
|
|
}
|
|
}
|
|
|
|
TTFFontDescriptor *ttf_get_font_from_sprite_base(uint16 spriteBase);
|
|
SDL_Surface *_ttf_surface_cache_get_or_add(TTF_Font *font, const utf8 *text);
|
|
|
|
void scrolling_text_set_bitmap_for_ttf(utf8 *text, int scroll, uint8 *bitmap, sint16 *scrollPositionOffsets)
|
|
{
|
|
TTFFontDescriptor *fontDesc = ttf_get_font_from_sprite_base(FONT_SPRITE_BASE_TINY);
|
|
if (fontDesc->font == NULL) {
|
|
scrolling_text_set_bitmap_for_sprite(text, scroll, bitmap, scrollPositionOffsets);
|
|
return;
|
|
}
|
|
|
|
// Currently only supports one colour
|
|
uint8 colour = 0;
|
|
|
|
utf8 *dstCh = text;
|
|
utf8 *ch = text;
|
|
int codepoint;
|
|
while ((codepoint = utf8_get_next(ch, &ch)) != 0) {
|
|
if (utf8_is_format_code(codepoint)) {
|
|
if (codepoint >= FORMAT_COLOUR_CODE_START && codepoint <= FORMAT_COLOUR_CODE_END) {
|
|
colour = (uint8)codepoint;
|
|
}
|
|
} else {
|
|
dstCh = utf8_write_codepoint(dstCh, codepoint);
|
|
}
|
|
}
|
|
*dstCh = 0;
|
|
|
|
if (colour == 0) {
|
|
colour = scrolling_text_get_colour(RCT2_GLOBAL(0x013CE959, uint8));
|
|
} else {
|
|
colour = RCT2_GLOBAL(0x009FF048, uint8*)[(colour - FORMAT_COLOUR_CODE_START) * 4];
|
|
}
|
|
|
|
SDL_Surface *surface = _ttf_surface_cache_get_or_add(fontDesc->font, text);
|
|
if (surface == NULL) {
|
|
return;
|
|
}
|
|
|
|
if (SDL_MUSTLOCK(surface) && SDL_LockSurface(surface) == -1) {
|
|
return;
|
|
}
|
|
|
|
int pitch = surface->pitch;
|
|
int width = surface->w;
|
|
int height = surface->h;
|
|
uint8 *src = surface->pixels;
|
|
|
|
// Offset
|
|
height -= 3;
|
|
src += 3 * pitch;
|
|
height = min(height, 8);
|
|
|
|
int x = 0;
|
|
while (true) {
|
|
// Skip any none displayed columns
|
|
if (scroll == 0) {
|
|
sint16 scrollPosition = *scrollPositionOffsets;
|
|
if (scrollPosition == -1) return;
|
|
if (scrollPosition > -1) {
|
|
uint8 *dst = &bitmap[scrollPosition];
|
|
|
|
for (int y = 0; y < height; y++) {
|
|
if (src[y * pitch + x] != 0) *dst = colour;
|
|
|
|
// Jump to next row
|
|
dst += 64;
|
|
}
|
|
}
|
|
scrollPositionOffsets++;
|
|
} else {
|
|
scroll--;
|
|
}
|
|
|
|
x++;
|
|
if (x >= width) x = 0;
|
|
}
|
|
|
|
if (SDL_MUSTLOCK(surface)) SDL_UnlockSurface(surface);
|
|
}
|