Embed font into binary
This commit is contained in:
@@ -1,5 +1,9 @@
|
|||||||
# Dusk — Claude Code rules
|
# 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
|
## File headers
|
||||||
Every C, H, and JS file starts with:
|
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
|
## Adding a new script (JS) module
|
||||||
Dusk embeds JerryScript (`src/dusk/script/`, fetched via
|
Dusk embeds JerryScript (`src/dusk/script/`, fetched via
|
||||||
`cmake/modules/Findjerryscript.cmake`). Today only `Entity`, the
|
`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
|
or is disconnected, so clients can spawn or remove the
|
||||||
corresponding `clientplayer` entity in the world.
|
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
|
## Principles
|
||||||
|
|
||||||
- Never trust the network implicitly. Neither side (server or client)
|
- 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
|
# Sources
|
||||||
target_sources(${DUSK_LIBRARY_TARGET_NAME}
|
target_sources(${DUSK_LIBRARY_TARGET_NAME}
|
||||||
PUBLIC
|
PUBLIC
|
||||||
|
font.c
|
||||||
text.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
|
#pragma once
|
||||||
|
#include "error/error.h"
|
||||||
#include "display/texture/texture.h"
|
#include "display/texture/texture.h"
|
||||||
#include "display/texture/tileset.h"
|
#include "display/texture/tileset.h"
|
||||||
|
|
||||||
@@ -13,3 +14,53 @@ typedef struct {
|
|||||||
texture_t *texture;
|
texture_t *texture;
|
||||||
tileset_t *tileset;
|
tileset_t *tileset;
|
||||||
} font_t;
|
} 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 "assert/assert.h"
|
||||||
#include "util/memory.h"
|
#include "util/memory.h"
|
||||||
#include "display/spritebatch/spritebatch.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"
|
#include "display/shader/shaderunlit.h"
|
||||||
|
|
||||||
font_t FONT_DEFAULT;
|
|
||||||
|
|
||||||
errorret_t textInit(void) {
|
errorret_t textInit(void) {
|
||||||
assetloaderinput_t input = { .texture = TEXTURE_FORMAT_RGBA };
|
errorChain(fontInitDefault());
|
||||||
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;
|
|
||||||
errorOk();
|
errorOk();
|
||||||
}
|
}
|
||||||
|
|
||||||
errorret_t textDispose(void) {
|
errorret_t textDispose(void) {
|
||||||
FONT_DEFAULT.texture = NULL;
|
errorChain(fontDisposeDefault());
|
||||||
FONT_DEFAULT.tileset = NULL;
|
|
||||||
assetUnlock("ui/minogram.png");
|
|
||||||
assetUnlock("ui/minogram.dtf");
|
|
||||||
errorOk();
|
errorOk();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -12,8 +12,6 @@
|
|||||||
|
|
||||||
#define TEXT_CHAR_START '!'
|
#define TEXT_CHAR_START '!'
|
||||||
|
|
||||||
extern font_t FONT_DEFAULT;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initializes the text system.
|
* Initializes the text system.
|
||||||
*
|
*
|
||||||
|
|||||||
Reference in New Issue
Block a user