mirror of
https://github.com/OpenRCT2/OpenRCT2
synced 2026-01-25 15:54:31 +01:00
uncapped FPS: fix viewport chopiness and reset after park load
This commit is contained in:
@@ -670,6 +670,7 @@ int game_load_sv6(const char *path)
|
||||
reset_loaded_objects();
|
||||
map_update_tile_pointers();
|
||||
reset_0x69EBE4();
|
||||
gOpenRCT2ResetFrameSmoothing = true;
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
@@ -156,6 +156,13 @@ void window_dispatch_update_all()
|
||||
RCT2_CALLPROC_EBPSAFE(0x006EE411); // handle_text_input
|
||||
}
|
||||
|
||||
void window_update_all_viewports()
|
||||
{
|
||||
for (rct_window *w = g_window_list; w < RCT2_NEW_WINDOW; w++)
|
||||
if (w->viewport != NULL)
|
||||
viewport_update_position(w);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* rct2: 0x006E77A1
|
||||
@@ -169,10 +176,7 @@ void window_update_all()
|
||||
return;
|
||||
|
||||
gfx_draw_all_dirty_blocks();
|
||||
|
||||
for (w = g_window_list; w < RCT2_NEW_WINDOW; w++)
|
||||
if (w->viewport != NULL)
|
||||
viewport_update_position(w);
|
||||
window_update_all_viewports();
|
||||
|
||||
// 1000 tick update
|
||||
RCT2_GLOBAL(0x009DEB7C, sint16) += RCT2_GLOBAL(0x009DE588, sint16);
|
||||
|
||||
@@ -459,6 +459,7 @@ extern rct_window* g_window_list;
|
||||
extern ride_list_item _window_track_list_item;
|
||||
|
||||
void window_dispatch_update_all();
|
||||
void window_update_all_viewports();
|
||||
void window_update_all();
|
||||
rct_window *window_create(int x, int y, int width, int height, uint32 *event_handlers, rct_windowclass cls, uint16 flags);
|
||||
rct_window *window_create_auto_pos(int width, int height, uint32 *event_handlers, rct_windowclass cls, uint16 flags);
|
||||
|
||||
@@ -42,6 +42,10 @@ bool gOpenRCT2Headless = false;
|
||||
|
||||
bool gOpenRCT2ShowChangelog;
|
||||
|
||||
// This needs to be set when a park is loaded. It could also be used to reset other important states, it should then be renamed
|
||||
// to something more general.
|
||||
bool gOpenRCT2ResetFrameSmoothing = false;
|
||||
|
||||
/** If set, will end the OpenRCT2 game loop. Intentially private to this module so that the flag can not be set back to 0. */
|
||||
int _finished;
|
||||
|
||||
@@ -231,6 +235,21 @@ void openrct2_dispose()
|
||||
platform_free();
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether its worth tweening a sprite or not when frame smoothing is on.
|
||||
*/
|
||||
static bool sprite_should_tween(rct_sprite *sprite)
|
||||
{
|
||||
if (sprite->unknown.linked_list_type_offset == SPRITE_LINKEDLIST_OFFSET_VEHICLE)
|
||||
return true;
|
||||
if (sprite->unknown.linked_list_type_offset == SPRITE_LINKEDLIST_OFFSET_PEEP)
|
||||
return true;
|
||||
if (sprite->unknown.linked_list_type_offset == SPRITE_LINKEDLIST_OFFSET_UNKNOWN)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Run the main game loop until the finished flag is set at 40fps (25ms interval).
|
||||
*/
|
||||
@@ -250,6 +269,7 @@ static void openrct2_loop()
|
||||
if (gConfigGeneral.uncap_fps) {
|
||||
currentTick = SDL_GetTicks();
|
||||
if (!uncappedinitialized) {
|
||||
// Reset sprite locations
|
||||
uncapTick = SDL_GetTicks();
|
||||
for (uint16 i = 0; i < MAX_SPRITES; i++) {
|
||||
spritelocations1[i].x = spritelocations2[i].x = g_sprite_list[i].unknown.x;
|
||||
@@ -258,28 +278,51 @@ static void openrct2_loop()
|
||||
}
|
||||
uncappedinitialized = 1;
|
||||
}
|
||||
|
||||
while (uncapTick <= currentTick && currentTick - uncapTick > 25) {
|
||||
// Get the original position of each sprite
|
||||
for (uint16 i = 0; i < MAX_SPRITES; i++) {
|
||||
spritelocations1[i].x = g_sprite_list[i].unknown.x;
|
||||
spritelocations1[i].y = g_sprite_list[i].unknown.y;
|
||||
spritelocations1[i].z = g_sprite_list[i].unknown.z;
|
||||
}
|
||||
|
||||
// Update the game so the sprite positions update
|
||||
rct2_update();
|
||||
if (gOpenRCT2ResetFrameSmoothing) {
|
||||
gOpenRCT2ResetFrameSmoothing = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Get the next position of each sprite
|
||||
for (uint16 i = 0; i < MAX_SPRITES; i++) {
|
||||
spritelocations2[i].x = g_sprite_list[i].unknown.x;
|
||||
spritelocations2[i].y = g_sprite_list[i].unknown.y;
|
||||
spritelocations2[i].z = g_sprite_list[i].unknown.z;
|
||||
}
|
||||
|
||||
uncapTick += 25;
|
||||
}
|
||||
|
||||
// Tween the position of each sprite from the last position to the new position based on the time between the last
|
||||
// tick and the next tick.
|
||||
float nudge = 1 - ((float)(currentTick - uncapTick) / 25);
|
||||
for (uint16 i = 0; i < MAX_SPRITES; i++) {
|
||||
if (!(g_sprite_list[i].unknown.linked_list_type_offset == SPRITE_LINKEDLIST_OFFSET_VEHICLE || g_sprite_list[i].unknown.linked_list_type_offset == SPRITE_LINKEDLIST_OFFSET_PEEP || g_sprite_list[i].unknown.linked_list_type_offset == SPRITE_LINKEDLIST_OFFSET_UNKNOWN)) {
|
||||
if (!sprite_should_tween(&g_sprite_list[i]))
|
||||
continue;
|
||||
}
|
||||
sprite_move(spritelocations2[i].x + (sint16)((spritelocations1[i].x - spritelocations2[i].x) * nudge), spritelocations2[i].y + (sint16)((spritelocations1[i].y - spritelocations2[i].y) * nudge), spritelocations2[i].z + (sint16)((spritelocations1[i].z - spritelocations2[i].z) * nudge), &g_sprite_list[i]);
|
||||
|
||||
sprite_move(
|
||||
spritelocations2[i].x + (sint16)((spritelocations1[i].x - spritelocations2[i].x) * nudge),
|
||||
spritelocations2[i].y + (sint16)((spritelocations1[i].y - spritelocations2[i].y) * nudge),
|
||||
spritelocations2[i].z + (sint16)((spritelocations1[i].z - spritelocations2[i].z) * nudge),
|
||||
&g_sprite_list[i]
|
||||
);
|
||||
invalidate_sprite(&g_sprite_list[i]);
|
||||
}
|
||||
|
||||
// Viewports need to be updated to reduce chopiness of those which follow sprites
|
||||
window_update_all_viewports();
|
||||
|
||||
platform_process_messages();
|
||||
rct2_draw();
|
||||
platform_draw();
|
||||
@@ -288,10 +331,12 @@ static void openrct2_loop()
|
||||
fps = 0;
|
||||
secondTick = SDL_GetTicks();
|
||||
}
|
||||
|
||||
// Restore the real positions of the sprites so they aren't left at the mid-tween positions
|
||||
for (uint16 i = 0; i < MAX_SPRITES; i++) {
|
||||
if (!(g_sprite_list[i].unknown.linked_list_type_offset == SPRITE_LINKEDLIST_OFFSET_VEHICLE || g_sprite_list[i].unknown.linked_list_type_offset == SPRITE_LINKEDLIST_OFFSET_PEEP || g_sprite_list[i].unknown.linked_list_type_offset == SPRITE_LINKEDLIST_OFFSET_UNKNOWN)) {
|
||||
if (!sprite_should_tween(&g_sprite_list[i]))
|
||||
continue;
|
||||
}
|
||||
|
||||
sprite_move(spritelocations2[i].x, spritelocations2[i].y, spritelocations2[i].z, &g_sprite_list[i]);
|
||||
}
|
||||
} else {
|
||||
@@ -307,7 +352,10 @@ static void openrct2_loop()
|
||||
lastTick = currentTick;
|
||||
|
||||
platform_process_messages();
|
||||
|
||||
rct2_update();
|
||||
gOpenRCT2ResetFrameSmoothing = false;
|
||||
|
||||
rct2_draw();
|
||||
platform_draw();
|
||||
}
|
||||
|
||||
@@ -35,6 +35,7 @@ extern char gOpenRCT2StartupActionPath[512];
|
||||
extern char gExePath[MAX_PATH];
|
||||
extern bool gOpenRCT2Headless;
|
||||
extern bool gOpenRCT2ShowChangelog;
|
||||
extern bool gOpenRCT2ResetFrameSmoothing;
|
||||
|
||||
bool openrct2_initialise();
|
||||
void openrct2_launch();
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
#include "management/research.h"
|
||||
#include "management/news_item.h"
|
||||
#include "object.h"
|
||||
#include "openrct2.h"
|
||||
#include "peep/staff.h"
|
||||
#include "platform/platform.h"
|
||||
#include "ride/ride.h"
|
||||
@@ -178,6 +179,7 @@ int scenario_load(const char *path)
|
||||
reset_loaded_objects();
|
||||
map_update_tile_pointers();
|
||||
reset_0x69EBE4();
|
||||
gOpenRCT2ResetFrameSmoothing = true;
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user