Files

207 lines
6.0 KiB
C++

#pragma once
#include <array>
#include <cmath>
#include <cstddef>
namespace onion::overlay {
inline constexpr float kOffscreen = -4096.0f;
inline constexpr float kFontH = 18.0f;
inline constexpr float kBarExtra = 6.0f;
inline constexpr float kTextTopInset = 5.0f;
inline constexpr float kGap = 28.0f;
inline constexpr float kEdgeInset = 24.0f;
inline constexpr float kCpuAvgWidth = 190.0f;
inline constexpr float kCpuAllWidth = 420.0f;
inline constexpr float kGpuWidth = 190.0f;
inline constexpr float kRamWidth = 170.0f;
inline constexpr float kIpWidth = 200.0f;
inline constexpr float kFanWidth = 130.0f;
inline constexpr float kFpsWidth = 130.0f;
inline constexpr int kMetricCount = 6;
inline constexpr int kMetricFps = 0;
inline constexpr int kMetricCpu = 1;
inline constexpr int kMetricGpu = 2;
inline constexpr int kMetricMemory = 3;
inline constexpr int kMetricIp = 4;
inline constexpr int kMetricFan = 5;
enum class BarEdge { Top, Bottom };
enum class BarAlign { Left, Center, Right };
inline BarEdge bar_edge_from_pos(int pos) {
return (pos == 2 || pos == 3) ? BarEdge::Bottom : BarEdge::Top;
}
inline BarAlign bar_align_from_value(int align) {
if (align == 0) {
return BarAlign::Left;
}
if (align == 2) {
return BarAlign::Right;
}
return BarAlign::Center;
}
inline float pack_origin(float screen_w, float content_w, BarAlign align) {
if (content_w <= 0.0f) {
return kOffscreen;
}
if (align == BarAlign::Right) {
const float x = screen_w - kEdgeInset - content_w;
return x < kEdgeInset ? kEdgeInset : x;
}
if (align == BarAlign::Left) {
return kEdgeInset;
}
return (screen_w - content_w) * 0.5f;
}
struct Layout {
float screen_w = 0.0f;
float screen_h = 0.0f;
float bar_x = 0.0f;
float bar_y = 0.0f;
float bar_w = 0.0f;
float bar_h = kFontH + kBarExtra;
float label_margin_top = kTextTopInset;
float overlay_cpu_x = 160.0f;
float overlay_cpu_y = 12.0f;
float overlay_gpu_x = 360.0f;
float overlay_gpu_y = 12.0f;
float overlay_ram_x = 560.0f;
float overlay_ram_y = 12.0f;
float overlay_ip_x = 740.0f;
float overlay_ip_y = 12.0f;
float overlay_fan_x = 960.0f;
float overlay_fan_y = 12.0f;
float overlay_fps_x = 40.0f;
float overlay_fps_y = 12.0f;
};
struct Metrics {
bool enabled = true;
bool show_fps = true;
bool show_cpu = true;
bool show_gpu = true;
bool show_ram = true;
bool show_ip = false;
bool show_fan = false;
bool per_core_cpu = false;
int font_size_pt = static_cast<int>(kFontH);
/* Must match onion::kOverlayMetric* / kOverlayOrderDefault. */
std::array<int, kMetricCount> order{kMetricFps, kMetricCpu, kMetricGpu,
kMetricMemory, kMetricIp, kMetricFan};
};
inline void normalize_metric_order(std::array<int, kMetricCount> &order) {
bool seen[kMetricCount] = {};
std::array<int, kMetricCount> out{};
int n = 0;
for (int metric : order) {
if (metric < 0 || metric >= kMetricCount || seen[metric])
continue;
seen[metric] = true;
out[n++] = metric;
}
for (int metric = 0; metric < kMetricCount; ++metric) {
if (seen[metric])
continue;
out[n++] = metric;
}
order = out;
}
inline bool valid_screen_dimension(float value) {
return std::isfinite(value) && value > 1.0f;
}
inline Layout compute_overlay_layout(float screen_w, float screen_h,
BarEdge edge, BarAlign align,
const Metrics &metrics) {
Layout out{};
const int font_pt =
metrics.font_size_pt > 0 ? metrics.font_size_pt : static_cast<int>(kFontH);
const float scale = static_cast<float>(font_pt) / kFontH;
const float gap = kGap * scale;
out.bar_h = static_cast<float>(font_pt) + kBarExtra;
out.label_margin_top = kTextTopInset;
out.overlay_cpu_x = kOffscreen;
out.overlay_gpu_x = kOffscreen;
out.overlay_ram_x = kOffscreen;
out.overlay_ip_x = kOffscreen;
out.overlay_fan_x = kOffscreen;
out.overlay_fps_x = kOffscreen;
if (!valid_screen_dimension(screen_w) || !valid_screen_dimension(screen_h)) {
return out;
}
out.screen_w = screen_w;
out.screen_h = screen_h;
out.bar_x = 0.0f;
out.bar_w = screen_w;
out.bar_y = (edge == BarEdge::Bottom) ? (screen_h - out.bar_h) : 0.0f;
const bool show_cpu =
metrics.enabled && (metrics.show_cpu || metrics.per_core_cpu);
const bool show_gpu = metrics.enabled && metrics.show_gpu;
const bool show_ram = metrics.enabled && metrics.show_ram;
const bool show_ip = metrics.enabled && metrics.show_ip;
const bool show_fan = metrics.enabled && metrics.show_fan;
const bool show_fps = metrics.enabled && metrics.show_fps;
const float cpu_w =
(metrics.per_core_cpu ? kCpuAllWidth : kCpuAvgWidth) * scale;
struct Slot {
bool on;
float width;
float *x;
float *y;
};
Slot by_metric[kMetricCount] = {
{show_fps, kFpsWidth * scale, &out.overlay_fps_x, &out.overlay_fps_y},
{show_cpu, cpu_w, &out.overlay_cpu_x, &out.overlay_cpu_y},
{show_gpu, kGpuWidth * scale, &out.overlay_gpu_x, &out.overlay_gpu_y},
{show_ram, kRamWidth * scale, &out.overlay_ram_x, &out.overlay_ram_y},
{show_ip, kIpWidth * scale, &out.overlay_ip_x, &out.overlay_ip_y},
{show_fan, kFanWidth * scale, &out.overlay_fan_x, &out.overlay_fan_y},
};
std::array<int, kMetricCount> order = metrics.order;
normalize_metric_order(order);
float content_w = 0.0f;
int visible = 0;
for (int metric : order) {
const Slot &slot = by_metric[metric];
if (!slot.on) {
continue;
}
if (visible++) {
content_w += gap;
}
content_w += slot.width;
}
float x = pack_origin(screen_w, content_w, align);
for (int metric = 0; metric < kMetricCount; ++metric) {
*by_metric[metric].y = out.bar_y;
*by_metric[metric].x = kOffscreen;
}
for (int metric : order) {
Slot &slot = by_metric[metric];
*slot.y = out.bar_y;
if (!slot.on || content_w <= 0.0f) {
*slot.x = kOffscreen;
continue;
}
*slot.x = x;
x += slot.width + gap;
}
return out;
}
} // namespace onion::overlay