Embed font into binary
This commit is contained in:
@@ -1,5 +1,9 @@
|
||||
# Dusk — Claude Code rules
|
||||
|
||||
See `STATUS.md` for a periodically-refreshed inventory of subsystem
|
||||
maturity, test coverage gaps, and known open issues — check it before
|
||||
assuming a subsystem is fully wired up or before picking a next task.
|
||||
|
||||
## File headers
|
||||
Every C, H, and JS file starts with:
|
||||
|
||||
@@ -251,6 +255,31 @@ Entity prefabs (`src/dusk/entity/entityprefab.h`) and scene prefabs
|
||||
|
||||
---
|
||||
|
||||
## Save system
|
||||
Save data lives under `src/dusk/save/` (`save.h`/`savefile.h`/
|
||||
`saveplatform.h`). Slots are fixed-count (`SAVE_FILE_COUNT_MAX`), each
|
||||
holding a yyjson document persisted with its byte size and a CRC32
|
||||
checksum. `saveLoad`/`saveSave` read/write the JSON fresh every call —
|
||||
callers own the returned/passed `yyjson_doc`/`yyjson_mut_doc` and must
|
||||
free it themselves. Actual file I/O goes through platform-specific
|
||||
`saveplatform_t`/stream hooks (one implementation per platform under
|
||||
`src/dusk<platform>/save/`) — do not add direct filesystem calls to the
|
||||
core `save.c`, extend the platform stream hooks instead.
|
||||
|
||||
## Network system
|
||||
`src/dusk/network/` (`network.h`) is a connection-state layer only — a
|
||||
`networkstate_t` state machine (`DISCONNECTED`/`CONNECTING`/`CONNECTED`/
|
||||
`DISCONNECTING`) plus an HTTP client (`network/http/`) used for one-off
|
||||
requests. It is not a multiplayer/replication protocol — that layer
|
||||
doesn't exist yet (see `ROADMAP.md` items on the socket server/client
|
||||
and packet handlers). Platform-specific connection logic (e.g. PSP's
|
||||
`sceNetApctl` polling, GameCube/Wii's `if_config()`) lives under
|
||||
`src/dusk<platform>/network/`, wired through `networkplatform.h` macros
|
||||
the same way display/input are. Whenever this eventually grows a
|
||||
multiplayer protocol, apply `ROADMAP.md`'s principle: never trust
|
||||
incoming packet data — validate defensively with `errorret_t`/
|
||||
`errorThrow()`, not asserts.
|
||||
|
||||
## Adding a new script (JS) module
|
||||
Dusk embeds JerryScript (`src/dusk/script/`, fetched via
|
||||
`cmake/modules/Findjerryscript.cmake`). Today only `Entity`, the
|
||||
|
||||
+33
@@ -44,6 +44,39 @@ Tracking upcoming milestones for the engine.
|
||||
or is disconnected, so clients can spawn or remove the
|
||||
corresponding `clientplayer` entity in the world.
|
||||
|
||||
## Infrastructure / debt backlog
|
||||
|
||||
Found during a full-codebase inventory pass (2026-07-30, see `STATUS.md`
|
||||
for the full survey). These aren't new feature milestones so much as
|
||||
loose ends worth closing, roughly in order of how cheap/safe they are to
|
||||
fix:
|
||||
|
||||
1. Re-enable `test/item` (currently commented out in
|
||||
`test/CMakeLists.txt`) -- confirm it still passes and turn it back on.
|
||||
2. Restore `itemgive.c/h` in `src/duskrpg/item/CMakeLists.txt` -- the
|
||||
textbox UI dependency it was waiting on (`ui/textbox/`) is already
|
||||
back.
|
||||
3. Decide the fate of the `vita` target: `scripts/build-vita.sh` and
|
||||
`docker/vita/` reference `-DDUSK_TARGET_SYSTEM=vita`, but no
|
||||
`cmake/targets/vita.cmake` exists, so the build is currently broken.
|
||||
Either implement it or remove the dangling scripts/Dockerfile.
|
||||
4. Add per-PR CI build coverage for at least one non-Linux target (PSP,
|
||||
Knulli, GameCube, Wii currently only build on tag push, so
|
||||
regressions there are invisible until a release).
|
||||
5. Tackle milestone 4 above (poor UI rendering performance) with a
|
||||
concrete lead: extend `uiconsole.c`'s cached-mesh pattern (rebuild
|
||||
only on dirty) to the general widget framework
|
||||
(`uiframe.c`/`uilabel.c`/buttons/menus), which currently rebuilds and
|
||||
re-uploads geometry via `spriteBatchBuffer`/`meshFlush` every frame.
|
||||
6. Revisit the GameCube/Wii networking static-IP workaround in
|
||||
`networkdolphin.c` -- it's standing in for an unresolved suspected
|
||||
memory-corruption bug in `if_config()`'s DHCP path.
|
||||
7. Decide whether the PSP dialog-based network connect UI needs to come
|
||||
back -- it was removed entirely (not fixed) when the original
|
||||
dialog-tearing bug proved hard to resolve.
|
||||
8. Backfill unit tests for the biggest untested surfaces: `ui/` (whole
|
||||
widget framework), `save/`, `script/` (JerryScript bindings), `event/`.
|
||||
|
||||
## Principles
|
||||
|
||||
- Never trust the network implicitly. Neither side (server or client)
|
||||
|
||||
@@ -0,0 +1,102 @@
|
||||
# Dusk Engine - Status Snapshot
|
||||
|
||||
This is a point-in-time inventory of the codebase's maturity, test coverage,
|
||||
and known gaps. It is not auto-maintained -- re-survey periodically (or
|
||||
whenever picking a new roadmap milestone) rather than trusting it blindly.
|
||||
See `ROADMAP.md` for the ordered feature milestones this status feeds into,
|
||||
and `CLAUDE.md` for coding conventions.
|
||||
|
||||
Last surveyed: 2026-07-30, at commit `e61914ba`.
|
||||
|
||||
## Core engine (`src/dusk/`)
|
||||
|
||||
| Subsystem | Maturity | Notes |
|
||||
|------------|------------------------------------|-------|
|
||||
| asset | Mature, fully wired | Model loading's "async" path is actually synchronous (`assetmodelloader.h`) -- only real stub found in core. |
|
||||
| script | Mature for its current scope | Registered modules: `modulePlatform`, `moduleComponent`, `moduleEntity`, `moduleScene` only. No typed per-component JS wrappers (all components go through the generic `Component`). No unit tests. |
|
||||
| entity | Mature | Engine-level prefab lists are empty sentinels; all real prefabs live in `duskrpg`. |
|
||||
| scene | Mature | Same prefab-delegation pattern as entity. No JSON serialize/deserialize (removed by design). |
|
||||
| save | Mature, but undocumented | Slot-based, yyjson + CRC32, platform stream hooks. Not covered in `CLAUDE.md`, no tests. |
|
||||
| network | Connection-state layer only | HTTP client + connection state machine; no multiplayer/replication protocol (expected -- that's roadmap items 8-17). Not covered in `CLAUDE.md`, has HTTP tests only. |
|
||||
| physics | Mature, recently churned | Recent revert/re-disable of "old ent code" suggests component wiring around physics isn't fully settled. Well tested. |
|
||||
| animation | Early/mid-stage | Keyframes + easing only, no blend trees or state machines. Terse commit history ("ANIM") suggests still iterating. |
|
||||
| display | Most mature/battle-tested | Backbone of the engine; dominated by platform optimization commits. |
|
||||
| ui | Actively churning | Widget framework has had features added and ripped out repeatedly (story/battle UI added then removed). Rendering path is the likely root cause of roadmap item 4 (see below). No tests at all. |
|
||||
| console | Small, finished for its scope | Already has the cached-mesh optimization pattern the rest of `ui/` lacks. |
|
||||
| event | Clean, small, finished | Pub/sub, rebuilt to replace the old input system. |
|
||||
| game | Intentionally header-only | Real implementation lives in `duskrpg/game/game.c`. |
|
||||
|
||||
### UI rendering performance (roadmap item 4)
|
||||
Confirmed root-cause candidate: `src/dusk/ui/debug/uiconsole.c` caches a
|
||||
persistent mesh and only rebuilds on dirty/scroll change. The rest of the
|
||||
widget framework (`uiframe.c`, `uilabel.c`, buttons, menus, settings
|
||||
screens) still goes through `spriteBatchBuffer`/`spriteBatchFlush` and
|
||||
re-uploads vertex data via `meshFlush` every frame, with a full flush
|
||||
forced on every shader/material change. This is almost certainly what
|
||||
"tanks framerate" on PSP. Fix direction: extend the console's cached-mesh
|
||||
pattern to the general widget path (rebuild only on dirty, not every
|
||||
frame).
|
||||
|
||||
## Game layer (`src/duskrpg/`)
|
||||
|
||||
Actively maintained, not orphaned (despite an old "remove rpg" commit deep
|
||||
in history) -- last touched the same day as this survey.
|
||||
|
||||
- **cutscene/** -- actively developed, matches `CLAUDE.md`'s documented
|
||||
recipe exactly. 16 registered item types.
|
||||
- **entity/, scene/** -- overworld player/camera/interactable components
|
||||
and prefabs, active.
|
||||
- **item/** -- `item.c`/`inventory.c`/`backpack.c` built via a working
|
||||
`item.json` -> `itemdef.h` codegen pipeline. `itemgive.c/h` exist on
|
||||
disk but are explicitly excluded from the CMake build pending textbox
|
||||
UI restoration -- **that UI (`ui/textbox/`) is already restored**, so
|
||||
this looks like an overdue follow-up, not a real blocker.
|
||||
- **input/** -- headers only, no implementation. Contains the one
|
||||
genuine TODO found in the whole `duskrpg` tree: `// TODO: Wiimote, USB
|
||||
Keyboard, probably more.`
|
||||
- **ui/** -- textbox restored and built; `uitestlabel.c/h` is an
|
||||
intentional smoke-test scaffold, not dead code.
|
||||
|
||||
## Platform layers
|
||||
|
||||
| Platform | Status |
|
||||
|--------------|--------|
|
||||
| duskgl / dusksdl2 | Complete, shared by Linux/Knulli/PSP, no gaps found. |
|
||||
| dusklinux | Complete, well-trodden. |
|
||||
| duskpsp | Complete for current design. The historical dialog/tearing bug (see memory `project_psp_dialog_tearing` etc.) was **not fixed -- the dialog-based connect UI was removed entirely** (commit `d7982599`, "Simplified PSP network") in favor of a silent profile-based connect. Revisit if the dialog UX is still wanted. |
|
||||
| duskdolphin (GameCube/Wii) | Functional, not a stub -- real GX-based display/mesh/shader/texture. Wii input uses only the GameCube `PAD_*` library; no WPAD/Wiimote support (`inputdolphin.h` has `#error "Wii not implemented"` gated behind macros that are never defined, so currently dormant, not a live build break). `networkdolphin.c` hardcodes a static IP as an explicit temporary workaround for a suspected DHCP-related memory-corruption bug in `if_config()` -- root cause still open. |
|
||||
| vita | **Referenced by `scripts/build-vita.sh` and `docker/vita/` but no `cmake/targets/vita.cmake` exists** -- the build target is broken/unfinished at the CMake level. |
|
||||
|
||||
### CI coverage gap
|
||||
`.github/workflows/test.yml` only builds+tests Linux, on PRs to `main`.
|
||||
`build.yml` builds all other platforms (PSP, Knulli, GameCube, Wii +
|
||||
ISO variants) but **only on tag push** (release time). Vita and Dolphin
|
||||
aren't in CI at all. Net effect: regressions on 4+ platforms can land
|
||||
silently until a release tag is cut.
|
||||
|
||||
## Test coverage gaps
|
||||
|
||||
Core `src/dusk/` subsystems with **zero** unit tests: `console`,
|
||||
`engine`, `event`, `game`, `input`, `log`, `save`, `script` (+ all JS
|
||||
module bindings), `system`, `ui` (entire widget framework).
|
||||
|
||||
`src/duskrpg/` has almost no test coverage: `test/item/test_inventory.c`
|
||||
exists but **`add_subdirectory(item)` is commented out in
|
||||
`test/CMakeLists.txt`**, so even that one test never runs. `cutscene`,
|
||||
`entity`, `game`, `input`, `scene`, `ui` under `duskrpg` have no tests at
|
||||
all.
|
||||
|
||||
No stale tests were found referencing deleted systems (old JSON
|
||||
serialize/deserialize, old event/cutscene modules) -- the test suite is
|
||||
internally consistent with current code, just incomplete in coverage.
|
||||
|
||||
## Build/tooling gaps worth knowing about
|
||||
|
||||
- `assetsraw/` -> `assets/` (chunk JSON -> `.dcf`) is a manual/editor-only
|
||||
step (`tools.asset.chunk`), not part of the CMake build -- committed
|
||||
`.dcf` files can silently drift from their raw source.
|
||||
- Several Python tool packages exist but aren't wired into any build:
|
||||
`tools/color/csv/`, `tools/asset/chunk_json/`, `tools/asset/dmf/`,
|
||||
`tools/asset/tiles/`, `tools/input/csv/`. Some may be superseded by
|
||||
`tools/color.py`/`tools/item.py`; worth a pass to confirm which are
|
||||
live vs leftover.
|
||||
@@ -6,5 +6,6 @@
|
||||
# Sources
|
||||
target_sources(${DUSK_LIBRARY_TARGET_NAME}
|
||||
PUBLIC
|
||||
font.c
|
||||
text.c
|
||||
)
|
||||
@@ -0,0 +1,168 @@
|
||||
/**
|
||||
* Copyright (c) 2026 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "font.h"
|
||||
#include "util/memory.h"
|
||||
#include "util/math.h"
|
||||
#include "display/color.h"
|
||||
|
||||
font_t FONT_DEFAULT;
|
||||
static texture_t FONT_DEFAULT_TEXTURE;
|
||||
static tileset_t FONT_DEFAULT_TILESET;
|
||||
|
||||
const uint8_t FONT_DEFAULT_GLYPHS[FONT_DEFAULT_TILE_COUNT][
|
||||
FONT_DEFAULT_TILE_HEIGHT
|
||||
] = {
|
||||
{ 0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x10, 0x00, 0x00 }, // !
|
||||
{ 0x00, 0x14, 0x14, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // "
|
||||
{ 0x00, 0x14, 0x14, 0x3E, 0x14, 0x3E, 0x14, 0x14, 0x00, 0x00 }, // #
|
||||
{ 0x00, 0x08, 0x1E, 0x28, 0x1C, 0x0A, 0x3C, 0x08, 0x00, 0x00 }, // $
|
||||
{ 0x00, 0x00, 0x22, 0x24, 0x08, 0x12, 0x22, 0x00, 0x00, 0x00 }, // %
|
||||
{ 0x00, 0x08, 0x14, 0x14, 0x1A, 0x24, 0x24, 0x1A, 0x00, 0x00 }, // &
|
||||
{ 0x00, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // '
|
||||
{ 0x00, 0x04, 0x08, 0x08, 0x08, 0x08, 0x08, 0x04, 0x00, 0x00 }, // (
|
||||
{ 0x00, 0x10, 0x08, 0x08, 0x08, 0x08, 0x08, 0x10, 0x00, 0x00 }, // )
|
||||
{ 0x00, 0x00, 0x08, 0x2A, 0x1C, 0x2A, 0x08, 0x00, 0x00, 0x00 }, // *
|
||||
{ 0x00, 0x00, 0x08, 0x08, 0x3E, 0x08, 0x08, 0x00, 0x00, 0x00 }, // +
|
||||
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x20, 0x00 }, // ,
|
||||
{ 0x00, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x00, 0x00, 0x00 }, // -
|
||||
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x00, 0x00 }, // .
|
||||
{ 0x00, 0x04, 0x04, 0x08, 0x08, 0x08, 0x10, 0x10, 0x00, 0x00 }, // /
|
||||
{ 0x00, 0x1C, 0x22, 0x26, 0x2A, 0x32, 0x22, 0x1C, 0x00, 0x00 }, // 0
|
||||
{ 0x00, 0x08, 0x18, 0x08, 0x08, 0x08, 0x08, 0x3E, 0x00, 0x00 }, // 1
|
||||
{ 0x00, 0x1C, 0x22, 0x02, 0x04, 0x08, 0x10, 0x3E, 0x00, 0x00 }, // 2
|
||||
{ 0x00, 0x1C, 0x22, 0x02, 0x0C, 0x02, 0x22, 0x1C, 0x00, 0x00 }, // 3
|
||||
{ 0x00, 0x22, 0x22, 0x22, 0x3E, 0x02, 0x02, 0x02, 0x00, 0x00 }, // 4
|
||||
{ 0x00, 0x3E, 0x20, 0x20, 0x3C, 0x02, 0x22, 0x1C, 0x00, 0x00 }, // 5
|
||||
{ 0x00, 0x1C, 0x20, 0x20, 0x3C, 0x22, 0x22, 0x1C, 0x00, 0x00 }, // 6
|
||||
{ 0x00, 0x3E, 0x02, 0x02, 0x04, 0x08, 0x08, 0x08, 0x00, 0x00 }, // 7
|
||||
{ 0x00, 0x1C, 0x22, 0x22, 0x1C, 0x22, 0x22, 0x1C, 0x00, 0x00 }, // 8
|
||||
{ 0x00, 0x1C, 0x22, 0x22, 0x1E, 0x02, 0x22, 0x1C, 0x00, 0x00 }, // 9
|
||||
{ 0x00, 0x00, 0x10, 0x10, 0x00, 0x10, 0x10, 0x00, 0x00, 0x00 }, // :
|
||||
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // ;
|
||||
{ 0x00, 0x04, 0x08, 0x10, 0x20, 0x10, 0x08, 0x04, 0x00, 0x00 }, // <
|
||||
{ 0x00, 0x00, 0x00, 0x3E, 0x00, 0x3E, 0x00, 0x00, 0x00, 0x00 }, // =
|
||||
{ 0x00, 0x10, 0x08, 0x04, 0x02, 0x04, 0x08, 0x10, 0x00, 0x00 }, // >
|
||||
{ 0x00, 0x1C, 0x22, 0x02, 0x04, 0x08, 0x00, 0x08, 0x00, 0x00 }, // ?
|
||||
{ 0x00, 0x1C, 0x26, 0x2A, 0x2A, 0x26, 0x20, 0x1C, 0x00, 0x00 }, // @
|
||||
{ 0x00, 0x1C, 0x22, 0x22, 0x22, 0x3E, 0x22, 0x22, 0x00, 0x00 }, // A
|
||||
{ 0x00, 0x3C, 0x22, 0x22, 0x3C, 0x22, 0x22, 0x3C, 0x00, 0x00 }, // B
|
||||
{ 0x00, 0x1C, 0x22, 0x20, 0x20, 0x20, 0x22, 0x1C, 0x00, 0x00 }, // C
|
||||
{ 0x00, 0x3C, 0x22, 0x22, 0x22, 0x22, 0x22, 0x3C, 0x00, 0x00 }, // D
|
||||
{ 0x00, 0x3E, 0x20, 0x20, 0x3C, 0x20, 0x20, 0x3E, 0x00, 0x00 }, // E
|
||||
{ 0x00, 0x3E, 0x20, 0x20, 0x3C, 0x20, 0x20, 0x20, 0x00, 0x00 }, // F
|
||||
{ 0x00, 0x1C, 0x22, 0x20, 0x2E, 0x22, 0x22, 0x1C, 0x00, 0x00 }, // G
|
||||
{ 0x00, 0x22, 0x22, 0x22, 0x3E, 0x22, 0x22, 0x22, 0x00, 0x00 }, // H
|
||||
{ 0x00, 0x3E, 0x08, 0x08, 0x08, 0x08, 0x08, 0x3E, 0x00, 0x00 }, // I
|
||||
{ 0x00, 0x02, 0x02, 0x02, 0x02, 0x22, 0x22, 0x1C, 0x00, 0x00 }, // J
|
||||
{ 0x00, 0x22, 0x24, 0x28, 0x30, 0x28, 0x24, 0x22, 0x00, 0x00 }, // K
|
||||
{ 0x00, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3E, 0x00, 0x00 }, // L
|
||||
{ 0x00, 0x22, 0x36, 0x2A, 0x22, 0x22, 0x22, 0x22, 0x00, 0x00 }, // M
|
||||
{ 0x00, 0x22, 0x22, 0x32, 0x2A, 0x26, 0x22, 0x22, 0x00, 0x00 }, // N
|
||||
{ 0x00, 0x1C, 0x22, 0x22, 0x22, 0x22, 0x22, 0x1C, 0x00, 0x00 }, // O
|
||||
{ 0x00, 0x3C, 0x22, 0x22, 0x3C, 0x20, 0x20, 0x20, 0x00, 0x00 }, // P
|
||||
{ 0x00, 0x1C, 0x22, 0x22, 0x22, 0x22, 0x22, 0x1C, 0x06, 0x00 }, // Q
|
||||
{ 0x00, 0x3C, 0x22, 0x22, 0x3C, 0x22, 0x22, 0x22, 0x00, 0x00 }, // R
|
||||
{ 0x00, 0x1C, 0x22, 0x20, 0x1C, 0x02, 0x22, 0x1C, 0x00, 0x00 }, // S
|
||||
{ 0x00, 0x3E, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00 }, // T
|
||||
{ 0x00, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x1C, 0x00, 0x00 }, // U
|
||||
{ 0x00, 0x22, 0x22, 0x22, 0x22, 0x14, 0x14, 0x08, 0x00, 0x00 }, // V
|
||||
{ 0x00, 0x22, 0x22, 0x22, 0x22, 0x2A, 0x36, 0x22, 0x00, 0x00 }, // W
|
||||
{ 0x00, 0x22, 0x22, 0x14, 0x08, 0x14, 0x22, 0x22, 0x00, 0x00 }, // X
|
||||
{ 0x00, 0x22, 0x22, 0x14, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00 }, // Y
|
||||
{ 0x00, 0x3E, 0x02, 0x04, 0x08, 0x10, 0x20, 0x3E, 0x00, 0x00 }, // Z
|
||||
{ 0x00, 0x0C, 0x08, 0x08, 0x08, 0x08, 0x08, 0x0C, 0x00, 0x00 }, // [
|
||||
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // backslash (not drawn in source font)
|
||||
{ 0x00, 0x18, 0x08, 0x08, 0x08, 0x08, 0x08, 0x18, 0x00, 0x00 }, // ]
|
||||
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // ^ (not drawn in source font)
|
||||
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // _ (not drawn in source font)
|
||||
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // ` (not drawn in source font)
|
||||
{ 0x00, 0x00, 0x00, 0x1E, 0x22, 0x22, 0x22, 0x1E, 0x00, 0x00 }, // a
|
||||
{ 0x00, 0x20, 0x20, 0x3C, 0x22, 0x22, 0x22, 0x3C, 0x00, 0x00 }, // b
|
||||
{ 0x00, 0x00, 0x00, 0x1C, 0x22, 0x20, 0x22, 0x1C, 0x00, 0x00 }, // c
|
||||
{ 0x00, 0x02, 0x02, 0x1E, 0x22, 0x22, 0x22, 0x1E, 0x00, 0x00 }, // d
|
||||
{ 0x00, 0x00, 0x00, 0x1C, 0x22, 0x3E, 0x20, 0x1C, 0x00, 0x00 }, // e
|
||||
{ 0x00, 0x0C, 0x12, 0x10, 0x3C, 0x10, 0x10, 0x10, 0x00, 0x00 }, // f
|
||||
{ 0x00, 0x00, 0x00, 0x1E, 0x22, 0x22, 0x22, 0x1E, 0x02, 0x1C }, // g
|
||||
{ 0x00, 0x20, 0x20, 0x3C, 0x22, 0x22, 0x22, 0x22, 0x00, 0x00 }, // h
|
||||
{ 0x00, 0x08, 0x00, 0x18, 0x08, 0x08, 0x08, 0x3E, 0x00, 0x00 }, // i
|
||||
{ 0x00, 0x02, 0x00, 0x06, 0x02, 0x02, 0x02, 0x02, 0x22, 0x1C }, // j
|
||||
{ 0x00, 0x20, 0x20, 0x22, 0x24, 0x38, 0x24, 0x22, 0x00, 0x00 }, // k
|
||||
{ 0x00, 0x30, 0x10, 0x10, 0x10, 0x10, 0x10, 0x0E, 0x00, 0x00 }, // l
|
||||
{ 0x00, 0x00, 0x00, 0x3C, 0x2A, 0x2A, 0x2A, 0x2A, 0x00, 0x00 }, // m
|
||||
{ 0x00, 0x00, 0x00, 0x3C, 0x22, 0x22, 0x22, 0x22, 0x00, 0x00 }, // n
|
||||
{ 0x00, 0x00, 0x00, 0x1C, 0x22, 0x22, 0x22, 0x1C, 0x00, 0x00 }, // o
|
||||
{ 0x00, 0x00, 0x00, 0x3C, 0x22, 0x22, 0x22, 0x3C, 0x20, 0x20 }, // p
|
||||
{ 0x00, 0x00, 0x00, 0x1E, 0x22, 0x22, 0x22, 0x1E, 0x02, 0x02 }, // q
|
||||
{ 0x00, 0x00, 0x00, 0x2C, 0x32, 0x20, 0x20, 0x20, 0x00, 0x00 }, // r
|
||||
{ 0x00, 0x00, 0x00, 0x1E, 0x20, 0x1C, 0x02, 0x3C, 0x00, 0x00 }, // s
|
||||
{ 0x00, 0x10, 0x10, 0x3C, 0x10, 0x10, 0x10, 0x0E, 0x00, 0x00 }, // t
|
||||
{ 0x00, 0x00, 0x00, 0x22, 0x22, 0x22, 0x22, 0x1E, 0x00, 0x00 }, // u
|
||||
{ 0x00, 0x00, 0x00, 0x22, 0x22, 0x22, 0x14, 0x08, 0x00, 0x00 }, // v
|
||||
{ 0x00, 0x00, 0x00, 0x22, 0x22, 0x2A, 0x2A, 0x14, 0x00, 0x00 }, // w
|
||||
{ 0x00, 0x00, 0x00, 0x22, 0x14, 0x08, 0x14, 0x22, 0x00, 0x00 }, // x
|
||||
{ 0x00, 0x00, 0x00, 0x22, 0x22, 0x22, 0x22, 0x1E, 0x02, 0x1C }, // y
|
||||
{ 0x00, 0x00, 0x00, 0x3E, 0x04, 0x08, 0x10, 0x3E, 0x00, 0x00 }, // z
|
||||
{ 0x00, 0x04, 0x08, 0x08, 0x10, 0x08, 0x08, 0x04, 0x00, 0x00 }, // {
|
||||
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // | (not drawn in source font)
|
||||
{ 0x00, 0x10, 0x08, 0x08, 0x04, 0x08, 0x08, 0x10, 0x00, 0x00 }, // }
|
||||
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // ~ (not drawn in source font)
|
||||
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // unused trailing tile
|
||||
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // unused trailing tile
|
||||
};
|
||||
|
||||
errorret_t fontInitDefault(void) {
|
||||
const int32_t width = (int32_t)mathNextPowTwo(
|
||||
FONT_DEFAULT_COLUMNS * FONT_DEFAULT_TILE_WIDTH
|
||||
);
|
||||
const int32_t height = (int32_t)mathNextPowTwo(
|
||||
FONT_DEFAULT_ROWS * FONT_DEFAULT_TILE_HEIGHT
|
||||
);
|
||||
|
||||
color_t *pixels = memoryAllocate(sizeof(color_t) * width * height);
|
||||
memoryZero(pixels, sizeof(color_t) * width * height);
|
||||
|
||||
for(uint16_t i = 0; i < FONT_DEFAULT_TILE_COUNT; i++) {
|
||||
const uint16_t tileX = (i % FONT_DEFAULT_COLUMNS) * FONT_DEFAULT_TILE_WIDTH;
|
||||
const uint16_t tileY = (i / FONT_DEFAULT_COLUMNS) * FONT_DEFAULT_TILE_HEIGHT;
|
||||
|
||||
for(uint8_t row = 0; row < FONT_DEFAULT_TILE_HEIGHT; row++) {
|
||||
const uint8_t bits = FONT_DEFAULT_GLYPHS[i][row];
|
||||
|
||||
for(uint8_t col = 0; col < FONT_DEFAULT_TILE_WIDTH; col++) {
|
||||
if(!((bits >> (FONT_DEFAULT_TILE_WIDTH - 1 - col)) & 1)) continue;
|
||||
pixels[((tileY + row) * width) + (tileX + col)] = COLOR_WHITE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
FONT_DEFAULT_TILESET.tileWidth = FONT_DEFAULT_TILE_WIDTH;
|
||||
FONT_DEFAULT_TILESET.tileHeight = FONT_DEFAULT_TILE_HEIGHT;
|
||||
FONT_DEFAULT_TILESET.columns = FONT_DEFAULT_COLUMNS;
|
||||
FONT_DEFAULT_TILESET.rows = FONT_DEFAULT_ROWS;
|
||||
FONT_DEFAULT_TILESET.tileCount = FONT_DEFAULT_TILE_COUNT;
|
||||
FONT_DEFAULT_TILESET.uv[0] = (float_t)FONT_DEFAULT_TILE_WIDTH / (float_t)width;
|
||||
FONT_DEFAULT_TILESET.uv[1] = (float_t)FONT_DEFAULT_TILE_HEIGHT / (float_t)height;
|
||||
|
||||
const texturedata_t data = { .rgbaColors = pixels };
|
||||
errorret_t textureResult = textureInit(
|
||||
&FONT_DEFAULT_TEXTURE, width, height, TEXTURE_FORMAT_RGBA, data
|
||||
);
|
||||
memoryFree(pixels);
|
||||
errorChain(textureResult);
|
||||
|
||||
FONT_DEFAULT.texture = &FONT_DEFAULT_TEXTURE;
|
||||
FONT_DEFAULT.tileset = &FONT_DEFAULT_TILESET;
|
||||
errorOk();
|
||||
}
|
||||
|
||||
errorret_t fontDisposeDefault(void) {
|
||||
errorChain(textureDispose(&FONT_DEFAULT_TEXTURE));
|
||||
FONT_DEFAULT.texture = NULL;
|
||||
FONT_DEFAULT.tileset = NULL;
|
||||
errorOk();
|
||||
}
|
||||
@@ -6,6 +6,7 @@
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "error/error.h"
|
||||
#include "display/texture/texture.h"
|
||||
#include "display/texture/tileset.h"
|
||||
|
||||
@@ -13,3 +14,53 @@ typedef struct {
|
||||
texture_t *texture;
|
||||
tileset_t *tileset;
|
||||
} font_t;
|
||||
|
||||
/**
|
||||
* Pixel width/height of a single default-font glyph tile. Matches the
|
||||
* glyph grid baked into the (now retired) ui/minogram.png + .dtf asset
|
||||
* pair this data was extracted from.
|
||||
*/
|
||||
#define FONT_DEFAULT_TILE_WIDTH 6
|
||||
#define FONT_DEFAULT_TILE_HEIGHT 10
|
||||
|
||||
/** Grid layout of the generated default-font texture, in tiles. */
|
||||
#define FONT_DEFAULT_COLUMNS 16
|
||||
#define FONT_DEFAULT_ROWS 6
|
||||
|
||||
/**
|
||||
* Number of glyphs defined in FONT_DEFAULT_GLYPHS (FONT_DEFAULT_COLUMNS *
|
||||
* FONT_DEFAULT_ROWS), covering the printable ASCII range starting at
|
||||
* TEXT_CHAR_START ('!') plus a couple of unused trailing tiles.
|
||||
*/
|
||||
#define FONT_DEFAULT_TILE_COUNT (FONT_DEFAULT_COLUMNS * FONT_DEFAULT_ROWS)
|
||||
|
||||
extern font_t FONT_DEFAULT;
|
||||
|
||||
/**
|
||||
* Hard coded bitmap data for the built-in default font, extracted
|
||||
* pixel-for-pixel from the original ui/minogram.png glyph atlas (alpha
|
||||
* >= 128 counts as set). Indexed [glyph][row], where glyph 0 corresponds
|
||||
* to TEXT_CHAR_START ('!') and glyphs run consecutively through the
|
||||
* printable ASCII range. Each row byte holds FONT_DEFAULT_TILE_WIDTH bit
|
||||
* flags, one per pixel column: bit (FONT_DEFAULT_TILE_WIDTH - 1) is the
|
||||
* leftmost pixel and bit 0 is the rightmost; 1 means the pixel is set,
|
||||
* 0 means it is not.
|
||||
*/
|
||||
extern const uint8_t FONT_DEFAULT_GLYPHS[FONT_DEFAULT_TILE_COUNT][
|
||||
FONT_DEFAULT_TILE_HEIGHT
|
||||
];
|
||||
|
||||
/**
|
||||
* Builds the built-in default font (texture + tileset) directly from
|
||||
* FONT_DEFAULT_GLYPHS, without going through the asset system.
|
||||
*
|
||||
* @return Either an error or success result.
|
||||
*/
|
||||
errorret_t fontInitDefault(void);
|
||||
|
||||
/**
|
||||
* Disposes of the built-in default font created by fontInitDefault.
|
||||
*
|
||||
* @return Either an error or success result.
|
||||
*/
|
||||
errorret_t fontDisposeDefault(void);
|
||||
|
||||
@@ -9,34 +9,15 @@
|
||||
#include "assert/assert.h"
|
||||
#include "util/memory.h"
|
||||
#include "display/spritebatch/spritebatch.h"
|
||||
#include "asset/asset.h"
|
||||
#include "asset/loader/display/assettextureloader.h"
|
||||
#include "asset/loader/display/assettilesetloader.h"
|
||||
#include "display/shader/shaderunlit.h"
|
||||
|
||||
font_t FONT_DEFAULT;
|
||||
|
||||
errorret_t textInit(void) {
|
||||
assetloaderinput_t input = { .texture = TEXTURE_FORMAT_RGBA };
|
||||
assetentry_t *entryTexture = assetLock(
|
||||
"ui/minogram.png", ASSET_LOADER_TYPE_TEXTURE, &input
|
||||
);
|
||||
assetentry_t *entryTileset = assetLock(
|
||||
"ui/minogram.dtf", ASSET_LOADER_TYPE_TILESET, NULL
|
||||
);
|
||||
errorChain(assetRequireLoaded(entryTexture));
|
||||
errorChain(assetRequireLoaded(entryTileset));
|
||||
|
||||
FONT_DEFAULT.texture = &entryTexture->data.texture;
|
||||
FONT_DEFAULT.tileset = &entryTileset->data.tileset;
|
||||
errorChain(fontInitDefault());
|
||||
errorOk();
|
||||
}
|
||||
|
||||
errorret_t textDispose(void) {
|
||||
FONT_DEFAULT.texture = NULL;
|
||||
FONT_DEFAULT.tileset = NULL;
|
||||
assetUnlock("ui/minogram.png");
|
||||
assetUnlock("ui/minogram.dtf");
|
||||
errorChain(fontDisposeDefault());
|
||||
errorOk();
|
||||
}
|
||||
|
||||
|
||||
@@ -12,8 +12,6 @@
|
||||
|
||||
#define TEXT_CHAR_START '!'
|
||||
|
||||
extern font_t FONT_DEFAULT;
|
||||
|
||||
/**
|
||||
* Initializes the text system.
|
||||
*
|
||||
|
||||
Reference in New Issue
Block a user