feat(fonts): deinterlace GIF i font ari-w9500 per placeholders
Fix: gif.cpp no desfeia l'interlace, trinxava qualsevol GIF entrellaçat (tota la sortida de Pillow). Afegeix Defaults::UI::Font per centralitzar noms/rutes i mou data/font → data/fonts. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
1 parent
03f1c5f926
commit
eb07e7e564
18 files changed
+859
-14
No files matched your search
@@ -198,10 +198,33 @@ namespace GIF {
|
||||
readBytes(buffer, &lzw_code_size, sizeof(uint8_t));
|
||||
|
||||
std::vector<uint8_t> compressed_data = readSubBlocks(buffer);
|
||||
int uncompressed_data_length = image_descriptor.image_width * image_descriptor.image_height;
|
||||
std::vector<uint8_t> uncompressed_data(uncompressed_data_length);
|
||||
const int IMG_W = image_descriptor.image_width;
|
||||
const int IMG_H = image_descriptor.image_height;
|
||||
std::vector<uint8_t> uncompressed_data(static_cast<std::size_t>(IMG_W) * IMG_H);
|
||||
|
||||
decompress(lzw_code_size, compressed_data.data(), static_cast<int>(compressed_data.size()), uncompressed_data.data());
|
||||
|
||||
// Interlaced GIF (flag 0x40 al byte de fields): les files no arriben
|
||||
// en ordre lineal, sinó en 4 passades (8:0, 8:4, 4:2, 2:1). Reordena
|
||||
// al buffer lineal que espera Surface. Sense aquest pas, les fuentes
|
||||
// i qualsevol GIF entrellaçat es veien completament trinxats.
|
||||
constexpr uint8_t INTERLACE_FLAG = 0x40;
|
||||
if ((image_descriptor.fields & INTERLACE_FLAG) != 0) {
|
||||
constexpr int PASS_START[4] = {0, 4, 2, 1};
|
||||
constexpr int PASS_STEP[4] = {8, 8, 4, 2};
|
||||
std::vector<uint8_t> deinterlaced(static_cast<std::size_t>(IMG_W) * IMG_H);
|
||||
int src_row = 0;
|
||||
for (int pass = 0; pass < 4; ++pass) {
|
||||
for (int dst_row = PASS_START[pass]; dst_row < IMG_H; dst_row += PASS_STEP[pass]) {
|
||||
std::memcpy(deinterlaced.data() + (static_cast<std::size_t>(dst_row) * IMG_W),
|
||||
uncompressed_data.data() + (static_cast<std::size_t>(src_row) * IMG_W),
|
||||
IMG_W);
|
||||
++src_row;
|
||||
}
|
||||
}
|
||||
return deinterlaced;
|
||||
}
|
||||
|
||||
return uncompressed_data;
|
||||
}
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#include <filesystem>
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
#include "core/audio/audio.hpp"
|
||||
@@ -80,11 +81,16 @@ Director::Director() {
|
||||
// Hotkeys globals. GlobalInputs::update() les consumirà a cada frame.
|
||||
KeyConfig::get().load("data/input/keys.yaml");
|
||||
|
||||
// Recursos compartits d'UI (paleta + font). Es carreguen abans que els
|
||||
// overlays perquè tots els reaprofiten sense duplicar la lògica.
|
||||
// Recursos compartits d'UI (paleta + fonts). Es carreguen abans que els
|
||||
// overlays perquè tots els reaprofiten sense duplicar la lògica. Els
|
||||
// noms de font viuen a Defaults::UI::Font (un únic lloc per canviar-los).
|
||||
Resource::Cache::get().loadPalette("ui", "data/palettes/sega-cube.pal");
|
||||
Resource::Cache::get().loadSurface("8bithud.gif", "data/font/8bithud.gif");
|
||||
Resource::Cache::get().getSurface("8bithud.gif")->setPalette(Resource::Cache::get().getPalette("ui"));
|
||||
const std::string HUD_FONT_GIF_KEY = std::string(Defaults::UI::Font::HUD_NAME) + ".gif";
|
||||
Resource::Cache::get().loadSurface(HUD_FONT_GIF_KEY, Defaults::UI::Font::HUD_GIF);
|
||||
Resource::Cache::get().getSurface(HUD_FONT_GIF_KEY)->setPalette(Resource::Cache::get().getPalette("ui"));
|
||||
const std::string PLACEHOLDER_FONT_GIF_KEY = std::string(Defaults::UI::Font::PLACEHOLDER_NAME) + ".gif";
|
||||
Resource::Cache::get().loadSurface(PLACEHOLDER_FONT_GIF_KEY, Defaults::UI::Font::PLACEHOLDER_GIF);
|
||||
Resource::Cache::get().getSurface(PLACEHOLDER_FONT_GIF_KEY)->setPalette(Resource::Cache::get().getPalette("ui"));
|
||||
|
||||
// Música de la piràmide 1 (primer i únic track de moment). Carreguem ací
|
||||
// perquè forma part del preload d'assets, com la font i la paleta.
|
||||
@@ -98,13 +104,19 @@ Director::Director() {
|
||||
// Font compartida pels overlays: construïm una sola instància de Text
|
||||
// i la injectem als consumidors (Notifier, RenderInfo) per a que cap
|
||||
// d'ells hagi de conèixer els noms dels recursos concrets.
|
||||
auto hud_font_surface = Resource::Cache::get().getSurface("8bithud.gif");
|
||||
auto hud_text = std::make_shared<Text>(hud_font_surface, "data/font/8bithud.fnt");
|
||||
auto hud_font_surface = Resource::Cache::get().getSurface(HUD_FONT_GIF_KEY);
|
||||
auto hud_text = std::make_shared<Text>(hud_font_surface, Defaults::UI::Font::HUD_FNT);
|
||||
const auto& ui_palette = Resource::Cache::get().getPalette("ui");
|
||||
|
||||
RenderInfo::get().init(Options::buildRenderInfoFrame(UiColor::RENDER_INFO_TEXT, UiColor::RENDER_INFO_SHADOW), hud_text);
|
||||
Notifier::get().init(hud_text, ui_palette);
|
||||
|
||||
// Font dels placeholders (LOGO / TITLE / INTRO). És una font distinta a
|
||||
// la de HUD perquè els placeholders desapareixeran amb les seues escenes
|
||||
// finals; mentrestant tenen estètica pròpia.
|
||||
auto placeholder_font_surface = Resource::Cache::get().getSurface(PLACEHOLDER_FONT_GIF_KEY);
|
||||
auto placeholder_text = std::make_shared<Text>(placeholder_font_surface, Defaults::UI::Font::PLACEHOLDER_FNT);
|
||||
|
||||
// Flux d'escenes LOGO → TITLE → INTRO → GAME. Cada placeholder rep una
|
||||
// factory que construeix la següent, construïda bottom-up des de GAME.
|
||||
//
|
||||
@@ -123,16 +135,16 @@ Director::Director() {
|
||||
std::cout << "Director: start_scene=" << DebugConfig::toString(START) << '\n';
|
||||
|
||||
auto make_game = []() -> std::unique_ptr<Scene> { return std::make_unique<GameScene>(); };
|
||||
auto make_intro = [hud_text, make_game]() -> std::unique_ptr<Scene> {
|
||||
return std::make_unique<IntroScene>(hud_text, make_game);
|
||||
auto make_intro = [placeholder_text, make_game]() -> std::unique_ptr<Scene> {
|
||||
return std::make_unique<IntroScene>(placeholder_text, make_game);
|
||||
};
|
||||
auto make_title = [hud_text, make_intro]() -> std::unique_ptr<Scene> {
|
||||
return std::make_unique<TitleScene>(hud_text, make_intro);
|
||||
auto make_title = [placeholder_text, make_intro]() -> std::unique_ptr<Scene> {
|
||||
return std::make_unique<TitleScene>(placeholder_text, make_intro);
|
||||
};
|
||||
|
||||
switch (START) {
|
||||
case DebugConfig::StartScene::LOGO:
|
||||
current_scene_ = std::make_unique<LogoScene>(hud_text, make_title);
|
||||
current_scene_ = std::make_unique<LogoScene>(placeholder_text, make_title);
|
||||
break;
|
||||
case DebugConfig::StartScene::TITLE:
|
||||
current_scene_ = make_title();
|
||||
|
||||
@@ -90,6 +90,24 @@ namespace Defaults {
|
||||
// pel codi. Si algun dia es volen temes múltiples, es pot moure a YAML
|
||||
// sense més impacte que dos accessors extra.
|
||||
namespace UI {
|
||||
// Fonts d'UI centralitzades: un únic lloc per conèixer la carpeta
|
||||
// (data/fonts/), el nom-clau al Resource::Cache i els fitxers .gif /
|
||||
// .fnt de cada font. Afegir-ne una nova és una constant ací i ja.
|
||||
namespace Font {
|
||||
constexpr const char* DIR = "data/fonts/";
|
||||
|
||||
// HUD/Notifier/RenderInfo: font principal de UI del joc.
|
||||
constexpr const char* HUD_NAME = "8bithud";
|
||||
constexpr const char* HUD_GIF = "data/fonts/8bithud.gif";
|
||||
constexpr const char* HUD_FNT = "data/fonts/8bithud.fnt";
|
||||
|
||||
// Placeholders (LOGO / TITLE / INTRO): font temporal fins que els
|
||||
// placeholders es substitueixin per les seues escenes finals.
|
||||
constexpr const char* PLACEHOLDER_NAME = "ari-w9500";
|
||||
constexpr const char* PLACEHOLDER_GIF = "data/fonts/ari-w9500.gif";
|
||||
constexpr const char* PLACEHOLDER_FNT = "data/fonts/ari-w9500.fnt";
|
||||
} // namespace Font
|
||||
|
||||
// Overlay de RenderInfo (F12).
|
||||
constexpr Uint8 RENDER_INFO_TEXT = 47;
|
||||
constexpr Uint8 RENDER_INFO_SHADOW = 34;
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
namespace Texts {
|
||||
constexpr const char* WINDOW_TITLE = "© 2026 Aventures en Egipte — JailDesigner";
|
||||
constexpr const char* COPYRIGHT = "© 2026 JailDesigner";
|
||||
constexpr const char* VERSION = "0.18.0"; // Single source of truth — Makefile el grep
|
||||
constexpr const char* VERSION = "0.19.0"; // Single source of truth — Makefile el grep
|
||||
} // namespace Texts
|
||||
|
||||
namespace GameCanvas {
|
||||
|
||||
Reference in new issue
Block a user