dfhack/plugins/tweak/tweaks/pausing-fps-counter.h

138 lines
4.5 KiB
C++

#include "df/global_objects.h"
#include "modules/Gui.h"
#include "modules/Screen.h"
#include "df/enabler.h"
#include "df/viewscreen_dwarfmodest.h"
#include "df/viewscreen_titlest.h"
struct dwarfmode_pausing_fps_counter_hook : df::viewscreen_dwarfmodest {
typedef df::viewscreen_dwarfmodest interpose_base;
static const uint32_t history_length = 3;
// whether init.txt have [FPS:YES]
static bool init_have_fps_yes()
{
static bool first = true;
static bool init_have_fps_yes;
if (first && df::global::gps)
{
// if first time called, then display_frames is set iff init.txt have [FPS:YES]
first = false;
init_have_fps_yes = (df::global::gps->display_frames == 1);
}
return init_have_fps_yes;
}
DEFINE_VMETHOD_INTERPOSE(void, render, ())
{
INTERPOSE_NEXT(render)();
if (!df::global::pause_state || !df::global::enabler || !df::global::world
|| !df::global::gps || !df::global::pause_state)
return;
// if init.txt does not have [FPS:YES] then dont show this FPS counter
if (!dwarfmode_pausing_fps_counter_hook::init_have_fps_yes())
return;
static bool prev_paused = true;
static uint32_t prev_clock = 0;
static int32_t prev_frames = 0;
static uint32_t elapsed_clock = 0;
static uint32_t elapsed_frames = 0;
static double history[history_length];
if (prev_clock == 0)
{
// init
for (uint32_t i = 0; i < history_length; i++)
history[i] = 0.0;
}
// disable default FPS counter because it is rendered on top of this FPS counter.
if (df::global::gps->display_frames == 1)
df::global::gps->display_frames = 0;
if (*df::global::pause_state)
prev_paused = true;
else
{
uint32_t clock = df::global::enabler->clock;
int32_t frames = df::global::world->frame_counter;
if (!prev_paused && prev_clock != 0
&& clock >= prev_clock && frames >= prev_frames)
{
// if we were previously paused, then dont add clock/frames,
// but wait for the next time render is called.
elapsed_clock += clock - prev_clock;
elapsed_frames += frames - prev_frames;
}
prev_paused = false;
prev_clock = clock;
prev_frames = frames;
// add FPS to history every second or after at least one frame.
if (elapsed_clock >= 1000 && elapsed_frames >= 1)
{
double fps = elapsed_frames / (elapsed_clock / 1000.0);
for (int i = history_length - 1; i >= 1; i--)
history[i] = history[i - 1];
history[0] = fps;
elapsed_clock = 0;
elapsed_frames = 0;
}
}
// average fps over a few seconds to stabilize the counter.
double fps_sum = 0.0;
int fps_count = 0;
for (uint32_t i = 0; i < history_length; i++)
{
if (history[i] > 0.0)
{
fps_sum += history[i];
fps_count++;
}
}
double fps = fps_count == 0 ? 1.0 : fps_sum / fps_count;
double gfps = df::global::enabler->calculated_gfps;
std::stringstream fps_counter;
fps_counter << "FPS:"
<< setw(4) << fixed << setprecision(fps >= 1.0 ? 0 : 2) << fps
<< " (" << gfps << ")";
// show this FPS counter same as the default counter.
int x = 10;
int y = 0;
OutputString(COLOR_WHITE, x, y, fps_counter.str(),
false, 0, COLOR_CYAN, false);
}
};
struct title_pausing_fps_counter_hook : df::viewscreen_titlest {
typedef df::viewscreen_titlest interpose_base;
DEFINE_VMETHOD_INTERPOSE(void, render, ())
{
INTERPOSE_NEXT(render)();
// if init.txt have FPS:YES then enable default FPS counter when exiting dwarf mode.
// So it is enabled if starting adventure mode without exiting dwarf fortress.
if (dwarfmode_pausing_fps_counter_hook::init_have_fps_yes()
&& df::global::gps && df::global::gps->display_frames == 0)
df::global::gps->display_frames = 1;
}
};
IMPLEMENT_VMETHOD_INTERPOSE(dwarfmode_pausing_fps_counter_hook, render);
IMPLEMENT_VMETHOD_INTERPOSE(title_pausing_fps_counter_hook, render);