font textwidth — engine-exact rendered text width as a screen-width fraction Reproduces the FreeType branch of Engine::GetTextWidth (FontDraw.cpp): resolve the font alias through the active per-role slot mapping (FindFontMapping), load the mapped TTF, then apply the same widthScale / letterSpacing / synthetic bold-oblique and aspect/FOV scaling. Output is a fraction of screen width, so it compare
| 197 | // it compares directly against a control's `w`. Used to flag credit / cutscene |
| 198 | // text that overflows its bounds with the real shipping font. |
| 199 | static void setupFontTextWidth(CLI::App& font) |
| 200 | { |
| 201 | auto* cmd = font.add_subcommand( |
| 202 | "textwidth", "Engine-exact rendered text width (screen-width fraction) for a font alias + sizeEx"); |
| 203 | |
| 204 | static std::string alias; |
| 205 | static double sizeEx = 0.0; |
| 206 | static std::string text; |
| 207 | static std::string dataDir = "packages/Remaster"; |
| 208 | static int width = 1920; |
| 209 | static int height = 1080; |
| 210 | static double fovTop = 0.75; |
| 211 | static double fovLeft = 1.0; |
| 212 | static double maxW = -1.0; |
| 213 | static bool asJson = false; |
| 214 | |
| 215 | cmd->add_option("font", alias, "Font alias as used in a resource (e.g. SteelfishB64CE)")->required(); |
| 216 | cmd->add_option("sizeEx", sizeEx, "Control sizeEx (font height as a fraction of screen height)")->required(); |
| 217 | cmd->add_option("text", text, "Text to measure")->required(); |
| 218 | cmd->add_option("--data-dir", dataDir, "Game data dir holding fonts/ (default packages/Remaster)"); |
| 219 | cmd->add_option("--width", width, "Surface width px (default 1920)"); |
| 220 | cmd->add_option("--height", height, "Surface height px (default 1080)"); |
| 221 | cmd->add_option("--fov-top", fovTop, "Aspect topFOV (config fovTop, default 0.75)"); |
| 222 | cmd->add_option("--fov-left", fovLeft, "Aspect leftFOV (config fovLeft, default 1.0)"); |
| 223 | cmd->add_option("--max-width", maxW, "If set, also report fits = width <= maxWidth (the control w)"); |
| 224 | cmd->add_flag("--json", asJson, "Emit a single-line JSON result"); |
| 225 | |
| 226 | cmd->callback( |
| 227 | []() |
| 228 | { |
| 229 | std::string low = alias; |
| 230 | for (char& c : low) |
| 231 | c = static_cast<char>(std::tolower(static_cast<unsigned char>(c))); |
| 232 | |
| 233 | const Poseidon::FreeTypeFontMapping* m = Poseidon::FindFontMapping(low.c_str()); |
| 234 | if (!m) |
| 235 | { |
| 236 | std::cerr << "Error: no font mapping for alias '" << alias << "' (prefix not found)\n"; |
| 237 | throw CLI::RuntimeError(2); |
| 238 | } |
| 239 | |
| 240 | std::string ttf = dataDir; |
| 241 | if (!ttf.empty() && ttf.back() != '/' && ttf.back() != '\\') |
| 242 | ttf += '/'; |
| 243 | for (const char* p = m->ttfPath; *p; ++p) |
| 244 | ttf += (*p == '\\') ? '/' : *p; |
| 245 | |
| 246 | Poseidon::ui::FontRenderer fr; |
| 247 | fr.SetSyntheticOblique(m->syntheticOblique); |
| 248 | fr.SetSyntheticBold(m->syntheticBold); |
| 249 | if (!fr.LoadFont(ttf)) |
| 250 | { |
| 251 | std::cerr << "Error: cannot load font file: " << ttf << "\n"; |
| 252 | throw CLI::RuntimeError(1); |
| 253 | } |
| 254 | |
| 255 | // Engine::GetTextWidth FreeType branch, headless: Width2D()/Height2D() |
| 256 | // collapse to Width()/Height() over the full-screen UI region. |
no test coverage detected