Feature/hd engine#25
Open
mdrobniu wants to merge 3 commits into
Open
Conversation
added 3 commits
May 9, 2026 20:29
This series layers an HD-rendering / automation feature set on top of the upstream hode engine without altering the original game logic. New modules: - hd_compositor: HD framebuffer, multi-resolution presets (HD/FullHD/QHD/4K), 16:9 widescreen with palette-derived gradient borders, sprite/background composition, prerender driver + unified console progress bar. - sprite_upscaler: chained xBRZ scalers (2x..5x with 4x via 2x*2x and 5x via nearest), MLAA edge smoothing, RAM LRU + disk cache keyed by content hash (sprite bytes + dims + flip flags + palette hash) so cached frames remain correct across screen palette changes and persist across runs. - edge_smooth: MLAA anti-aliasing applied to upscaled output. - automation_api: Unix-domain socket JSON server (input injection, frame step, screenshot, get_state, set_level) for scripted/headless testing. - test_*.py: Python regression scripts driving the automation API. Engine integration: - main.cpp: --hd, --fullhd, --4k, --hd-scale=N, --hd-wide, --hd-cache=PATH, --smooth, --automation=PATH, --prerender flags. - game.cpp: HD compositor begin/end-frame hooks in drawScreen, smooth-anim decoupled render loop (60 Hz render, 12.5 Hz logic), prerender phase that walks every sprite type x frame x flip variant plus the level's small in-gameplay PAF clips and intro cutscene, with one shared progress bar. - paf.cpp: HD frame callback path, _prerenderMode that decodes every frame full-speed without audio/display/sleep so the disk cache populates, peekFramesCount helper for sizing the unified progress bar. - video.cpp: zero-init _font in ctor. Menu and input fixes: - menu.cpp/h: keyboard binding screen learns OK / Cancel / Test sub-buttons, binding a key clears the same scancode from any other action (one key per action), Space/Enter/Tab/Backspace/Win can now be bound, fallback text labels (SP/EN/TB/BS/WN) for keys without an icon glyph. - system_sdl2.cpp: applyKeyboardControls() now keeps the original default mappings active and adds user keys on top so binding one action no longer silences the others. waitForKeyPress clears edge state on return so the user's previously held SELECT key doesn't re-fire on the next event tick. - main.cpp: wire _video->_font from _res->_fontBuffer right after loadSetupDat(), since the menu (which runs before Game::mainLoop) draws text via _video->drawStringCharacter. Portability: - intern.h: macOS branch using <libkern/OSByteOrder.h> (macOS doesn't ship glibc-style <endian.h>).
Replaces the brief README with a structured reference covering: - macOS / Linux / Windows-WSL build instructions (incl. macOS-specific notes on the libkern/OSByteOrder.h shim, Homebrew SDL2 setup, Gatekeeper, headless mode caveats). - Full CLI flag reference table (--hd, --fullhd, --4k, --hd-scale, --hd-wide, --hd-cache, --prerender, --smooth, --automation, --level, --checkpoint, --datapath, --savepath, --debug, --cheats). - Full hode.ini reference for both [engine] and [display] sections. - Display modes deep-dive: standard, HD upscaling, scale-chain table for every supported factor, widescreen 16:9 borders, smooth 60 Hz interpolated render. - Disk cache and prerender flow: on-disk layout, cache key formula (FNV-1a over decoded SPR bytes + dims + flags + palette hash), why upstream's pointer-keyed cache never produced cross-run hits. - Automation API: protocol, every JSON command (get_state, input, step, screenshot, set_level), reply schema, input bit layout, Python client example, headless testing, bundled test scripts. - Engine architecture: high-level dataflow diagram, core types, HD pipeline, PAF cutscene flow. - Source-file map: original engine files, files added by this fork, files modified vs upstream with the why. - Game world reference: levels, all 25 cutscenes, default key bindings, settings menu (incl. OK/Cancel/Test, one-key-one-action, fallback text labels for Space/Enter/Tab/Backspace/Win), cheat flag bitmask, debug bitmask. - Data formats brief: LVL/SSS/MST/PAF/SETUP/setup.cfg structure. - Troubleshooting, differences from upstream, known limitations, contributing notes, credits, license/legal.
- Promotes README.md to the canonical README and removes the bare README.txt (GitHub already prefers .md, but having two is confusing and README.txt was the upstream plain-text version). - Adds badges, a centered hero block, a 2-column highlight matrix, GitHub-flavoured admonition callouts (NOTE/TIP/IMPORTANT/CAUTION/ WARNING), collapsible <details> sections for the long lists (macOS notes, source-file map, cutscene table, data formats), and a styled footer. - Restructures with emoji-prefixed sections so the GitHub TOC reads like a proper docs landing page. - Tightens the macOS build section (Apple Silicon vs Intel, brew PATH for /opt/homebrew, lldb debug-build recipe, headless caveats). - Standardises code block language hints and table alignment.
|
I suggest you add this to your AI's context: Then you can open 50 smaller PRs instead of this one, no-one is going to review this. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
This PR adds a configurable presentation pipeline on top of the existing
hodeengine without altering the original game logic. The 12.5 Hz tick,data-file format and per-level scripted callbacks are unchanged.
It also fixes a few long-standing UX rough edges (broken keyboard rebinding
flow, font-pointer dereference in the menu, sprite cache key not surviving
across runs) and gets the engine to build cleanly on macOS.
The work is split into two commits on
feature/hd-engineso the docschurn doesn't drown the engine diff.
What's added
HD rendering pipeline (
HdCompositor,SpriteUpscaler,edge_smooth)Nxvia decompose into two passes, 6×..16× presets).
RAM (LRU, 512 MB cap) and on disk under
cache/<scale>x/.cache/paf/<scale>x/v<NN>/f<NNNN>.raw.gameplay), sampled per-screen so the borders track lighting/mood.
Decoupled smooth animation
--smoothruns render at ~60 Hz with linear sprite-positioninterpolation between game ticks. The 12.5 Hz tick is untouched, so
collision/AI/sound/scripted callbacks behave exactly as before.
Sprite + cutscene prerender
--prerenderwalks every(sprite-type, frame, flip)tuple — includingevery screen's
backgroundLvlObjectDataTable[0..7](per-screenbackground animations like trees / water) — and fast-forward decodes
the in-gameplay PAF clips (Canyon falling with cannon, Canyon falling,
Island falling) plus the level intro cutscene.
prerender so your save isn't polluted with movies you didn't watch.
inp.prevMask = inp.maskso any held keys don't fire phantompress/release events on the first gameplay tick.
Automation API (
automation_api.{h,cpp})AF_UNIXJSON socket. Newline-delimited.get_state,input(direction/action/raw),step(framestepping),
screenshot(256×192 RGB),set_level.--automationalso impliesdisable_menu,loading_screen=false,disable_paf=truefor fast scripted boot.test_*.py.macOS portability
intern.hadds an__APPLE__branch using<libkern/OSByteOrder.h>.Upstream fails to compile on macOS because clang's libc has no
glibc-style
<endian.h>.What's fixed
SpriteUpscalercache key changed from(uintptr_t)sprData(heap pointer) to a content hash: FNV-1a over decoded SPR bytes ⊕ dims ⊕ flip flags ⊕ palette FNV-1a.--hd-wideborders were "still black"--widescreenwas on, so the wide framebuffer was squished into a 4:3 logical surface and the gradient borders disappeared.--hd-widenow also sizes the SDL window 16:9.HdCompositor::beginFrame()used to pack the engine's 6-bit palette directly into 8-bit RGB without expanding. Now expands 6→8 bits before sampling forcomputeBorderColors().Video::_fontwas only assigned inGame::mainLoop, but the menu (which runs beforemainLoop) draws keycode glyphs viadrawStringCharacter. Garbage pointer + uncommon key offset = SIGSEGV. Now: zero-init inVideoctor, and wire from_res->_fontBufferright afterloadSetupDat().applyKeyboardControlsused to wipe the default mappings and only re-add arrows + ESC + the user's custom keys. So if the user boundZto Run,LCtrl/F/LAlt/G/LShift/Hall went dead — meaning the menu's Select handler (which fires onkeyReleased(SYS_INP_RUN/JUMP/SHOOT)) couldn't trigger Jump/Shoot binding. Now the defaults stay live alongside user keys.waitForKeyPressreturned,inp.prevMaskstill held the SELECT key the user pressed to enter bind mode; on the nextprocessEventsthat registered as a freshkeyReleased(SHOOT)and re-fired SELECT. NowwaitForKeyPresssnapshots current state intoprevMaskbefore returning, so no edges fire.Escduring bind closed the entire menu and quit the gamescancodeToDisplayCodenow accepts these. The bitmap font has no glyphs, sodrawKeyboardKeyCodefalls back to short text labels (SP,EN,TB,BS,WN)._keyboardControlsNum == 3is now sub-state-routed via a new_kbdButton(0=OK, 1=Cancel, 2=Test); ←/→ cycles, OK keeps changes, Cancel reverts to the snapshot taken on screen entry, Test enters live key-press visualisation (state 8) which now pollsg_system->inp.maskinstead of being hard-coded to 0.New CLI flags
--hd--hd-scale=N--fullhd--hd-scale=8--4k--hd-scale=15--hd-wide--hd-cache=PATH--prerender--smooth--automation=PATHAll also available as
[display]/[engine]keys inhode.ini(
hd_mode,hd_scale,hd_widescreen,hd_cache,smooth_anim,automation_socket).New / modified files
New:
Modified:
Backwards compatibility
setup.cfg) format unchanged — your saves keep working.HOD.PAF,*_HOD.*,SETUP.DAT) untouched.cache/directories from earlierbuilds (or any pre-existing pointer-keyed cache) won't be hit.
Delete
cache/before the first run with this PR. The engine willrebuild it.
not wired into this Makefile (only
system_sdl2.cppis built).How to test
The new code is gated behind CLI/INI flags — running without any of the
new flags is bit-identical (modulo the small portability/menu fixes) to
upstream behaviour.