Initial public source release
Split reusable rendering and format support into vectorail-core and vectorail-gc.
This commit is contained in:
@@ -0,0 +1,183 @@
|
||||
# GC Track and Background Reverse Notes
|
||||
|
||||
Status: linear track evaluation and the base background color table are
|
||||
implemented in the Vectorail player. Camera mode bytes, fade modes and stage
|
||||
objects still need deeper mapping.
|
||||
|
||||
## Track wire data
|
||||
|
||||
The main stage file stores track keys as big-endian records:
|
||||
|
||||
```text
|
||||
u32 count
|
||||
repeat count times:
|
||||
u32 time_ms
|
||||
f32 x
|
||||
f32 y
|
||||
f32 z
|
||||
```
|
||||
|
||||
The stage constructor `FUN_005ed4c0` loads these into 16-byte runtime entries.
|
||||
The fourth float is not read from disk: the constructor computes the physical
|
||||
length to the next point and stores it there. It also accumulates the complete
|
||||
track length at stage-object offset `+0xb0`.
|
||||
|
||||
## Confirmed evaluation
|
||||
|
||||
`FUN_005e9690` evaluates a track position at an integer timestamp. It finds the
|
||||
adjacent `time_ms` keys and computes:
|
||||
|
||||
```text
|
||||
u = (time_ms - key[i].time_ms) / (key[i+1].time_ms - key[i].time_ms)
|
||||
position = key[i] + (key[i+1] - key[i]) * u
|
||||
```
|
||||
|
||||
There is no Catmull-Rom or other spline interpolation in this path.
|
||||
|
||||
The Android symbol `GameScene::DrawWay` (`0x001b3b68`) establishes how the
|
||||
visible route itself is rendered. It clips the authored point list to the
|
||||
requested first and last timestamps, inserts linearly interpolated points at
|
||||
both exact boundaries, interpolates an RGBA color over that time interval, and
|
||||
submits the result as primitive mode 3: a line strip. It does not generate a
|
||||
camera-facing ribbon, resample by physical distance, or cull triangles.
|
||||
|
||||
`FUN_005e9990` is a separate physical-distance sampler used while constructing
|
||||
duration-note paths. It carries leftover distance between segments so those
|
||||
generated samples remain uniform over corners; it is not the normal route
|
||||
renderer.
|
||||
|
||||
The player now mirrors `DrawWay`: it uploads the original authored points plus
|
||||
the two exact timestamp intersections and draws separate behind/current and
|
||||
current/ahead line strips with endpoint color gradients. The stage values
|
||||
`backwardsDrawDist` and `forwardDrawDist` behave as seconds and are converted
|
||||
to milliseconds before comparison with track and note timestamps.
|
||||
|
||||
Dynamic `TrackDrawDist` records are step changes, not interpolation keys. The
|
||||
StageConfig forward distance remains active until the timestamp of the first
|
||||
matching record, then each record replaces it. This matters for Knight Rider:
|
||||
its only record is `128400 ms: 0`, which hides the route at the end of the song;
|
||||
using the first record before its timestamp incorrectly hid the entire future
|
||||
route from the beginning.
|
||||
|
||||
For `ac_10pt8tion_hard.dat`:
|
||||
|
||||
```text
|
||||
first track key: 0 ms, (0, 0, 0)
|
||||
second track key: 6486 ms, (0, 0, 199.985)
|
||||
draw behind: 10 s
|
||||
draw ahead: 7 s
|
||||
```
|
||||
|
||||
Treating 7/10 as world units collapses the visible rail to a tiny fraction of
|
||||
the first segment; timestamp clipping produces the expected visible range.
|
||||
|
||||
## Track colors
|
||||
|
||||
The stage config stores two RGBA colors directly after the draw-range values.
|
||||
They are used for the forward and already-travelled portions of the rail. For
|
||||
`10pt8tion_hard` they are `(255,0,128)` ahead and `(255,255,255)` behind.
|
||||
|
||||
## Base background
|
||||
|
||||
The main `.dat` contains a `ColorTable` section. Each 22-byte record is:
|
||||
|
||||
```text
|
||||
u32 time_ms
|
||||
rgba top_right
|
||||
rgba top_left
|
||||
rgba bottom_right
|
||||
rgba bottom_left
|
||||
u8 interpolate_to_next
|
||||
u8 audio_reactive_color
|
||||
```
|
||||
|
||||
`FUN_00642390` holds the active colors unless `interpolate_to_next` is set; in
|
||||
that case it linearly interpolates all four RGBA values to the following key.
|
||||
`audio_reactive_color` applies `FUN_005d9650` to each active color using the
|
||||
runtime analyser value. The Linux player now implements the exact hold versus
|
||||
interpolate selection and keeps the second mode at its neutral color factor
|
||||
until the analyser feeding `stage renderer +0x24` is ported.
|
||||
|
||||
`data/stage/2d/<song>_menu.dds` is not the gameplay background. It is a
|
||||
512x256 UI atlas whose top-left 197x197 cell is the song jacket. The player has
|
||||
a small uncompressed DDS loader, but the jacket is disabled by default and is
|
||||
only an explicit debug comparison layer (`B`). The inherited procedural
|
||||
blue/black square grid has also been removed: the base layer is now only the
|
||||
stage-authored color table before particles, visualizers and objects are drawn.
|
||||
|
||||
The remaining original scene is produced by the stage `particles`,
|
||||
`visualizer`, and `objects` sections (plus `.tumo` models), not by a single
|
||||
background bitmap. These sections are now decoded completely by
|
||||
`StagePattern`: particle records are 44 bytes, visualizer records are 12 bytes,
|
||||
and every variable-length object record is consumed through its visibility,
|
||||
movement, scaling, rotation and color-key arrays. Oshama contains 5 particle
|
||||
keys, 19 visualizer keys, 46 model names and 316 object instances; 10pt8tion
|
||||
contains 2, 28, 37 and 352 respectively. The Vectorail level data retains this
|
||||
decoded scene for the model-rendering pass.
|
||||
|
||||
The PSP package now retains all three timelines. The particle constructor at
|
||||
`FUN_005f0940` creates a 64-instance pool for every configured particle key.
|
||||
`FUN_005f0130` scales both `repeatMeasure` and `lifespanMeasure` by the active
|
||||
beat duration. Recovered spawn layouts are: type 1, a deterministic/random
|
||||
point; type 2, a screen/grid group using `groupShapeSize`; type 3, six points
|
||||
at 60-degree intervals around a circle. The PSP implementation follows these
|
||||
timing and layout rules, but substitutes geometry for the original particle
|
||||
texture resource until that resource binding is mapped.
|
||||
|
||||
The common `.tumo` container is also big-endian. Its outer count is followed,
|
||||
for each mesh, by resource names, an XYZ vertex table, eight bound floats,
|
||||
render parts, and polygon lists. A polygon corner is `u32 vertexIndex, f32 u,
|
||||
f32 v`; a separate block contains explicit line-index pairs. The player now
|
||||
triangulates polygon fans, retains line primitives, and renders stage objects
|
||||
with the original five animation channels: visibility, movement, scaling,
|
||||
linearly interpolated Euler rotation, and RGBA color. The final rotation uses
|
||||
the recovered `(-Y, X, Z)` quaternion-builder convention. Base and animated transform
|
||||
components are composed as separate matrices, matching `FUN_00643b20`;
|
||||
visibility fades use the original fixed 250 ms window. All 46 unique Oshama
|
||||
models and all 37 unique 10pt8tion models decode. `O` toggles this object layer
|
||||
for comparison.
|
||||
|
||||
For stage format versions newer than `0x29ce`, the supplemental table beginning
|
||||
at the header's `ColorTable2` offset has a relative pointer at `base + 8`. Its
|
||||
stream is `u32 objectCount` followed by one signed big-endian `int16`
|
||||
`parentIndex` per object (`-1` means no parent). `FUN_006445b0` evaluates one
|
||||
parent level and renders `parentTransform * childTransform`; parent and child
|
||||
RGBA are multiplied component-wise. Oshama uses this on 80 of 316 objects and
|
||||
10pt8tion on 87 of 352, so omitting it visibly loses grouped scale, placement,
|
||||
and opacity.
|
||||
|
||||
The object's `wireframe` byte also selects mutually exclusive model paths:
|
||||
`FUN_005dd8e0` draws polygon parts, while `FUN_005dd7f0` draws the explicit TUMO
|
||||
edge buffer. The player previously drew both. Polygon/edge selection now
|
||||
matches the flag. `FUN_00648c30` enables `D3DRS_ZENABLE` and
|
||||
`D3DRS_ZWRITEENABLE` for the complete authored object loop, then disables both
|
||||
before the rail and markers are submitted. Objects therefore depth-test one
|
||||
another in file order, but never hide gameplay geometry drawn afterwards.
|
||||
|
||||
### Per-frame object clipping
|
||||
|
||||
The stage loader also opens `data/stage/<chart>_clip.dat`. `FUN_005ed4c0`
|
||||
decodes it as:
|
||||
|
||||
```text
|
||||
u32be object_count
|
||||
u32be frame_count
|
||||
u8 visible[object_count][frame_count]
|
||||
```
|
||||
|
||||
The payload is object-major. `FUN_006445b0` selects frame
|
||||
`round(time_ms / (1000 / 60))` and skips the object when the byte is zero;
|
||||
when the table is absent or the requested frame is past its end, it falls
|
||||
back to the normal authored-visibility path. Knight Rider has 178 objects and
|
||||
7909 clip frames. Ignoring this table submits many objects which the original
|
||||
never draws in that camera frame and turns its background into overlapping
|
||||
full-screen geometry. The Linux player now applies the same test before object
|
||||
animation and submission.
|
||||
|
||||
`FUN_005dd8e0` itself supports two TUMO part types. Type `0` is a triangle
|
||||
list; type `1` is a line list. Type-1 source polygons contain exactly two
|
||||
corners. Oshama's models contain ten such parts, including one with 1498 line
|
||||
vertices; treating them as polygon fans silently discarded all of them. The
|
||||
player now keeps solid line parts separate from both triangle parts and the
|
||||
wireframe edge buffer. All Oshama and 10pt8tion models end with a zero node
|
||||
count, so an internal model hierarchy is not responsible for their transforms.
|
||||
Reference in New Issue
Block a user