claude.md
This commit is contained in:
50
CLAUDE.md
50
CLAUDE.md
@@ -57,15 +57,22 @@ Flat C-style APIs (no classes), prefixed by subsystem. **Do not touch gameplay l
|
||||
|
||||
### Presentation Layer (`source/core/rendering/`)
|
||||
|
||||
- **Screen** (`screen.hpp/cpp`) — Singleton. Manages SDL_Window, SDL_Renderer, SDL_Texture. Dual rendering path: SDL3GPU with shaders (primary) or SDL_Renderer fallback. Handles fullscreen, zoom, aspect ratio 4:3, integer scaling, VSync. Counts FPS and updates render info text
|
||||
- **Overlay** (`overlay.hpp/cpp`) — Paints directly on the ARGB pixel buffer before presentation. Handles notifications (slide-in animation), render info display (top/bottom/off, configurable colors), and double-ESC-to-quit logic
|
||||
- **Text** (`text.hpp/cpp`) — Bitmap font renderer. Loads `.fnt` + `.gif` pairs, renders UTF-8 glyphs directly on `Uint32*` ARGB buffer. No dependency on SDL_Texture or palettes
|
||||
- **Screen** (`screen.hpp/cpp`) — Singleton. Manages SDL_Window, SDL_Renderer, SDL_Texture. Dual rendering path: SDL3GPU with shaders (primary) or SDL_Renderer fallback. Handles fullscreen, zoom, aspect ratio 4:3, integer scaling, VSync. Counts FPS and updates render info segments
|
||||
- **Overlay** (`overlay.hpp/cpp`) — Paints directly on the ARGB pixel buffer before presentation. Handles notifications (slide-in animation), animated render info (4 independent segments with per-segment anim + vertical slide state machine), persistent PAUSA indicator, and double-ESC-to-quit logic
|
||||
- **Text** (`text.hpp/cpp`) — Bitmap font renderer. Loads `.fnt` + `.gif` pairs, renders UTF-8 glyphs directly on `Uint32*` ARGB buffer. Supports `drawClipped(x, y, text, color, clip_xmin, clip_xmax, clip_ymin, clip_ymax)` for per-pixel 2D clipping (used by menu transitions)
|
||||
- **Menu** (`menu.hpp/cpp`) — Floating options menu with stack-based page navigation (root → VIDEO/AUDIO/CONTROLS). Uses ItemKind enum: Toggle/Cycle/IntRange/Submenu/KeyBind. Features: vertical expand animation on open (outQuad), horizontal slide + height interpolation on page transitions (forward/backward direction), key capture mode for remapping. Callbacks delegate to `Screen::*` / `Overlay::*` / `Options::applyAudio()` to avoid duplication
|
||||
- **SDL3GPUShader** (`sdl3gpu/`) — GPU shader backend (Vulkan/Metal). PostFX and CRT-Pi shaders with presets, supersampling (3×/6×/9×), Lanczos downscaling. Supports 4:3 aspect ratio stretch fused into the upscale pass to avoid artifacts
|
||||
|
||||
### Input Layer (`source/core/input/`)
|
||||
|
||||
- **GlobalInputs** (`global_inputs.hpp/cpp`) — Maps configurable function keys to presentation actions. Uses debounce. Returns whether a key was consumed (to suppress from game layer)
|
||||
- **Mouse** (`mouse.hpp/cpp`) — Auto-hides cursor after 3 seconds of inactivity
|
||||
- **Gamepad** (`gamepad.hpp/cpp`) — First-gamepad support with hot-plug. Poll-based each frame: D-pad/left stick (deadzone 12000) → virtual arrow keys for game movement; A/B buttons, Start, Back translate to synthetic SDL key events (F12/ESC/Enter/Backspace) when menu is open, so Director handles them exactly like keyboard
|
||||
- **KeyRemap** (`key_remap.hpp/cpp`) — Each frame, reads `Options::keys_game.*` and mirrors physical keyboard state to virtual standard scancodes (`SDL_SCANCODE_UP`/DOWN/LEFT/RIGHT). Allows full movement key remapping without touching hardcoded game code in `prota.cpp`/`mapa.cpp`
|
||||
|
||||
### Locale Layer (`source/core/locale/`)
|
||||
|
||||
- **Locale** (`locale.hpp/cpp`) — Flat key → string map loaded from YAML at boot. Keys use dot notation (`menu.items.zoom`, `notifications.pause`). Returns the key itself when missing (visible fallback for debugging). Strings live in [data/locale/ca.yaml](data/locale/ca.yaml) (Valencian, default). Designed for future multilanguage support
|
||||
|
||||
### Configuration System (`source/game/`)
|
||||
|
||||
@@ -78,6 +85,7 @@ Follows the pattern from `jaildoctors_dilemma`, persists to YAML:
|
||||
### Utilities (`source/utils/`)
|
||||
|
||||
- **utils.hpp/cpp** — `toLower()` and other helpers
|
||||
- **easing.hpp/cpp** — Easing functions for animations: `linear`, `outQuad`, `inQuad`, `inOutQuad`, `outCubic`, `inCubic`, `lerp`, `lerpInt`. Used by Menu transitions, render info slide, and segment animations
|
||||
|
||||
### Function Key Map
|
||||
|
||||
@@ -93,9 +101,13 @@ Follows the pattern from `jaildoctors_dilemma`, persists to YAML:
|
||||
| F8 | Cycle shader presets |
|
||||
| F9 | Toggle stretch filter (nearest ↔ linear) |
|
||||
| F10 | Cycle render info (off → top → bottom → off) |
|
||||
| ESC | Double-press to quit (with overlay notification) |
|
||||
| F11 | Toggle pause (blocks game thread at publishFrame + `JA_PauseMusic`/`JA_ResumeMusic`) |
|
||||
| F12 | Toggle floating options menu |
|
||||
| ESC | Double-press to quit (with overlay notification) / close menu if open |
|
||||
| Backspace | Go up one menu level / close menu if at root |
|
||||
| ↑↓←→ / Enter | Menu navigation |
|
||||
|
||||
All key bindings are configurable via `Options::keys_gui` and stored in `config.yaml`.
|
||||
All key bindings are configurable via `Options::keys_gui` and stored in `config.yaml` (section `controls:` with SDL scancode names). Game movement keys (`Options::keys_game.up/down/left/right`) can be remapped via the CONTROLS submenu — the `KeyRemap` module mirrors custom physical keys to virtual standard scancodes so hardcoded game code keeps working.
|
||||
|
||||
### Threading Model (Emulator Architecture)
|
||||
|
||||
@@ -146,7 +158,7 @@ JD8_Flip produces ABGR byte order: `0xFF000000 + R + (G<<8) + (B<<16)`. SDL text
|
||||
|
||||
| File | Content |
|
||||
|------|---------|
|
||||
| `~/.config/jailgames/aee/config.yaml` | Main config (video, audio, window, render_info, game, shader selection) |
|
||||
| `~/.config/jailgames/aee/config.yaml` | Main config: video (incl. `vsync`, `integer_scale`), audio (incl. `enabled` master + `music_*` + `sound_*`), window, render_info (incl. `show_time`), game, shader selection, controls (movement keys + menu_toggle + pause_toggle) |
|
||||
| `~/.config/jailgames/aee/postfx.yaml` | PostFX shader presets (6 defaults: CRT, NTSC, CURVED, SCANLINES, SUBTLE, CRT LIVE) |
|
||||
| `~/.config/jailgames/aee/crtpi.yaml` | CRT-Pi shader presets (4 defaults: DEFAULT, CURVED, SHARP, MINIMAL) |
|
||||
|
||||
@@ -161,19 +173,43 @@ JD8_Flip produces ABGR byte order: `0xFF000000 + R + (G<<8) + (B<<16)`. SDL text
|
||||
- `*.gif`, `*.ogg` — Original game assets (**do not modify**)
|
||||
- `fonts/8bithud.fnt + .gif` — Bitmap font for overlay (8×8, 124 glyphs, UTF-8 with accents)
|
||||
- `shaders/` — GLSL sources: `postfx.vert`, `postfx.frag`, `upscale.frag`, `downscale.frag`, `crtpi_frag.glsl`
|
||||
- `locale/ca.yaml` — UI strings in Valencian (menu titles/items/values, notifications). Edit freely; reload at restart
|
||||
- `ui/` — Reserved for future UI graphics
|
||||
|
||||
### Known Issues & Technical Debt
|
||||
|
||||
1. **gif.h cannot be included twice**: Functions are not `static` or `inline`, causing multiple definition errors. Text class uses `extern` forward declarations as workaround
|
||||
2. **Cheats are broken (`reviu`, `alone`, `obert`)**: `JI_CheatActivated` in [jinput.cpp:46](source/core/jail/jinput.cpp#L46) compares `SDL_Scancode` values (e.g. `SDL_SCANCODE_R`=21) against ASCII chars (`'r'`=114). They never match. Regression from SDL3 migration. Fix requires either scancode→char conversion in `JI_moveCheats` or storing chars directly.
|
||||
3. **No sound effects in game**: Game code never calls `JA_PlaySound*`/`JA_LoadSound` — only music via `JA_PlayMusic`/`JA_FadeOutMusic`. The SONS and VOL SONS menu items control volume of an empty channel pool. Infrastructure ready for future SFX.
|
||||
|
||||
### Pending / Ideas for Later
|
||||
|
||||
- **Gamepad**: map Y button (North) to `P` key for Pepe character selection at title screen (only input path not covered by current mapping).
|
||||
- **Menu items for game**: habitacio_inicial, piramide_inicial, vides (already in `Options::game`, not exposed).
|
||||
- **Multi-language**: add `data/locale/es.yaml` / `en.yaml` and a language selector item in menu. `Locale::load()` already handles arbitrary files.
|
||||
- **Game keys remap**: currently only UP/DOWN/LEFT/RIGHT + `menu_toggle`. Could add remap for `pause_toggle`, `keys_game.exit` (needs care with ESC double-press flow).
|
||||
- **Notification persistence**: notifications clear on each new one (`showNotification` does `notifications_.clear()`). Could queue instead.
|
||||
- **FPS counter jitter**: time segment width changes per frame (100 Hz centi updates) causes ~1-2 px horizontal jitter in centered layout. Could lock to max-width or use monospace digits.
|
||||
- **Notification messages partially hardcoded**: overlay/global_inputs/director now use Locale, but the window title (`Texts::WINDOW_TITLE`) and some game-layer strings remain hardcoded.
|
||||
|
||||
### Previously Fixed (kept for reference)
|
||||
|
||||
- **ESC double-press**: Fixed by intercepting KEY_DOWN in Director, setting atomic `esc_blocked_` immediately. `JI_KeyPressed(ESCAPE)` consults this flag. No race condition possible because Director's flag wins before game polls
|
||||
- **Overlay freeze during intros**: Fixed by threading model. Director runs independently at 60 FPS regardless of game delays. Double buffer avoids overlay smearing on re-presented frames
|
||||
- **ESC-closes-menu then closes game**: When menu closes via ESC, `esc_swallow_until_release_` flag blocks `JI_KeyPressed(ESC)` until physical key release. Cleared on ESC `KEY_UP`
|
||||
- **Backspace-closes-menu skipping cinematics**: `menu_keys_held_[SDL_SCANCODE_COUNT]` array tracks scancodes consumed by menu on KEY_DOWN; matching KEY_UP is swallowed so game polling (`JI_AnyKey`) doesn't see them. Also covers F12, Backspace, cursor keys, capture-mode keys
|
||||
- **Key remap not working after Backspace-close**: `JI_SetInputBlocked(false)` now also called when `Menu::handleKey` causes menu to close via Backspace (previously only cleared on ESC/F12 close paths)
|
||||
|
||||
### Virtual Keystates (OR'd sources)
|
||||
|
||||
`jinput.cpp` maintains `virtual_keystates[JI_VSRC_COUNT][SDL_SCANCODE_COUNT]` with two sources: `JI_VSRC_GAMEPAD` (from Gamepad::update) and `JI_VSRC_REMAP` (from KeyRemap::update). `JI_KeyPressed` returns true if either physical keystate OR any virtual source has the key set. `JI_SetInputBlocked` still overrides everything (menu open = input suppressed). `JI_SetVirtualKey(scancode, source, pressed)` is the write API — sources are independent so gamepad and keymap can't clobber each other.
|
||||
|
||||
### Variable FPS Cap
|
||||
|
||||
Director loop uses `FRAME_MS_VSYNC = 16` (60 FPS) or `FRAME_MS_NO_VSYNC = 4` (~250 FPS) depending on `Options::video.vsync`. Selected each iteration, so toggling VSync from the menu updates cap immediately. The GPU swapchain is also reconfigured via `shader_backend_->setVSync()` (IMMEDIATE/MAILBOX vs VSYNC present modes).
|
||||
|
||||
### Main Entry (`source/main.cpp`)
|
||||
|
||||
Init order: `file_setconfigfolder` → `Options::load` → `Options::loadPostFX/CrtPi` → `JG_Init` → `Screen::init` → `JD8_Init` → `JA_Init` → `Overlay::init` → `Director::init` → `Director::run()` (blocks until quit). Shutdown: `Options::save` → `Director::destroy` → `Overlay::destroy` → `JA_Quit` → `JD8_Quit` → `Screen::destroy` → `JG_Finalize`.
|
||||
Init order: `file_setconfigfolder` → `Options::load` → `Locale::load("locale/ca.yaml")` → `Options::loadPostFX/CrtPi` → `JG_Init` → `Screen::init` → `JD8_Init` → `JA_Init` → `Options::applyAudio()` → `Overlay::init` → `Menu::init` → `Director::init` (also calls `Gamepad::init()`) → `Director::run()` (blocks until quit). Shutdown: `Options::save` → `Director::destroy` → `Menu::destroy` → `Overlay::destroy` → `JA_Quit` → `JD8_Quit` → `Screen::destroy` → `JG_Finalize`.
|
||||
|
||||
The state machine (alternating `ModuleSequence` state=1 and `ModuleGame` state=0) now lives inside `Director::gameThreadFunc()`, running on the game thread.
|
||||
|
||||
Reference in New Issue
Block a user