Skip to content

fix(ui): take the splash font from memory, and <cstring> for ocean_fft - #60

Merged
Force67 merged 1 commit into
mainfrom
feat/splash-font-from-memory
Sep 16, 2026
Merged

Force67 merged 1 commit into
mainfrom
feat/splash-font-from-memory

Conversation

@Force67

@Force67 Force67 commented Sep 16, 2026

Copy link
Copy Markdown
Owner

Two portability fixes, both one-liners in effect, unrelated to each other beyond
living in this tree.

The splash no longer writes a font to disk

Splash::LoadFont mirrored Roboto out of rx_fonts.rxp into a temp file and
handed ultragui the path, because FT_New_Face was the only way into its text
engine. The file needed a name no concurrent process would also pick — the
editor and a game starting together would otherwise delete each other's copy
mid-face — so it carried ::getpid(). That one call is the only reason
<unistd.h> was in the module, and MSVC has no such header: any Windows build
that links rx::ui fails on the include
, which is rx::app, which is every rx
application.

libultragui grew a memory loader for exactly this (Force67/libultragui#5), so
the archive's bytes go straight in:

const ugui::FontHandle font = ui_->LoadFontMemory(
    reinterpret_cast<const char*>(bytes->data()), bytes->size());

The temp path, the pid, the write, the Shutdown() unlink and
font_cache_path_ all go with it — 30 lines out, 8 in. ultragui copies the
bytes, so the Vector can die at the end of the scope as it already did. The
system-font fallback is untouched: a tree whose rx_fonts.rxp was never packed
still gets its line of text.

Depends on Force67/libultragui#5. Merge that first, or this does not compile.

<cstring> in ocean_fft.cc

OceanFft calls std::memcpy and never included <cstring>; it arrived
transitively through equilibrium's headers. equilibrium removed the STL from
base's production surface (Force67/equilibrium#14, now on devel5), so the
include has to be where the call is. This is the entire fallout of that change
in rx — one file.

Verification

Built through a consumer (recreation) against libultragui#5 and equilibrium
devel5: engine, game and tools compile and link. Running the plate:

[info] mounted .../rx_fonts.rxp at fonts://
ultragui: loaded font '<memory>' (Roboto)

and no rx-splash-*.ttf is left anywhere under the temp dir, where the old path
wrote one per process.

Two portability fixes that have nothing to do with each other beyond both
being one-liners in the same tree.

The splash wrote Roboto to a temp file and handed ultragui the path,
because FT_New_Face was the only way into its text engine. The file
needed a name no concurrent process would also pick, so it carried
::getpid() -- and that single call dragged <unistd.h> into the module,
which MSVC does not have. A windows build of anything linking rx::ui
fails on the include.

libultragui grew LoadFontMemory (Force67/libultragui#5), so the bytes
from rx_fonts.rxp go straight in. The temp path, the pid, the write, the
unlink in Shutdown and font_cache_path_ all go with it; a splash that
fails to find its font still falls back to a system one.

ocean_fft.cc calls std::memcpy and never included <cstring>; it arrived
transitively through equilibrium's headers until equilibrium removed the
STL from base's production surface. Include it where it is used.
@Force67
Force67 merged commit 2634566 into main Sep 16, 2026
Force67 added a commit to Force67/recreation that referenced this pull request Sep 16, 2026
Retarget the build onto rx main (2198552), which moved its ultragui
integration out of apps/editor into an rx::ui module and put an engine
splash on it. rx::app links that module, so the plate needs nothing from
the game -- but libultragui stops being optional, and the engine now owns
three files and six shaders recreation carried its own copies of.

libultragui is configured ahead of rx: rx::ui adds the checkout itself
when no ultragui target exists yet, and that copy would carry ultragui's
Lua scripting instead of recreation's C# host (adding the same source
directory twice is a hard error anyway). The platform and RHI shims now
come from the engine, as do the ugui pipeline shaders -- both repos
embedded those six blobs to the same generated header path, which ninja
refuses outright. RX_LIBULTRAGUI_DIR is forwarded for the builds that
compile no HUD of their own; android checks the library out for that.

The HUD's own Vulkan backend stays, renamed HudRenderBackend so it no
longer collides with rx::ui::GuiRenderBackend. It keeps the growing
descriptor pool chain a vanilla Scaleform screen's art needs, which the
engine's single fixed block does not hold; it can go when that lands in
rx::ui.

The flake stops reading the siblings out of one developer's home
directory. All six (rx, zetanet, nanobuf, libultragui, kinema,
equilibrium) are fetched from github at the revisions build.yml pins, with submodules
wherever CI checks them out recursively, so the sandbox and CI compile
the same engine on any machine. What git does not carry does not arrive:
rx's FidelityFX/DLSS/NRD/Jolt SDKs are downloads, so that build
configures with those features off and a working copy stays the way to
build with them.

equilibrium stops being welded to the submodule. It is where base::
comes from, and it was reachable one way only: third_party/equilibrium,
checked out recursively, which drags in its own eight submodules
(googletest, musl, mbedtls, tracy and the rest) that sit behind
EQ_BUILD_TESTS and never compile here. Every CI job cloned all of them,
and `src = self` carries no submodules at all, so the nix build could
not see equilibrium in the first place. RECREATION_EQUILIBRIUM_DIR now
names the checkout, the submodule stays the default, the sandbox gets a
tarball input at the revision the submodule records, and the checkouts
that only need equilibrium itself ask for one level instead of eight.
With that and slangc (rx compiles .slang shaders now), `nix build`
produces recreation, recreation-server and esminfo for the first time.

The sibling pins move together, because the retarget needed fixes in
three of them. zetanet spells out the <string.h> its bare mem* calls
always needed (Force67/zetanet#2). libultragui can load a font from
memory instead of only from a path (Force67/libultragui#5). rx uses that
for the splash wordmark, which deletes the temp file it used to write,
the pid in its name and the <unistd.h> that came with it -- the include
MSVC does not have, and the reason a windows build of anything linking
rx::ui failed (Force67/rx#60).

Verified against rx 2198552: full build, 107/107 tests, and a windowed
run that shows the plate and hands the frame back to the game's own UI
when it expires. RECREATION_NET=OFF, the no-SDL3 path and an out-of-tree
equilibrium all configure. `nix build .#default` completes.
Force67 added a commit to Force67/recreation that referenced this pull request Sep 16, 2026
Retarget the build onto rx main (2198552), which moved its ultragui
integration out of apps/editor into an rx::ui module and put an engine
splash on it. rx::app links that module, so the plate needs nothing from
the game -- but libultragui stops being optional, and the engine now owns
three files and six shaders recreation carried its own copies of.

libultragui is configured ahead of rx: rx::ui adds the checkout itself
when no ultragui target exists yet, and that copy would carry ultragui's
Lua scripting instead of recreation's C# host (adding the same source
directory twice is a hard error anyway). The platform and RHI shims now
come from the engine, as do the ugui pipeline shaders -- both repos
embedded those six blobs to the same generated header path, which ninja
refuses outright. RX_LIBULTRAGUI_DIR is forwarded for the builds that
compile no HUD of their own; android checks the library out for that.

The HUD's own Vulkan backend stays, renamed HudRenderBackend so it no
longer collides with rx::ui::GuiRenderBackend. It keeps the growing
descriptor pool chain a vanilla Scaleform screen's art needs, which the
engine's single fixed block does not hold; it can go when that lands in
rx::ui.

The flake stops reading the siblings out of one developer's home
directory. All six (rx, zetanet, nanobuf, libultragui, kinema,
equilibrium) are fetched from github at the revisions build.yml pins, with submodules
wherever CI checks them out recursively, so the sandbox and CI compile
the same engine on any machine. What git does not carry does not arrive:
rx's FidelityFX/DLSS/NRD/Jolt SDKs are downloads, so that build
configures with those features off and a working copy stays the way to
build with them.

equilibrium moves to the head of devel5, the branch .gitmodules names
and the pin had drifted off: a commit on no branch at all, five behind
devel5 and one ahead, reachable by sha alone. devel5 brings the STL out
of base's production surface, the security pass behind it, and a string
option that owns its value instead of pointing at the buffer it was
parsed from (Force67/equilibrium#15) -- the bug that had RX_UI_SHOT
writing captures to a filename made of freed memory.

equilibrium also stops being welded to the submodule. It is where base::
comes from, and it was reachable one way only: third_party/equilibrium,
checked out recursively, which drags in its own eight submodules
(googletest, musl, mbedtls, tracy and the rest) that sit behind
EQ_BUILD_TESTS and never compile here. Every CI job cloned all of them,
and `src = self` carries no submodules at all, so the nix build could
not see equilibrium in the first place. RECREATION_EQUILIBRIUM_DIR now
names the checkout, the submodule stays the default, the sandbox gets a
tarball input at the revision the submodule records, and the checkouts
that only need equilibrium itself ask for one level instead of eight.
With that and slangc (rx compiles .slang shaders now), `nix build`
produces recreation, recreation-server and esminfo for the first time.

The sibling pins move together, because the retarget needed fixes in
three of them. zetanet spells out the <string.h> its bare mem* calls
always needed (Force67/zetanet#2). libultragui can load a font from
memory instead of only from a path (Force67/libultragui#5). rx uses that
for the splash wordmark, which deletes the temp file it used to write,
the pid in its name and the <unistd.h> that came with it -- the include
MSVC does not have, and the reason a windows build of anything linking
rx::ui failed (Force67/rx#60).

Verified against rx 2198552: full build, 107/107 tests, and a windowed
run that shows the plate and hands the frame back to the game's own UI
when it expires. RECREATION_NET=OFF, the no-SDL3 path and an out-of-tree
equilibrium all configure. `nix build .#default` completes.
Force67 added a commit to Force67/recreation that referenced this pull request Sep 16, 2026
Retarget the build onto rx main (2198552), which moved its ultragui
integration out of apps/editor into an rx::ui module and put an engine
splash on it. rx::app links that module, so the plate needs nothing from
the game -- but libultragui stops being optional, and the engine now owns
three files and six shaders recreation carried its own copies of.

libultragui is configured ahead of rx: rx::ui adds the checkout itself
when no ultragui target exists yet, and that copy would carry ultragui's
Lua scripting instead of recreation's C# host (adding the same source
directory twice is a hard error anyway). The platform and RHI shims now
come from the engine, as do the ugui pipeline shaders -- both repos
embedded those six blobs to the same generated header path, which ninja
refuses outright. RX_LIBULTRAGUI_DIR is forwarded for the builds that
compile no HUD of their own; android checks the library out for that.

The HUD's own Vulkan backend stays, renamed HudRenderBackend so it no
longer collides with rx::ui::GuiRenderBackend. It keeps the growing
descriptor pool chain a vanilla Scaleform screen's art needs, which the
engine's single fixed block does not hold; it can go when that lands in
rx::ui.

The flake stops reading the siblings out of one developer's home
directory. All six (rx, zetanet, nanobuf, libultragui, kinema,
equilibrium) are fetched from github at the revisions build.yml pins, with submodules
wherever CI checks them out recursively, so the sandbox and CI compile
the same engine on any machine. What git does not carry does not arrive:
rx's FidelityFX/DLSS/NRD/Jolt SDKs are downloads, so that build
configures with those features off and a working copy stays the way to
build with them.

equilibrium moves to the head of devel5, the branch .gitmodules names
and the pin had drifted off: a commit on no branch at all, five behind
devel5 and one ahead, reachable by sha alone. devel5 brings the STL out
of base's production surface, the security pass behind it, and a string
option that owns its value instead of pointing at the buffer it was
parsed from (Force67/equilibrium#15) -- the bug that had RX_UI_SHOT
writing captures to a filename made of freed memory.

equilibrium also stops being welded to the submodule. It is where base::
comes from, and it was reachable one way only: third_party/equilibrium,
checked out recursively, which drags in its own eight submodules
(googletest, musl, mbedtls, tracy and the rest) that sit behind
EQ_BUILD_TESTS and never compile here. Every CI job cloned all of them,
and `src = self` carries no submodules at all, so the nix build could
not see equilibrium in the first place. RECREATION_EQUILIBRIUM_DIR now
names the checkout, the submodule stays the default, the sandbox gets a
tarball input at the revision the submodule records, and the checkouts
that only need equilibrium itself ask for one level instead of eight.
With that and slangc (rx compiles .slang shaders now), `nix build`
produces recreation, recreation-server and esminfo for the first time.

The sibling pins move together, because the retarget needed fixes in
three of them. zetanet spells out the <string.h> its bare mem* calls
always needed (Force67/zetanet#2). libultragui can load a font from
memory instead of only from a path (Force67/libultragui#5). rx uses that
for the splash wordmark, which deletes the temp file it used to write,
the pid in its name and the <unistd.h> that came with it -- the include
MSVC does not have, and the reason a windows build of anything linking
rx::ui failed (Force67/rx#60).

Verified against rx 2198552: full build, 107/107 tests, and a windowed
run that shows the plate and hands the frame back to the game's own UI
when it expires. RECREATION_NET=OFF, the no-SDL3 path and an out-of-tree
equilibrium all configure. `nix build .#default` completes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant