.SSQ
The .SSQ file format, also known as a Stage Definition file, is used in Gitaroo Man and Gitaroo Man Lives!. This file:
- Tells models & the camera where to go and what to do
- Tells the player model how to react to controller inputs, damage, etc
- Sets up sprites, such as the charge effects
- Sets up texture animations for speaking and such
Notes:
- only checked on PS2 version so far
Data types used in this article (all little-endian):
- uint32: unsigned 4-byte integer
- float32: 4-byte floating-point decimal
- char[num]: character array aka string. Strings are null/zero-terminated, and after the null byte there maybe garbage (which is ignored).
File overview
- 1 Stage
- 0 or more ImxEntry
- 0 or more XgEntry
- 0 or more ModelSetup (same as number of XgEntries, one of four types)
- 1 CameraSetup
- 1 or more LightSetup
- 1 SpritesSetup
- 0 or 1 FixedSpritesSetup
- 1 or more FixedSprite
- (might be some other sprite types possible here, but game doesn't use any)
- 0 or 1 FixedSpritesSetup
- 0 or more TexAnim
- 1 PSetup (might be particle setup, but it's always empty)
Stage
This section encompasses the entire SSQ file.
offset | size | data |
---|---|---|
+0x00 | 0x4 | Magic stamp, always 'GMSX' |
+0x04 | 0x4 | uint32 stage_header_version: always 0x1200? |
+0x08 | 0xC | all 0? Likely ignored[1] |
+0x14 | 0x10 | garbage? Likely ignored[1] |
+0x24 | 0x4 | uint32 num_xg_entries_related: Equal to num_xg_entries below. Details: All SSQ files in the game (PS2 US, PSP US) have this value equal to num_xg_entries. Messing with this value in the PS2 version affects memory allocation somehow. When experimenting with stage 1: Especially large values would crash the game from running out of memory. Values lower than num_xg_entries did not use less memory, in fact it used slightly more. Setting this value equal to num_xg_entries used the least memory and is recommended. |
+0x28 | 0x4 | uint32: num_imx_entries |
+0x2C | num_imx_entries*0x20 | ImxEntry[num_imx_entries] |
(varies) | 0x4 | uint32: num_xg_entries |
(varies) | num_xg_entries*0x30 | XgEntry[num_xg_entries] |
(varies) | (varies) | ModelSetup[num_xg_entries] |
(varies) | (varies) | CameraSetup |
(varies) | (varies) | SpritesSetup |
Afterwards, the following values are read only if stage_header_version >= 0x1100:
offset | size | data |
---|---|---|
(varies) | 0x4 | uint32: num_texanims |
(varies) | (varies) | TexAnim[num_texanims] |
Afterwards, the following values are read only if stage_header_version >= 0x1200 (not in the Japanese PS2 version):
offset | size | data |
---|---|---|
(varies) | (varies) | PSetup |
ImxEntry
An ImxEntry refer to an IMX texture file. Often contains CHARGE_BLUE/RED.IMX—the game gets them from here specifically, seeing how those two textures aren't associated with any models. An ImxEntry may also contain a texture that is associated with a model. (In one particular case, Stage 0 has an ImxEntry containing a nonexistent texture.)
offset | size | data |
---|---|---|
+0x00 | 0x10 | char[16] imxname: name of IMX file (e.g. FILENAME.IMX) |
+0x10 | 0x4 | unused (gets copied to memory, but is never used) |
+0x14 | 0x4 | unused (gets copied to memory, but value gets overwritten before game uses it) |
+0x18 | 0x8 | unused (gets copied to memory, but is never used) |
XgEntry
An XgEntry refers to an XG model file and describes what type of model it is.
offset | size | data |
---|---|---|
+0x00 | 0x10 | char[16] xgname: name of XG file (e.g. FILENAME.XG) |
+0x10 | 0x4 | uint32 is_clone: unused (copied to memory but not read back) Details: This value is 1 if this is a clone of a model from a previous XGEntry, 0 if it is not. |
+0x14 | 0x4 | uint32 clone_id: unused (copied to memory but not read back) Details: It may be that if is_clone==1, this value is the index of the XGEntry to clone from. |
+0x18 | 0x4 | unused (copied to memory but not read back) |
+0x1C | 0x4 | uint32 model_type:
|
+0x20 | 0x04 | [unused] float32, some animation length value (copied to memory but not read back) |
+0x24 | 0x04 | [unused] float32, animation speed (copied to memory but not read back) |
+0x28 | 0x04 | [unused] float32, framerate (copied to memory but not read back) |
+0x2C | 0x04 | [unused] unknown, probably junk (copied to memory but not read back) |
ModelSetup
The are 4 possible types of ModelSetup entries. The type of ModelSetup read depends on the value of the corresponding XgEntry's model_type.
NormalModelSetup
Base setup for every model to be used
offset | size | data |
---|---|---|
+0x00 | 0x4 | Magic stamp, always 'GMPX' |
+0x04 | 0x4 | uint32 modelsetup_header_version: seen 0x1400, 0x1200. Any other values? |
+0x08 | 0x4 | vaguely size-related? Likely ignored[1] |
+0x0C | 0x8 | all 0? Likely ignored[1] |
+0x14 | 0x10 | garbage? Likely ignored[1] |
+0x24 | 0x4 | uint32 numPositions |
+0x28 | 0x4 | uint32 numRotations |
+0x2C | 0x20*numPositions | ModelPosition[numPositions] |
(varies) | 0x20*numRotations | ModelRotation[numRotations] |
(varies) | 0x4 | uint32 numAnims |
(varies) | 0x30*numAnims | ModelAnim[numAnims], Only read if numAnims >= 2 |
Afterwards, the following values are read only if modelsetup_header_version >= 0x1100:
offset | size | data |
---|---|---|
(varies) | 0x4 | uint32 numScalars |
(varies) | 0x20*numScalars | ModelScalar[numScalars], only read if numScalars >= 2 |
(varies) | 0x40 | a single 0x40-byte entry |
ModelPosition
Model position in 3D space
offset | size | data |
---|---|---|
0x00 | 0x4 | float32, frame index on global timeline |
0x04 | 0x4 | float32, number of frames before the next position value, reciprocated |
0x08 | 0x4 | float32, X-coordinate |
0x0C | 0x4 | float32, Y-coordinate |
0x00 | 0x4 | float32, Z-coordinate |
0x04 | 0x4 | uint32, interpolation between positions - 1 if true |
0x08 | 0x4 | uint32, frame index * 160 |
0x0C | 0x4 | uint32, unknown |
ModelRotation
Model rotation along the XYZ axes [2]
offset | size | data |
---|---|---|
0x00 | 0x04 | float32, frame index on global timeline |
0x04 | 0x04 | float32, number of frames before the next position value, reciprocated |
0x08 | 0x10 | float32, quaternion of rotation (XYZW) |
0x18 | 0x04 | uint32, interpolation between rotations - 1 if true |
0x1C | 0x04 | uint32, frame index * 160 |
ModelAnim
Handles applying model animations
offset | size | data |
---|---|---|
+0x00 | 0x4 | float32, frame index on global timeline |
+0x04 | 0x4 | float32, number of frames before the next animation, reciprocated |
+0x08 | 0x4 | uint32, index of the appropriate animation (found in .XGM) |
+0x0C | 0x4 | uint32, 0 or 1, force starting the animation from this node's frame |
+0x10 | 0x4 | uint32, determines whether to render the model, 0 if true |
+0x14 | 0x4 | uint32, animate the model based on the game's current state (only useful with model types 1 - 3 & 5 - 8) |
+0x18 | 0x4 | uint32, loop animation |
+0x1C | 0x4 | uint32, untested |
+0x20 | 0x4 | uint32, untested |
+0x24 | 0x4 | uint32, produce a drop shadow |
+0x28 | 0x4 | uint32, unknown, possibly ignored - sometimes matches the next value |
+0x2C | 0x4 | uint32, frame index * 160 |
ModelScalar
Model scaling in 3D space, rarely used
offset | size | data |
---|---|---|
0x00 | 0x4 | float32, frame index on global timeline |
0x04 | 0x4 | float32, number of frames before the next scalar, reciprocated |
0x08 | 0x4 | float32, X-scalar |
0x0C | 0x4 | float32, Y-scalar |
0x00 | 0x4 | float32, Z-scalar |
0x04 | 0x4 | uint32, unknown |
0x08 | 0x4 | uint32, interpolation between scalars - 1 if true |
0x0C | 0x4 | uint32, unknown |
PlayerModelSetup
Sets up a model tied to player or CPU control.
First it reads everything as though it were a NormalModelSetup. Then, if the PlayerModelSetup's modelsetup_header_version >= 0x1300, it also reads the following values:
offset | size | data |
---|---|---|
+0x00 | 0x4 | uint32 num_controllables |
+0x04 | 0x30*num_controllables | Controllable[num_controllables] |
(varies) | (varies) | Connections[num_controllables] |
(varies) | 0x4*num_controllable | int32[num_controllable], event defaults, Controllable indices
If no connection matches the current state of the chosen player, the default event at the current index will get used. If the default is -1, then nothing changes. |
Controllable
Contains controller/event/button flags + analog stick angles
offset | size | data |
---|---|---|
0x00 | 0x4 | float32, minimum angle in radians |
0x04 | 0x4 | float32, maximum angle in radians |
0x08 | 0x4 | uint32, a descriptor of sorts - aligns with strum animations (1 - 3) and guarding (1 - 4) |
0x0C | 0x4 | uint32, event flag - used with bitwise '&' comparisons |
0x10 | 0x4 | uint32, index of animation to use |
0x14 | 0x4 | uint32, length of time (in frames) to hold the last frame of animation for |
0x18 | 0x4 | uint32, 0 or 1, playback direction: 1 - normal; 0 - reverse |
0x1C | 0x4 | uint32, 0 or 1, controls whether the animation can be interrupted mid-playback |
0x20 | 0x4 | uint32, unknown |
0x24 | 0x4 | uint32, 0 or 1, controls whether to choose a connected event by random |
0x28 | 0x8 | [unused] junk for padding |
Connections
Provides each respective controllable with a list of events to poll for.
offset | size | data |
---|---|---|
0x00 | 0x4 | uint32 num_connections |
0x04 | 0x4*num | uint32[num_connections], indices to corresponding Controllables |
AtkDefModelSetup
Sets up a model to be used as an attack, damage, or guard effect.
First it reads everything as though it were a NormalModelSetup. Then if the AtkDefModelSetup's modelstup_header_version >= 0x1200, it also reads the following values:
Z-length
float32 Length value along the Z-axis used to scale attack models
offset | size | data |
---|---|---|
+0x00 | 0xC | float32[3] XYZ, offset from the starting model |
+0x0C | 0xC | float32[3] XYZ, offset from the target model |
+0x18 | 0x10 | char[16], name of model to start from |
+0x28 | 0x10 | char[16], name of model set as the target to stretch to |
+0x38 | 0x4 | [unusued?] possibly could be space saved for a 32bit pointer to the starting model's 4x4 matrix |
+0x3C | 0x4 | [unusued?] possibly could be space saved for a 32bit pointer to the target model's 4x4 matrix |
SnakeModelSetup
Sets up a model to be connected between two points. In practice, it's only used for CHAIN.XG in stage 4.
A SnakeModelSetup has the same file structure as a NormalModelSetup. In addition, the game will use some hardcoded shenanigans to connect one end to the model WOOFA_F.XG and the other end to WOOFA_B.XG.
CameraSetup
Contains camera and lighting information.
offset | size | data |
---|---|---|
+0x00 | 0x4 | Magic stamp, always 'GMPX' |
+0x04 | 0x4 | uint32 camera_header_version: seen 0x1200. Any other values? |
+0x08 | 0x4 | vaguely size-related? Likely ignored[1] |
+0x0C | 0x8 | all 0? Likely ignored[1] |
+0x14 | 0x10 | garbage? Likely ignored[1] |
+0x24 | 0x40 | BaseGlobalValues |
+0x64 | 0x4 | uint32 numPositions |
+0x68 | 0x4 | uint32 numRotations |
+0x6C | 0x20*numPositions | CamPosition[numPositions] |
(varies) | 0x20*numRotations | CamRotation[numRotations] |
(varies) | 0x4 | uint32 numProjections |
(varies) | 0x20*numProjections | Projection[numProjections], but only if numProjections >= 2 |
(varies) | 0x4 | uint32 numAmbientColors |
(varies) | 0x20*numAmbientColors | AmbientColor[numAmbientColors], but only if numAmbientColors>= 2 |
(varies) | 0x4 | uint32 numLightSetups |
(varies) | (varies) | LightSetup[numLightSetups] |
Afterwards, the following values are read only if camera_header_version >= 0x1200:
offset | size | data |
---|---|---|
(varies) | 0x4 | uint32 num_unk4 |
(varies) | 0x40*num_unk4 | Num40[num_unk4], only read if num_unk4 >= 2 |
BaseGlobalValues
Contains the base values for ambient & diffuse colors along with the values used to create a projection matrix
offset | size | data |
---|---|---|
0x00 | 0x16 | float32[4], RGBA distance fog color - seemingly unused in gameplay (can be seen near the end of a loading screen, at least in 16:9) |
0x10 | 0x12 | uint32[3], base RGB material ambient color - each value between 0 and 255 |
0x1C | 0x4 | uint32, signals that the following diffuse is used (maybe?) Likely ignored[1] |
0x20 | 0x12 | uint32[3], RGB material diffuse color - each value between 0 and 255 |
0x2C | 0x4 | float32, field of view |
0x30 | 0x4 | float32, aspect ratio |
0x34 | 0x4 | float32, ZNear |
0x38 | 0x4 | float32, ZFar |
0x3C | 0x4 | uint32, unknown, causes bad rendering with values too far above 1000 |
CamPosition
Camera position in 3D space
offset | size | data |
---|---|---|
0x00 | 0x4 | float32, frame index on global timeline |
0x04 | 0x4 | float32, number of frames before the next position value, reciprocated |
0x08 | 0x12 | float32[3], XYZ coordinate |
0x14 | 0x4 | uint32, interpolation between positions - 1 if true |
0x18 | 0x4 | uint32, frame index * 160 |
0x1C | 0x4 | uint32, unknown |
CamRotation
Camera rotation along the XYZ axes
offset | size | data |
---|---|---|
0x00 | 0x4 | float32, frame index on global timeline |
0x04 | 0x4 | float32, number of frames before the next position value, reciprocated |
0x08 | 0x10 | float32[4], quaternion of rotation (XYZW) |
0x18 | 0x4 | uint32, interpolation between rotations - 1 if true |
0x1C | 0x4 | uint32, frame index * 160 |
Projection
Contains values used to generate a projection matrix
offset | size | data |
---|---|---|
0x00 | 0x4 | float32, frame index on global timeline |
0x04 | 0x4 | float32, number of frames before the next position value, reciprocated |
0x08 | 0x4 | float32, field of view |
0x0C | 0x4 | float32, aspect ratio |
0x10 | 0x4 | float32, ZNear |
0x14 | 0x4 | float32, ZFar |
0x18 | 0x4 | uint32, unknown, causes weird artifacts with values too far above 1000 |
0x1C | 0x4 | uint32, interpolation between projections - 1 if true |
AmbientColor
Manipulates the ambient color on objects with shading-enabled materials.
offset | size | data |
---|---|---|
0x00 | 0x4 | float32, frame index on global timeline |
0x04 | 0x4 | float32, number of frames before the next color value, reciprocated |
0x08 | 0x12 | float32[3], RGB color values - each value between 0 and 1 |
0x14 | 0x4 | uint32, interpolation between colors - 1 if true |
0x18 | 0x4 | uint32, frame index * 160 |
0x1C | 0x4 | uint32, unknown |
LightSetup
offset | size | data |
---|---|---|
+0x00 | 0x50 | 0x50 bytes |
+0x50 | 0x4 | Magic stamp, always 'GMLT' |
+0x54 | 0x4 | uint32 light_header_version: always 0x1000? |
+0x58 | 0x4 | vaguely size-related? Likely ignored[1] |
+0x5C | 0x8 | always 0? Likely ignored[1] |
+0x64 | 0x10 | garbage? Likely ignored[1] |
+0x74 | 0x4 | num20_gmlt |
+0x78 | 0x4 | num30_gmlt |
+0x7C | 0x20*num20_gmlt | Num20_gmlt[num20_gmlt] (only read if num20_gmlt >= 2) |
(varies) | 0x30*num30_gmlt | Num30_gmlt[num30_gmlt] (only read if num30_gmlt >= 2) |
SpritesSetup
offset | size | data |
---|---|---|
+0x00 | 0x4 | Magic stamp, always 'GMSP' |
+0x04 | 0x4 | uint32 spritesetup_header_version: seen 0x1000. Any other values? |
+0x08 | 0xC | all 0? Likely ignored[1] |
+0x14 | 0x10 | garbage? Likely ignored[1] |
+0x24 | 0x4 | uint32 num_fixedsprites |
+0x28 | 0x4 | uint32 num_unk1sprites (always 0 in all PS2 US SSQ files) |
+0x2C | 0x4 | uint32 num_unk2sprites (always 0 in all PS2 US SSQ files) |
+0x30 | 0x4 | unused, ignored by the game |
+0x34 | (varies) | FixedSpritesSetup, if num_fixedsprites > 0 |
(varies) | (varies) | Unk1SpritesSetup, if num_unk1sprites >= 0 (in practice this never happens, at least in PS2 US) |
(varies) | (varies) | Unk2SpritesSetup, if num_unk2sprites >= 0 (in practice this never happens, at least in PS2 US) |
FixedSpritesSetup
offset | size | data |
---|---|---|
+0x00 | 0x4 | Magic stamp, always 'GMF0' |
+0x04 | 0x4 | uint32 fixspritesetup_header_version: seen 0x1000. Any other values? |
+0x08 | 0xC | all 0? Likely ignored[1] |
+0x14 | 0x10 | garbage? Likely ignored[1] |
+0x18 | 0x4 | num_fixedsprites (presumably same as SpritesSetup's num_fixedsprites) |
+0x1C | 0x50 * num_fixedsprites | Num50[num_fixedsprites] |
(varies) | (varies) | FixedSprite[num_fixedsprites] |
FixedSprite
offset | size | data |
---|---|---|
+0x00 | 0x4 | Magic stamp, always 'GMSP' |
+0x04 | 0x4 | uint32 fixedsprite_header_version: seen 0x1000. Any other values? |
+0x08 | 0xC | all 0? Likely ignored[1] |
+0x14 | 0x10 | garbage? Likely ignored[1] |
+0x24 | 0x40 | 0x40 bytes |
+0x64 | 0x4 | uint32 num_30 |
+0x68 | 0x4 | uint32 numColors |
+0x6C | 0x4 | uint32 numFrames |
+0x70 | 0x30*num_30 | Num30[num_30], only read if num_30 >= 2 |
(varies) | 0x20*numColors | ColorMultipliers[numColors], only read if numColors>= 2 |
(varies) | 0x20*numFrames | SpriteFrame[numFrames], only read if numFrames >= 2 |
ColorMultipliers
Handles multiplying a sprite's color values mid-stage. Can be mainly used for fading images in/out (ex: ST08's angels).
offset | size | data |
---|---|---|
+0x00 | 0x4 | float32, frame index on global timeline |
+0x04 | 0x4 | float32, number of frames before the next multipliers, reciprocated |
+0x08 | 0x10 | float32[4], RGBA multipliers |
+0x18 | 0x4 | uint32, interpolation between multipliers - 1 if true |
+0x1C | 0x4 | [unused] uint32, frame index * 160 |
SpriteFrame
Define the bounding boxes to cut into frames of the sprite
offset | size | data |
---|---|---|
+0x00 | 0x4 | float32, frame index in the sprite sequence |
+0x04 | 0x4 | float32, number of frames before the next spriteFrame, reciprocated |
+0x08 | 0x8 | float32[2], Bottom Left XY Pixel Coordinate |
+0x10 | 0x8 | float32[2], XY Pixel offset to define the frame bounding box |
+0x18 | 0x4 | uint32, interpolation between spriteFrames - 1 if true |
+0x1C | 0x4 | [unused] uint32, frame index * 160 |
TexAnim
"Animates" a texture by cutting and pasting chosen pieces from and onto said texture. Used mainly for dialogue.
offset | size | data |
---|---|---|
+0x00 | 0x4 | Magic stamp, always '\0\0\0\0'? |
+0x04 | 0x4 | uint32, texanim_header_version: seen 0x1000. Any other values? |
+0x08 | 0xC | all 0?, Likely ignored[1] |
+0x14 | 0x10 | garbage?, Likely ignored[1] |
+0x24 | 0x8 | uint32[2], XY coordinate paste location (from top left corner) |
+0x2C | 0x18 | 0x18 bytes, includes name of texture to animate |
+0x44 | 0x4 | uint32, num_cut_outs |
+0x48 | 0x10*num_cut_outs | TexCutOut[num_cut_outs] |
(varies) | 0x4 | uint32, num_tex_frames |
(varies) | 0x10*num_tex_frames | TexFrame[num_tex_frames] |
TexCutOut
Specifies the section of a texture to cut out.
- The cut-out region includes the top and left borders (defined by the top-left coordinate), but it stops right before the bottom and right borders.
offset | size | data |
---|---|---|
+0x00 | 0x4 | float32, top left corner: X coordinate |
+0x04 | 0x4 | float32, top left corner: Y coordinate |
+0x08 | 0x4 | float32, bottom right corner: X coordinate |
+0x0C | 0x4 | float32, bottom right corner: Y coordinate |
TexFrame
offset | size | data |
---|---|---|
+0x00 | 0x4 | float32, frame position on the global timeline |
+0x04 | 0x4 | float32, number of frames before the next cutout, reciprocated |
+0x08 | 0x4 | uint32, index of the cutout to use |
+0x0C | 0x4 | uint32, unknown but always 0 |
PSetup
PSTP may stand for "Particle Setup". Non-Japanese PS2 versions of the game mention an unused particle system not far from the code that reads this section, but more investigation is needed.
offset | size | data |
---|---|---|
+0x00 | 0x4 | Magic stamp, always 'PSTP'? |
+0x04 | 0x4 | uint32 pstp_header_version: seen 0x1000. Any other values? |
+0x08 | 0xC | all 0? Likely ignored[1] |
+0x14 | 0x10 | garbage? Likely ignored[1] |
+0x18 | 0x4 | uint32 num_mystery. Always 0 in the game's SSQ files? |
+0x1C | (varies) | if num_mystery were not 0, the game might read more stuff here. |
Remarks
- ↑ 1.00 1.01 1.02 1.03 1.04 1.05 1.06 1.07 1.08 1.09 1.10 1.11 1.12 1.13 1.14 1.15 1.16 1.17 1.18 1.19 1.20 1.21 Many of these values were tested by loading Stage 1 (US PS2 version) and seeing if the game uses these values after reading them from the file (it didn't, but who knows if other stages do).
Sections tested this way: GMSX, a few GMPXs including U1 and camera, first GMLT, one of each kind of GMSP, GMF0, first TexAnim, PSTP - ↑ Orientation of the axes for rotation may vary from most graphics programs (i.e Blender).