Presets PostFX carregats de shaders/postfx.yaml; Screen aplica params (v0.5.0)
This commit is contained in:
1 parent
6c8ef9ff44
commit
26b4d9e610
7 files changed
+194
-4
No files matched your search
@@ -136,6 +136,12 @@ void Screen::createSdl() {
|
|||||||
SDL_SetTextureScaleMode(game_texture_, toSdlScaleMode(config_.texture_filter));
|
SDL_SetTextureScaleMode(game_texture_, toSdlScaleMode(config_.texture_filter));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Screen::applyPostFXParams(const Rendering::PostFXParams& params) {
|
||||||
|
if (shader_backend_ != nullptr) {
|
||||||
|
shader_backend_->setPostFXParams(params);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void Screen::clear(std::uint8_t r, std::uint8_t g, std::uint8_t b) {
|
void Screen::clear(std::uint8_t r, std::uint8_t g, std::uint8_t b) {
|
||||||
const std::uint32_t COLOR = (0xFFU << 24) | (static_cast<std::uint32_t>(r) << 16) | (static_cast<std::uint32_t>(g) << 8) | static_cast<std::uint32_t>(b);
|
const std::uint32_t COLOR = (0xFFU << 24) | (static_cast<std::uint32_t>(r) << 16) | (static_cast<std::uint32_t>(g) << 8) | static_cast<std::uint32_t>(b);
|
||||||
std::ranges::fill(canvas_, COLOR);
|
std::ranges::fill(canvas_, COLOR);
|
||||||
|
|||||||
@@ -44,6 +44,10 @@ class Screen {
|
|||||||
// i tanca el subsistema de vídeo. El Director el crida ABANS de SDL_Quit.
|
// i tanca el subsistema de vídeo. El Director el crida ABANS de SDL_Quit.
|
||||||
void shutdown();
|
void shutdown();
|
||||||
|
|
||||||
|
// Reenvia paràmetres PostFX al backend GPU. No-op si estem al path
|
||||||
|
// SDL_Renderer (fallback) o si encara no hi ha backend.
|
||||||
|
void applyPostFXParams(const Rendering::PostFXParams& params);
|
||||||
|
|
||||||
void clear(std::uint8_t r = 0, std::uint8_t g = 0, std::uint8_t b = 0);
|
void clear(std::uint8_t r = 0, std::uint8_t g = 0, std::uint8_t b = 0);
|
||||||
void present();
|
void present();
|
||||||
|
|
||||||
|
|||||||
@@ -16,6 +16,7 @@
|
|||||||
#include "core/system/event_buffer.hpp"
|
#include "core/system/event_buffer.hpp"
|
||||||
#include "game/options.hpp"
|
#include "game/options.hpp"
|
||||||
#include "game/scenes/game_scene.hpp"
|
#include "game/scenes/game_scene.hpp"
|
||||||
|
#include "utils/defaults.hpp"
|
||||||
|
|
||||||
Director::Director() {
|
Director::Director() {
|
||||||
if (!SDL_Init(0)) {
|
if (!SDL_Init(0)) {
|
||||||
@@ -30,9 +31,17 @@ Director::Director() {
|
|||||||
std::cerr << "Director: no s'ha pogut carregar ni desar config.yaml a " << system_folder_ << '\n';
|
std::cerr << "Director: no s'ha pogut carregar ni desar config.yaml a " << system_folder_ << '\n';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Carrega els presets de PostFX des de shaders/postfx.yaml; si no existeix
|
||||||
|
// es crea amb presets per defecte (off, crt, ntsc).
|
||||||
|
Options::setPostFXFile(system_folder_ + Defaults::Video::POSTFX_FILE);
|
||||||
|
if (!Options::loadPostFXFromFile()) {
|
||||||
|
std::cerr << "Director: no s'ha pogut carregar ni desar postfx.yaml.\n";
|
||||||
|
}
|
||||||
|
|
||||||
// Screen es configura ara (subsystem + finestra + GPU/renderer); la seua
|
// Screen es configura ara (subsystem + finestra + GPU/renderer); la seua
|
||||||
// destrucció la fa aquest Director (veure ~Director). Res de static dtor.
|
// destrucció la fa aquest Director (veure ~Director). Res de static dtor.
|
||||||
Screen::get().configure(Options::buildScreenConfig());
|
Screen::get().configure(Options::buildScreenConfig());
|
||||||
|
Screen::get().applyPostFXParams(Options::buildPostFXParams());
|
||||||
(void)Resource::Cache::get();
|
(void)Resource::Cache::get();
|
||||||
|
|
||||||
current_scene_ = std::make_unique<GameScene>();
|
current_scene_ = std::make_unique<GameScene>();
|
||||||
@@ -65,6 +74,8 @@ void Director::createSystemFolder() {
|
|||||||
|
|
||||||
std::error_code error;
|
std::error_code error;
|
||||||
std::filesystem::create_directories(system_folder_, error);
|
std::filesystem::create_directories(system_folder_, error);
|
||||||
|
// Subcarpeta per als presets de shaders. std::filesystem és tolerant si ja existeix.
|
||||||
|
std::filesystem::create_directories(system_folder_ + "shaders/", error);
|
||||||
if (error) {
|
if (error) {
|
||||||
std::cerr << "Director: no s'ha pogut crear " << system_folder_ << ": " << error.message() << '\n';
|
std::cerr << "Director: no s'ha pogut crear " << system_folder_ << ": " << error.message() << '\n';
|
||||||
}
|
}
|
||||||
|
|||||||
+139
-1
@@ -1,5 +1,6 @@
|
|||||||
#include "game/options.hpp"
|
#include "game/options.hpp"
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
@@ -71,6 +72,15 @@ namespace {
|
|||||||
if (node.contains("preferred_driver")) { Options::video.gpu.preferred_driver = node["preferred_driver"].get_value<std::string>(); }
|
if (node.contains("preferred_driver")) { Options::video.gpu.preferred_driver = node["preferred_driver"].get_value<std::string>(); }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void parseShader(const fkyaml::node& video_node) {
|
||||||
|
if (!video_node.contains("shader")) { return; }
|
||||||
|
const auto& node = video_node["shader"];
|
||||||
|
if (node.contains("enabled")) { Options::video.shader.enabled = node["enabled"].get_value<bool>(); }
|
||||||
|
if (node.contains("current_postfx_preset")) {
|
||||||
|
Options::video.shader.current_postfx_preset = node["current_postfx_preset"].get_value<std::string>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void parseVideo(const fkyaml::node& yaml) {
|
void parseVideo(const fkyaml::node& yaml) {
|
||||||
if (!yaml.contains("video")) { return; }
|
if (!yaml.contains("video")) { return; }
|
||||||
const auto& node = yaml["video"];
|
const auto& node = yaml["video"];
|
||||||
@@ -82,6 +92,7 @@ namespace {
|
|||||||
Options::video.texture_filter = filterFromString(node["texture_filter"].get_value<std::string>());
|
Options::video.texture_filter = filterFromString(node["texture_filter"].get_value<std::string>());
|
||||||
}
|
}
|
||||||
parseGpu(node);
|
parseGpu(node);
|
||||||
|
parseShader(node);
|
||||||
}
|
}
|
||||||
|
|
||||||
void parseMusic(const fkyaml::node& audio_node) {
|
void parseMusic(const fkyaml::node& audio_node) {
|
||||||
@@ -107,6 +118,55 @@ namespace {
|
|||||||
parseSound(node);
|
parseSound(node);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Presets per defecte de PostFX, usats quan el fitxer postfx.yaml no existeix.
|
||||||
|
auto defaultPostFXPresets() -> std::vector<Options::PostFXPreset> {
|
||||||
|
return {
|
||||||
|
{.name = "off"}, // passthrough (tot a 0)
|
||||||
|
{.name = "crt",
|
||||||
|
.vignette = 0.6F,
|
||||||
|
.scanlines = 0.7F,
|
||||||
|
.chroma = 0.15F,
|
||||||
|
.mask = 0.6F,
|
||||||
|
.gamma = 0.8F,
|
||||||
|
.curvature = 0.0F,
|
||||||
|
.bleeding = 0.0F,
|
||||||
|
.flicker = 0.0F},
|
||||||
|
{.name = "ntsc",
|
||||||
|
.vignette = 0.4F,
|
||||||
|
.scanlines = 0.5F,
|
||||||
|
.chroma = 0.25F,
|
||||||
|
.mask = 0.3F,
|
||||||
|
.gamma = 0.6F,
|
||||||
|
.curvature = 0.0F,
|
||||||
|
.bleeding = 0.4F,
|
||||||
|
.flicker = 0.1F},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
void parsePostFXPreset(const fkyaml::node& node, Options::PostFXPreset& preset) {
|
||||||
|
if (node.contains("name")) { preset.name = node["name"].get_value<std::string>(); }
|
||||||
|
if (node.contains("vignette")) { preset.vignette = node["vignette"].get_value<float>(); }
|
||||||
|
if (node.contains("scanlines")) { preset.scanlines = node["scanlines"].get_value<float>(); }
|
||||||
|
if (node.contains("chroma")) { preset.chroma = node["chroma"].get_value<float>(); }
|
||||||
|
if (node.contains("mask")) { preset.mask = node["mask"].get_value<float>(); }
|
||||||
|
if (node.contains("gamma")) { preset.gamma = node["gamma"].get_value<float>(); }
|
||||||
|
if (node.contains("curvature")) { preset.curvature = node["curvature"].get_value<float>(); }
|
||||||
|
if (node.contains("bleeding")) { preset.bleeding = node["bleeding"].get_value<float>(); }
|
||||||
|
if (node.contains("flicker")) { preset.flicker = node["flicker"].get_value<float>(); }
|
||||||
|
}
|
||||||
|
|
||||||
|
void writePostFXPreset(std::ostringstream& out, const Options::PostFXPreset& preset) {
|
||||||
|
out << " - name: \"" << preset.name << "\"\n";
|
||||||
|
out << " vignette: " << preset.vignette << "\n";
|
||||||
|
out << " scanlines: " << preset.scanlines << "\n";
|
||||||
|
out << " chroma: " << preset.chroma << "\n";
|
||||||
|
out << " mask: " << preset.mask << "\n";
|
||||||
|
out << " gamma: " << preset.gamma << "\n";
|
||||||
|
out << " curvature: " << preset.curvature << "\n";
|
||||||
|
out << " bleeding: " << preset.bleeding << "\n";
|
||||||
|
out << " flicker: " << preset.flicker << "\n";
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
namespace Options {
|
namespace Options {
|
||||||
@@ -166,7 +226,10 @@ namespace Options {
|
|||||||
out << " texture_filter: \"" << filterToString(video.texture_filter) << "\"\n";
|
out << " texture_filter: \"" << filterToString(video.texture_filter) << "\"\n";
|
||||||
out << " gpu:\n";
|
out << " gpu:\n";
|
||||||
out << " acceleration: " << (video.gpu.acceleration ? "true" : "false") << "\n";
|
out << " acceleration: " << (video.gpu.acceleration ? "true" : "false") << "\n";
|
||||||
out << " preferred_driver: \"" << video.gpu.preferred_driver << "\"\n\n";
|
out << " preferred_driver: \"" << video.gpu.preferred_driver << "\"\n";
|
||||||
|
out << " shader:\n";
|
||||||
|
out << " enabled: " << (video.shader.enabled ? "true" : "false") << "\n";
|
||||||
|
out << " current_postfx_preset: \"" << video.shader.current_postfx_preset << "\"\n\n";
|
||||||
|
|
||||||
out << "audio:\n";
|
out << "audio:\n";
|
||||||
out << " enabled: " << (audio.enabled ? "true" : "false") << "\n";
|
out << " enabled: " << (audio.enabled ? "true" : "false") << "\n";
|
||||||
@@ -193,4 +256,79 @@ namespace Options {
|
|||||||
return config;
|
return config;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void setPostFXFile(const std::string& path) {
|
||||||
|
postfx_file_path = path;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto loadPostFXFromFile() -> bool {
|
||||||
|
if (postfx_file_path.empty()) { return false; }
|
||||||
|
|
||||||
|
const std::string CONTENT = readFileOrEmpty(postfx_file_path);
|
||||||
|
if (CONTENT.empty()) {
|
||||||
|
postfx_presets = defaultPostFXPresets();
|
||||||
|
return savePostFXToFile();
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
auto yaml = fkyaml::node::deserialize(CONTENT);
|
||||||
|
if (!yaml.contains("presets") || !yaml["presets"].is_sequence()) {
|
||||||
|
postfx_presets = defaultPostFXPresets();
|
||||||
|
return savePostFXToFile();
|
||||||
|
}
|
||||||
|
|
||||||
|
postfx_presets.clear();
|
||||||
|
for (const auto& preset_node : yaml["presets"]) {
|
||||||
|
PostFXPreset preset;
|
||||||
|
parsePostFXPreset(preset_node, preset);
|
||||||
|
postfx_presets.push_back(preset);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (postfx_presets.empty()) {
|
||||||
|
postfx_presets = defaultPostFXPresets();
|
||||||
|
return savePostFXToFile();
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
} catch (const std::exception& e) {
|
||||||
|
std::cerr << "Options: error parsejant postfx.yaml: " << e.what() << '\n';
|
||||||
|
std::cerr << "Options: reescrivint el fitxer amb presets per defecte.\n";
|
||||||
|
postfx_presets = defaultPostFXPresets();
|
||||||
|
return savePostFXToFile();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
auto savePostFXToFile() -> bool {
|
||||||
|
if (postfx_file_path.empty()) { return false; }
|
||||||
|
|
||||||
|
std::ostringstream out;
|
||||||
|
out << "# Presets PostFX per a AEE 2026. Editable a mà.\n";
|
||||||
|
out << "# Els noms han de coincidir amb config.yaml > video.shader.current_postfx_preset.\n";
|
||||||
|
out << "presets:\n";
|
||||||
|
for (const auto& preset : postfx_presets) {
|
||||||
|
writePostFXPreset(out, preset);
|
||||||
|
}
|
||||||
|
return writeFile(postfx_file_path, out.str());
|
||||||
|
}
|
||||||
|
|
||||||
|
auto buildPostFXParams() -> Rendering::PostFXParams {
|
||||||
|
// Si el shader està deshabilitat, retornem params a zero → passthrough.
|
||||||
|
if (!video.shader.enabled) { return {}; }
|
||||||
|
|
||||||
|
const auto IT = std::ranges::find_if(postfx_presets,
|
||||||
|
[](const PostFXPreset& preset) { return preset.name == video.shader.current_postfx_preset; });
|
||||||
|
if (IT == postfx_presets.end()) {
|
||||||
|
std::cerr << "Options: preset PostFX \"" << video.shader.current_postfx_preset << "\" no trobat; aplicant passthrough.\n";
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
.vignette = IT->vignette,
|
||||||
|
.scanlines = IT->scanlines,
|
||||||
|
.chroma = IT->chroma,
|
||||||
|
.mask = IT->mask,
|
||||||
|
.gamma = IT->gamma,
|
||||||
|
.curvature = IT->curvature,
|
||||||
|
.bleeding = IT->bleeding,
|
||||||
|
.flicker = IT->flicker,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace Options
|
} // namespace Options
|
||||||
@@ -1,8 +1,10 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
#include "core/rendering/screen.hpp"
|
#include "core/rendering/screen.hpp"
|
||||||
|
#include "core/rendering/shader_backend.hpp"
|
||||||
#include "utils/defaults.hpp"
|
#include "utils/defaults.hpp"
|
||||||
|
|
||||||
// Gestor de configuració del joc. És l'ÚNIC lloc que coneix YAML i la ruta
|
// Gestor de configuració del joc. És l'ÚNIC lloc que coneix YAML i la ruta
|
||||||
@@ -21,11 +23,30 @@ namespace Options {
|
|||||||
std::string preferred_driver{Defaults::Video::GPU_PREFERRED_DRIVER};
|
std::string preferred_driver{Defaults::Video::GPU_PREFERRED_DRIVER};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct Shader {
|
||||||
|
bool enabled{Defaults::Video::SHADER_ENABLED};
|
||||||
|
std::string current_postfx_preset{Defaults::Video::POSTFX_DEFAULT_PRESET};
|
||||||
|
};
|
||||||
|
|
||||||
struct Video {
|
struct Video {
|
||||||
bool vsync{Defaults::Video::VSYNC};
|
bool vsync{Defaults::Video::VSYNC};
|
||||||
Defaults::ScalingMode scaling_mode{Defaults::Video::SCALING_MODE};
|
Defaults::ScalingMode scaling_mode{Defaults::Video::SCALING_MODE};
|
||||||
Defaults::TextureFilter texture_filter{Defaults::Video::TEXTURE_FILTER};
|
Defaults::TextureFilter texture_filter{Defaults::Video::TEXTURE_FILTER};
|
||||||
Gpu gpu{};
|
Gpu gpu{};
|
||||||
|
Shader shader{};
|
||||||
|
};
|
||||||
|
|
||||||
|
// Preset d'efectes PostFX (un per entrada a postfx.yaml).
|
||||||
|
struct PostFXPreset {
|
||||||
|
std::string name;
|
||||||
|
float vignette{0.0F};
|
||||||
|
float scanlines{0.0F};
|
||||||
|
float chroma{0.0F};
|
||||||
|
float mask{0.0F};
|
||||||
|
float gamma{0.0F};
|
||||||
|
float curvature{0.0F};
|
||||||
|
float bleeding{0.0F};
|
||||||
|
float flicker{0.0F};
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Music {
|
struct Music {
|
||||||
@@ -49,16 +70,23 @@ namespace Options {
|
|||||||
// el programa sense necessitar un .cpp extra per a cada una) ---
|
// el programa sense necessitar un .cpp extra per a cada una) ---
|
||||||
inline std::string config_version{};
|
inline std::string config_version{};
|
||||||
inline std::string config_file_path{};
|
inline std::string config_file_path{};
|
||||||
|
inline std::string postfx_file_path{};
|
||||||
inline Window window{};
|
inline Window window{};
|
||||||
inline Video video{};
|
inline Video video{};
|
||||||
inline Audio audio{};
|
inline Audio audio{};
|
||||||
|
inline std::vector<PostFXPreset> postfx_presets{};
|
||||||
|
|
||||||
// --- API pública ---
|
// --- API pública ---
|
||||||
void setConfigFile(const std::string& path);
|
void setConfigFile(const std::string& path);
|
||||||
auto loadFromFile() -> bool;
|
auto loadFromFile() -> bool;
|
||||||
auto saveToFile() -> bool;
|
auto saveToFile() -> bool;
|
||||||
|
|
||||||
|
void setPostFXFile(const std::string& path);
|
||||||
|
auto loadPostFXFromFile() -> bool;
|
||||||
|
auto savePostFXToFile() -> bool;
|
||||||
|
|
||||||
// --- Builders per als subsistemes ---
|
// --- Builders per als subsistemes ---
|
||||||
[[nodiscard]] auto buildScreenConfig() -> Screen::Config;
|
[[nodiscard]] auto buildScreenConfig() -> Screen::Config;
|
||||||
|
[[nodiscard]] auto buildPostFXParams() -> Rendering::PostFXParams;
|
||||||
|
|
||||||
} // namespace Options
|
} // namespace Options
|
||||||
@@ -32,8 +32,11 @@ namespace Defaults {
|
|||||||
constexpr bool VSYNC = true;
|
constexpr bool VSYNC = true;
|
||||||
constexpr ScalingMode SCALING_MODE = ScalingMode::LETTERBOX;
|
constexpr ScalingMode SCALING_MODE = ScalingMode::LETTERBOX;
|
||||||
constexpr TextureFilter TEXTURE_FILTER = TextureFilter::NEAREST;
|
constexpr TextureFilter TEXTURE_FILTER = TextureFilter::NEAREST;
|
||||||
constexpr bool GPU_ACCELERATION = true; // Path SDL3 GPU per defecte; fallback a SDL_Renderer si falla.
|
constexpr bool GPU_ACCELERATION = true; // Path SDL3 GPU per defecte; fallback a SDL_Renderer si falla.
|
||||||
constexpr const char* GPU_PREFERRED_DRIVER = ""; // Buit = auto. Aplica a l'arrencada.
|
constexpr const char* GPU_PREFERRED_DRIVER = ""; // Buit = auto. Aplica a l'arrencada.
|
||||||
|
constexpr bool SHADER_ENABLED = true; // Aplica PostFX; si false, sempre passthrough.
|
||||||
|
constexpr const char* POSTFX_DEFAULT_PRESET = "off"; // Preset inicial a config.yaml.
|
||||||
|
constexpr const char* POSTFX_FILE = "shaders/postfx.yaml"; // Relatiu a la carpeta de sistema.
|
||||||
} // namespace Video
|
} // namespace Video
|
||||||
|
|
||||||
namespace Audio {
|
namespace Audio {
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
namespace Texts {
|
namespace Texts {
|
||||||
constexpr const char* WINDOW_TITLE = "© 2026 Aventures en Egipte — JailDesigner";
|
constexpr const char* WINDOW_TITLE = "© 2026 Aventures en Egipte — JailDesigner";
|
||||||
constexpr const char* COPYRIGHT = "© 2026 JailDesigner";
|
constexpr const char* COPYRIGHT = "© 2026 JailDesigner";
|
||||||
constexpr const char* VERSION = "0.4.0"; // Single source of truth — Makefile el grep
|
constexpr const char* VERSION = "0.5.0"; // Single source of truth — Makefile el grep
|
||||||
} // namespace Texts
|
} // namespace Texts
|
||||||
|
|
||||||
namespace GameCanvas {
|
namespace GameCanvas {
|
||||||
|
|||||||
Reference in new issue
Block a user