|
|
| (19 intermediate revisions by 4 users not shown) |
| Line 1: |
Line 1: |
| '''[[OBD_Talk:CRSA|ssg's version is here]]'''
| | {{OBD_File_Header | type=CRSA | prev=CONS | next=DOOR | name=Corpse Array | family=Level | align=center | onistuff=crsa}} |
| ==CRSA - Corpse Array== | |
| Related :
| |
| [[OBD:File types/Level|Level files]]
| |
| [[OBD:Oni Binary Data|Oni Binary Data]]
| |
|
| |
|
| The array consists of
| |
| *a 32-byte header
| |
| *a number of fixed-size corpse chunks (1100 bytes each)
| |
| *a number of unused corpse chunks integrally set to 0 (1100 bytes each)
| |
| (used chunks and unused chunks add up to the capacity of the array : 20 chunks in the original binaries)
| |
| *the resulting file is completed to a 32-byte multiple with the 0xADDE blank filler
| |
|
| |
|
| Since the capacity of the array is always the same (20 corpses), CRSA files are all the same size (0x5620 bytes) : actual arrays take up 0x5610 bytes, and the last 16 bytes are filled with the blank filler 0xADDE.
| | The first image shows the header and the beginning of the first element. The second image the end of it. |
| ===Header===
| | |
| ;What's in the header?
| | |
| *File ID and level ID as usual : 4 bytes each
| | [[image:crsa_a.gif]] |
| *A blank field filled with 0xADDE (dead) : 12 bytes
| |
| *Array size (number of corpses) duplicated : 2*4 bytes
| |
| *Array capacity (maximum number of corpses, always 20) : another 4 bytes
| |
| The total size of a header is thus 0x20 = 32 bytes.
| |
| ;Example:'''00565-.CRSA''' in '''level3_Final.dat'''
| |
| {|border=1 cellspacing=0
| |
| |+Header
| |
| !Offset
| |
| !Raw hex/string
| |
| !Value
| |
| !Meaning
| |
| |-
| |
| |0x00
| |
| |01 35 02 00
| |
| |565
| |
| |File ID for 00565-.CRSA
| |
| |-
| |
| |0x04
| |
| |01 00 00 06
| |
| |3
| |
| |Level ID
| |
| |-
| |
| |0x08<br>0x0C<br>0x010
| |
| |AD DE AD DE<br>AD DE AD DE<br>AD DE AD DE
| |
| |DEAD
| |
| |blank filler
| |
| |-
| |
| |0x14
| |
| |11 00 00 00
| |
| |17
| |
| |17 corpses (array size)
| |
| |-
| |
| |0x18
| |
| |11 00 00 00
| |
| |17
| |
| |17 corpses (array size again)
| |
| |-
| |
| |0x1C
| |
| |14 00 00 00
| |
| |20
| |
| |Room for 20 corpses (array capacity)
| |
| |}
| |
|
| |
|
| ===Corpse chunks===
| |
| They follow the header directly
| |
|
| |
|
| ;What's in a corpse?
| | [[image:crsa_m.gif]] |
| *A space for notes (160 bytes) : often the name of the file the corpse was taken from when packing the array.
| |
| *A link to the [[OBD:ONCC|ONCC]] (model that should be used for the corpse) : that's 4 bytes as usual.
| |
| *Then, 19 bones, each of them defined by absolute orientation and position (unlike in a TRAM, where orientations are relative)<br>Every bone is (3x3 + 3)x4 = 48 bytes, so that's 19x48 = 912 bytes.
| |
| *Finally, an axis-aligned bounding box (2x3x4 = 24 bytes)
| |
| The total size of a corpse is thus 1100 bytes.
| |
|
| |
|
| ;What's in a bone?:The absolute orientation is defined in a "heavy" way ''via'' an orthonormal trihedron :
| |
| :three 3D vectors '''x''', '''y''' and '''z''', each of length 1, at right angles with each other, and ordered "directly"
| |
| :(like Oni's world axes : if '''x''' points left and '''y''' points up then '''z''' points to ''front'', not back).
| |
| :Each one of those vectors is stored as 3 floats (3x4 bytes), first '''x''', then '''y''', then '''z''' (so 3x3x4 = 36 bytes in total).
| |
| :The absolute position '''R''' of a bone (of its parent node, actually) is stored as 3 floats right after the orientation trihedron.
| |
| :That's another 12 bytes, so 48 bytes in total.
| |
| Reminder : the 2nd coordinate of '''R''' aka ''y'' is the height; same for '''x''', '''y''' and '''z'''.
| |
|
| |
|
| ;Example:first corpse of '''00565-.CRSA''' in '''level3_Final.dat'''.
| | {{Table}} |
| :Offsets are measured from the start of the corpse chunk : add 0x20 for the offset from the start of file.
| | {{OBDth}} |
| {|border=1 cellspacing=0 | | {{OBDtr| 0x000 | res_id |FF0000| 01 35 02 00 | 565 | 00565-.CRSA }} |
| |+Notes and ONCC link | | {{OBDtr| 0x004 | lev_id |FFFF00| 01 00 00 06 | 3 | level 3 }} |
| !Offset
| | {{OBDtr| 0x008 | char[12] |00FF00| AD DE | dead | padding }} |
| !Raw hex/string
| | {{OBDtr| 0x014 | uint32 |00FFFF| 11 00 00 00 | 17 | number of "fixed" corpses }} |
| !Value
| | {{OBDtr| 0x018 | uint32 |FF00FF| 11 00 00 00 | 17 | number of "used" corpses }} |
| !Meaning
| | {{OBDtr| 0x01C | uint32 |FF8000| 14 00 00 00 | 20 | array capacity; always the same in original Oni }} |
| |- | | {{OBDtrBK}} |
| |0x00 | | {{OBDtr2|0x000 | char[32]|FFC8C8| _lvl_3_Intro_TCL_A_corpse.dat| ignored; the name of the source file }} |
| |colspan=2|_lvl_3_Intro_TCL_A_corpse.dat | | {{OBDtr|0x020 | uint[32] |FFC8C8| | | node list; runtime only }} |
| |probably the name of the source file | | {{OBDtr| 0x0A0 | link |FFFFC8| 01 36 02 00 | 566 | link to 00566-TCTF_lite_1.[[OBD:ONCC|ONCC]] }} |
| |- | | |- ALIGN=CENTER VALIGN=TOP |
| |0xA0 | | |0x0A4||matrix|| |
| |01 36 02 00 | | {|border=1 cellspacing=0 style="white-space:nowrap" |
| |566 | | |-BGCOLOR="#C8FFC8" |
| |Link to 00566-TCTF_lite_1.[[OBD:ONCC|ONCC]] | | |C1 74 66 3F||00 78 3E 3D||45 AB DD 3E |
| | |-BGCOLOR="#C8FFC8" |
| | |A6 8B 7D 3D||19 73 7F BF||EE 67 B0 BC |
| | |-BGCOLOR="#C8FFC8" |
| | |03 AE DC 3E||82 2C 3D 3D||8D B2 66 BF |
| | |-BGCOLOR="#C8FFC8" |
| | |C5 FA E7 41||2E 2B CB C1||58 B4 45 C1 |
| |} | | |} |
| {|border=1 cellspacing=0 | | | |
| |+Bone orientation and position | | {|border=1 cellspacing=0 style="white-space:nowrap" |
| !Offset
| | |0.900219||0.046501||0.432947 |
| !Bone
| |
| !Raw hex
| |
| !Value/Meaning
| |
| |- | | |- |
| |0xA4 | | |0.061901||-0.997850||0.021534 |
| |Pelvis
| |
| |C1 74 66 3F 00 78 3E 3D 45 AB DD 3E<br>A6 8B 7D 3D 19 73 7F BF EE 67 B0 BC<br>03 AE DC 3E 82 2C 3D 3D 8D B2 66 BF<br>C5 FA E7 41 2E 2B CB C1 58 B4 45 C1
| |
| |'''x''' = (0.900219, 0.046501, 0.432947)<br>'''y''' = (0.061901, -0.997850, -0.021534)<br>'''z''' = (0.431015, 0.0461850, -0.901162)<br>'''R''' = (28.997446, -25.396084, -12.356529)
| |
| |- | | |- |
| |0xD4 | | |0.431015||0.0461850||-0.901162 |
| |Lt Thigh | |
| |... | |
| |'''x''' = (, , )<br>'''y''' = (, , )<br>'''z''' = (, , )<br>'''R''' = (, , )
| |
| |- | | |- |
| |0x104 | | |28.997446||-25.396084||-12.356529 |
| |Lt Calf | | |} |
| |... | | |ALIGN=LEFT|transform matrix for the pelvis (in world space) |
| |'''x''' = (, , )<br>'''y''' = (, , )<br>'''z''' = (, , )<br>'''R''' = (, , ) | | {{OBDtrBK|0xD4-0x434 : transform matrices for the other 18 bones}} |
| |- | | |- ALIGN=CENTER VALIGN=TOP |
| |0x134 | | |0x434||AABB|| |
| |Lt Foot | | {|border=1 cellspacing=0 style="white-space:nowrap" |
| |... | | |-BGCOLOR="#C8FFFF" |
| |'''x''' = (, , )<br>'''y''' = (, , )<br>'''z''' = (, , )<br>'''R''' = (, , ) | | |D4 22 8C 41||95 50 E9 C1||BC 31 9C C1 |
| |- | | |-BGCOLOR="#C8FFFF" |
| |0x164 | | |75 E6 14 42||2E 20 B1 C1||07 B1 D3 C0 |
| |Rt Thigh | | |} |
| |... | | | |
| |'''x''' = (, , )<br>'''y''' = (, , )<br>'''z''' = (, , )<br>'''R''' = (, , ) | | {|border=1 cellspacing=0 style="white-space:nowrap" |
| | |17.517006||-29.164347||-19.524284 |
| |- | | |- |
| |0x194 | | |37.225056||-22.140713||-6.615360 |
| |Rt Calf
| |
| |...
| |
| |'''x''' = (, , )<br>'''y''' = (, , )<br>'''z''' = (, , )<br>'''R''' = (, , )
| |
| |-
| |
| |0x1C4
| |
| |Rt Foot
| |
| |...
| |
| |'''x''' = (, , )<br>'''y''' = (, , )<br>'''z''' = (, , )<br>'''R''' = (, , )
| |
| |-
| |
| |0x1F4
| |
| |Mid
| |
| |...
| |
| |'''x''' = (, , )<br>'''y''' = (, , )<br>'''z''' = (, , )<br>'''R''' = (, , )
| |
| |-
| |
| |0x224
| |
| |Chest
| |
| |...
| |
| |'''x''' = (, , )<br>'''y''' = (, , )<br>'''z''' = (, , )<br>'''R''' = (, , )
| |
| |-
| |
| |0x254
| |
| |Neck
| |
| |...
| |
| |'''x''' = (, , )<br>'''y''' = (, , )<br>'''z''' = (, , )<br>'''R''' = (, , )
| |
| |-
| |
| |0x284
| |
| |Head
| |
| |...
| |
| |'''x''' = (, , )<br>'''y''' = (, , )<br>'''z''' = (, , )<br>'''R''' = (, , )
| |
| |-
| |
| |0x2B4
| |
| |Lt Shoulder
| |
| |...
| |
| |'''x''' = (, , )<br>'''y''' = (, , )<br>'''z''' = (, , )<br>'''R''' = (, , ) | |
| |- | |
| |0x2E4
| |
| |Lt Arm
| |
| |...
| |
| |'''x''' = (, , )<br>'''y''' = (, , )<br>'''z''' = (, , )<br>'''R''' = (, , ) | |
| |- | |
| |0x314
| |
| |Lt Wrist
| |
| |...
| |
| |'''x''' = (, , )<br>'''y''' = (, , )<br>'''z''' = (, , )<br>'''R''' = (, , )
| |
| |-
| |
| |0x344
| |
| |Lt Fist
| |
| |...
| |
| |'''x''' = (, , )<br>'''y''' = (, , )<br>'''z''' = (, , )<br>'''R''' = (, , )
| |
| |-
| |
| |0x374
| |
| |Rt Shoulder
| |
| |...
| |
| |'''x''' = (, , )<br>'''y''' = (, , )<br>'''z''' = (, , )<br>'''R''' = (, , )
| |
| |-
| |
| |0x3A4
| |
| |Rt Arm
| |
| |...
| |
| |'''x''' = (, , )<br>'''y''' = (, , )<br>'''z''' = (, , )<br>'''R''' = (, , )
| |
| |-
| |
| |0x3D4
| |
| |Rt Wrist
| |
| |...
| |
| |'''x''' = (, , )<br>'''y''' = (, , )<br>'''z''' = (, , )<br>'''R''' = (, , )
| |
| |-
| |
| |0x404
| |
| |Rt Fist
| |
| |...
| |
| |'''x''' = (, , )<br>'''y''' = (, , )<br>'''z''' = (, , )<br>'''R''' = (, , )
| |
| |} | | |} |
| {|border=1 cellspacing=0
| | |ALIGN=LEFT|bounding box for the whole corpse |
| |+axis-aligned bounding box | |
| !Offset
| |
| !Raw hex/string
| |
| !Value
| |
| !Meaning
| |
| |-
| |
| |0x434
| |
| |D4 22 8C 41 95 50 E9 C1 BC 31 9C C1
| |
| |(17.517006, -29.164347, -19.524284)
| |
| |"minimal" corner of the AABB
| |
| |-
| |
| |0x440
| |
| |75 E6 14 42 2E 20 B1 C1 07 B1 D3 C0
| |
| |(37.225056, -22.140713, -6.615360)
| |
| |"maximal" corner of the AABB
| |
| |} | | |} |
| | ;Array capacity |
| | :The array capacity is larger than the number of "fixed"/"used" corpses to allow the engine to store new corpses at runtime. "Fixed" means that those corpses are never overwritten/deleted at runtime, all new corpses are stored after the "fixed" ones. This means that "fixed" <= "used" <= "capacity". |
| | |
| | ;Bones |
| | :Here is one of the few places where the bone count 19 is apparently hardcoded. |
| | :I.e., custom characters with weird bone counts won't work. See, e.g., [[OBD:TRIA#Bones|TRIA]] |
|
| |
|
| | ;What's in a bone? |
| | :The transformation matrix (3D rotation/scale/shear/mirror and translation) |
| | ::can be seen as four 3D vectors '''X''', '''Y''', '''Z''', and '''R''' in world space. |
| | :If a bone mesh has a vertex at (x, y, z) in its native coordinates, |
| | ::then the actual position of that vertex in the level will be '''R''' + x '''X''' + y '''Y''' + z '''Z''' |
| | :That's the transformation defined by the 3x4 transform matrix. |
| | Reminder : the 2nd coordinate of '''X''', '''Y''', '''Z''', and '''R''' is the height. |
|
| |
|
| ----
| | ;Authoring |
| | :The script command [[make_corpse]](filename) creates a separate corpse file in the Oni folder. The pose of this corpse is taken from the player character (the [[Dev Mode]] shortcut Ctrl+F7, "Play dead", would have come in handy here). The format is roughly as above. The contents of the files thus created can then be inserted as elements in a level's CRSA. |
|
| |
|
| ==Screenshot==
| |
| The example is the same as above : '''00565-.CRSA''' in '''level3_Final.dat'''
| |
|
| |
|
| The first corpse chunk has been outlined in black.
| | {{OBD_File_Footer | type=CRSA | prev=CONS | next=DOOR | name=Corpse Array | family=Level}} |
|
| |
|
| http://www6.fh-eberswalde.de/user/dkriesch/onistuff/images/crsa_a.gif
| | {{OBD}} |