- afegides les habitacions de tot el joc (buides)

- minimapa mostra els numeros d'habitacio
- tecla per a fer captures de pantalla
This commit is contained in:
2026-04-12 10:25:12 +02:00
parent c1764ba0d8
commit 234ae82f56
124 changed files with 7744 additions and 35 deletions

View File

@@ -7,8 +7,9 @@
#include "core/input/input.hpp" // Para Input, InputAction, Input::DO_NOT_ALLOW_REPEAT
#include "core/locale/locale.hpp" // Para Locale
#include "core/rendering/render_info.hpp" // Para RenderInfo
#include "core/rendering/screen.hpp" // Para Screen
#include "core/rendering/render_info.hpp" // Para RenderInfo
#include "core/rendering/screen.hpp" // Para Screen
#include "core/rendering/screenshot.hpp" // Para Screenshot
#ifdef _DEBUG
#include "core/system/debug.hpp" // Para Debug (persistencia de render_info en debug.yaml)
#endif
@@ -124,6 +125,17 @@ namespace GlobalInputs {
Notifier::get()->show({Locale::get()->get("ui.palette") + " " + toUpper(Screen::get()->getPalettePrettyName())});
}
void handleScreenshot() {
std::vector<Uint32> buffer;
int width = 0;
int height = 0;
Screen::get()->captureComposite(buffer, width, height);
std::string filename = Screenshot::save(buffer.data(), width, height);
if (!filename.empty()) {
Notifier::get()->show({filename});
}
}
void handleNextPaletteSortMode() {
Screen::get()->nextPaletteSortMode();
Notifier::get()->show({Locale::get()->get("ui.palette_sort") + " " + toUpper(Screen::get()->getPaletteSortModeName())});
@@ -194,6 +206,10 @@ namespace GlobalInputs {
if (Input::get()->checkAction(InputAction::TOGGLE_CONSOLE, Input::DO_NOT_ALLOW_REPEAT)) {
return InputAction::TOGGLE_CONSOLE;
}
if (Input::get()->checkAction(InputAction::SCREENSHOT, Input::DO_NOT_ALLOW_REPEAT) &&
((SDL_GetModState() & SDL_KMOD_CTRL) != 0U)) {
return InputAction::SCREENSHOT;
}
return InputAction::NONE;
}
@@ -294,6 +310,10 @@ namespace GlobalInputs {
if (Console::get() != nullptr) { Console::get()->toggle(); }
break;
case InputAction::SCREENSHOT:
handleScreenshot();
break;
case InputAction::TOGGLE_INFO:
if (RenderInfo::get() != nullptr) {
// Leemos la intención antes del toggle: isActive() incluye la

View File

@@ -53,7 +53,8 @@ Input::Input(std::string game_controller_db_path)
{Action::TOGGLE_VSYNC, KeyState{.scancode = SDL_SCANCODE_F10}},
{Action::PAUSE, KeyState{.scancode = SDL_SCANCODE_F11}},
{Action::TOGGLE_INFO, KeyState{.scancode = SDL_SCANCODE_F12}},
{Action::TOGGLE_CONSOLE, KeyState{.scancode = SDL_SCANCODE_GRAVE}}};
{Action::TOGGLE_CONSOLE, KeyState{.scancode = SDL_SCANCODE_GRAVE}},
{Action::SCREENSHOT, KeyState{.scancode = SDL_SCANCODE_S}}};
initSDLGamePad(); // Inicializa el subsistema SDL_INIT_GAMEPAD
}

View File

@@ -25,6 +25,7 @@ const std::unordered_map<InputAction, std::string> ACTION_TO_STRING = {
{InputAction::TOGGLE_SHADER, "TOGGLE_POSTFX"},
{InputAction::NEXT_SHADER_PRESET, "NEXT_POSTFX_PRESET"},
{InputAction::TOGGLE_INFO, "TOGGLE_DEBUG"},
{InputAction::SCREENSHOT, "SCREENSHOT"},
{InputAction::NONE, "NONE"}};
const std::unordered_map<std::string, InputAction> STRING_TO_ACTION = {
@@ -49,6 +50,7 @@ const std::unordered_map<std::string, InputAction> STRING_TO_ACTION = {
{"TOGGLE_POSTFX", InputAction::TOGGLE_SHADER},
{"NEXT_POSTFX_PRESET", InputAction::NEXT_SHADER_PRESET},
{"TOGGLE_DEBUG", InputAction::TOGGLE_INFO},
{"SCREENSHOT", InputAction::SCREENSHOT},
{"NONE", InputAction::NONE}};
const std::unordered_map<SDL_GamepadButton, std::string> BUTTON_TO_STRING = {

View File

@@ -36,6 +36,7 @@ enum class InputAction : std::uint8_t { // Acciones de entrada posibles en el j
NEXT_PALETTE_SORT,
TOGGLE_INFO,
TOGGLE_CONSOLE,
SCREENSHOT,
// Input obligatorio
NONE,

View File

@@ -221,6 +221,40 @@ void Screen::setBorderColor(Uint8 color) {
border_argb_color_ = border_pixel_buffer_[0];
}
// Captura el contenido actual (borde + juego si el borde está activo, solo juego si no)
void Screen::captureComposite(std::vector<Uint32>& buffer, int& out_width, int& out_height) const {
const int GAME_W = static_cast<int>(game_surface_->getWidth());
const int GAME_H = static_cast<int>(game_surface_->getHeight());
if (Options::video.border.enabled) {
const int BORDER_W = static_cast<int>(border_surface_->getWidth());
const int BORDER_H = static_cast<int>(border_surface_->getHeight());
const int OFF_X = Options::video.border.width;
const int OFF_Y = Options::video.border.height;
buffer.resize(static_cast<size_t>(BORDER_W) * BORDER_H);
border_surface_->toARGBBuffer(buffer.data());
std::vector<Uint32> game_buf(static_cast<size_t>(GAME_W) * GAME_H);
game_surface_->toARGBBuffer(game_buf.data());
for (int y = 0; y < GAME_H; ++y) {
std::memcpy(
&buffer[(static_cast<size_t>(OFF_Y + y) * BORDER_W) + OFF_X],
&game_buf[static_cast<size_t>(y) * GAME_W],
static_cast<size_t>(GAME_W) * sizeof(Uint32));
}
out_width = BORDER_W;
out_height = BORDER_H;
} else {
buffer.resize(static_cast<size_t>(GAME_W) * GAME_H);
game_surface_->toARGBBuffer(buffer.data());
out_width = GAME_W;
out_height = GAME_H;
}
}
// Cambia entre borde visible y no visible
void Screen::toggleBorder() {
Options::video.border.enabled = !Options::video.border.enabled;

View File

@@ -82,6 +82,9 @@ class Screen {
void setNotificationsEnabled(bool value); // Establece la visibilidad de las notificaciones
void updateZoomFactor(); // Recalcula y almacena el factor de zoom real
// Captura el contenido actual (borde + juego si el borde está activo, solo juego si no)
void captureComposite(std::vector<Uint32>& buffer, int& out_width, int& out_height) const;
// Getters
auto getRenderer() -> SDL_Renderer*;
auto getRendererSurface() -> std::shared_ptr<Surface>;

View File

@@ -0,0 +1,70 @@
#include "core/rendering/screenshot.hpp"
#include <SDL3/SDL.h>
#include <chrono> // Para system_clock, time_point
#include <ctime> // Para localtime, strftime, time_t, tm
#include <filesystem> // Para create_directories
#include <string> // Para string
#include <vector> // Para vector
#define STB_IMAGE_WRITE_IMPLEMENTATION
#include "external/stb_image_write.h" // Para stbi_write_png
#include "core/rendering/surface.hpp" // Para Surface
namespace Screenshot {
namespace {
// Genera la ruta del fichero y crea la carpeta si no existe
auto generateFilePath(std::string& filename) -> std::string {
std::filesystem::create_directories("screenshots");
auto now = std::chrono::system_clock::now();
std::time_t time = std::chrono::system_clock::to_time_t(now);
std::tm* tm = std::localtime(&time);
char timestamp[20];
std::strftime(timestamp, sizeof(timestamp), "%Y%m%d_%H%M%S", tm);
filename = std::string("scr_") + timestamp + ".png";
return "screenshots/" + filename;
}
// Convierte ARGB8888 a RGBA8888 in-place y guarda como PNG
auto writePng(Uint32* buffer, int width, int height, const std::string& filepath) -> bool {
for (int i = 0; i < width * height; ++i) {
Uint32 p = buffer[i];
Uint32 a = (p >> 24) & 0xFF;
Uint32 r = (p >> 16) & 0xFF;
Uint32 g = (p >> 8) & 0xFF;
Uint32 b = p & 0xFF;
buffer[i] = r | (g << 8) | (b << 16) | (a << 24);
}
return stbi_write_png(filepath.c_str(), width, height, 4, buffer, width * 4) != 0;
}
} // namespace
auto save(const Surface& surface) -> std::string {
int width = static_cast<int>(surface.getWidth());
int height = static_cast<int>(surface.getHeight());
std::vector<Uint32> buffer(static_cast<size_t>(width * height));
surface.toARGBBuffer(buffer.data());
std::string filename;
std::string filepath = generateFilePath(filename);
return writePng(buffer.data(), width, height, filepath) ? filename : "";
}
auto save(const Uint32* buffer, int width, int height) -> std::string {
// Copia local para la conversión ARGB → RGBA
std::vector<Uint32> copy(buffer, buffer + static_cast<size_t>(width * height));
std::string filename;
std::string filepath = generateFilePath(filename);
return writePng(copy.data(), width, height, filepath) ? filename : "";
}
} // namespace Screenshot

View File

@@ -0,0 +1,15 @@
#pragma once
#include <SDL3/SDL.h>
#include <string> // Para string
class Surface;
namespace Screenshot {
// Guarda la surface como PNG en screenshots/. Retorna el nombre del fichero o "" si falla.
auto save(const Surface& surface) -> std::string;
// Guarda un buffer ARGB8888 como PNG en screenshots/.
auto save(const Uint32* buffer, int width, int height) -> std::string;
} // namespace Screenshot

View File

@@ -139,6 +139,7 @@ class Surface {
// Paleta
void setPalette(const std::array<Uint32, 256>& palette) { palette_ = palette; }
[[nodiscard]] auto getPalette() const -> const Palette& { return palette_; }
[[nodiscard]] auto getPaletteColor(Uint8 index) const -> Uint32 { return palette_[index]; }
// Inicializa la sub paleta