From abf12632bbc1e310753591289927180e940f9ae2 Mon Sep 17 00:00:00 2001 From: Dav999 Date: Thu, 7 Dec 2023 18:02:43 +0100 Subject: [PATCH] Load plain font.png beyond U+007F VVVVVV 2.2 only supported displaying characters 00-7F with its font system. VVVVVV 2.3 added support for unicode, by supplying a font.txt with all the characters that are in the font image. But 2.3 made another change that I didn't immediately realize, even after reading the code: if font.txt is not present, then the font is not assumed to have _only_ 00-7F, but _all_ of unicode, as far as the image dimensions allow. However, an inconsistency I _did_ notice is how unknown characters would be rendered in 2.3. If a font had a font.txt, then any unknown characters would be shown as a '?'. If a font had no font.txt however, then suddenly any unknown characters would just come out as a space. I fixed this behavior with the new font system; but what was actually happening for characters to come out blank is that characters up to U+00FF, which _were_ technically in the font image but as fully transparent, would be shown as they were in the image, and characters beyond U+00FF wouldn't be shown since they were outside of the image. I don't really want to show blank characters for any character between 80-FF if it is technically inside the image, because pretty much every single ASCII-only font.png in existence (including the one in data.zip) contains a blank lower half, just because the font in the game had always had this specific resolution. (We didn't want to do things that might crash the game because something was different from what it expected...) We have had some confusing occasions before with the old behavior where the fonts weren't correctly packaged or something (like when the Catalan translator was sent the first version of the translator pack, or when people customize their fonts wrong) and special characters were just blank spaces. So, instead, for characters beyond 7F, I decided to consider them part of the font, as long as they are not blank. That means, if a character beyond the ASCII range has any (non-alpha-0) pixels, then it will be added, otherwise it won't be. This is just to handle legacy fonts, and the case where all fonts are missing and the one from data.zip is used; new fonts should just use .fontmeta or .txt to define their characters. --- desktop_version/src/Font.cpp | 45 +++++++++++++++++++++++++++++++++--- 1 file changed, 42 insertions(+), 3 deletions(-) diff --git a/desktop_version/src/Font.cpp b/desktop_version/src/Font.cpp index 57170aed..bd919795 100644 --- a/desktop_version/src/Font.cpp +++ b/desktop_version/src/Font.cpp @@ -21,6 +21,7 @@ extern "C" // Sigh... This is the second forward-declaration, we need to put this in a header file SDL_Texture* LoadImage(const char *filename, TextureLoadType loadtype); +SDL_Surface* LoadImageSurface(const char* filename); namespace font { @@ -396,10 +397,48 @@ static uint8_t load_font(FontContainer* container, const char* name) if (!charset_loaded) { /* If we don't have font.txt and no tag either, - * this font is 2.2-and-below-style plain ASCII. */ - for (uint32_t codepoint = 0x00; codepoint < 0x80; codepoint++) + * this font is 2.2-and-below-style plain ASCII. + * Or well... 2.3 interpreted these as + * "all unicode from 0 to however much is in the image"... */ + + SDL_Surface* temp_surface = LoadImageSurface(name_png); + if (temp_surface != NULL) { - add_glyphinfo(f, codepoint, codepoint); + const uint32_t chars_per_line = temp_surface->w / f->glyph_w; + const uint32_t max_codepoint = (temp_surface->h / f->glyph_h) * chars_per_line; + + for (uint32_t codepoint = 0x00; codepoint <= max_codepoint; codepoint++) + { + if (codepoint > 0x7F) + { + /* Only include characters with actual pixels... + * If the font.png is too big (normally it is) we _want_ question marks. */ + const int glyph_x = (codepoint % chars_per_line) * f->glyph_w; + const int glyph_y = (codepoint / chars_per_line) * f->glyph_h; + + bool found_pixel = false; + for (int pixel_y = 0; pixel_y < f->glyph_h; pixel_y++) + { + for (int pixel_x = 0; pixel_x < f->glyph_w; pixel_x++) + { + if (ReadPixel(temp_surface, glyph_x+pixel_x, glyph_y+pixel_y).a > 0) + { + found_pixel = true; + goto no_more_pixels; + } + } + } + no_more_pixels: + if (!found_pixel) + { + // Do not add it + continue; + } + } + add_glyphinfo(f, codepoint, codepoint); + } + + VVV_freefunc(SDL_FreeSurface, temp_surface); } }