{"id":1064,"date":"2026-09-09T01:50:03","date_gmt":"2026-09-09T01:50:03","guid":{"rendered":"https:\/\/x.sheep-mine.ts.net\/index.php\/full-ui-upscaling-part-4-simpler-lightweight-fonts\/"},"modified":"2026-09-09T01:50:03","modified_gmt":"2026-09-09T01:50:03","slug":"full-ui-upscaling-part-4-simpler-lightweight-fonts","status":"publish","type":"post","link":"https:\/\/x.sheep-mine.ts.net\/index.php\/full-ui-upscaling-part-4-simpler-lightweight-fonts\/","title":{"rendered":"Full UI Upscaling, Part 4: Simpler Lightweight Fonts &#8211; Cogmind \/ Grid Sage Games"},"content":{"rendered":"<p><br \/>\n<\/p>\n<div>\n<p>So we\u2019ve developed <a rel=\"nofollow\" target=\"_blank\" href=\"https:\/\/www.gridsagegames.com\/blog\/2024\/01\/full-ui-upscaling-part-1-history-and-theory\/\">the theories<\/a>, we\u2019ve got <a rel=\"nofollow\" target=\"_blank\" href=\"https:\/\/www.gridsagegames.com\/blog\/2024\/01\/full-ui-upscaling-part-2-holy-mockups\/\">mockups<\/a>, we\u2019ve got the necessary <a rel=\"nofollow\" target=\"_blank\" href=\"https:\/\/www.gridsagegames.com\/blog\/2024\/01\/full-ui-upscaling-part-3-dynamic-terminal-swapping\/\">architecture<\/a>\u2026 surely it\u2019s time to start building the new UI layout, yeah? Not so fast!<\/p>\n<p>It\u2019s true we could start now, but on the horizon I could already see the increasing usefulness of another supporting feature, and decided it was a good opportunity to finally automate Cogmind\u2019s font scaling.<\/p>\n<p>Cogmind has always included many fonts available at many different sizes, all of these stored as bitmaps for pixel-perfect crispness. Each requires its own image file, and in the past I have always manually upscaled them to ensure availability at the appropriate higher resolutions, which means even more files.<\/p>\n<p>Well with the advent of <a rel=\"nofollow\" target=\"_blank\" href=\"https:\/\/www.gridsagegames.com\/blog\/2023\/12\/adventures-in-map-zooming-part-3-implementation\/\">map zooming<\/a>, which itself needs 2x upscale versions of all fonts within each set, and this whole UI upscale project, which unlocks an average 33% font size increase for everyone, we\u2019re going to need quite a few more upscaled bitmap font files and going forward it doesn\u2019t really make much sense to keep doing this manually.<\/p>\n<h2>REX, Again Again<\/h2>\n<p>Okay if anyone\u2019s keeping count this will be the <em>fourth<\/em> time I\u2019ve revisited the engine for a major update since starting map zoom and UI scaling work xD<\/p>\n<p>Hi, REX.<\/p>\n<p>I thought this would be a quick project, but it actually took several days to finally finish this feature because I ended up rewriting <em>a lot<\/em> of the engine\u2019s font handling code, encountering a few challenging (hair-ripping) bugs along the way. The original system had made a lot of assumptions which would no longer hold true, and I wanted more features on top of the autoscaling as well, like only generating upscaled fonts once they\u2019re actually needed (yay for faster startup), and having all font sets reusing the same source file share a single reference image in memory rather than having multiple copies of the same bitmap. Individually nothing too complex, just a lot of changes necessary to the original architecture to make these features possible.<\/p>\n<p>Once again back in the good old REX testing environment, I set to testing two new syntax options for the font set configuration file:<\/p>\n<ul>\n<li>\u201cNewFontName [SourceFontName*2]\u201d would create an entire new font set by upscaling an existing one, in this case by a factor of 2. (A font \u201cset\u201d means a collection of text, tiles, zoomed text and so forth, all categorized under a single name and selected as an option by the user.)<\/li>\n<li>\u201c<source_image_name>\u201d is a sample of syntax usable in any single field for a bitmap font source image, instead taking another image and upscaling it by the specified factor.<\/source_image_name><\/li>\n<\/ul>\n<div id=\"attachment_5235\" style=\"width: 866px\" class=\"wp-caption aligncenter\"><img fetchpriority=\"high\" decoding=\"async\" aria-describedby=\"caption-attachment-5235\" class=\"wp-image-5235 size-full\" src=\"https:\/\/www.gridsagegames.com\/blog\/gsg-content\/uploads\/2024\/01\/rex_font_config_scaling_tests.png\" alt=\"rex_font_config_scaling_tests\" width=\"856\" height=\"197\" \/><\/p>\n<p id=\"caption-attachment-5235\" class=\"wp-caption-text\">A sample config file used during REX testing, in some cases with font sets purely loaded from files, and in others partially or fully generated based on existing sets or bitmaps.<\/p>\n<\/div>\n<p>This same format is used by anything else built on the engine, so both Cogmind and <a rel=\"nofollow\" target=\"_blank\" href=\"https:\/\/www.gridsagegames.com\/rexpaint\/\">REXPaint<\/a> can benefit from this, the latter of which I hope to also release a new version before long!<\/p>\n<div id=\"attachment_5236\" style=\"width: 1706px\" class=\"wp-caption aligncenter\"><img loading=\"lazy\" decoding=\"async\" aria-describedby=\"caption-attachment-5236\" class=\"wp-image-5236 size-full\" src=\"https:\/\/www.gridsagegames.com\/blog\/gsg-content\/uploads\/2024\/01\/cogmind_font_scaling_demo_4x8mini_to_8x16.png\" alt=\"cogmind_font_scaling_demo_4x8mini_to_8x16\" width=\"1696\" height=\"960\" \/><\/p>\n<p id=\"caption-attachment-5236\" class=\"wp-caption-text\">A quick autoscaling test back in Cogmind, here using a 2x scale of a 4\u00d78 font, therefore turning it into a 8\u00d716 font for a 960p window. (This 4\u00d78 font is technically distributed with Cogmind, but since it\u2019s too small to be reasonably considered by players, or needed at all, it is not available by default and must be activated manually.)<\/p>\n<\/div>\n<h2>Cogmind Applications<\/h2>\n<p>Cogmind\u2019s last public release, Beta 12, includes a total of 118 bitmaps font images, and that was <em>before<\/em> all the map zooming and Beta 13 work, so without this autoscaling feature that number would balloon significantly.<\/p>\n<p>As of writing, Beta 13 has currently dropped that file count to 80, this despite the zooming, nine brand new font types, and supporting even more large options derived from smaller ones.<\/p>\n<p>I had to spend a while going back through all those files to confirm which were original files and which were upscaled&#8211;in most cases there were records, but I had to be sure, and did find a few outliers to which I made further manual modifications to their upscaled versions, or sourced from multiple different sets. Those required special treatment, but otherwise it was really nice to cut down on the clutter.<\/p>\n<div id=\"attachment_5237\" style=\"width: 1260px\" class=\"wp-caption aligncenter\"><img loading=\"lazy\" decoding=\"async\" aria-describedby=\"caption-attachment-5237\" class=\"wp-image-5237 size-full\" src=\"https:\/\/www.gridsagegames.com\/blog\/gsg-content\/uploads\/2024\/01\/cogmind_beta13_font_config_comparison.png\" alt=\"cogmind_beta13_font_config_comparison\" width=\"1250\" height=\"1074\" \/><\/p>\n<p id=\"caption-attachment-5237\" class=\"wp-caption-text\">Comparing Cogmind\u2019s original font config file to the new one with automated upscaling enabled (and zoom support!).<\/p>\n<\/div>\n<p>As of the current Beta 13 prerelease, the current max font size included with Cogmind is 48, needed for 5K displays, but with the new upscaled UI the max needed for that resolution will be 64! Definitely about time to get automated scaling\u2026<\/p>\n<p>New font sizes aside, this also saves time when new tiles are added and need to be inserted throughout the images, since tiles themselves are also part of the font bitmaps. Tiles aren\u2019t added very often, but a new batch is indeed being released gradually over the next several versions.<\/p>\n<p>Since I was working with fonts anyway, I also took advantage of this opportunity to add brand new options! In classic terminal roguelike style, some people like to switch their display font after a while in order to freshen up the whole experience, so in addition to others who simply want more options from which to select their favorite for readability or stylistic preferences, that\u2019s another good reason to make sure there is a good variety of styles available.<\/p>\n<p>The main two new typefaces are <a rel=\"nofollow\" target=\"_blank\" href=\"http:\/\/www.fial.com\/~scott\/tamsyn-font\/\">Tamsyn<\/a>\u00a0and <a rel=\"nofollow\" target=\"_blank\" href=\"https:\/\/github.com\/turquoise-hexagon\/cherry\">Cherry<\/a>, available at several sizes.<\/p>\n<div id=\"attachment_5238\" style=\"width: 2314px\" class=\"wp-caption aligncenter\"><img loading=\"lazy\" decoding=\"async\" aria-describedby=\"caption-attachment-5238\" class=\"wp-image-5238 size-full\" src=\"https:\/\/www.gridsagegames.com\/blog\/gsg-content\/uploads\/2024\/01\/cogmind_screenshot_sample_tamsyn_24.png\" alt=\"cogmind_screenshot_sample_tamsyn_24\" width=\"2304\" height=\"1440\" \/><\/p>\n<p id=\"caption-attachment-5238\" class=\"wp-caption-text\">Sample Cogmind screenshot using size 24 Tamsyn.<\/p>\n<\/div>\n<p>\u00a0<\/p>\n<div id=\"attachment_5239\" style=\"width: 1354px\" class=\"wp-caption aligncenter\"><img loading=\"lazy\" decoding=\"async\" aria-describedby=\"caption-attachment-5239\" class=\"wp-image-5239 size-full\" src=\"https:\/\/www.gridsagegames.com\/blog\/gsg-content\/uploads\/2024\/01\/cogmind_screenshot_sample_cherryshadow_14.png\" alt=\"cogmind_screenshot_sample_cherryshadow_14\" width=\"1344\" height=\"840\" \/><\/p>\n<p id=\"caption-attachment-5239\" class=\"wp-caption-text\">Sample Cogmind screenshot using size 14 Cherry Shadow,\u00a0 for which I added a slight drop shadow I think looks pretty cool, especially on a light background like item labels.<\/p>\n<\/div>\n<p>While I was at it, I also made other font-related improvements, like having Cogmind\u2019s options menu list fonts from largest to smallest to be able to more easily adjust style via the menu without changing map size. The original approach based purely on how they\u2019re listed in the config file didn\u2019t make sense, and I\u2019m not sure why I left it that way for so long.<\/p>\n<div id=\"attachment_5241\" style=\"width: 568px\" class=\"wp-caption aligncenter\"><img loading=\"lazy\" decoding=\"async\" aria-describedby=\"caption-attachment-5241\" class=\"wp-image-5241 size-full\" src=\"https:\/\/www.gridsagegames.com\/blog\/gsg-content\/uploads\/2024\/01\/cogmind_options_menu_font_set_sorting.gif\" alt=\"cogmind_options_menu_font_set_sorting\" width=\"558\" height=\"462\" \/><\/p>\n<p id=\"caption-attachment-5241\" class=\"wp-caption-text\">New sorting order for the font options menu!<\/p>\n<\/div>\n<h2>Pixel Corruption<\/h2>\n<p>Shortly after releasing a build with autoscaled fonts to patrons, a wild bug appeared! Apparently some people were seeing artifacts on the display\u2026<\/p>\n<div id=\"attachment_5240\" style=\"width: 1372px\" class=\"wp-caption aligncenter\"><img loading=\"lazy\" decoding=\"async\" aria-describedby=\"caption-attachment-5240\" class=\"wp-image-5240 size-full\" src=\"https:\/\/www.gridsagegames.com\/blog\/gsg-content\/uploads\/2024\/01\/cogmind_prerelease_bug_font_scaling_artifacts.png\" alt=\"cogmind_prerelease_bug_font_scaling_artifacts\" width=\"1362\" height=\"554\" \/><\/p>\n<p id=\"caption-attachment-5240\" class=\"wp-caption-text\">Screenshot excerpt showing visual oddities. (sample provided by Luigi; you\u2019ll have to open it at full size to see some of the evidence)<\/p>\n<\/div>\n<p>At first we weren\u2019t sure what it was, since it was only affecting a few people, and recent SDL DLL optimizations aimed at improving rendering speed had also been introduced as well. But bugs aren\u2019t all that elusive if they only affect some people and a discernible, repeatable pattern emerges, which happens to be the case here. That these artifacts only appeared for players using very high resolutions suggested it might be an issue with font scaling, since all of the high-resolution fonts are upscales.<\/p>\n<p>So I set up a bunch of tests to confirm, and eventually found that <em>some<\/em> large fonts ended up with these artifacts when scaled, and in all cases had a scaling multiplier of at least 3. How weird!<\/p>\n<p>Anyway it\u2019s now even more clear this has gotta be something with the scaling process, right, for which I had actually just plugged in <a rel=\"nofollow\" target=\"_blank\" href=\"https:\/\/github.com\/ferzkopp\/SDL_gfx\">SDL_gfx<\/a>, a common companion library for doing this sort of thing. Cue stepping through its zoomSurface() function, specifically zoomSurfaceRGBA(), and while comparing how it handled a 2x vs a 3x scale operation, I noticed that there seems to be\u2026 a bug in the library?<\/p>\n<div id=\"attachment_5242\" style=\"width: 496px\" class=\"wp-caption aligncenter\"><img loading=\"lazy\" decoding=\"async\" aria-describedby=\"caption-attachment-5242\" class=\"wp-image-5242 size-full\" src=\"https:\/\/www.gridsagegames.com\/blog\/gsg-content\/uploads\/2024\/01\/SDL_gfx_suspicious_zooming_code.png\" alt=\"SDL_gfx_suspicious_zooming_code\" width=\"486\" height=\"85\" \/><\/p>\n<p id=\"caption-attachment-5242\" class=\"wp-caption-text\">This code truncates the result of floating point arithmetic, which under the right combination of variables causes the intended optimizations based on these values to generate artifacts.<\/p>\n<\/div>\n<p>I\u2019m kinda surprised since this library has been in relatively wide use for over two decades, and even continues to be <a rel=\"nofollow\" target=\"_blank\" href=\"https:\/\/github.com\/ferzkopp\/SDL2_gfx\">used alongside subsequent SDL versions<\/a>, but that code remains the same. Maybe most people tend to use it with smoothing\/antialiasing turned on (I had it off because I want crisp), or are using less tightly packed tilesets (or even separate files for their images), all of which may help conceal such an issue from discovery? Or maybe there\u2019s something else at play.<\/p>\n<p>I replaced that whole optimized method with my own brute force scaling solution and *poof* the problem indeed disappeared. It\u2019s only rarely called anyway&#8211;as mentioned before fonts are only scaled when they\u2019re first needed, not before or ever again afterward, so we don\u2019t need to worry about performance. (And anyone who actually does need to worry about performance should probably avoid doing this in software mode in the first place \ud83d\ude1b &#8211;that\u2019s probably where all the other potential bug finders went off to\u2026)<\/p>\n<p><em>This is the fourth in a multi-part series about building Cogmind\u2019s fully upscaled semi-modal interface layout:<\/em><\/p>\n<\/p><\/div>\n<p><br \/>\n<br \/><a href=\"https:\/\/www.gridsagegames.com\/blog\/2024\/01\/full-ui-upscaling-part-4-simpler-lightweight-fonts\/\">Source link <\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>So we\u2019ve developed the theories, we\u2019ve got mockups, we\u2019ve got the necessary architecture\u2026 surely it\u2019s&#8230;<\/p>\n","protected":false},"author":1,"featured_media":1065,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[715,1825,2182,1826,1827,1828],"tags":[],"class_list":["post-1064","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-cogmind","category-dev-series-full-ui-upscaling","category-fonts","category-gui","category-scaling","category-ui"],"_links":{"self":[{"href":"https:\/\/x.sheep-mine.ts.net\/index.php\/wp-json\/wp\/v2\/posts\/1064","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/x.sheep-mine.ts.net\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/x.sheep-mine.ts.net\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/x.sheep-mine.ts.net\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/x.sheep-mine.ts.net\/index.php\/wp-json\/wp\/v2\/comments?post=1064"}],"version-history":[{"count":0,"href":"https:\/\/x.sheep-mine.ts.net\/index.php\/wp-json\/wp\/v2\/posts\/1064\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/x.sheep-mine.ts.net\/index.php\/wp-json\/wp\/v2\/media\/1065"}],"wp:attachment":[{"href":"https:\/\/x.sheep-mine.ts.net\/index.php\/wp-json\/wp\/v2\/media?parent=1064"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/x.sheep-mine.ts.net\/index.php\/wp-json\/wp\/v2\/categories?post=1064"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/x.sheep-mine.ts.net\/index.php\/wp-json\/wp\/v2\/tags?post=1064"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}