TTF support#2232
Conversation
Integrates FreeType for font rasterization and HarfBuzz for complex text shaping, including support for right-to-left (RTL) languages like Arabic. This new system overrides the legacy BitFont rendering for certain text elements, enabling the use of TrueType/OpenType fonts and configurable sizing via `UIMD.INI`. External dependencies (FreeType, HarfBuzz, Fribidi, etc.) are managed through vcpkg. Project settings (`Phobos.props`) are updated to include vcpkg paths and switch to the Cdecl calling convention.
Replaces the FreeType and HarfBuzz-based text renderer with a GDI-based implementation. This change simplifies external dependencies by removing the `vcpkg` submodule and all direct references to its installed libraries in `Phobos.props`. The new system leverages Windows' native GDI for font rasterization and text layout, while retaining support for configurable fonts via `UIMD.INI`. The `MessageListClass_Draw_TTF` hook, which previously used the FreeType renderer, is also removed.
No hasArabic — GDI handles RTL automatically No DT_RTLREADING — not needed, Windows detects text direction No font caching — single font, loaded once No GDIFont struct — just an HFONT ~50 lines for the core rendering logic Color conversion simplified: (c & 0x1F) * 8 instead of * 255 / 31
-TTF not applying to igname msgs
|
Stop rewrite my code! |
That's not how it works, broski. In order to contribute your changes you've made a derivative of Phobos' GPL licensed code, modified it and published it. Your contribution is under GPL license and was distributed as a pull request. You can't just tell people to stop modifying it. The only thing I agree with is that you should be added to credits list for it (which you should've done in the first place). @Gedo6922 please add him and yourself to CREDITS.md. |
sure thing I already mentioned that it's Continuation of his work and will be added to the credit anyway |
-Adjusted pause menu
-Useless changes removed
-Known issues:
* Text Box for deployed MCV is smaller than the text "Power = XX Drain =XX"
* Multiplayer and game msg chat yet to support ttf
Excuse me??? Kerb, you ruined my project that adds Arabic RTL support to the CnCNet client. I also worked on TTF font rendering in-game and either through HarfBuzz or my own implementation Why did you change your mind about my project? Why did you turn against it? Why are you unwilling to let me improve the code? |
|
@G-LimeJuice We are not obliged to accept your code. We are not obliged to accept your code without edits as well. None of this is implied, written in any policies or licenses. I haven't "ruined" anything, it's you who ragequitted upon receiving criticism from the folks. Our only goal is for the code to be optimal, producing correct results AND maintainable. Throwing a tantrum in response is childish.
This is bullshit, it's you who quit without any explanation and closed your PR(s) upon receiving criticism, and now you're saying this. Maybe don't lie? If you don't want to understand and accept how civilized software development is done, then don't make a headache for everyone else. You are free to collaborate with us, but this isn't collaboration. |
|
Nightly build for this pull request:
This comment is automatic and is meant to allow guests to get latest nightly builds for this pull request without registering. It is updated on every successful build. |
- Optimize `DrawText` by reusing the DIB bitmap for reduced allocation overhead. - Extend GDI rendering to `BitText_Print` and `BitFont_Blit` via new hooks. - Improve text dimension calculation and single-character drawing logic. - Remove `vcpkg` from `.gitignore` as it's no longer a dependency for the text renderer.
- Refactor internal implementation for improved clarity, including variable naming and detailed comments. - Correct font creation by switching from `CreateFontW` to `CreateFontA` for reliable font name parsing from `UIMD.INI`. - Improve drawing process with explicit DIB background copying and 16-bit word alignment for stability. - Refine surface locking coordinates and drawing boundary calculations.
WalkthroughThis PR introduces a new TextRenderer module that provides Win32 GDI-based TrueType font rendering for the Phobos mod. The implementation includes lazy font initialization from configuration, text drawing with DIB backbuffer composition, text measurement, and four binary hooks that integrate the renderer into the game engine's existing font and text operations. ChangesTextRenderer Module & Engine Integration
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 5
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@Phobos.vcxproj`:
- Line 33: Move the TextRenderer.h entry out of the compiled-files ItemGroup and
into the header-files ItemGroup in Phobos.vcxproj: locate the line `<ClInclude
Include="src\TextRenderer\TextRenderer.h" />` currently placed with
`<ClCompile>` entries and cut/paste it under the `<ItemGroup>` that contains
other `<ClInclude>` entries so header files are grouped with header ItemGroup,
preserving XML ordering and project formatting.
In `@src/TextRenderer/Hooks.cpp`:
- Around line 46-53: In BitText_Print (Hooks.cpp) the caller's width (W,
populated by GET_STACK) is ignored and a hardcoded 2000 is passed to
TextRenderer::DrawText; update the TextRenderer::DrawText invocation to pass W
instead of 2000 so wrapping/clipping honors the original narrow print region
(ensure the argument order remains pFont, pSurface, pWideString, X, Y, W, H, 0).
- Around line 49-50: The guard using TextRenderer::IsInitialized() must not
short-circuit lazy initialization; instead either make IsInitialized() perform
the lazy init (call LoadFontOnce()) or remove the early return and call DrawText
(or GetTextDimension where appropriate) directly so the renderer initializes on
first use; update the BitText_Print and BitFont_Blit hook sites to invoke
DrawText/GetTextDimension (or call LoadFontOnce() before checking
IsInitialized()) so the TTF renderer switches on the first call rather than
being permanently bypassed.
- Around line 68-74: The code mutates the shared font color (pFont->Color) when
nColor != -1 and never restores it, which taints later draws; fix by saving the
original color from pFont before changing it, set pFont->Color to the new color
only for the duration of the draw (TextRenderer::DrawText / any subsequent
BitFont_Blit calls), and always restore the saved original color after the draw
completes (including on all execution paths). Locate the change around
pFont->Color, the DrawText call in TextRenderer::DrawText and any BitFont_Blit
usage, and ensure restoration happens even if GetTextDimension or DrawText
returns early.
In `@src/TextRenderer/TextRenderer.cpp`:
- Around line 67-77: The code currently computes drawingWidth/drawingHeight from
raw posX/posY but only clamps the lock origin (lockX/lockY), causing negative
posX/posY to leave unclipped left/top content and oversized temp bitmaps; before
creating the temporary HBITMAP and before calling DrawTextW, adjust the visible
box by subtracting the clamped offset (clampedX = max(0,posX), clampedY =
max(0,posY)), reduce drawingWidth/drawingHeight by (clampedX - posX) and
(clampedY - posY) respectively so the temp bitmap only covers visible pixels,
and shift the GDI RECT/DrawTextW origin by (posX - clampedX, posY - clampedY)
(i.e. offset the drawing origin into the temp bitmap) so DrawTextW writes into
the correct location while Lock still uses lockX/lockY.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: b55e1deb-ae4d-45e8-a7ef-da25733e467a
📒 Files selected for processing (4)
Phobos.vcxprojsrc/TextRenderer/Hooks.cppsrc/TextRenderer/TextRenderer.cppsrc/TextRenderer/TextRenderer.h
TaranDahl
left a comment
There was a problem hiding this comment.
I don't see any issues, but I do not understand the font-related things.
|
@Gedo6922 Please explicit address each AI review comment. Meanwhile, please describe how to use TTF font in this PR and what known limitation a tester needs to know |
It has to remain 2k or wrapping and clipping happens which we dont need for ingame chat and msgs |
- Add `AntiAlias` setting to enable/disable ClearType font smoothing. - Consolidate all TrueType font configuration under the `[EnableTTF]` INI section. - Ensure `BitFont_Blit` preserves the font's original color after drawing. - Improve drawing boundaries and coordinate clamping for more accurate text rendering. - Streamline code by removing redundant `IsInitialized` checks and excessive comments.
The original game code sometimes supplies a narrow width to `BitText::Print`, which is intended for single-line text. This causes GDI to word-wrap text, such as CSF messages, leading to incorrect display. This change overrides the width with a large fixed value to ensure single-line rendering as intended.
- Make `BitFont_Blit` hook measure-only, delegating actual character drawing to the main `DrawText` function for consistency and simplified logic. - Enhance `TextRenderer` robustness by introducing a `MAX_DRAWING_WIDTH` safety cap and ensuring all GDI drawing commands are flushed. - Improve code readability and maintainability with extensive comments
SadPencil
left a comment
There was a problem hiding this comment.
Also, we must find a way to test the performance, especially check whether there exist memory leaks or not
- Introduce `MAX_TEXT_WIDTH` for consistent width capping in `DrawText` and forcing single-line output for `BitText::Print` callers. - Add comprehensive documentation to `Hooks.cpp` and `TextRenderer.cpp/.h` explaining component roles and drawing logic. - Explicitly define `BitFont::Blit` as a measure-only hook, streamlining character width measurement for cursor positioning. - Refactor internal variable names and remove obsolete includes for better maintainability.
did more tests with debugger by tracking the GDI object count and DIB allocations. but to note the issues I already listed 1- CSF Message Typewriter Animation vertical instead of horizontal 1st idk about but it has 0 impact on performance I think |
TTF Support
Summary
Replaces the legacy
.FNTbitmap font rendering with modern TrueType/OpenType (.ttf/.otf) font support using Windows GDI. All game text is rendered throughDrawTextWwith proper alignment, word-wrapping, and bidirectional text support handled automatically by the operating system.Continuation of TTF work of which the previous owner disappeared from existence in unknown circumstances
The old pr: #2178
Changes
New Files:
src/TextRenderer/TextRenderer.h— Header for the TTF rendering namespacesrc/TextRenderer/TextRenderer.cpp— GDI-based font loading and text rendering enginesrc/TextRenderer/Hooks.cpp— Four engine hooks intercepting all text drawing pathsModified Files:
Phobos.vcxproj— Added new source files and header to projectEngine Hooks:
BitFont_GetTextDimension0x433CF0BitText_DrawText0x434CD0BitText_Print0x434B90BitFont_Blit0x434120Key Features:
DrawTextW— no external library dependenciesUIMD.INIINI Configuration:
Testing Instructions
Setup:
-Place a .ttf font file in the game directory alongside gamemd.exe
-Add the [EnableTTF] section to UIMD.INI with desired settings
-Launch the game
Known Limitations for Testers:
-CSF Message Typewriter Animation:
Symptom: Game messages like "Tech Building Captured" appear as a whole sentence vertically instead of character-by-character horizontally during the reveal animation.
-Continuous msgs ghosting in fog of war and lower bar.
-fps drop when a lot of text displayed.