diff --git a/data/language/english_uk.txt b/data/language/english_uk.txt index 1c03cb38e3..d3e40fd882 100644 --- a/data/language/english_uk.txt +++ b/data/language/english_uk.txt @@ -3919,6 +3919,7 @@ STR_5577 :South Korean Won (W) STR_5578 :Russian Rouble (R) STR_5579 :Window scale factor: STR_5580 :Czech koruna (Kc) +STR_5581 :Show FPS ##################### # Rides/attractions # diff --git a/distribution/changelog.txt b/distribution/changelog.txt index 8a608f91b3..68dec593c4 100644 --- a/distribution/changelog.txt +++ b/distribution/changelog.txt @@ -1,5 +1,6 @@ 0.0.4 (not yet released) ------------------------------------------------------------------------ +- Feature: Add displaying of frames per second (FPS). - Fix: [#2126] Ferris Wheels set to "backward rotation" stop working (original bug) - Fix: [#2449] Turning off Day/Night Circle while it is night doesn't reset back to day diff --git a/src/config.c b/src/config.c index aa43f54fbd..47aecd3b5c 100644 --- a/src/config.c +++ b/src/config.c @@ -198,7 +198,8 @@ config_property_definition _generalDefinitions[] = { { offsetof(general_configuration, upper_case_banners), "upper_case_banners", CONFIG_VALUE_TYPE_BOOLEAN, false, NULL }, { offsetof(general_configuration, allow_loading_with_incorrect_checksum),"allow_loading_with_incorrect_checksum", CONFIG_VALUE_TYPE_BOOLEAN, false, NULL }, { offsetof(general_configuration, steam_overlay_pause), "steam_overlay_pause", CONFIG_VALUE_TYPE_BOOLEAN, true, NULL }, - { offsetof(general_configuration, window_scale), "window_scale", CONFIG_VALUE_TYPE_FLOAT, { .value_float = 1.0f }, NULL }, + { offsetof(general_configuration, window_scale), "window_scale", CONFIG_VALUE_TYPE_FLOAT, { .value_float = 1.0f }, NULL }, + { offsetof(general_configuration, show_fps), "show_fps", CONFIG_VALUE_TYPE_BOOLEAN, false, NULL }, }; config_property_definition _interfaceDefinitions[] = { diff --git a/src/config.h b/src/config.h index 951727ca21..b376954884 100644 --- a/src/config.h +++ b/src/config.h @@ -168,6 +168,7 @@ typedef struct { uint8 allow_loading_with_incorrect_checksum; uint8 steam_overlay_pause; float window_scale; + uint8 show_fps; } general_configuration; typedef struct { diff --git a/src/localisation/string_ids.h b/src/localisation/string_ids.h index ca77bb40f6..941f9b4170 100644 --- a/src/localisation/string_ids.h +++ b/src/localisation/string_ids.h @@ -2177,6 +2177,8 @@ enum { STR_CZECH_KORUNA = 5580, + STR_SHOW_FPS = 5581, + // Have to include resource strings (from scenarios and objects) for the time being now that language is partially working STR_COUNT = 32768 }; diff --git a/src/rct2.c b/src/rct2.c index 23e2b88af6..6d1aed4ad7 100644 --- a/src/rct2.c +++ b/src/rct2.c @@ -63,6 +63,7 @@ void print_launch_information(); int rct2_init_directories(); int rct2_startup_checks(); +static void rct2_draw_fps(); static void rct2_update_2(); static jmp_buf _end_update_jump; @@ -259,9 +260,58 @@ void rct2_draw() //game } + if (gConfigGeneral.show_fps) { + rct2_draw_fps(); + } + gCurrentDrawCount++; } +static uint32 _lastFPSUpdateTicks; +static uint32 _lastFPSTicks; +static float _currentFPS; + +static float rct2_measure_fps() +{ + uint32 currentTicks = SDL_GetTicks(); + if (currentTicks - _lastFPSUpdateTicks > 500) { + _lastFPSUpdateTicks = currentTicks; + + uint32 frameDelta = currentTicks - _lastFPSTicks; + _currentFPS = 1000.0f / frameDelta; + } + _lastFPSTicks = currentTicks; + return _currentFPS; +} + +static void rct2_draw_fps() +{ + rct_drawpixelinfo *dpi = RCT2_ADDRESS(RCT2_ADDRESS_SCREEN_DPI, rct_drawpixelinfo); + int x = RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_WIDTH, uint16) / 2; + int y = 2; + + // Measure FPS + float fps = rct2_measure_fps(); + + // Format string + utf8 buffer[64]; + utf8 *ch = buffer; + ch = utf8_write_codepoint(ch, FORMAT_MEDIUMFONT); + ch = utf8_write_codepoint(ch, FORMAT_OUTLINE); + ch = utf8_write_codepoint(ch, FORMAT_WHITE); + + const char *formatString = (_currentFPS >= 100.0f ? "%.0f" : "%.1f"); + sprintf(ch, formatString, _currentFPS); + + // Draw Text + int stringWidth = gfx_get_string_width(buffer); + x = x - (stringWidth / 2); + gfx_draw_string(dpi, buffer, 0, x, y); + + // Make area dirty so the text doesn't get drawn over the last + gfx_set_dirty_blocks(x - 16, y - 4, gLastDrawStringX + 16, 16); +} + int rct2_open_file(const char *path) { char *extension = strrchr(path, '.'); diff --git a/src/title.c b/src/title.c index a6b35904f9..032d4eb8e0 100644 --- a/src/title.c +++ b/src/title.c @@ -470,7 +470,7 @@ void DrawOpenRCT2(int x, int y) rct_drawpixelinfo *dpi = RCT2_ADDRESS(RCT2_ADDRESS_SCREEN_DPI, rct_drawpixelinfo); // Draw background - gfx_fill_rect_inset(dpi, x, y, x + 128, y + 20, 0x80 | 12, 0x8); + gfx_fill_rect_inset(dpi, x, y, x + 128, y + 20, TRANSLUCENT(COLOUR_DARK_GREEN), 0x8); // Write format codes utf8 *ch = buffer; diff --git a/src/windows/options.c b/src/windows/options.c index 14f072530a..73c2851089 100644 --- a/src/windows/options.c +++ b/src/windows/options.c @@ -80,6 +80,7 @@ enum WINDOW_OPTIONS_WIDGET_IDX { WIDX_FULLSCREEN_DROPDOWN, WIDX_HARDWARE_DISPLAY_CHECKBOX, WIDX_UNCAP_FPS_CHECKBOX, + WIDX_SHOW_FPS_CHECKBOX, WIDX_MINIMIZE_FOCUS_LOSS, WIDX_STEAM_OVERLAY_PAUSE, WIDX_SCALE, @@ -182,6 +183,7 @@ static rct_widget window_options_display_widgets[] = { { WWT_DROPDOWN_BUTTON, 1, 288, 298, 84, 93, STR_DROPDOWN_GLYPH, STR_NONE }, { WWT_CHECKBOX, 1, 10, 290, 99, 110, STR_HARDWARE_DISPLAY, STR_NONE }, // hardware display { WWT_CHECKBOX, 1, 10, 290, 114, 125, STR_UNCAP_FPS, STR_NONE }, // uncap fps + { WWT_CHECKBOX, 1, 155, 299, 114, 125, STR_SHOW_FPS, STR_NONE }, // show fps { WWT_CHECKBOX, 1, 10, 290, 129, 140, STR_MININISE_FULL_SCREEN_ON_FOCUS_LOSS, STR_NONE }, // minimise fullscreen focus loss { WWT_CHECKBOX, 1, 10, 290, 144, 155, STR_STEAM_OVERLAY_PAUSE, STR_NONE }, // minimise fullscreen focus loss { WWT_SPINNER, 1, 155, 299, 159, 170, STR_NONE, STR_NONE }, // scale spinner @@ -366,6 +368,7 @@ static uint32 window_options_page_enabled_widgets[] = { (1 << WIDX_GRIDLINES_CHECKBOX) | (1 << WIDX_HARDWARE_DISPLAY_CHECKBOX) | (1 << WIDX_UNCAP_FPS_CHECKBOX) | + (1 << WIDX_SHOW_FPS_CHECKBOX) | (1 << WIDX_MINIMIZE_FOCUS_LOSS) | (1 << WIDX_STEAM_OVERLAY_PAUSE) | (1 << WIDX_SCALE) | @@ -522,6 +525,11 @@ static void window_options_mouseup(rct_window *w, int widgetIndex) config_save_default(); window_invalidate(w); break; + case WIDX_SHOW_FPS_CHECKBOX: + gConfigGeneral.show_fps ^= 1; + config_save_default(); + window_invalidate(w); + break; case WIDX_MINIMIZE_FOCUS_LOSS: gConfigGeneral.minimize_fullscreen_focus_loss ^= 1; platform_refresh_video(); @@ -1178,6 +1186,7 @@ static void window_options_invalidate(rct_window *w) widget_set_checkbox_value(w, WIDX_GRIDLINES_CHECKBOX, RCT2_GLOBAL(RCT2_ADDRESS_CONFIG_FLAGS, uint8) & CONFIG_FLAG_ALWAYS_SHOW_GRIDLINES); widget_set_checkbox_value(w, WIDX_HARDWARE_DISPLAY_CHECKBOX, gConfigGeneral.hardware_display); widget_set_checkbox_value(w, WIDX_UNCAP_FPS_CHECKBOX, gConfigGeneral.uncap_fps); + widget_set_checkbox_value(w, WIDX_SHOW_FPS_CHECKBOX, gConfigGeneral.show_fps); widget_set_checkbox_value(w, WIDX_MINIMIZE_FOCUS_LOSS, gConfigGeneral.minimize_fullscreen_focus_loss); widget_set_checkbox_value(w, WIDX_STEAM_OVERLAY_PAUSE, gConfigGeneral.steam_overlay_pause); widget_set_checkbox_value(w, WIDX_DAY_NIGHT_CHECKBOX, gConfigGeneral.day_night_cycle); @@ -1196,6 +1205,7 @@ static void window_options_invalidate(rct_window *w) window_options_display_widgets[WIDX_CONSTRUCTION_MARKER_DROPDOWN].type = WWT_DROPDOWN_BUTTON; window_options_display_widgets[WIDX_HARDWARE_DISPLAY_CHECKBOX].type = WWT_CHECKBOX; window_options_display_widgets[WIDX_UNCAP_FPS_CHECKBOX].type = WWT_CHECKBOX; + window_options_display_widgets[WIDX_SHOW_FPS_CHECKBOX].type = WWT_CHECKBOX; window_options_display_widgets[WIDX_MINIMIZE_FOCUS_LOSS].type = WWT_CHECKBOX; window_options_display_widgets[WIDX_STEAM_OVERLAY_PAUSE].type = WWT_CHECKBOX; window_options_display_widgets[WIDX_DAY_NIGHT_CHECKBOX].type = WWT_CHECKBOX;