void format_string_part_from_raw(utf8 **dest, const utf8 *src, char **args) { unsigned int code; while (1) { code = utf8_get_next(src, &src); if (code < ' ') { if (code == 0) { *(*dest)++ = code; break; } else if (code <= 4) { *(*dest)++ = code; *(*dest)++ = *src++; } else if (code <= 16) { *(*dest)++ = code; } else if (code <= 22) { *(*dest)++ = code; *(*dest)++ = *src++; *(*dest)++ = *src++; } else { *(*dest)++ = code; *(*dest)++ = *src++; *(*dest)++ = *src++; *(*dest)++ = *src++; *(*dest)++ = *src++; } } else if (code <= 'z') { *(*dest)++ = code; } else if (code < FORMAT_COLOUR_CODE_START || code == FORMAT_COMMA1DP16) { format_string_code(code, dest, args); } else { *dest = utf8_write_codepoint(*dest, code); } } }
void textinputbuffer_insert(textinputbuffer * tib, utf8 * source) { const utf8 *ch = source; uint32 codepoint; while ((codepoint = utf8_get_next(ch, &ch)) != 0) { textinputbuffer_insert_codepoint(tib, codepoint); } }
static int32_t large_scenery_sign_text_height(const utf8* str, rct_large_scenery_text* 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 int32_t large_scenery_sign_text_width(const utf8* str, rct_large_scenery_text* 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; }
bool font_supports_string_sprite(const utf8 *text) { const utf8 *src = text; uint32 codepoint; while ((codepoint = utf8_get_next(src, &src)) != 0) { bool supported = false; switch (codepoint) { case FORMAT_ENDQUOTES: case FORMAT_AMINUSCULE: case FORMAT_UP: case FORMAT_SYMBOL_i: case FORMAT_CENT: case FORMAT_POUND: case FORMAT_YEN: case FORMAT_COPYRIGHT: case FORMAT_DOWN: case FORMAT_LEFTGUILLEMET: case FORMAT_TICK: case FORMAT_CROSS: case FORMAT_RIGHT: case FORMAT_DEGREE: case FORMAT_SYMBOL_RAILWAY: case FORMAT_SQUARED: case FORMAT_OPENQUOTES: case FORMAT_EURO: case FORMAT_SYMBOL_ROAD: case FORMAT_SYMBOL_FLAG: case FORMAT_APPROX: case FORMAT_POWERNEGATIVEONE: case FORMAT_BULLET: case FORMAT_RIGHTGUILLEMET: case FORMAT_SMALLUP: case FORMAT_SMALLDOWN: case FORMAT_LEFT: case FORMAT_INVERTEDQUESTION: supported = true; break; default: if (codepoint >= 32 && codepoint < 256) { supported = true; } break; } if (!supported) { return false; } } return true; }
bool font_supports_string_ttf(const utf8 *text, int fontSize) { const utf8 *src = text; const TTF_Font *font = gCurrentTTFFontSet->size[fontSize].font; uint32 codepoint; while ((codepoint = utf8_get_next(src, &src)) != 0) { bool supported = TTF_GlyphIsProvided(font, (uint16)codepoint); if (!supported) { return false; } } return true; }
void scrolling_text_set_bitmap_for_sprite(utf8 *text, sint32 scroll, uint8 *bitmap, const sint16 *scrollPositionOffsets) { uint8 characterColour = scrolling_text_get_colour(gCommonFormatArgs[7]); utf8 *ch = text; while (true) { uint32 codepoint = utf8_get_next(ch, (const utf8**)&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 = g1Elements[SPR_TEXT_PALETTE].offset[codepoint * 4]; continue; } // If another type of control character ignore if (codepoint < 32) continue; sint32 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++; } }
void chat_history_add(const char* src) { size_t bufferSize = strlen(src) + 64; utf8* buffer = (utf8*)calloc(1, bufferSize); // Find the start of the text (after format codes) const char* ch = src; const char* nextCh; uint32_t codepoint; while ((codepoint = utf8_get_next(ch, &nextCh)) != 0) { if (!utf8_is_format_code(codepoint)) { break; } ch = nextCh; } const char* srcText = ch; // Copy format codes to buffer std::memcpy(buffer, src, std::min(bufferSize, (size_t)(srcText - src))); // Prepend a timestamp time_t timer; time(&timer); struct tm* tmInfo = localtime(&timer); strcatftime(buffer, bufferSize, "[%H:%M] ", tmInfo); safe_strcat(buffer, srcText, bufferSize); // Add to history list int32_t index = _chatHistoryIndex % CHAT_HISTORY_SIZE; std::fill_n(_chatHistory[index], CHAT_INPUT_SIZE, 0x00); std::memcpy(_chatHistory[index], buffer, std::min<size_t>(strlen(buffer), CHAT_INPUT_SIZE - 1)); _chatHistoryTime[index] = platform_get_ticks(); _chatHistoryIndex++; // Log to file (src only as logging does its own timestamp) network_append_chat_log(src); free(buffer); Mixer_Play_Effect(SOUND_NEWS_ITEM, 0, MIXER_VOLUME_MAX, 0.5f, 1.5f, true); }
static const utf8* large_scenery_sign_fit_text(const utf8* str, rct_large_scenery_text* text, bool height) { static utf8 fitStr[32]; utf8* fitStrEnd = fitStr; safe_strcpy(fitStr, str, sizeof(fitStr)); int32_t w = 0; uint32_t codepoint; while (w <= text->max_width && (codepoint = utf8_get_next(fitStrEnd, (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; return fitStr; }
bool font_supports_string_ttf(const utf8 *text, sint32 fontSize) { #ifndef NO_TTF const utf8 *src = text; const TTF_Font *font = gCurrentTTFFontSet->size[fontSize].font; if (font == NULL) { return false; } uint32 codepoint; while ((codepoint = utf8_get_next(src, &src)) != 0) { bool supported = ttf_provides_glyph(font, codepoint); if (!supported) { return false; } } return true; #else return false; #endif // NO_TTF }
static void large_scenery_sign_paint_line( paint_session* session, const utf8* str, rct_large_scenery_text* text, int32_t textImage, int32_t textColour, uint8_t direction, int32_t y_offset) { const utf8* fitStr = large_scenery_sign_fit_text(str, text, false); 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; while ((codepoint = utf8_get_next(fitStr, &fitStr)) != 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) { paint_attach_to_previous_ps(session, image_id, x_offset, -div_to_minus_infinity(acc, 2)); } else { if (text->flags & LARGE_SCENERY_TEXT_FLAG_VERTICAL) { paint_attach_to_previous_ps(session, image_id, x_offset, div_to_minus_infinity(acc, 2)); } else { paint_attach_to_previous_attach(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; } }
static money32 BannerSetStyle(uint8 bannerIndex, uint8 colour, uint8 textColour, uint8 bannerFlags, uint8 flags) { if (bannerIndex >= MAX_BANNERS) { gGameCommandErrorText = STR_INVALID_SELECTION_OF_OBJECTS; return MONEY32_UNDEFINED; } rct_banner* banner = &gBanners[bannerIndex]; rct_tile_element* tileElement = banner_get_tile_element(bannerIndex); if (tileElement == nullptr) { return MONEY32_UNDEFINED; } if (!(flags & GAME_COMMAND_FLAG_APPLY)) { return 0; } banner->colour = colour; banner->text_colour = textColour; banner->flags = bannerFlags; tileElement->properties.banner.flags = 0xFF; if (banner->flags & BANNER_FLAG_NO_ENTRY) { tileElement->properties.banner.flags &= ~(1 << tileElement->properties.banner.position); } sint32 colourCodepoint = FORMAT_COLOUR_CODE_START + banner->text_colour; utf8 buffer[256]; format_string(buffer, 256, banner->string_idx, nullptr); sint32 firstCodepoint = utf8_get_next(buffer, nullptr); if (firstCodepoint >= FORMAT_COLOUR_CODE_START && firstCodepoint <= FORMAT_COLOUR_CODE_END) { utf8_write_codepoint(buffer, colourCodepoint); } else { utf8_insert_codepoint(buffer, colourCodepoint); } rct_string_id stringId = user_string_allocate(USER_STRING_DUPLICATION_PERMITTED, buffer); if (stringId != 0) { rct_string_id prevStringId = banner->string_idx; banner->string_idx = stringId; user_string_free(prevStringId); auto intent = Intent(INTENT_ACTION_UPDATE_BANNER); intent.putExtra(INTENT_EXTRA_BANNER_INDEX, bannerIndex); context_broadcast_intent(&intent); } else { gGameCommandErrorText = STR_ERR_CANT_SET_BANNER_TEXT; return MONEY32_UNDEFINED; } return 0; }
static void window_text_input_paint(rct_window *w, rct_drawpixelinfo *dpi) { window_draw_widgets(w, dpi); sint32 y = w->y + 25; sint32 no_lines = 0; sint32 font_height = 0; gfx_draw_string_centred(dpi, input_text_description, w->x + WW / 2, y, w->colours[1], &TextInputDescriptionArgs); y += 25; gCurrentFontSpriteBase = FONT_SPRITE_BASE_MEDIUM; gCurrentFontFlags = 0; char wrapped_string[512]; safe_strcpy(wrapped_string, text_input, 512); // String length needs to add 12 either side of box // +13 for cursor when max length. gfx_wrap_string(wrapped_string, WW - (24 + 13), &no_lines, &font_height); gfx_fill_rect_inset(dpi, w->x + 10, y, w->x + WW - 10, y + 10 * (no_lines + 1) + 3, w->colours[1], INSET_RECT_F_60); y += 1; char* wrap_pointer = wrapped_string; size_t char_count = 0; uint8 cur_drawn = 0; sint32 cursorX = 0, cursorY = 0; for (sint32 line = 0; line <= no_lines; line++) { gfx_draw_string(dpi, wrap_pointer, w->colours[1], w->x + 12, y); size_t string_length = get_string_size(wrap_pointer) - 1; if (!cur_drawn && (gTextInput.selection_offset <= char_count + string_length)) { // Make a copy of the string for measuring the width. char temp_string[512] = { 0 }; memcpy(temp_string, wrap_pointer, gTextInput.selection_offset - char_count); cursorX = w->x + 13 + gfx_get_string_width(temp_string); cursorY = y; sint32 width = 6; if (gTextInput.selection_offset < strlen(text_input)){ // Make a 1 utf8-character wide string for measuring the width // of the currently selected character. utf8 tmp[5] = { 0 }; // This is easier than setting temp_string[0..5] uint32 codepoint = utf8_get_next(text_input + gTextInput.selection_offset, NULL); utf8_write_codepoint(tmp, codepoint); width = max(gfx_get_string_width(tmp) - 2, 4); } if (w->frame_no > 15){ uint8 colour = ColourMapA[w->colours[1]].mid_light; gfx_fill_rect(dpi, cursorX, y + 9, cursorX + width, y + 9, colour + 5); } cur_drawn++; } wrap_pointer += string_length + 1; if (text_input[char_count + string_length] == ' ')char_count++; char_count += string_length; y += 10; } if (!cur_drawn) { cursorX = gLastDrawStringX; cursorY = y - 10; } // IME composition if (gTextInputCompositionActive) { draw_ime_composition(dpi, cursorX, cursorY); } }