Difference between revisions of "Character Battle Models"

From Chrono Compendium
Jump to: navigation, search
 
(12 intermediate revisions by 2 users not shown)
Line 1: Line 1:
 
As they exist on the game CD, Chrono Cross character battle models consist of applicable textures followed by the model geometry itself. The model data begin with a header that points to various sections, and the sections have their own subheaders and subsections.
 
As they exist on the game CD, Chrono Cross character battle models consist of applicable textures followed by the model geometry itself. The model data begin with a header that points to various sections, and the sections have their own subheaders and subsections.
  
Below Serge's, Kid's, and Guile's models are employed as examples of how the model data (vertices, shaders, animations, etc) are structured within the model file itself. Keep in mind that all data is represented in "Little Endian" Mode, meaning we humans must employ a byte-order reversal technique to understand it. For example, 06 00 00 00 means 0x06, and F8 4E 00 00 means 0x4EF8.
+
Below, the model format is detailed byte-by-byte. Keep in mind that all data in PSX games are represented in "Little Endian" Mode, meaning we humans must employ a byte-order reversal technique to understand it. For example, 06 00 00 00 means 0x06, and F8 4E 00 00 means 0x4EF8.
  
Also keep in mind that offset ranges are relative, meaning pointer tables report locations that are are a certain number of bytes from the beginning of the current header/subheader. This makes no difference in the overall file header when you're looking at the model data file as excised from the game CD, but it most certainly affects the correct interpretation of subheaders. Therefore, the offsets reported in subheader pointer tables are accompanied by (true offsets) from the beginning of the model file.  
+
Also keep in mind that offset ranges are relative, meaning pointer tables report locations that are are a certain number of bytes from the beginning of the current header/subheader. This makes no difference in the overall file header when you're looking at the model data file as excised from the game CD, but it most certainly affects the correct interpretation of subheaders.
  
=Example 1: Serge=
+
=Overall Structure=
<pre>
+
A general overview of how a given battle model's various sections fit together:
BATTLE MODEL HEADER...
+
<pre>MODEL HEADER
OFFSETS  OFFSET VALUES
+
*Section 1
00000000 06 00 00 00 20 00 00 00-F8 4E 00 00 C8 50 00 00
+
  Section 1 Header
00000010 28 52 00 00 CC A2 00 00-00 00 00 00 DC AB 00 00
+
  "Constructs"
</pre>
+
    UV Map
 +
    Vertex Pool
 +
    VDDM (Vestigial Data that Doesn't Matter)
 +
*Section 2 (Skeleton)
 +
  Section 2 Header
 +
  Skeletal Units
 +
*Section 3 (Yet Uknown; affects model shading and placement on the battlefield)
 +
*Section 4 (Animations)
 +
*Section 5 (Uknown)</pre>
  
Split into 4-byte chunks, the header can be interpreted in the following way. "Section1," etc., report the beginning offsets of each section:
+
==MODEL HEADER==
 
+
<pre>#S #S #S #S S1 S1 S1 S1 - S2 S2 S2 S2 S3 S3 S3 S3
<pre>
+
S4 S4 S4 S4 S5 S5 S5 S5 - S6 S6 S6 S6 EF EF EF EF
Header Offset Range: 00 ~ 1F
+
  Where...
6 Sections      | Section1 0x20   | Section2 0x4EF8 | Section3 0x50C8
+
  #S = Number of Sections in the model.
Section4 0x5228  | Section5 0xA2CC | Section6 N/A    | End of File 0xABDC
+
  S1 = Starting Offset of Section 1.
 +
  S2 = Starting Offset of Section 2.
 +
  S3 = Starting Offset of Section 3.
 +
  S4 = Starting Offset of Section 4.
 +
  S5 = Starting Offset of Section 5.
 +
   S6 = Starting Offset of Section 6 (usually set to zero, making it de facto nonexistent).
 +
  EF = End of File address.
 
</pre>
 
</pre>
  
 +
==Section 1==
 +
Section 1 is composed of a number of units we'll call "Constructs" for lack of a better term at the moment. Each "Construct" apparently ties together parts of the model's UV Map, Vertex Pool, the VDDM, and the skeleton defined in Section 2.<br>
 +
<br>
 +
<b>Section 1 Header</b>
 +
<pre>#C #C #C #C C1 C1 C1 C1 - C2 C2 C2 C2 ...
 +
?? ?? ?? ?? ?? ?? ?? ??
 +
  Where...
 +
  #C = Number of Constructs
 +
  C1 = Starting Offset of the First Construct, relative to the beginning of Section 1.
 +
  C2 = Starting Offset of the Second Construct, relative to the beginning of Section 1.
 +
  ... = More starting offsets of additional Constructs, relative to the beginning of Section 1.
 +
  ?? = There are four bytes of data that may be a checksum, followed by an additional four
 +
      bytes of unknown purpose.</pre>
 +
<b>Constructs</b><br>
 +
Each construct consists of a Header followed by 8-byte mode vertex assignments, 16-byte mode vertex assignments, and a UV Footer.
 
<pre>
 
<pre>
SECTION 1 HEADER...
+
Construct Header:
OFFSETS  OFFSET VALUES
+
  UM UM UM UM VP VP VP VP - VD VD VD VD
00000020 02 00 00 00 14 00 00 00-80 02 00 00 05 02 2B 04
+
  Where...
00000030 F9 00 00 00 38 03 00 00-C8 28 00 00 28 42 00 00
+
  UM = Offset into the UV Map, relative to the beginning of Section 1;
 +
      start grabbing texture pieces here.
 +
  VP = Offset into the Vertex Pool, relative to the beginning of Section 1;
 +
      start grabbing vertices here.
 +
  VD = Offset into unknown Vestigial Data (the VDDM) that can be zero'd out
 +
      with absolutely no effect on the model.
  
Section1 Offset Range: 20 ~ 4EF7
+
8-byte mode vertex assignment header format: #A #A #A #A VO VO VO VO
Section1 Header Offset Range: 20 ~ 40
+
8-byte mode vertex assignment format: NV NV JJ JJ
*Pointer 0x02 | PointerTable Start 0x14(34)| ??? 0x0280(2A0)        | * 0x042B0205
+
  Where...
??? 0xF9      | Section 1-2 0x0338(0358)  | Section 1-3 0x28C8(28E8)| Section 1-4 0x4228(4248)
+
  #A = Number of assignments that follow.
 +
  VO = Offset into the Vertex Pool, relative to the VP offset given in the Construct Header.
 +
  NV = Next NV Vertices are assigned to JJ JJ.
 +
  JJ =Index of the joint to which the body of vertices is assigned.
  
Section 1-1 (Vertex Assignment) Offset Range: 40 ~ 357
+
16-byte mode vertex assignment header format: #A #A #A #A VO VO VO VO
Section 1-1 contains vertex assignments to the battle model skeleton. Its structure consists 
+
16-byte mode vertex assigment format: NV NV 00 00 J1 J1 W1 W1 J2 J2 W2 W2
of alternating series of 8-byte mode and 16-byte mode vertex assignments that match the
+
pattern established in Section 1-3. Appended to the end of each 16-byte mode assignment series
+
is unknown data that may affect the model texture's application to the 3D data.
+
+
Section 1-1 Map...
+
0x40 ~ 0x8B: 8-byte mode vertex assignment header followed by assignments.
+
0x8C ~ 0x28B: 16-byte mode vertex assignment header followed by assignments.
+
0x28C ~ 0x2AB: Unknown data.
+
0x2AC ~ 0x2B7: 8-byte mode vertex assignment header followed by assignments.
+
0x2B8 ~ 0x343: 16-byte mode vertex assignment header followed by assignments.
+
0x343 ~ 0x357: Unknown data.
+
 
+
8-byte mode vertex assignment header format: #A #A #A #A 00 00 00 00
+
8-byte mode vertex assignment format: NV NV JJ JJ
+
 
   Where...
 
   Where...
    #A: Number of assignments that follow.
+
  #A = Number of assignments that follow.
    NV: Next NV Vertices are assigned to JJ JJ.
+
  VO = Offset into the Vertex Pool, relative to the VP offset given in the Construct Header.
    JJ: Index of the joint to which the body of vertices is assigned.
+
  NV = Next NV Vertices are assigned to J1 J1 and J2 J2.
 +
00 00 = Buffer bytes that are apparently always zero'd. If more than FF FF vertices are
 +
        assigned, they might come into play, but this should be extremely rare.
 +
  J1 = Index of the first joint to which the body of vertices is assigned.
 +
  W1 = Weight of the association between NV and J1 for animation purposes.
 +
  J2 = Index of the second joint to which the body of vertices is assigned.
 +
  W2 = Weight of the association between NV and J2 for animation purposes.
  
16-byte mode vertex assignment header format: #A #A #A #A PP PP PP PP
+
UV Footer: This tells the game engine where to look in the UV Map for the triangles and quads
16-byte mode vertex assigment format: NV NV 00 00 J1 J1 W1 W1 J2 J2 W2 W2
+
assigned to each construct.
 +
  #E #E #E #E TQ TQ ## ## UO UO UO UO...
 
   Where...
 
   Where...
    #A: Number of assignments that follow.
+
  #E = Number of 8-byte entries.
    NV: Next NV Vertices are assigned to J1 J1 and J2 J2.
+
  TQ = First two bytes in the 8-byte entry. If it's set to 0x24, the next bytes refer to
    PP: Pointer value necessary for the 16-byte mode vertex asignments. It is equivalent to the  
+
         triangles; if set to 0x2C, the next bytes refer to quads.
         length in bytes of the 8-byte mode vertex run in Section 1-3 from which the preceding
+
  ## = Number of quads or triangles assigned to the Construct.
        8-byte mode vertex assignments in this section are made.
+
  UO = UV Map offset from which to start pulling the triangles or quads.  
    J1: Index of the first joint to which the body of vertices is assigned.
+
        Relative to the UM offset given in the construct header.
    W1: Weight of the association between NV and J1 for animation purposes.
+
  ... = More TQ, ##, and UO information for each additional entry.</pre>
    J2: Index of the second joint to which the body of vertices is assigned.
+
<b>UV Map</b><br>
    W2: Weight of the association between NV and J2 for animation purposes.
+
This part of Section 1 defines how the model texture is split into pieces and wrapped around the 3D structure. It lacks a header, but is split up into distinct Triangle and Quad sections that alternate according to the specifications of the preceding Constructs.<br>
  
 +
<pre>Triangle UV data and pointer setup: U1 V1 U2 V2 U3 V3 P1 P1 - P2 P2 P3 P3
 +
  Quad UV data and pointer setup:    U1 V1 U2 V2 U3 V3 U4 V4 - P1 P1 P2 P2 P3 P3 P4 P4
 +
  Where...
 +
  U? V? are pixel coordinates on the model texture; top-left corner is 0, 0.
 +
  P? P? are pointer values that tell the game engine which polygon the texture piece is
 +
        applied to.
  
Section 1-2(UV Texture Map) Offset Range: 358 ~ 28E7
 
Section 1-2 Map...
 
0x0358 ~ 0x0FB7: Triangle UV data and pointers (264 triangles)
 
0x0FB8 ~ 0x2657: Quad UV data and pointers (362 quads)
 
0x2658 ~ 0x26E7: Triangle UV data and pointers (12 triangles)
 
0x26E8 ~ 0x28E7: Quad UV data and pointers (32 quads)
 
  Triangle UV data and pointer setup: U1 V1 U2 V2 U3 V3 P1 P1 - P2 P2 P3 P3
 
  Quad UV data and pointer setup:    U1 V1 U2 V2 U3 V3 U4 V4 - P1 P1 P2 P2 P3 P3 P4 P4
 
  ...where U? V? are pixel coordinates on the model texture; top-left corner is 0, 0.
 
  ...and P? P? are pointer values that tell the game engine which polygon the texture piece is
 
      applied to.
 
</pre>
 
 
Rules for interpreting quad pointers...
 
Rules for interpreting quad pointers...
 
Rule for Positive Pointers (as interpreted in hexadecimal)
 
Rule for Positive Pointers (as interpreted in hexadecimal)
*If you're in one of the first two columns, divide the byte pair value by 0x2, then by 0x8. This value is the index for the vertex to which the UV point is mapped.
+
*If you're reading one of the first two pointers, divide the byte pair value by 0x2, then by
*If you're in one of the last two columns, divide the byte pair value by 0x8. This value is the index for the vertex to which the UV point is mapped.
+
  0x8. This value is the index for the vertex to which the UV point is mapped.
 +
*If you're reading one of the last two pointers, divide the byte pair value by 0x8. This value  
 +
  is the index for the vertex to which the UV point is mapped.
 +
*Texture Page Rule...
 +
**If the first two vertex pointers end in a "1" instead of a "0" nybble, then
 +
  the texture piece is pulled from the RIGHT texture.
 +
**If the first two vertex pointers end in a "0" instead of a "1" nybble, then
 +
  the texture piece is pulled from the LEFT texture.
 +
 
  
Rule for Negative Pointers (as interpreted in decimal)
+
Rule for Negative Pointers (as interpreted in hexadecimal)
*If you're in one of the first two columns, divide the byte pair value by 16. Go backward that number of positions into the non-UV data.
+
*If you're in one of the first two columns, divide the byte pair value by 0x10. Go backward  
*If you're in one of the last two columns, divide the byte pair value by 8. Go backward that number of positions into the non-UV data.
+
  that number of positions into the pointer data.
 +
*If you're in one of the last two columns, divide the byte pair value by 0x8. Go backward that
 +
number of positions into the pointer data.
 +
*Texture Page Rule...
 +
**If the first two vertex pointers end in a "1" instead of a "0" nybble, then
 +
  the texture piece is pulled from the RIGHT texture.
 +
**If the first two vertex pointers end in a "0" instead of a "1" nybble, then
 +
  the texture piece is pulled from the LEFT texture.
  
 
Rules for interpreting triangle pointers...
 
Rules for interpreting triangle pointers...
 +
For triangles, switch pointers such that the first UV coordinate gets the second pointer; the
 +
second UV coordinate gets the third pointer; the third UV coordinate gets the first pointer.
 +
The pointers retain the division properties they had in their original positions.
 +
 
Rule for Positive Pointers (hex)
 
Rule for Positive Pointers (hex)
*If you're in the first column, divide the byte pair value by 0x8. This value is the vertex index.
+
*If you're reading the first pointer, divide the byte pair value by 0x8. This value is the  
*If you're in one of the last two columns, divide the byte pair value by 0x2, then by 0x8. This value is the vertex index.
+
vertex index.
 
+
*If you're in one of the last two columns, divide the byte pair value by 0x2, then by 0x8. This  
Rule for Negative Pointers (dec)
+
value is the vertex index.
*If you're in the first column, divide the byte pair value by 8. Go backward that number of positions into the non-UV data, adding an invisible position to the three extant positions.
+
*Texture Page Rule...
*If you're in one of the last two columns, divide the byte pair value by 16. Go backward that  number of positions into the non-UV data, adding an invisible position to the three extant  positions.
+
**If the last two vertex pointers end in a "1" instead of a "0" nybble, then
 
+
  the texture piece is pulled from the RIGHT texture.  
*For triangles, switch pointers such that the first UV coordinate gets the second pointer; the second UV coordinate gets the third pointer; the third UV coordinate gets the first pointer. The pointers retain the division properties they had in their original positions.
+
**If the last two vertex pointers end in a "0" instead of a "1" nybble, then
 +
  the texture piece is pulled from the LEFT texture.
  
 +
Rule for Negative Pointers (hex)
 +
*If you're reading the first pointer, divide the byte pair value by 0x8. Go backward that
 +
number of positions into the pointer data, adding an invisible position to the three extant
 +
positions.
 +
*If you're in one of the last two columns, divide the byte pair value by 0x10. Go backward that
 +
number of positions into the non-UV data, adding an invisible position to the three extant
 +
positions.
 +
*Texture Page Rule...
 +
**If the last two vertex pointers end in a "1" instead of a "0" nybble, then
 +
  the texture piece is pulled from the RIGHT texture.
 +
**If the last two vertex pointers end in a "0" instead of a "1" nybble, then
 +
  the texture piece is pulled from the LEFT texture.
 +
</pre>
 +
<b>Vertex Pool</b><br>
 +
This part of Section 1 defines the 3D structure of the model's arms, legs, etc. It lacks a header, but is split up into distinct 8-byte mode and 16-byte mode sections that alternate according to the specifications of the preceding Constructs. Note that the coordinate byte pairs should be read as signed 16 bit, fixed point 4.12 numbers.<br>
 
<pre>
 
<pre>
Section 1-3(Vertex Pool) Offset Range: 28E8 ~ 4247
 
Section 1-3 Map...
 
0x28E8 ~ 0x324F: "8-byte mode", 301 vertices
 
0x3250 ~ 0x3F6F: "16-byte mode", 210 vertices
 
0x3F70 ~ 0x3F97: "8-byte mode", 5 vertices
 
0x3F98 ~ 0x4247: "16-byte mode", 43 vertices
 
 
   "8-byte mode" setup...
 
   "8-byte mode" setup...
   ZZ ** YY ** XX ** 00 00 - ZZ ** YY ** XX ** 01 00
+
   ZZ ZZ YY YY XX XX 00 00 - ZZ ZZ YY YY XX XX 01 00
   ZZ ** YY ** XX ** 02 00 - ZZ ** YY ** XX ** 03 00
+
   ZZ ZZ YY YY XX XX 02 00 - ZZ ZZ YY YY XX XX 03 00
 
   "16-byte mode" setup...
 
   "16-byte mode" setup...
   ZZ ** YY ** XX ** 00 00 - ZZ ** YY ** XX ** 00 00
+
   ZZ ZZ YY YY XX XX 00 00 - ZZ ZZ YY YY XX XX 00 00
   ZZ ** YY ** XX ** 01 00 - ZZ ** YY ** XX ** 01 00
+
   ZZ ZZ YY YY XX XX 01 00 - ZZ ZZ YY YY XX XX 01 00
 
     Where...
 
     Where...
 
     ZZ: Magnitude of coordinate on the up & down axis on the screen plane
 
     ZZ: Magnitude of coordinate on the up & down axis on the screen plane
Line 117: Line 170:
 
         screen.
 
         screen.
 
     XX: Magnitude of coordinate on right & left axis on the screen plane
 
     XX: Magnitude of coordinate on right & left axis on the screen plane
    **: A directional reverser byte. If 00, the vertex is placed in one direction on the axis,
+
00 00: The vertex index; two bytes per vertex. They progress from 00 00 to 01 00, and so on.
        and if FF, the vertex gets placed on a coordinate the same "magnitude" but opposite 
+
        direction on that axis. (In actuality, it merely specifies whether the value is
+
        positive or negative in hex).
+
?? ??: The vertex index; two bytes per vertex.
+
  
 
     16-byte mode appears to come into play when a vertex is associated with more than one bone.
 
     16-byte mode appears to come into play when a vertex is associated with more than one bone.
Line 127: Line 176:
 
       associated with.
 
       associated with.
 
     * The second eight bytes represent the vertex's location relative to the second bone it is  
 
     * The second eight bytes represent the vertex's location relative to the second bone it is  
       associated with.
+
       associated with.</pre>
 
+
<b>VDDM: Vestigial Data that Doesn't Matter</b><br>
Section 1-4 Offset Range: 4248 ~ 4EF7
+
Section 1 ends with a curious string of bytes that is mathematically related to the number of vertices, but which does not have an apparent purpose. It can be safely zero'd out (bytes converted to all 00s) with absolutely no detectable effect on the model.<br>
Section 1-4 Pattern...
+
<pre>Format: Four-byte stride, the fourth byte always being 00.
 
  ?? ?? ?? 00 ?? ?? ?? 00 - ?? ?? ?? 00 ?? ?? ?? 00
 
  ?? ?? ?? 00 ?? ?? ?? 00 - ?? ?? ?? 00 ?? ?? ?? 00
  ?? ?? ?? 00 ?? ?? ?? 00 - ?? ?? ?? 00 ?? ?? ?? 00
+
  ?? ?? ?? 00 ?? ?? ?? 00 - ?? ?? ?? 00 ?? ?? ?? 00</pre>
  The purpose of this SubSection is unknown; all data can be safely 00'd out and not affect 
+
  Serge's model shape or animations.
+
</pre>
+
 
+
<pre>
+
SECTION 2 (Skeleton) HEADER:
+
OFFSETS OFFSET VALUES
+
0004EF8 17 00 00 00
+
 
+
0x17, or 23, bones in the skeleton. Section 2 offset range 0x4EF8 ~ 0x50C8
+
  
Bone format...
+
==Section 2==
PJ PJ PJ PJ XR XR YR YR - ZR ZR XC XC YC YC ZC ZC  
+
This is the model's "skeleton," so to speak. Bone lengths are not specified in the model structure, but rather can be inferred from the 3D coordinates given to each joint. Each
 +
"bone" consists of a parent joint and a "current joint" to which the 3D coordinates and the rotational data apply.<br>
 +
<br>
 +
<b>Section 2 Header</b><br>
 +
  NB NB NB NB
 +
  Where NB = Number of Bones<br>
 +
<br>
 +
<b>Bone Format</b>
 +
<pre>PJ PJ PJ PJ XR XR YR YR - ZR ZR XC XC YC YC ZC ZC  
 
BI BI BI BI
 
BI BI BI BI
 
  Where...  
 
  Where...  
Line 155: Line 202:
 
  YC = Y coordinate in 3D space relative to parent joint  
 
  YC = Y coordinate in 3D space relative to parent joint  
 
  ZC = Z coordinate in 3D space relative to parent joint  
 
  ZC = Z coordinate in 3D space relative to parent joint  
  BI = Current bone index (0xFFFF, or -1 if current joint and parent joint do not form a bone)
+
  BI = Current bone index (0xFFFF, or -1 if current joint and parent joint do not form a bone)</pre>
</pre>
+
==Section 3==
 
+
=Example 2: Kid=
+
 
+
<pre>
+
BATLE MODEL HEADER...
+
OFFSETS  OFFSET VALUES
+
00000000 06 00 00 00 20 00 00 00-B4 4D 00 00 C4 50 00 00
+
00000010 24 52 00 00 F0 C6 00 00-00 00 00 00 00 D0 00 00
+
</pre>
+
 
+
Split into 4-byte chunks, the header and subheaders can be interpreted in the following way. "Section1," etc., report the beginning offsets of each section:
+
 
+
<pre>
+
Header Offset Range: 00 ~ 1F
+
6 sections      | Section1 0x20    | Section2 0x4DB4  | Section3 0x50C4
+
Section4 0x5224 | Section5 0xC6F0  | Section6 N/A      | End of File 0xD000
+
 
+
 
+
SECTION 1 HEADER...
+
OFFSETS  OFFSET VALUES
+
00000020 02 00 00 00 14 00 00 00-38 02 00 00 D9 01 07 04
+
00000030 26 02 00 00 74 03 00 00-04 2C 00 00 64 42 00 00
+
 
+
Section1 Offset Range: 20 ~ 4DB3
+
Section1 Header Offset Range: 20 ~ 40
+
*Pointer 0x02 | PointerTableStart 0x14(34)| ??? 0x0238(258)        | * 0x040701D9
+
??? 0x0226    | Section 1-2 0x0374(0394)  | Section 1-3 0x2C04(2C24)| Section 1-4 0x4264(4284)
+
 
+
Section 1-1 Offset Range: 40 ~ 393
+
Section 1-2 (UV Texture Map) Offset Range: 394 ~ 2C23
+
Section 1-3 (Vertex Pool) Offset Range: 2C24 ~ 4283
+
Section 1-4 Offset Range: 4284 ~ 4DB3
+
</pre>
+
 
+
=Example 3: Guile=
+
 
+
<pre>
+
BATTLE MODEL HEADER...
+
OFFSETS  OFFSET VALUES
+
00000000 06 00 00 00 20 00 00 00-3C 4C 00 00 10 4F 00 00
+
00000010 70 50 00 00 1C E4 00 00-00 00 00 00 2C ED 00 00
+
</pre>
+
 
+
Split into 4-byte chunks, the header can be read as follows:
+
 
+
<pre>
+
Header Offset Range: 00 ~ 1F
+
6 Sections      | Section1 0x20    | Section2 0x4C3C  | Section3 0x4F10
+
Section4 0x5070  | Section5 0xE41C  | Section6 N/A    | End of File 0xED2C
+
</pre>
+
 
+
<pre>
+
SECTION 1 HEADER...
+
OFFSETS  OFFSET VALUES
+
00000020 05 00 00 00 20 00 00 00-D8 00 00 00 C6 01 00 00
+
00000030 B8 01 00 00 5C 02 00 00-4B 03 9A 04 BE 02 00 00
+
00000040 3C 03 00 00 38 2A 00 00-D0 40 00 00
+
 
+
Section 1 Offset Range: 20 ~ 4C3B
+
Section 1 Header Offset Range: 20 ~ 4B
+
*Pointer 0x05              | PointerTableStart 0x20(40)| ??? 0xD8(F8)            | ??? 0x016C
+
??? 0x01B8(1D8)            | ??? 0x025C(27C)          | * 0x049A034B            | ??? 0x02BE
+
Section 1-2 0x033C(035C)  | Section 1-3  0x2A38(2A58) | Section 1-4 0x40D0(40F0)
+
 
+
Section 1-1 Offset Range: 4C ~ 35B
+
Section 1-2 (UV Texture Map) Offset Range: 35C ~ 2A57
+
Section 1-3 (Vertex Pool) Offset Range: 2A58 ~ 40EF
+
Section 1-4 40F0 ~ 4C3B
+
</pre>
+
  
=Example 4: Flea=
+
==Section 4==
  
=Example 5: Slash=
+
==Section 5==
  
DISCLAIMER: This is still a working entry. All interpretations are subject to change with time.
+
SPECIAL THANKS: To Gemini for identifying the battle textures that led us to the models; to Luminaire85 for finding and interpreting the headers and subheaders, fine-tuning various theories, and coding the model viewer; to MDenham for figuring out how the pointers and Section 1-1 work; to Halkun, Cyberman and yaz0r for providing constant advice and guidance; and to jono for making sure this wiki entry makes sense.
  
SPECIAL THANKS: To Gemini for identifying the battle textures that led us to the models; to Luminaire85 for finding and interpreting the headers and subheaders, fine-tuning various theories, and coding the model viewer; to MDenham for figuring out how the pointers and Section 1-1 work; and to Halkun, Cyberman and yaz0r for providing constant advice and guidance.
+
''From'': [[Chrono Cross File Structure]]

Latest revision as of 01:39, 14 January 2009

As they exist on the game CD, Chrono Cross character battle models consist of applicable textures followed by the model geometry itself. The model data begin with a header that points to various sections, and the sections have their own subheaders and subsections.

Below, the model format is detailed byte-by-byte. Keep in mind that all data in PSX games are represented in "Little Endian" Mode, meaning we humans must employ a byte-order reversal technique to understand it. For example, 06 00 00 00 means 0x06, and F8 4E 00 00 means 0x4EF8.

Also keep in mind that offset ranges are relative, meaning pointer tables report locations that are are a certain number of bytes from the beginning of the current header/subheader. This makes no difference in the overall file header when you're looking at the model data file as excised from the game CD, but it most certainly affects the correct interpretation of subheaders.

Overall Structure

A general overview of how a given battle model's various sections fit together:

MODEL HEADER
*Section 1
  Section 1 Header
   "Constructs"
    UV Map
    Vertex Pool
    VDDM (Vestigial Data that Doesn't Matter)
*Section 2 (Skeleton)
  Section 2 Header
  Skeletal Units
*Section 3 (Yet Uknown; affects model shading and placement on the battlefield)
*Section 4 (Animations)
*Section 5 (Uknown)

MODEL HEADER

#S #S #S #S S1 S1 S1 S1 - S2 S2 S2 S2 S3 S3 S3 S3
S4 S4 S4 S4 S5 S5 S5 S5 - S6 S6 S6 S6 EF EF EF EF
  Where...
  #S = Number of Sections in the model.
  S1 = Starting Offset of Section 1.
  S2 = Starting Offset of Section 2.
  S3 = Starting Offset of Section 3.
  S4 = Starting Offset of Section 4.
  S5 = Starting Offset of Section 5.
  S6 = Starting Offset of Section 6 (usually set to zero, making it de facto nonexistent).
  EF = End of File address.

Section 1

Section 1 is composed of a number of units we'll call "Constructs" for lack of a better term at the moment. Each "Construct" apparently ties together parts of the model's UV Map, Vertex Pool, the VDDM, and the skeleton defined in Section 2.

Section 1 Header

#C #C #C #C C1 C1 C1 C1 - C2 C2 C2 C2 ... 
?? ?? ?? ?? ?? ?? ?? ??
  Where...
  #C = Number of Constructs
  C1 = Starting Offset of the First Construct, relative to the beginning of Section 1.
  C2 = Starting Offset of the Second Construct, relative to the beginning of Section 1.
  ... = More starting offsets of additional Constructs, relative to the beginning of Section 1.
  ?? = There are four bytes of data that may be a checksum, followed by an additional four 
       bytes of unknown purpose.

Constructs
Each construct consists of a Header followed by 8-byte mode vertex assignments, 16-byte mode vertex assignments, and a UV Footer.

Construct Header:
  UM UM UM UM VP VP VP VP - VD VD VD VD 
  Where...
  UM = Offset into the UV Map, relative to the beginning of Section 1; 
       start grabbing texture pieces here.
  VP = Offset into the Vertex Pool, relative to the beginning of Section 1; 
       start grabbing vertices here.
  VD = Offset into unknown Vestigial Data (the VDDM) that can be zero'd out
       with absolutely no effect on the model.

8-byte mode vertex assignment header format: #A #A #A #A VO VO VO VO
8-byte mode vertex assignment format: NV NV JJ JJ
   Where...
   #A = Number of assignments that follow.
   VO = Offset into the Vertex Pool, relative to the VP offset given in the Construct Header.
   NV = Next NV Vertices are assigned to JJ JJ.
   JJ =Index of the joint to which the body of vertices is assigned.

16-byte mode vertex assignment header format: #A #A #A #A VO VO VO VO
16-byte mode vertex assigment format: NV NV 00 00 J1 J1 W1 W1 J2 J2 W2 W2
   Where...
   #A = Number of assignments that follow.
   VO = Offset into the Vertex Pool, relative to the VP offset given in the Construct Header.
   NV = Next NV Vertices are assigned to J1 J1 and J2 J2.
00 00 = Buffer bytes that are apparently always zero'd. If more than FF FF vertices are
        assigned, they might come into play, but this should be extremely rare.
   J1 = Index of the first joint to which the body of vertices is assigned.
   W1 = Weight of the association between NV and J1 for animation purposes.
   J2 = Index of the second joint to which the body of vertices is assigned.
   W2 = Weight of the association between NV and J2 for animation purposes.

UV Footer: This tells the game engine where to look in the UV Map for the triangles and quads 
assigned to each construct.
   #E #E #E #E TQ TQ ## ## UO UO UO UO...
   Where...
   #E = Number of 8-byte entries.
   TQ = First two bytes in the 8-byte entry. If it's set to 0x24, the next bytes refer to
        triangles; if set to 0x2C, the next bytes refer to quads.
   ## = Number of quads or triangles assigned to the Construct.
   UO = UV Map offset from which to start pulling the triangles or quads. 
        Relative to the UM offset given in the construct header.
  ... = More TQ, ##, and UO information for each additional entry.

UV Map
This part of Section 1 defines how the model texture is split into pieces and wrapped around the 3D structure. It lacks a header, but is split up into distinct Triangle and Quad sections that alternate according to the specifications of the preceding Constructs.

Triangle UV data and pointer setup: U1 V1 U2 V2 U3 V3 P1 P1 - P2 P2 P3 P3
  Quad UV data and pointer setup:     U1 V1 U2 V2 U3 V3 U4 V4 - P1 P1 P2 P2 P3 P3 P4 P4
   Where... 
   U? V? are pixel coordinates on the model texture; top-left corner is 0, 0.
   P? P? are pointer values that tell the game engine which polygon the texture piece is 
         applied to.

Rules for interpreting quad pointers...
Rule for Positive Pointers (as interpreted in hexadecimal)
*If you're reading one of the first two pointers, divide the byte pair value by 0x2, then by
  0x8. This value is the index for the vertex to which the UV point is mapped.
*If you're reading one of the last two pointers, divide the byte pair value by 0x8. This value 
  is the index for the vertex to which the UV point is mapped.
*Texture Page Rule...
**If the first two vertex pointers end in a "1" instead of a "0" nybble, then
  the texture piece is pulled from the RIGHT texture. 
**If the first two vertex pointers end in a "0" instead of a "1" nybble, then 
  the texture piece is pulled from the LEFT texture.


Rule for Negative Pointers (as interpreted in hexadecimal)
*If you're in one of the first two columns, divide the byte pair value by 0x10. Go backward 
 that number of positions into the pointer data.
*If you're in one of the last two columns, divide the byte pair value by 0x8. Go backward that
 number of positions into the pointer data.
*Texture Page Rule...
**If the first two vertex pointers end in a "1" instead of a "0" nybble, then
  the texture piece is pulled from the RIGHT texture. 
**If the first two vertex pointers end in a "0" instead of a "1" nybble, then 
  the texture piece is pulled from the LEFT texture.

Rules for interpreting triangle pointers...
 For triangles, switch pointers such that the first UV coordinate gets the second pointer; the 
 second UV coordinate gets the third pointer; the third UV coordinate gets the first pointer. 
 The pointers retain the division properties they had in their original positions.

Rule for Positive Pointers (hex)
*If you're reading the first pointer, divide the byte pair value by 0x8. This value is the 
 vertex index.
*If you're in one of the last two columns, divide the byte pair value by 0x2, then by 0x8. This 
 value is the vertex index.
*Texture Page Rule...
**If the last two vertex pointers end in a "1" instead of a "0" nybble, then
  the texture piece is pulled from the RIGHT texture. 
**If the last two vertex pointers end in a "0" instead of a "1" nybble, then 
  the texture piece is pulled from the LEFT texture.

Rule for Negative Pointers (hex)
*If you're reading the first pointer, divide the byte pair value by 0x8. Go backward that 
 number of positions into the pointer data, adding an invisible position to the three extant 
 positions.
*If you're in one of the last two columns, divide the byte pair value by 0x10. Go backward that 
 number of positions into the non-UV data, adding an invisible position to the three extant 
 positions.
*Texture Page Rule...
**If the last two vertex pointers end in a "1" instead of a "0" nybble, then
  the texture piece is pulled from the RIGHT texture. 
**If the last two vertex pointers end in a "0" instead of a "1" nybble, then 
  the texture piece is pulled from the LEFT texture.

Vertex Pool
This part of Section 1 defines the 3D structure of the model's arms, legs, etc. It lacks a header, but is split up into distinct 8-byte mode and 16-byte mode sections that alternate according to the specifications of the preceding Constructs. Note that the coordinate byte pairs should be read as signed 16 bit, fixed point 4.12 numbers.

  "8-byte mode" setup...
   ZZ ZZ YY YY XX XX 00 00 - ZZ ZZ YY YY XX XX 01 00
   ZZ ZZ YY YY XX XX 02 00 - ZZ ZZ YY YY XX XX 03 00
  "16-byte mode" setup...
   ZZ ZZ YY YY XX XX 00 00 - ZZ ZZ YY YY XX XX 00 00
   ZZ ZZ YY YY XX XX 01 00 - ZZ ZZ YY YY XX XX 01 00
    Where...
    ZZ: Magnitude of coordinate on the up & down axis on the screen plane
    YY: Magnitude of coordinate on depth axis; toward or away from you with respect to the 
        screen.
    XX: Magnitude of coordinate on right & left axis on the screen plane
 00 00: The vertex index; two bytes per vertex. They progress from 00 00 to 01 00, and so on.

    16-byte mode appears to come into play when a vertex is associated with more than one bone.
    * The first eight bytes represent the vertex's location relative to the first bone it is 
      associated with.
    * The second eight bytes represent the vertex's location relative to the second bone it is 
      associated with.

VDDM: Vestigial Data that Doesn't Matter
Section 1 ends with a curious string of bytes that is mathematically related to the number of vertices, but which does not have an apparent purpose. It can be safely zero'd out (bytes converted to all 00s) with absolutely no detectable effect on the model.

Format: Four-byte stride, the fourth byte always being 00.
 ?? ?? ?? 00 ?? ?? ?? 00 - ?? ?? ?? 00 ?? ?? ?? 00
 ?? ?? ?? 00 ?? ?? ?? 00 - ?? ?? ?? 00 ?? ?? ?? 00

Section 2

This is the model's "skeleton," so to speak. Bone lengths are not specified in the model structure, but rather can be inferred from the 3D coordinates given to each joint. Each "bone" consists of a parent joint and a "current joint" to which the 3D coordinates and the rotational data apply.

Section 2 Header

 NB NB NB NB 
 Where NB = Number of Bones


Bone Format

PJ PJ PJ PJ XR XR YR YR - ZR ZR XC XC YC YC ZC ZC 
BI BI BI BI
 Where... 
 PJ = Index of parent joint (0xFFFF, or -1 if this bone has no parent joint) 
 XR = X rotation (range: 0XF000 ~ 0xFFF, or -4096 to 4095, where 4096 = 360 degrees) 
 YR = Y rotation (range: 0XF000 ~ 0xFFF, or -4096 to 4095, where 4096 = 360 degrees) 
 ZR = Z rotation (range: 0XF000 ~ 0xFFF, or -4096 to 4095, where 4096 = 360 degrees) 
 XC = X coordinate in 3D space relative to parent joint 
 YC = Y coordinate in 3D space relative to parent joint 
 ZC = Z coordinate in 3D space relative to parent joint 
 BI = Current bone index (0xFFFF, or -1 if current joint and parent joint do not form a bone)

Section 3

Section 4

Section 5

SPECIAL THANKS: To Gemini for identifying the battle textures that led us to the models; to Luminaire85 for finding and interpreting the headers and subheaders, fine-tuning various theories, and coding the model viewer; to MDenham for figuring out how the pointers and Section 1-1 work; to Halkun, Cyberman and yaz0r for providing constant advice and guidance; and to jono for making sure this wiki entry makes sense.

From: Chrono Cross File Structure