Skip to content

Conversation

@ivan-mogilko
Copy link
Contributor

@ivan-mogilko ivan-mogilko commented Mar 27, 2025

Drafting a change required to resolve #1528.

What is done:

  1. Replaced FreeType 2.1.3 with contemporary FreeType 2.13.2. Moves library sources to libsrc dir in the project root.
  2. Replaced Alfont library with SDL_ttf (it also seems small enough to place in our repository).
  3. As a consequence AGS.Native and thus Editor now also requires SDL2.dll.
  4. Had to add a temporary hack, where TTFRenderer would retrieve a FT_Face struct from TTF_Font by guessing its memory location, and read font's BBOX information from there. That is not a safe thing to do, so we'll need a proper way of doing this (see [Feature request]: query font's BBOX libsdl-org/SDL_ttf#536)
  5. Deprecated Font's "TTF font adjustment" property. As a result some previously used fonts may be positioned differently. I recommend setting "How the true-type font height will be defined" in General Settings to "Real graphical height". Maybe this should be made new default, or the property deprecated as well. But we need to think this over well first. There are still fonts out there which contain incorrect ascent/descent/height parameters.

What will not be part of this PR:

  1. Harfbuzz and proper rendering of specific languages (Arabic, Persian etc). I think it's best leave this for the next update, after this transition is proven good.

What should be added to this PR:

  1. Fix CMake scripts and project building on all platforms.
  2. Resolve a temporary hack which is used to read BBOX info from the font (see its mention above).
  3. Try to fix any rendering issues with fonts commonly used in AGS games, unless we prove that it's impossible (if they have actually incorrect data). The most trivial case is incorrectly reported height, which may cause text to be drawn higher or lower than expected. I also noticed issues with letters having "jagged" edges, like pixels either missing or extra pixels present. We might need to add more properties to the font that would allow users to fine-tune their rendering.
  4. Wrapped text optimization. SDL_ttf has a peculiarity: it does not draw on a ready surface, but creates a new one containing rendered text, which then should be drawn on destination. This means that if we draw a multiline text, there will be a new surface allocation per line. Idk how much of a performance issue that will be in practice, as text is not redrawn each frame, but only once when initializing a textual overlay or a gui control (or a new text is assigned). But another consideration is rendering multiline text in particular languages, the ones that might require their own word-wrapping rules. Or rendering text containing unicode control characters (text direction, etc). In the end we might have to let SDL_ttf handle wrapping anyway.
    But that will require to change few bits in the engine, as right now text wrapping is done prior to calling Font Renderer interface.
    Likely, a IAGSFontRenderer interface will have to be expanded with RenderTextWrapped method, and same done in plugin API.

@ivan-mogilko ivan-mogilko added ags 4 related to the ags4 development context: fonts labels Mar 27, 2025
@ivan-mogilko ivan-mogilko added this to the 4.0.0 (preliminary) milestone Mar 27, 2025
@ivan-mogilko ivan-mogilko force-pushed the ags4--sdlttf branch 3 times, most recently from fdc2f06 to 2f57807 Compare April 15, 2025 02:35
@ivan-mogilko
Copy link
Contributor Author

ivan-mogilko commented Apr 15, 2025

@ericoporto if you have some spare time, could you take a look at the CMake scripts in this pr?
There are following things that concern me.

  1. Currently I left original CMakeLists.txt in freetype, but i am not sure if that's a right thing to do, because it may be not building what i think it should (i.e. maybe it builds a separate static library which is not linked to the engine). Should we replace that with our own script, similar to what we have in other lib sources?
    2. Afaik, freetype must have a FT2_BUILD_LIBRARY compiler flag enabled.
  2. As SDL_ttf is going to be a part of the Common lib, it needs to include SDL headers. How do I add such instruction in CMake scripts?

I will read about CMake scripts and try figure this out too in the meantime.

@ivan-mogilko ivan-mogilko force-pushed the ags4--sdlttf branch 5 times, most recently from 5812598 to ba821f1 Compare April 16, 2025 19:11
@ivan-mogilko
Copy link
Contributor Author

ivan-mogilko commented Apr 16, 2025

It seems like I figured out most things, using existing scripts as an example (although few things still are strange to me).
Haven't actually tested this on anything but Windows and Linux yet.

Following immediate issues remain with building:

  1. Emscripten fails to compile FreeType, because it does not know "open"/"read" etc posix specific functions in unix/ftsystem.c file. These are declared in "fnctl.h". FreeType has a condition under which it includes "fcntl.h", but it does work here. Need to find out whether Emscripten was supposed to use this file at all, or a generic ftsystem.c instead.
  2. I got "OOMKilled" error once while making Android build on cirrus. Don't know if that's an accident, or a problem with our settings / project. Requested to rurun failed tasks, and it completed successfully this time.
  3. Game auto-tests are failing. Haven't checked these yet, maybe this is something wrong in ags4 branch.

@ivan-mogilko ivan-mogilko force-pushed the ags4--sdlttf branch 2 times, most recently from 18aabd3 to 1eeca86 Compare April 17, 2025 03:08
@ericoporto
Copy link
Member

This looks alright, but I can look into this next week when I am back home, I have a variant of this in one of my older branches where Freetype and SDL_ttf are built as static libraries (in VS it gets added to VS dependencies built on the server), if it’s desirable. The advantage of having Freetype built alongside the engine instead is to take advantage of miniz + libpng to get colorful emojis, but perhaps this is not necessary. And also having the sources makes it much easier to build with different build systems. I can’t tell the issues with the things that aren’t building.

@ericoporto
Copy link
Member

This will take me a little while but my idea is to put SDL_ttf like we have SDL_sound as a dependency, and then put in the docker images (an attempt here ericoporto@364655b) and add to sdl2.props too. The pure CMake route will be using find ot fetch it in CMake, and I will need to fetch dependencies too if SDL_ttf is being fetch due to it using dynamic linking to its dependencies.

@ivan-mogilko
Copy link
Contributor Author

I am confused by the last two comments, cannot tell if they suggest same or opposite approaches? The first one looked like you say that having sources along with the engine is better (?), the second sais that it's better to have them separate. Also, I cannot tell if you mean to only have SDL_ttf downloaded separately, or both SDL_ttf and freetype.

The problem with SDL_ttf source in the current branch is that it's missing one functionality that is important for the engine (see libsdl-org/SDL_ttf#538). Here I added it directly, but if it's loaded from elsewhere then either we have to wait until it's added to the upstream library (if that happens at all), or alternatively maintain our own library version and fetch that.

@ericoporto
Copy link
Member

I think you got it right. Overall it’s easier to have the sources in the directory directly so updating or changing something can be done more easily - in parts. But having the sources not there and have the dependencies outside is less code we are committing in our main repository.

My feeling is we are never going to edit Freetype's code directly because we haven’t done so in a long time. So I think this could be done in a sort of middle ground where the current old Freetype is removed, and we get the new one as an external dependency and build SDL_ttf from code directly in the repo. The “get Freetype as an external dependency” could be done as we have for other dependencies right now or alternatively as a submodule.

@ericoporto

This comment was marked as outdated.

@ericoporto
Copy link
Member

ericoporto commented Jul 10, 2025

I think your fork of SDL_ttf should be under AGS organization to make it easy to sync changes from upstream, like fork to the org, add an AGS branch and add your changes to this branch. This is my learning from syncing changes manually from mojoAL.

@ericoporto
Copy link
Member

ericoporto commented Jul 21, 2025

I tried to throw away the Freetype CMakeLists.txt because it was too complex and replaced with our own... It seems things are building. ericoporto@cd19e67 (Cirrus, GHA) , I also had to rebase because I was getting a weird error at link time in my computer.

It also builds much faster for me because freetype configuration step on it's own CMakelists was taking three minutes on my PC and now it's instant.

@ericoporto
Copy link
Member

ericoporto commented Aug 6, 2025

@ivan-mogilko could you rebase this and apply my commit from above? Outside maybe (haven't checked) some README or License information somewhere it should be good.

Used this as an opportunity to move sources from Common to libsrc folder in the project root.
A simpler CMake file is easier to deal and configure for our possible platforms.

The original CMake wasn't building on Emscripten or on Windows and I had no idea how to fix, but with this one it appears it works on all the platforms we care.
@ivan-mogilko
Copy link
Contributor Author

Okay, I rebased.

But I am unsure about the future of this PR. You have mentioned that it's better to fetch SDL_ttf from its own repository (I am not certain about Freetype). Is this what should be done instead?

I wish we make a decision now, and finalize this, since the PR is stalling for several months now.

My addition to SDL_ttf (which has not been approved upstream yet) is not critically necessary, but needed mostly as a fixup for "bad" fonts. I suppose that there could be a way to detect if the function is present in the loaded SDL_ttf library, and use this function or follow a fallback scenario in case it's not present. Same could be done for other custom additions, like "character spacing" feature proposed by edmundito. This way we may have a custom SDL_ttf fork, but at the same time someone can still use a SDL_ttf installed on their system from upstream.

@ericoporto
Copy link
Member

ericoporto commented Aug 7, 2025

I changed my mind on fetching things vs having in the repository. Having in the repository is easier to adjust for different build systems, specifically VS and Xcode (for iOS). Plus If there's something that isn't building due to minor issues (like for Emscripten), it's easier. I think if we supported only regular desktop systems and nothing else I would trust upstream, but as soon as iOS, Android and Emscripten join in, things may break. I have been playing also with Windows Arm64, which is another thing that upstream libraries usually rarely test. Also we want SDL_ttf on the Editor too, and this way it's easier to build.

About the PR I believe it should be done now and we can move on with it as is and then fix anything else that comes up - I think like minor stuff like license mentions, on the Editor and on Linux. I will take a look on this after merge.

@ivan-mogilko it appears there is something wrong in the Vcxproj file?

@ericoporto
Copy link
Member

@ivan-mogilko this needs to be rebased and fixed again before merging. Other than this, it looks done, any reason for being a draft still?

@ivan-mogilko
Copy link
Contributor Author

ivan-mogilko commented Aug 12, 2025

There are two things that are bothering me:

  1. Some common ags fonts look "garbled", maybe caused by a different freetype lib. I recall seeing in the past that enabling or disabling "font hinting" may fix this, but did not try here yet.
  2. Text measurement and wrapping done in the engine may become sub-performant with SDL_ttf, because it's caching a number of things itself. We might need to let SDL_ttf do the text wrapping. I suspect that this may be required if we use harfbuzz too, so maybe can be postponed until then. But it is worth doing performance tests with large wrapped texts to see the difference between alfont and SDL-ttf versions.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ags 4 related to the ags4 development context: fonts

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants