9.3 KiB
OpenRoller PSP port
The first hardware target is a PSP-1004 (PSP-1000/Fat). The runtime must fit the original model's memory limits and must not depend on the extra application memory available on later PSP models.
Display contract
The arcade game uses a 720x1280 portrait canvas. OpenRoller keeps those logical coordinates on PSP and rotates the final scene into the physical 480x272 panel:
- scale: 3/8;
- resulting image: 270x480;
- physical border: one pixel on each long side;
SELECT: swap clockwise/counter-clockwise tate orientation;START: pause/resume once a stage is loaded.
This transform must remain above both the gameplay renderer and the song-select renderer. Content code should not contain PSP screen coordinates.
Gameplay geometry is submitted to the native PSP Geometry Engine as
GU_TRANSFORM_3D vertices. The 720x1280 portrait projection is preserved in
tate mode by swapping its horizontal/vertical projection extents and rolling
the camera basis by 90 degrees. The GU performs perspective division,
near/far clipping, and depth testing; CPU projection is not part of the runtime
renderer except for the original screen-relative directional-note arrow and
lower-right helper overlays.
Memory rules for PSP-1000
- Use RGB565 double framebuffers and a 16-bit depth buffer. Together they use 0xcc000 bytes of VRAM, leaving about 1.2 MiB of VRAM for resident textures.
- Never load a whole song into RAM. Audio is decoded from a bounded streaming ring and the decoded sample count is the gameplay clock.
- Keep only the current jacket resident; replace it when selection moves.
- Convert DDS/MTX textures on the host to RGB565, RGBA4444, or indexed T8 data.
- Parse arcade formats on the host. PSP consumes little-endian, aligned binary arrays and never instantiates the reverse-engineering object graph.
- Generate/copy only the visible rail window and visible notes each frame.
- Background meshes require culling and a fixed resident-memory budget.
Build
The local machine does not need a permanent PSPDEV installation. The build script uses the official PSPDEV Docker image:
tools/build_psp.sh
The result is psp/EBOOT.PBP. Copy the runtime directory to:
ms0:/PSP/GAME/OpenRoller/
When catalog.orpc is present next to EBOOT.PBP, the runtime opens the
portrait song-select screen and lazily loads the selected jacket, chart and
audio stream. It renders the real track, camera, notes, draw window, four-corner color
background, and the stage-authored .tumo objects. Object translation, scale,
rotation, color and visibility channels are evaluated on PSP; one-level parent
composition, wireframe selection, the fixed 250 ms visibility fade and sorted
alpha rendering follow the recovered game471.exe path.
Particle repeat/lifetime, spawn shape, direction, velocity and opacity are now
evaluated against the authored timeline and current BPM. The sprite resource
lookup is not ported yet, so particle instances use a small geometric marker.
Visualizer type, color and timeline are also carried by .orps; the current GE
renderer maps those types to rings, rays, bars and scanlines, but still uses a
deterministic pulse rather than the original audio analyser/FFT path. TUMO
geometry is position/color only at this stage; its material textures remain the
next background fidelity layer.
Without a catalog, the legacy stage.orps/audio.mp3 pair still works. Without
either format, the executable falls back to the synthetic smoke scene.
The host preparation script applies both per-difficulty volumes from
stage_param.dat, pre-mixes the authored BGM and SHOT WAVs with a
latency-compensated limiter, and emits one CBR 128 kbit/s, 44.1 kHz stereo MP3
per chart. The PSP runtime decodes that stream incrementally through one handle
of the native MP3 module and submits it through one SRC channel. This is
deliberately single-stream: simultaneous MP3 handles stutter on PSP-1000 while
the 3D stage is active. Reactive SHOT muting is therefore temporarily disabled
in the PSP build. The number of samples accepted by audio output is the gameplay
clock; rendering framerate does not advance song time. SE_ARRANGE, TAP_SE1 and
TAP_SE2 are host-converted to small 44.1 kHz PCM effects mixed by the same
thread.
The host-side chart normalizer is built with the regular desktop CMake build:
cmake -S . -B build
cmake --build build --target openroller-psp-pack
build/openroller-psp-pack GC/data/stage/ac_example_easy.dat stage.orps
The version-4 .orps file is a little-endian, 16-byte-aligned snapshot containing the
track, notes, camera, draw distance, background colors, pre-triangulated TUMO
vertices, stage-object records, flattened animation keys, particles,
visualizer keys and BPM changes. Each note also carries the effective runtime
type, appearance/end times, directional vector, per-note early/late/miss/mute
windows, colour and effect selector produced by the recovered
BuildTimingDataSub path. It deliberately
retains unknown note fields so discoveries made later in the reverse do not
invalidate imported charts. For ac_10pt8tion_easy.dat the full package is
about 493 KiB; the 36 source models contribute about 356 KiB of position-only
vertices and are submitted to GU directly from the loaded package.
For a ready-to-copy Memory Stick directory using the default test chart:
tools/prepare_psp_demo.sh
This creates dist/PSP/GAME/OpenRoller/. Copy that OpenRoller directory to
ms0:/PSP/GAME/. Runtime controls are:
For the 30-song library build used by the PSP-1004 port:
tools/prepare_psp_library.sh
This produces 97 difficulty packages for 10pt8ion, Oshama Scramble!,
Bonetrousle, Shadow, Planet connection, Departure, Journey,
SPACE ARCADIAN, Altale, Analysis Division, Thrash Beat, Agent Angels,
FLOWER, ADRENA, and 7 days a week, plus Satisfiction and fourteen
VOCALOID tracks: MikuMiku, The Disappearance of Hatsune Miku,
World's End Dancehall, Rolling Girl, Uraomote Lovers,
Unknown Mother-Goose, Redial, Tell Your World, Umiyuri,
Karakuri Pierrot, Dappo Rock, ECHO, Vampire, and
PaIII.SENSATION. Audio is CBR 128 kbit/s MP3 and jackets are 128x128
RGBA4444. Only the selected song's resources are resident.
The song selector has a continuously scrolling public-test notice. Its build
identifier is compiled as tsuki@kagebaito-yyyymmdd-hhmmss by
tools/build_psp.sh; each release build therefore exposes its exact timestamp
on screen.
Song-select controls are:
- D-pad up/down: previous/next song;
L/R: move five songs;CIRCLE: enter difficulty selection, then start the selected chart;- D-pad in difficulty selection: choose an available mode;
CROSS: back (or exit from the song list);SELECT: switch tate side.
The physical D-pad is rotated into the portrait coordinate system. In the default clockwise orientation physical left/up/right/down becomes logical down/left/up/right; counter-clockwise tate uses the inverse mapping.
Gameplay controls are:
- D-pad or
CROSS/CIRCLE/TRIANGLE/SQUARE: tap; SELECT: switch tate side;START: open the pause menu;L/R: seek backward/forward five seconds;START+SELECT: exit (the PSPHOMEmenu also remains available).
The pause menu contains CONTINUE, RESTART, and BACK TO MENU; CIRCLE
confirms and CROSS cancels. At chart end the current song is unloaded and the
runtime returns to song select automatically. The Linux runtime performs the
same transition after the authored track duration and reopens its selector.
Every newly pressed D-pad or face-button bit is retained as an independent
input, so simultaneous buttons can judge CRITICAL and start DUAL HOLD.
Releases terminate HOLD/DUAL HOLD, while alternating/repeated presses keep
SCRATCH and BEAT active. The recovered game471.exe judge routine uses
25% / 50% / 100% of the full early or late input-window width for GREAT / COOL /
GOOD, with GreatMinTime = 32 ms as the lower GREAT bound. Windows come from
the chart timing lists or the per-difficulty system.cfg override, including
the recovered FLICK extension. Long-note ranks use the original held-percentage
thresholds and short-tail correction. SLIDE HOLD and MERRY GO ROUND rendering
data is packaged, but their final input state machines remain unresolved in
the desktop reverse as well.
Notes fade in/out on authored beat-relative times and are submitted after the rail without depth testing. HOLD/SCRATCH/BEAT/SLIDE/DUAL bodies and matching end markers are generated as PSP GE geometry; directional arrows are fixed in screen orientation using the camera at the note timestamp, and the control helper stays in the lower-right HUD slot. The original note/effect atlases are not yet converted for PSP, so these marks remain geometric rather than using the arcade textures.
Runtime package
OpenRoller/
EBOOT.PBP
catalog.orpc
songs/
<song-id>/
easy.orps
normal.orps
hard.orps
extra.orps # when present
easy_bgm.mp3
normal_bgm.mp3
...
jacket.orpj
sounds/
adlib.pcm
tap1.pcm
tap2.pcm
catalog.orpc is a fixed-record index generated from the original
stage_param.dat; it binds display title, artist, BPM, duration, genre,
difficulty ratings and availability to a stable song key. The menu uses that
same key to resolve the chart package, per-difficulty mix and jacket paths.