forked from tsuki/openroller
212 lines
9.3 KiB
Markdown
212 lines
9.3 KiB
Markdown
# 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:
|
|
|
|
```sh
|
|
tools/build_psp.sh
|
|
```
|
|
|
|
The result is `psp/EBOOT.PBP`. Copy the runtime directory to:
|
|
|
|
```text
|
|
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:
|
|
|
|
```sh
|
|
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:
|
|
|
|
```sh
|
|
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:
|
|
|
|
```sh
|
|
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 PSP `HOME` menu 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
|
|
|
|
```text
|
|
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.
|