From 93186103f1946a866956674672a6fcbe8026440f Mon Sep 17 00:00:00 2001 From: raistlen007 Date: Sat, 10 Oct 2026 13:08:46 +0300 Subject: [PATCH] fix(frontend): anti-alias original menu fonts before atlas upload Reconstruct 4x original ABP menu glyph coverage with a Mitchell-Netravali filter rather than nearest-neighbour sampling. Keep existing glyph metrics and untouched flight/HUD font loading. Do not include artwork restoration, GPU shader experiments or CI changes. --- CMakeLists.txt | 1 + src/xwa_remaster/assets.c | 16 +++++--- src/xwa_remaster/frontend_font_aa.c | 61 +++++++++++++++++++++++++++++ src/xwa_remaster/frontend_font_aa.h | 12 ++++++ 4 files changed, 84 insertions(+), 6 deletions(-) create mode 100644 src/xwa_remaster/frontend_font_aa.c create mode 100644 src/xwa_remaster/frontend_font_aa.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 307b6939..33b6a8cc 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -260,6 +260,7 @@ add_library(xwa_remaster STATIC src/xwa_remaster/original_2d.c src/xwa_remaster/sky_stars.c src/xwa_remaster/assets.c + src/xwa_remaster/frontend_font_aa.c src/xwa_remaster/text.c ) if(XWA_ENABLE_DEBUG_UI) diff --git a/src/xwa_remaster/assets.c b/src/xwa_remaster/assets.c index 48886356..12cd486e 100644 --- a/src/xwa_remaster/assets.c +++ b/src/xwa_remaster/assets.c @@ -5,6 +5,7 @@ */ #include "xwa_remaster/assets.h" +#include "xwa_remaster/frontend_font_aa.h" #include "aeron/aeron.h" #include "aeron/image.h" @@ -908,7 +909,7 @@ static AeronFontGlyph* assets_copy_font_glyphs(const Xwa2dFontAtlas* source, int } static int assets_init_original_font(AeronCommandBuffer* cmd, - const Xwa2dFontAtlas* font, int atlas_scale, int generate_mips, + const Xwa2dFontAtlas* font, int atlas_scale, int generate_mips, int frontend_aa, const char* debug_name, AeronFontAtlas* out) { if (!cmd || !font || !out || atlas_scale <= 0 || font->cell_width <= 0 || font->cell_height <= 0 || font->baseline < 0 || @@ -918,9 +919,12 @@ static int assets_init_original_font(AeronCommandBuffer* cmd, return 0; AeronFontGlyph* glyphs = assets_copy_font_glyphs(font, atlas_scale); int atlas_width = 0, atlas_height = 0; - uint8_t* atlas_rgba = glyphs ? Aeron_ImageUpscaleNearestRgba8(font->rgba, font->width, font->height, - atlas_scale, &atlas_width, &atlas_height) - : NULL; + uint8_t* atlas_rgba = glyphs ? (frontend_aa + ? XwaFrontendFontAA_Upscale(font->rgba, font->width, font->height, + atlas_scale, &atlas_width, &atlas_height) + : Aeron_ImageUpscaleNearestRgba8(font->rgba, font->width, font->height, + atlas_scale, &atlas_width, &atlas_height)) + : NULL; const int initialized = atlas_rgba && AeronFontAtlas_InitRgba8( out, cmd, &(AeronFontAtlasRgba8Desc) { @@ -965,7 +969,7 @@ static AssetLoadStatus assets_load_original_flight_font(XwaRemasterAssets* a, Ae return ASSET_LOAD_FAILED; } Xwa2dFrameSet_Free(&group); - if (!assets_init_original_font(cmd, &font, XWA_ORIGINAL_FONT_SCALE, 1, + if (!assets_init_original_font(cmd, &font, XWA_ORIGINAL_FONT_SCALE, 1, 0, "XWA original flight font", &slot->atlas)) { Xwa2dFontAtlas_Free(&font); return ASSET_LOAD_FAILED; @@ -1068,7 +1072,7 @@ static AssetLoadStatus assets_load_original_frontend_font(XwaRemasterAssets* a, Aeron_LogWarn("xwa.remaster", "frontend font %d: original load failed: %s", font_size, error); return status; } - if (!assets_init_original_font(cmd, &font, XWA_ORIGINAL_FONT_SCALE, 0, + if (!assets_init_original_font(cmd, &font, XWA_ORIGINAL_FONT_SCALE, 0, 1, "XWA original frontend font", &slot->atlas)) { Xwa2dFontAtlas_Free(&font); return ASSET_LOAD_FAILED; diff --git a/src/xwa_remaster/frontend_font_aa.c b/src/xwa_remaster/frontend_font_aa.c new file mode 100644 index 00000000..92ce85da --- /dev/null +++ b/src/xwa_remaster/frontend_font_aa.c @@ -0,0 +1,61 @@ +#include "xwa_remaster/frontend_font_aa.h" + +#include +#include +#include +#include + +/* Mitchell-Netravali (B=C=1/3) reconstructs the 4x enlarged original glyph + * coverage without nearest-neighbour's flat pixel steps. The original ABP + * decoder packs glyphs with gutters; neighbouring shapes cannot bleed into + * one another over this 2-original-pixel support radius. */ +static float aa_kernel(float x) { + x = fabsf(x); + if (x < 1.0f) + return ((7.0f*x - 12.0f)*x*x + (16.0f / 3.0f)) / 6.0f; + if (x < 2.0f) + return (((-7.0f / 3.0f)*x + 12.0f)*x*x - 20.0f*x + (32.0f/3.0f)) / 6.0f; + return 0.0f; +} + +uint8_t* XwaFrontendFontAA_Upscale(const uint8_t* rgba, int width, int height, + int scale, int* out_width, int* out_height) { + if (!rgba || !out_width || !out_height || width < 1 || height < 1 || + scale < 1 || width > INT32_MAX / scale || height > INT32_MAX / scale) + return NULL; + const int w = width * scale, h = height * scale; + if ((size_t)w > SIZE_MAX / (size_t)h / 4u) + return NULL; + uint8_t* out = (uint8_t*)malloc((size_t)w * (size_t)h * 4u); + if (!out) return NULL; + for (int y = 0; y < h; ++y) { + const float sy = ((float)y + 0.5f) / (float)scale - 0.5f; + const int cy = (int)floorf(sy); + float wy[4]; + for (int j = 0; j < 4; ++j) + wy[j] = aa_kernel(sy - (float)(cy + j - 1)); + for (int x = 0; x < w; ++x) { + const float sx = ((float)x + 0.5f) / (float)scale - 0.5f; + const int cx = (int)floorf(sx); + float weighted_alpha = 0.0f; + for (int j = 0; j < 4; ++j) { + const int yy = cy + j - 1; + if (yy < 0 || yy >= height) continue; + for (int i = 0; i < 4; ++i) { + const int xx = cx + i - 1; + if (xx < 0 || xx >= width) continue; + weighted_alpha += wy[j] * aa_kernel(sx - (float)xx) * + (float)rgba[((size_t)yy * (size_t)width + (size_t)xx) * 4u + 3u]; + } + } + if (weighted_alpha < 0.0f) weighted_alpha = 0.0f; + if (weighted_alpha > 255.0f) weighted_alpha = 255.0f; + uint8_t* pixel = out + ((size_t)y * (size_t)w + (size_t)x) * 4u; + pixel[0] = pixel[1] = pixel[2] = 255u; + pixel[3] = (uint8_t)(weighted_alpha + 0.5f); + } + } + *out_width = w; + *out_height = h; + return out; +} diff --git a/src/xwa_remaster/frontend_font_aa.h b/src/xwa_remaster/frontend_font_aa.h new file mode 100644 index 00000000..93469e6a --- /dev/null +++ b/src/xwa_remaster/frontend_font_aa.h @@ -0,0 +1,12 @@ +#ifndef XWA_FRONTEND_FONT_AA_H +#define XWA_FRONTEND_FONT_AA_H + +#include + +/* High-quality 4x reconstruction of decoded *frontend* ABP glyph coverage. + * Returns straight-alpha white ink. The atlas loader premultiplies it once. + * Caller owns the result; flight HUD fonts never use this function. */ +uint8_t* XwaFrontendFontAA_Upscale(const uint8_t* rgba, int width, int height, + int scale, int* out_width, int* out_height); + +#endif