Files
aee/source/core/rendering/overlay.cpp
Sergio Valor d4fc7c0ee8 - renderInfo
- fix: no guardava el preset actual
2026-04-04 20:14:11 +02:00

179 lines
6.4 KiB
C++

#include "core/rendering/overlay.hpp"
#include <algorithm>
#include <memory>
#include <string>
#include <vector>
#include "core/rendering/text.hpp"
#include "game/options.hpp"
namespace Overlay {
static std::unique_ptr<Text> font_;
// --- Aspecte de la notificació ---
static constexpr Uint32 NOTIF_BG_COLOR = 0xFF2E1A1A; // Fons blau fosc (ABGR)
static constexpr Uint32 NOTIF_TEXT_COLOR = 0xFFFFFF00; // Text cyan (ABGR)
static constexpr int NOTIF_PADDING_H = 8; // Padding horitzontal (esquerra/dreta dins la caixa)
static constexpr int NOTIF_PADDING_V = 4; // Padding vertical (dalt/baix dins la caixa)
static constexpr int NOTIF_MARGIN_X = 4; // Offset des de la vora esquerra de la pantalla
static constexpr int NOTIF_MARGIN_Y = 4; // Offset des de la vora superior de la pantalla
// --- Animació ---
static constexpr float SLIDE_SPEED = 4.0F; // Velocitat de l'animació (unitats/segon)
// --- Pantalla ---
static constexpr int SCREEN_W = 320;
static constexpr int SCREEN_H = 200;
// --- Estat de les notificacions ---
enum class Status { RISING,
STAY,
VANISHING,
FINISHED };
struct Notification {
std::string message;
Status status{Status::RISING};
float anim{0.0F}; // 0 = fora de pantalla, 1 = posició final
float timer{0.0F};
float duration{2.0F};
int box_w{0}; // Ample de la caixa (calculat al crear)
int box_h{0}; // Alçada de la caixa (calculat al crear)
};
static std::vector<Notification> notifications_;
static Uint32 last_ticks_ = 0;
// --- Render info ---
static std::string render_info_text_;
void init() {
font_ = std::make_unique<Text>("fonts/8bithud.fnt", "fonts/8bithud.gif");
last_ticks_ = SDL_GetTicks();
}
void destroy() {
font_.reset();
notifications_.clear();
}
// Pinta un rectangle sòlid dins els límits de la pantalla
static void drawRect(Uint32* pixel_data, int rx, int ry, int rw, int rh, Uint32 color) {
for (int row = ry; row < ry + rh; row++) {
if (row < 0 || row >= SCREEN_H) continue;
for (int col = rx; col < rx + rw; col++) {
if (col < 0 || col >= SCREEN_W) continue;
pixel_data[col + row * SCREEN_W] = color;
}
}
}
void render(Uint32* pixel_data) {
if (!font_ || !pixel_data) return;
// Calcula delta time
Uint32 now = SDL_GetTicks();
float dt = static_cast<float>(now - last_ticks_) / 1000.0F;
last_ticks_ = now;
// Actualitza i pinta cada notificació
for (auto& notif : notifications_) {
switch (notif.status) {
case Status::RISING:
notif.anim += SLIDE_SPEED * dt;
if (notif.anim >= 1.0F) {
notif.anim = 1.0F;
notif.status = Status::STAY;
notif.timer = 0.0F;
}
break;
case Status::STAY:
notif.timer += dt;
if (notif.timer >= notif.duration) {
notif.status = Status::VANISHING;
}
break;
case Status::VANISHING:
notif.anim -= SLIDE_SPEED * dt;
if (notif.anim <= 0.0F) {
notif.status = Status::FINISHED;
}
break;
case Status::FINISHED:
break;
}
if (notif.status == Status::FINISHED) continue;
// Posició: entra des de l'esquerra
int target_x = NOTIF_MARGIN_X;
int target_y = NOTIF_MARGIN_Y;
int box_x = target_x - static_cast<int>((1.0F - notif.anim) * (notif.box_w + NOTIF_MARGIN_X));
int box_y = target_y;
// Pinta fons de la caixa
drawRect(pixel_data, box_x, box_y, notif.box_w, notif.box_h, NOTIF_BG_COLOR);
// Pinta text dins la caixa
font_->draw(pixel_data, box_x + NOTIF_PADDING_H, box_y + NOTIF_PADDING_V, notif.message.c_str(), NOTIF_TEXT_COLOR);
}
// Render info (FPS, driver, shader) — centrat, posició configurable
if (Options::render_info.position != Options::RenderInfoPosition::OFF && !render_info_text_.empty()) {
int info_w = font_->width(render_info_text_.c_str());
int info_x = (SCREEN_W - info_w) / 2;
int info_y = (Options::render_info.position == Options::RenderInfoPosition::TOP)
? 1
: SCREEN_H - font_->charHeight() - 1;
// Ombra (1px desplaçat)
font_->draw(pixel_data, info_x + 1, info_y + 1, render_info_text_.c_str(), Options::render_info.shadow_color);
// Text
font_->draw(pixel_data, info_x, info_y, render_info_text_.c_str(), Options::render_info.text_color);
}
// Elimina les acabades
notifications_.erase(
std::remove_if(notifications_.begin(), notifications_.end(), [](const Notification& n) { return n.status == Status::FINISHED; }),
notifications_.end());
}
void showNotification(const char* text, float duration_seconds) {
// Reemplaça la notificació anterior
notifications_.clear();
Notification notif;
notif.message = text;
notif.duration = duration_seconds;
notif.box_w = font_->width(text) + NOTIF_PADDING_H * 2;
notif.box_h = font_->charHeight() + NOTIF_PADDING_V * 2;
notifications_.push_back(notif);
}
void toggleRenderInfo() {
// Cicla: OFF → TOP → BOTTOM → OFF
switch (Options::render_info.position) {
case Options::RenderInfoPosition::OFF:
Options::render_info.position = Options::RenderInfoPosition::TOP;
break;
case Options::RenderInfoPosition::TOP:
Options::render_info.position = Options::RenderInfoPosition::BOTTOM;
break;
case Options::RenderInfoPosition::BOTTOM:
Options::render_info.position = Options::RenderInfoPosition::OFF;
break;
}
}
void setRenderInfoText(const char* text) {
render_info_text_ = text;
}
} // namespace Overlay