From b845372efa6dd36ba6ed97a8a26c2b63dc425c42 Mon Sep 17 00:00:00 2001 From: mchughalex <25671999+mchughalex@users.noreply.github.com> Date: Thu, 4 Jun 2026 19:56:26 +0200 Subject: [PATCH] add product version metadata --- cmake/rex_version.cmake | 12 +++++------- include/rex/rex_app.h | 10 ++++++++++ include/rex/ui/overlay/debug_overlay.h | 6 +++++- src/ui/overlay/debug_overlay.cpp | 14 +++++++++----- src/ui/rex_app.cpp | 20 +++++++++++++++----- 5 files changed, 44 insertions(+), 18 deletions(-) diff --git a/cmake/rex_version.cmake b/cmake/rex_version.cmake index d593ee4..d0298b3 100644 --- a/cmake/rex_version.cmake +++ b/cmake/rex_version.cmake @@ -9,7 +9,7 @@ # Emits a CMake-style version string: MAJOR.MINOR[.PATCH[.TWEAK]][-id]. # See https://cmake.org/cmake/help/latest/variable/CMAKE_VERSION.html # -# Tagged commit (vX.Y[.Z[.W]]): emits the tag verbatim (without the v). +# Tagged commit (vX.Y[.Z[.W]][-id]): emits the tag verbatim (without the v). # Untagged commit: emits MAJOR...- # where id is "dev.gSHA" on any branch and "rc.gSHA" on a release/* branch. #========================================================== @@ -18,7 +18,7 @@ function(rex_compute_version out_var) cmake_parse_arguments(ARG "" "${one_value}" "" ${ARGN}) if(NOT "${ARG_GIT_DESCRIBE_EXACT}" STREQUAL "") - if(ARG_GIT_DESCRIBE_EXACT MATCHES "^v([0-9]+\\.[0-9]+(\\.[0-9]+)?(\\.[0-9]+)?)$") + if(ARG_GIT_DESCRIBE_EXACT MATCHES "^v([0-9]+\\.[0-9]+(\\.[0-9]+)?(\\.[0-9]+)?(-[0-9A-Za-z][0-9A-Za-z.-]*)?)$") set(${out_var} "${CMAKE_MATCH_1}" PARENT_SCOPE) return() endif() @@ -35,7 +35,7 @@ function(rex_compute_version out_var) return() endif() - if(NOT ARG_GIT_DESCRIBE_LONG MATCHES "^v([0-9]+)\\.([0-9]+)(\\.([0-9]+))?(\\.([0-9]+))?-([0-9]+)-g([0-9a-f]+)$") + if(NOT ARG_GIT_DESCRIBE_LONG MATCHES "^v([0-9]+)\\.([0-9]+)(\\.([0-9]+))?(\\.([0-9]+))?(-[0-9A-Za-z][0-9A-Za-z.-]*)?-([0-9]+)-g([0-9a-f]+)$") message(FATAL_ERROR "rex_compute_version: unparseable describe output '${ARG_GIT_DESCRIBE_LONG}'") endif() set(tag_minor ${CMAKE_MATCH_2}) @@ -44,8 +44,8 @@ function(rex_compute_version out_var) else() set(tag_patch 0) endif() - set(commit_count ${CMAKE_MATCH_7}) - set(short_sha ${CMAKE_MATCH_8}) + set(commit_count ${CMAKE_MATCH_8}) + set(short_sha ${CMAKE_MATCH_9}) # Floor minor must never go backwards. if(ARG_FLOOR_MINOR LESS tag_minor) @@ -100,7 +100,6 @@ function(rex_resolve_version out_var) execute_process( COMMAND ${GIT_EXECUTABLE} describe --tags --exact-match --match "v[0-9]*.[0-9]*.[0-9]*" - --exclude "*-*" WORKING_DIRECTORY "${ARG_SOURCE_DIR}" OUTPUT_VARIABLE describe_exact ERROR_QUIET @@ -113,7 +112,6 @@ function(rex_resolve_version out_var) execute_process( COMMAND ${GIT_EXECUTABLE} describe --tags --long --match "v[0-9]*.[0-9]*" - --exclude "*-*" WORKING_DIRECTORY "${ARG_SOURCE_DIR}" OUTPUT_VARIABLE describe_long ERROR_QUIET diff --git a/include/rex/rex_app.h b/include/rex/rex_app.h index 56b378d..d3c1c2e 100644 --- a/include/rex/rex_app.h +++ b/include/rex/rex_app.h @@ -17,6 +17,7 @@ #include #include #include +#include #include #include @@ -139,6 +140,15 @@ class ReXApp : public ui::WindowedApp, public ui::WindowListener, public ui::Win /// Called after logging is initialized. Add log sinks here. virtual void OnPostInitLogging() {} + /// Product-specific title suffix shown in the host window title. + virtual std::string_view GetBuildTitle() const; + + /// Product-specific build stamp shown in debug overlays. + virtual std::string_view GetBuildStamp() const; + + /// Product-specific host window title. + virtual std::string GetWindowTitle() const; + /// Called after Runtime::LoadXexImage() succeeds. The XEX is loaded and /// mapped into guest memory but the module has not launched. /// Use this for data patches on the loaded image. diff --git a/include/rex/ui/overlay/debug_overlay.h b/include/rex/ui/overlay/debug_overlay.h index e15e410..aafdc83 100644 --- a/include/rex/ui/overlay/debug_overlay.h +++ b/include/rex/ui/overlay/debug_overlay.h @@ -14,6 +14,8 @@ #include #include #include +#include +#include namespace rex::ui { @@ -27,7 +29,8 @@ class DebugOverlayDialog : public ImGuiDialog { public: using FrameStatsProvider = std::function; - explicit DebugOverlayDialog(ImGuiDrawer* imgui_drawer, FrameStatsProvider stats_provider = {}); + explicit DebugOverlayDialog(ImGuiDrawer* imgui_drawer, FrameStatsProvider stats_provider = {}, + std::string_view build_stamp = {}); ~DebugOverlayDialog(); void SetStatsProvider(FrameStatsProvider provider) { stats_provider_ = std::move(provider); } @@ -37,6 +40,7 @@ class DebugOverlayDialog : public ImGuiDialog { private: FrameStatsProvider stats_provider_; + std::string build_stamp_; #ifdef REXGLUE_ENABLE_PERF_COUNTERS static constexpr size_t kFrameHistorySize = 120; std::array frame_time_history_{}; diff --git a/src/ui/overlay/debug_overlay.cpp b/src/ui/overlay/debug_overlay.cpp index 8d7106a..dbb5cdb 100644 --- a/src/ui/overlay/debug_overlay.cpp +++ b/src/ui/overlay/debug_overlay.cpp @@ -39,8 +39,11 @@ float CounterMs(rex::perf::CounterId id) { } // namespace #endif -DebugOverlayDialog::DebugOverlayDialog(ImGuiDrawer* imgui_drawer, FrameStatsProvider stats_provider) - : ImGuiDialog(imgui_drawer), stats_provider_(std::move(stats_provider)) {} +DebugOverlayDialog::DebugOverlayDialog(ImGuiDrawer* imgui_drawer, FrameStatsProvider stats_provider, + std::string_view build_stamp) + : ImGuiDialog(imgui_drawer), + stats_provider_(std::move(stats_provider)), + build_stamp_(build_stamp.empty() ? REXGLUE_BUILD_STAMP : std::string(build_stamp)) {} DebugOverlayDialog::~DebugOverlayDialog() {} @@ -200,7 +203,8 @@ void DebugOverlayDialog::OnDraw(ImGuiIO& io) { ImGui::PopFont(); // Build stamp watermark -- centered near bottom of screen - auto text_size = ImGui::CalcTextSize(REXGLUE_BUILD_STAMP); + const char* build_stamp = build_stamp_.c_str(); + auto text_size = ImGui::CalcTextSize(build_stamp); float padding = ImGui::GetStyle().WindowPadding.x * 2.0f; float bottom_offset = io.DisplaySize.y * 0.03f; ImGui::SetNextWindowPos(ImVec2((io.DisplaySize.x - text_size.x - padding) * 0.5f, @@ -208,10 +212,10 @@ void DebugOverlayDialog::OnDraw(ImGuiIO& io) { ImGui::SetNextWindowSize(ImVec2(0, 0)); ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(1.0f, 1.0f, 1.0f, 0.5f)); if (ImGui::Begin("##watermark", nullptr, - ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoBackground | + ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoBackground | ImGuiWindowFlags_NoInputs | ImGuiWindowFlags_NoNav | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_AlwaysAutoResize)) { - ImGui::TextUnformatted(REXGLUE_BUILD_STAMP); + ImGui::TextUnformatted(build_stamp); } ImGui::End(); ImGui::PopStyleColor(); diff --git a/src/ui/rex_app.cpp b/src/ui/rex_app.cpp index 9f00545..56c7634 100644 --- a/src/ui/rex_app.cpp +++ b/src/ui/rex_app.cpp @@ -73,6 +73,18 @@ ReXApp::ReXApp(ui::WindowedAppContext& ctx, std::string_view name, PPCImageInfo std::string_view usage) : WindowedApp(ctx, name, usage), ppc_info_(ppc_info) {} +std::string_view ReXApp::GetBuildTitle() const { + return REXGLUE_BUILD_TITLE; +} + +std::string_view ReXApp::GetBuildStamp() const { + return REXGLUE_BUILD_STAMP; +} + +std::string ReXApp::GetWindowTitle() const { + return std::string(GetName()) + " " + std::string(GetBuildTitle()); +} + bool ReXApp::OnInitialize() { if (!SetupEnvironment()) return false; @@ -353,9 +365,7 @@ bool ReXApp::SetupPresentation() { return false; } - // Set window title with SDK build stamp - std::string title = std::string(GetName()) + " " + REXGLUE_BUILD_TITLE; - window_->SetTitle(title); + window_->SetTitle(GetWindowTitle()); window_->AddListener(this); window_->AddInputListener(this, 0); @@ -380,8 +390,8 @@ bool ReXApp::SetupPresentation() { if (debug_overlay_) { debug_overlay_.reset(); } else { - debug_overlay_ = std::make_unique(imgui_drawer_.get(), - frame_stats_provider_); + debug_overlay_ = std::make_unique( + imgui_drawer_.get(), frame_stats_provider_, GetBuildStamp()); } }); rex::ui::RegisterBind("bind_console", "Backtick", "Toggle console overlay", [this] {