overlay fps/frametime/playtime

This commit is contained in:
a 2024-12-05 02:14:18 +02:00
parent d50f693348
commit 90cac09c12
7 changed files with 330 additions and 1 deletions

View File

@ -165,6 +165,16 @@ struct Overlay_Appearance {
float element_active_b = -1.0f;
float element_active_a = -1.0f;
float stats_background_r = 0.0f;
float stats_background_g = 0.0f;
float stats_background_b = 0.0f;
float stats_background_a = 0.6f;
float stats_text_r = 0.8f;
float stats_text_g = 0.7f;
float stats_text_b = 0.0f;
float stats_text_a = 1.0f;
NotificationPosition ach_earned_pos = NotificationPosition::bot_right; // achievement earned
NotificationPosition invite_pos = default_pos; // lobby/game invitation
NotificationPosition chat_msg_pos = NotificationPosition::top_center; // chat message from a friend
@ -315,6 +325,9 @@ public:
bool disable_overlay_achievement_notification = false;
bool disable_overlay_friend_notification = false;
bool disable_overlay_achievement_progress = false;
unsigned overlay_fps_avg_window = 10;
float overlay_stats_pos_x = 0.0f;
float overlay_stats_pos_y = 0.0f;
//warn people who use local save
bool overlay_warn_local_save = false;
//disable overlay warning for local save

View File

@ -376,6 +376,62 @@ static void load_overlay_appearance(class Settings *settings_client, class Setti
auto pos = Overlay_Appearance::translate_notification_position(value);
settings_client->overlay_appearance.chat_msg_pos = pos;
settings_server->overlay_appearance.chat_msg_pos = pos;
// >>> FPS background
} else if (name.compare("Stats_Background_R") == 0) {
float val = std::stof(value, NULL);
settings_client->overlay_appearance.stats_background_r = val;
settings_server->overlay_appearance.stats_background_r = val;
} else if (name.compare("Stats_Background_G") == 0) {
float val = std::stof(value, NULL);
settings_client->overlay_appearance.stats_background_g = val;
settings_server->overlay_appearance.stats_background_g = val;
} else if (name.compare("Stats_Background_B") == 0) {
float val = std::stof(value, NULL);
settings_client->overlay_appearance.stats_background_b = val;
settings_server->overlay_appearance.stats_background_b = val;
} else if (name.compare("Stats_Background_A") == 0) {
float val = std::stof(value, NULL);
settings_client->overlay_appearance.stats_background_a = val;
settings_server->overlay_appearance.stats_background_a = val;
// FPS background END <<<
// >>> FPS text color
} else if (name.compare("Stats_Text_R") == 0) {
float val = std::stof(value, NULL);
settings_client->overlay_appearance.stats_text_r = val;
settings_server->overlay_appearance.stats_text_r = val;
} else if (name.compare("Stats_Text_G") == 0) {
float val = std::stof(value, NULL);
settings_client->overlay_appearance.stats_text_g = val;
settings_server->overlay_appearance.stats_text_g = val;
} else if (name.compare("Stats_Text_B") == 0) {
float val = std::stof(value, NULL);
settings_client->overlay_appearance.stats_text_b = val;
settings_server->overlay_appearance.stats_text_b = val;
} else if (name.compare("Stats_Text_A") == 0) {
float val = std::stof(value, NULL);
settings_client->overlay_appearance.stats_text_a = val;
settings_server->overlay_appearance.stats_text_a = val;
// FPS text color END <<<
// >>> FPS position
} else if (name.compare("Stats_Pos_x") == 0) {
auto pos = std::stof(value);
if (pos < 0) {
pos = 0;
} else if (pos > 1.0f) {
pos = 1.0f;
}
settings_client->overlay_stats_pos_x = pos;
settings_server->overlay_stats_pos_x = pos;
} else if (name.compare("Stats_Pos_y") == 0) {
auto pos = std::stof(value);
if (pos < 0) {
pos = 0;
} else if (pos > 1.0f) {
pos = 1.0f;
}
settings_client->overlay_stats_pos_y = pos;
settings_server->overlay_stats_pos_y = pos;
// FPS position END <<<
} else {
PRINT_DEBUG("unknown overlay appearance setting");
}
@ -1366,6 +1422,20 @@ static void parse_overlay_general_config(class Settings *settings_client, class
settings_client->overlay_upload_achs_icons_to_gpu = ini.GetBoolValue("overlay::general", "upload_achievements_icons_to_gpu", settings_client->overlay_upload_achs_icons_to_gpu);
settings_server->overlay_upload_achs_icons_to_gpu = ini.GetBoolValue("overlay::general", "upload_achievements_icons_to_gpu", settings_server->overlay_upload_achs_icons_to_gpu);
{
auto val = ini.GetLongValue("overlay::general", "fps_averaging_window", settings_client->overlay_fps_avg_window);
if (val > 0) {
settings_client->overlay_fps_avg_window = val;
}
}
{
auto val = ini.GetLongValue("overlay::general", "fps_averaging_window", settings_server->overlay_fps_avg_window);
if (val > 0) {
settings_server->overlay_fps_avg_window = val;
}
}
}
// main::misc::steam_game_stats_reports_dir

View File

@ -12,6 +12,7 @@
#include <memory>
#include "InGameOverlay/RendererHook.h"
#include "InGameOverlay/ImGui/imgui.h"
#include "overlay/steam_overlay_stats.h"
static constexpr size_t max_chat_len = 768;
@ -109,6 +110,7 @@ class Steam_Overlay
class SteamCallBacks* callbacks;
class RunEveryRunCB* run_every_runcb;
class Networking* network;
class Steam_Overlay_Stats stats;
// friend id, show client window (to chat and accept invite maybe)
std::map<Friend, friend_window_state, Friend_Less> friends{};

View File

@ -0,0 +1,48 @@
#ifndef _STEAM_OVERLAY_STATS_H_
#define _STEAM_OVERLAY_STATS_H_
#include <chrono>
#include <string_view>
#include <unordered_map>
#include <vector>
#include "dll/settings.h"
#include "InGameOverlay/ImGui/imgui.h"
class Steam_Overlay_Stats {
private:
class Settings* settings{};
unsigned last_frametime_idx{};
std::chrono::high_resolution_clock::time_point last_frame_timepoint =
std::chrono::high_resolution_clock::now();
unsigned running_frametime_ms = 0; // used for the ongoing calculation
float active_frametime_ms = 0; // the final calculated frametime after averaging
unsigned active_fps = 0; // the final calculated FPS after averaging
std::chrono::high_resolution_clock::time_point initial_time =
std::chrono::high_resolution_clock::now();
std::chrono::high_resolution_clock::time_point last_playtime =
std::chrono::high_resolution_clock::now();
unsigned active_playtime_hr = 0;
unsigned active_playtime_min = 0;
unsigned active_playtime_sec = 0;
void update_frametime(const std::chrono::high_resolution_clock::time_point &now);
void update_playtime(const std::chrono::high_resolution_clock::time_point &now);
public:
ImFont *font = nullptr;
bool show_fps = false;
bool show_frametime = false;
bool show_playtime = false;
Steam_Overlay_Stats(class Settings* settings);
bool show_any_stats() const;
void render_stats();
};
#endif // _STEAM_OVERLAY_STATS_H_

View File

@ -101,7 +101,8 @@ Steam_Overlay::Steam_Overlay(Settings* settings, Local_Storage *local_storage, S
callback_results(callback_results),
callbacks(callbacks),
run_every_runcb(run_every_runcb),
network(network)
network(network),
stats(Steam_Overlay_Stats(settings))
{
// don't even bother initializing the overlay
if (settings->disable_overlay) return;
@ -299,6 +300,7 @@ void Steam_Overlay::create_fonts()
// note: base85 compressed arrays caused a compiler heap allocation error, regular compression is more guaranteed
ImFont *font = fonts_atlas.AddFontFromMemoryCompressedTTF(unifont_compressed_data, unifont_compressed_size, font_size, &font_cfg);
font_notif = font_default = font;
stats.font = font;
bool res = fonts_atlas.Build();
PRINT_DEBUG("created fonts atlas (result=%i)", (int)res);
@ -1253,6 +1255,10 @@ void Steam_Overlay::overlay_render_proc()
build_notifications(io.DisplaySize.x, io.DisplaySize.y);
}
if (stats.show_any_stats()) {
stats.render_stats();
}
load_next_ach_icon();
}
@ -1390,6 +1396,24 @@ void Steam_Overlay::render_main_window()
show_settings = !show_settings;
}
ImGui::Spacing();
ImGui::Spacing();
// user clicked on "FPS"
ImGui::SameLine();
if (ImGui::Checkbox("FPS", &stats.show_fps)) {
allow_renderer_frame_processing(stats.show_fps);
}
// user clicked on "Frametime"
ImGui::SameLine();
if (ImGui::Checkbox("Frametime", &stats.show_frametime)) {
allow_renderer_frame_processing(stats.show_frametime);
}
// user clicked on "Playtime"
ImGui::SameLine();
if (ImGui::Checkbox("Playtime", &stats.show_playtime)) {
allow_renderer_frame_processing(stats.show_playtime);
}
ImGui::Spacing();
ImGui::Spacing();
ImGui::LabelText("##label", "%s", translationFriends[current_language]);

View File

@ -0,0 +1,143 @@
#include "overlay/steam_overlay_stats.h"
#include <utility>
Steam_Overlay_Stats::Steam_Overlay_Stats(class Settings* settings):
settings(settings)
{
}
bool Steam_Overlay_Stats::show_any_stats() const
{
return show_fps || show_frametime || show_playtime;
}
void Steam_Overlay_Stats::update_frametime(const std::chrono::high_resolution_clock::time_point &now)
{
running_frametime_ms += static_cast<unsigned>(
std::chrono::duration_cast<std::chrono::milliseconds>(now - last_frame_timepoint).count()
);
last_frame_timepoint = now;
if (last_frametime_idx >= (settings->overlay_fps_avg_window - 1)) {
last_frametime_idx = 0;
active_frametime_ms = static_cast<float>(running_frametime_ms) / settings->overlay_fps_avg_window;
active_fps = static_cast<unsigned>((1000 * settings->overlay_fps_avg_window) / running_frametime_ms);
running_frametime_ms = 0;
} else {
++last_frametime_idx;
}
}
void Steam_Overlay_Stats::update_playtime(const std::chrono::high_resolution_clock::time_point &now)
{
const auto update_duration_sec = std::chrono::duration_cast<std::chrono::seconds>(
now - last_playtime
).count();
if (update_duration_sec < 1) return;
last_playtime = now;
const auto time_duration_sec = (unsigned long long)std::chrono::duration_cast<std::chrono::seconds>(
now - initial_time
).count();
active_playtime_sec = static_cast<unsigned>(time_duration_sec % 60);
const auto time_duration_min = time_duration_sec / 60;
active_playtime_min = static_cast<unsigned>(time_duration_min % 60);
const auto time_duration_hr = time_duration_min / 60;
active_playtime_hr = static_cast<unsigned>(time_duration_hr % 24);
}
void Steam_Overlay_Stats::render_stats()
{
auto now = std::chrono::high_resolution_clock::now();
if (show_fps || show_frametime) {
update_frametime(now);
}
if (show_playtime) {
update_playtime(now);
}
ImGui::PushFont(font);
ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, settings->overlay_appearance.notification_rounding);
ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, 0);
ImGui::PushStyleColor(ImGuiCol_WindowBg, ImVec4(
settings->overlay_appearance.stats_background_r,
settings->overlay_appearance.stats_background_g,
settings->overlay_appearance.stats_background_b,
settings->overlay_appearance.stats_background_a
));
ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(
settings->overlay_appearance.stats_text_r,
settings->overlay_appearance.stats_text_g,
settings->overlay_appearance.stats_text_b,
settings->overlay_appearance.stats_text_a
));
std::stringstream stats_txt_buff{};
if (show_fps) {
stats_txt_buff << "FPS: "
<< std::left << std::setw(2)
<< active_fps
<< std::right << std::setw(0);
}
if (show_frametime) {
if (stats_txt_buff.tellp() > 0) {
stats_txt_buff << " | ";
}
stats_txt_buff << "FRT: "
<< std::left << std::setw(4) << std::fixed << std::setprecision(1)
<< active_frametime_ms
<< std::defaultfloat << std::right << std::setw(0)
<< " ms";
}
if (show_playtime) {
if (stats_txt_buff.tellp() > 0) {
stats_txt_buff << " | ";
}
const auto org_fill = stats_txt_buff.fill();
stats_txt_buff << "PLT: "
<< std::setw(2) << std::setfill('0')
<< active_playtime_hr << ':'
<< std::setw(2) << std::setfill('0')
<< active_playtime_min << ':'
<< std::setw(2) << std::setfill('0')
<< active_playtime_sec
<< std::setw(0) << std::setfill(org_fill);
}
const auto stats_txt = stats_txt_buff.str();
// set FPS box width/height based on text size
const auto msg_box = ImGui::CalcTextSize(
stats_txt.c_str(),
stats_txt.c_str() + stats_txt.size()
);
auto &global_style = ImGui::GetStyle();
const float padding_all_sides = global_style.WindowPadding.y + global_style.WindowPadding.x;
const auto stats_box = ImVec2(msg_box.x + padding_all_sides, msg_box.y + padding_all_sides);
ImGui::SetNextWindowSize(stats_box);
auto &io = ImGui::GetIO();
const auto anchor_point_x = stats_box.x * settings->overlay_stats_pos_x;
const auto anchor_point_y = stats_box.y * settings->overlay_stats_pos_y;
ImGui::SetNextWindowPos({
io.DisplaySize.x * settings->overlay_stats_pos_x - anchor_point_x,
io.DisplaySize.y * settings->overlay_stats_pos_y - anchor_point_y
});
if (ImGui::Begin("wnd_fps_frametime", nullptr,
ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoResize |
ImGuiWindowFlags_NoFocusOnAppearing | ImGuiWindowFlags_NoBringToFrontOnFocus | ImGuiWindowFlags_NoInputs |
ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_NoScrollWithMouse)) {
ImGui::TextWrapped("%s", stats_txt.c_str());
}
ImGui::End();
ImGui::PopStyleColor(2);
ImGui::PopStyleVar(2);
ImGui::PopFont();
}

View File

@ -44,6 +44,12 @@ disable_warning_local_save=0
# in that case achievements icons win't be displayed
# default=1
upload_achievements_icons_to_gpu=1
# amount of frames to accumulate, to eventually calculate the average frametime (in milliseconds)
# lower values would result in instantaneous frametime/fps, but the FPS would be erratic
# higher values would result in a more stable frametime/fps, but will be inaccurate due to averaging over long time
# minimum allowed value = 1
# default=10
fps_averaging_window=10
[overlay::appearance]
# load custom TrueType font from a path, it could be absolute, or relative
@ -130,3 +136,26 @@ PosInvitation=top_right
# position of chat messages
PosChatMsg=top_center
# ############################# #
# ############################# #
# FPS background color
Stats_Background_R=0.0
Stats_Background_G=0.0
Stats_Background_B=0.0
Stats_Background_A=0.6
# FPS text color
Stats_Text_R=0.8
Stats_Text_G=0.7
Stats_Text_B=0.0
Stats_Text_A=1.0
# FPS position in percentage [0.0, 1.0]
# X=0.0 : left
# X=1.0 : right
Stats_Pos_x=0.0
# Y=0.0 : up
# Y=1.0 : down
Stats_Pos_y=0.0
# ############################# #