diff --git a/doc/specs/bioware/2DA_Format.pdf b/doc/specs/bioware/2DA_Format.pdf
deleted file mode 100644
index 80e4ec0adc..0000000000
Binary files a/doc/specs/bioware/2DA_Format.pdf and /dev/null differ
diff --git a/doc/specs/bioware/AreaFile_Format.pdf b/doc/specs/bioware/AreaFile_Format.pdf
deleted file mode 100644
index 2b418e86eb..0000000000
Binary files a/doc/specs/bioware/AreaFile_Format.pdf and /dev/null differ
diff --git a/doc/specs/bioware/CommonGFFStructs.pdf b/doc/specs/bioware/CommonGFFStructs.pdf
deleted file mode 100644
index 988650cc53..0000000000
Binary files a/doc/specs/bioware/CommonGFFStructs.pdf and /dev/null differ
diff --git a/doc/specs/bioware/Conversation_Format.pdf b/doc/specs/bioware/Conversation_Format.pdf
deleted file mode 100644
index 0d8951267d..0000000000
Binary files a/doc/specs/bioware/Conversation_Format.pdf and /dev/null differ
diff --git a/doc/specs/bioware/Creature_Format.pdf b/doc/specs/bioware/Creature_Format.pdf
deleted file mode 100644
index 7581e770bf..0000000000
Binary files a/doc/specs/bioware/Creature_Format.pdf and /dev/null differ
diff --git a/doc/specs/bioware/DoorPlaceableGFF.pdf b/doc/specs/bioware/DoorPlaceableGFF.pdf
deleted file mode 100644
index 42a0b7e7da..0000000000
Binary files a/doc/specs/bioware/DoorPlaceableGFF.pdf and /dev/null differ
diff --git a/doc/specs/bioware/ERF_Format.pdf b/doc/specs/bioware/ERF_Format.pdf
deleted file mode 100644
index 8fcacb9056..0000000000
Binary files a/doc/specs/bioware/ERF_Format.pdf and /dev/null differ
diff --git a/doc/specs/bioware/Encounter_Format.pdf b/doc/specs/bioware/Encounter_Format.pdf
deleted file mode 100644
index 66b056bae7..0000000000
Binary files a/doc/specs/bioware/Encounter_Format.pdf and /dev/null differ
diff --git a/doc/specs/bioware/Faction_Format.pdf b/doc/specs/bioware/Faction_Format.pdf
deleted file mode 100644
index ff2a2614f0..0000000000
Binary files a/doc/specs/bioware/Faction_Format.pdf and /dev/null differ
diff --git a/doc/specs/bioware/GFF_Format.pdf b/doc/specs/bioware/GFF_Format.pdf
deleted file mode 100644
index 72abcbc0c7..0000000000
Binary files a/doc/specs/bioware/GFF_Format.pdf and /dev/null differ
diff --git a/doc/specs/bioware/IFO_Format.pdf b/doc/specs/bioware/IFO_Format.pdf
deleted file mode 100644
index 2eec39cb5f..0000000000
Binary files a/doc/specs/bioware/IFO_Format.pdf and /dev/null differ
diff --git a/doc/specs/bioware/Item_Format.pdf b/doc/specs/bioware/Item_Format.pdf
deleted file mode 100644
index 7150b357d2..0000000000
Binary files a/doc/specs/bioware/Item_Format.pdf and /dev/null differ
diff --git a/doc/specs/bioware/Journal_Format.pdf b/doc/specs/bioware/Journal_Format.pdf
deleted file mode 100644
index 1b5a4302cf..0000000000
Binary files a/doc/specs/bioware/Journal_Format.pdf and /dev/null differ
diff --git a/doc/specs/bioware/KeyBIF_Format.pdf b/doc/specs/bioware/KeyBIF_Format.pdf
deleted file mode 100644
index a3f9ffe513..0000000000
Binary files a/doc/specs/bioware/KeyBIF_Format.pdf and /dev/null differ
diff --git a/doc/specs/bioware/LocalizedStrings_Format.pdf b/doc/specs/bioware/LocalizedStrings_Format.pdf
deleted file mode 100644
index b7a1de28f6..0000000000
Binary files a/doc/specs/bioware/LocalizedStrings_Format.pdf and /dev/null differ
diff --git a/doc/specs/bioware/PaletteITP_Format.pdf b/doc/specs/bioware/PaletteITP_Format.pdf
deleted file mode 100644
index 8112ffa1fc..0000000000
Binary files a/doc/specs/bioware/PaletteITP_Format.pdf and /dev/null differ
diff --git a/doc/specs/bioware/README b/doc/specs/bioware/README
deleted file mode 100644
index c58cdcfee6..0000000000
--- a/doc/specs/bioware/README
+++ /dev/null
@@ -1,3 +0,0 @@
-BioWare's Aurora specs: This spec is far from completion. And it may contains error. Use it at your own risk.
- 23 June 2007 SBNK update
- 20 June 2007 SSEQ Events
- 6 June 2007 SBNK + general update
- 23 May 2007 First published
- For enquiries please contact me at "kiwi.ds AT gmail.com"
-
- Crystal - the author of CrystalTile2.exe loveemu - the author of sseq2mid.exe, swave2wave.exe & strm2wave.exe Nintendon - the author of ndssndext.exe DJ Bouche - the author of sdattool.exe VGMTrans - the author of VGMTrans.exe
-
-
-
-Total length of geometry
-header: 80 bytes
-
- #
-
- item
-
- offset
-
- size (bytes)
-
- data type
-
-
-
- 1
-
- unknown
- 0
-
- 4
-
- long?
-
-
-
- 2
-
- unknown
-
- 4
-
- 4
-
- long?
-
-
-
- 3
-
- model name
-
- 8
-
- 32
-
- null terminated string
-
-
-
- 4
-
- location of root node
-
- 40
-
- 4
-
- long
-
-
-
- 5
-
- number of nodes
-
- 44
-
- 4
-
- long
-
-
-
- 6
-
- unknown bytes
-
- 48
-
- 28
-
-
-
-
-
- 7
-
- geometry type?
-
- 76
-
- 1
-
- char
-
-
-
-
-8
-
- padding?
-
- 77
-
- 3
-
- char
-
-
-
-Model header
-
-
-
-Total length of model
-header: 88 bytes
-
- #
-
- item
-
- offset
-
- size (bytes)
-
- data type
-
-
-
- 1
-
- unknown
-
- 0
-
- 1
-
- char
-
-
-
- 2
-
- unknown bytes
-
- 1
-
- 2
-
- char
-
-
-
- 3
-
- unknown
-
- 3
-
- 1
-
- char
-
-
-
- 4
-
- unknown
-
- 4
-
- 4
-
- long?
-
-
-
- 5
-
- location of the start of
-animation data
-
- 8
-
- 4
-
- long
-
-
-
- 6
-
- number of animations
-
- 12
-
- 4
-
- long
-
-
-
- 7
-
- duplicate of item 6
-
- 16
-
- 4
-
- long
-
-
-
- 8
-
- unknown
-
- 20
-
- 4
-
- long?
-
-
-
- 9
-
- bounding box min. x
-
- 24
-
- 4
-
- float
-
-
-
- 10
-
- bounding box min. y
-
- 28
-
- 4
-
- float
-
-
-
- 11
-
- bounding box min. z
-
- 32
-
- 4
-
- float
-
-
-
- 12
-
- bounding box max. x
-
- 36
-
- 4
-
- float
-
-
-
- 13
-
- bounding box max. y
-
- 40
-
- 4
-
- float
-
-
-
- 14
-
- bounding box max. z
-
- 44
-
- 4
-
- float
-
-
-
- 15
-
- radius
-
- 48
-
- 4
-
- float
-
-
-
- 16
-
- unknown
-
- 52
-
- 4
-
- float
-
-
-
-
-17
-
- super model
-
- 56
-
- 32
-
- null terminated string
-
-
-
-Names array header
-
-
-
-Total length of names array
-header: 28 bytes
-
- #
-
- item
-
- offset
-
- size (bytes)
-
- data type
-
-
-
- 1
-
- location of root node
-
- 0
-
- 4
-
- long
-
-
-
- 2
-
- unknown
-
- 4
-
- 4
-
- long?
-
-
-
- 3
-
- size of mdx data?
-
- 8
-
- 4
-
- long
-
-
-
- 4
-
- unknown
-
- 12
-
- 4
-
- long?
-
-
-
- 5
-
- location of names
-
- 16
-
- 4
-
- long
-
-
-
- 6
-
- number of names
-
- 20
-
- 4
-
- long
-
-
-
-
-7
-
- duplicate of item 6
-
- 24
-
- 4
-
- long
-
-
-
-The names are stored in the
-array one after the other seperated only by the null values.
-
-Animation header
-
-
-
-Total length of animation
-header: 56 bytes
-
- #
-
- item
-
- offset
-
- size (bytes)
-
- data type
-
-
-
- 1
-
- animation length
-
- 0
-
- 4
-
- float
-
-
-
- 2
-
- trans time
-
- 4
-
- 4
-
- float
-
-
-
- 3
-
- model name
-
- 8
-
- 32
-
- null terminated string
-
-
-
- 4
-
- location of events
-
- 40
-
- 4
-
- long
-
-
-
- 5
-
- number of events
-
- 44
-
- 4
-
- long
-
-
-
- 6
-
- duplicate of item 5
-
- 48
-
- 4
-
- long
-
-
-
-
-7
-
- unknown bytes
-
- 52
-
- 4
-
-
-
-
-
-Events structure:
-
-
-
-
-Total length of 1 structure: 36
-bytes
-
- #
-
- item
-
- offset
-
- size (bytes)
-
- data type
-
-
-
- 1
-
- activation time?
-
- 0
-
- 4
-
- float
-
-
-
-
-2
-
- event
-
- 4
-
- 32
-
- null terminated string
-
-
-
-Node header
-
-
-
-Total length of node header:
-80 bytes
-
- #
-
- item
-
- offset
-
- size (bytes)
-
- data type
-
-
-
- 1
-
- node type
-
- 0
-
- 2
-
- short
-
-
-
- 2
-
- supernode
-
- 2
-
- 2
-
- short
-
-
-
- 3
-
- node number
-
- 4
-
- 2
-
- short
-
-
-
- 4
-
- unknown
-
- 6
-
- 2
-
- short
-
-
-
- 5
-
- unknown
-
- 8
-
- 4
-
-
-
-
-
- 6
-
- location of parent node
-
- 12
-
- 4
-
- long
-
-
-
- 7
-
- position X (same value as
-position controller)
-
- 16
-
- 4
-
- float
-
-
-
- 8
-
- position Y (same value as
-position controller)
- 20
-
- 4
-
- float
-
-
- 9
-
- position Z (same value as
-position controller)
- 24
-
- 4
-
- float
-
-
- 10
-
- rotation W (same value as
-rotation controller)
- 28
-
- 4
-
- float
-
-
- 11
-
- rotation X (same value as
-rotation controller)
- 32
-
- 4
-
- float
-
-
- 12
-
- rotation Y (same value as
-rotation controller)
- 36
-
- 4
-
- float
-
-
- 13
-
- rotation Z (same value as
-rotation controller)
- 40
-
- 4
-
- float
-
-
- 14
-
- location of the array of child
-node locations
-
- 44
-
- 4
-
- long
-
-
-
- 15
-
- number of items in array in item
-8
-
- 48
-
- 4
-
- long
-
-
-
- 16
-
- duplicate of item 9
-
- 52
-
- 4
-
- long
-
-
-
- 17
-
- location of the array of
-controllers
-
- 56
-
- 4
-
- long
-
-
-
- 18
-
- number of items in array in item
-11
-
- 60
-
- 4
-
- long
-
-
-
- 19
-
- duplicate of item 12
-
- 64
-
- 4
-
- long
-
-
-
- 20
-
- location of the array of
-controller data
-
- 68
-
- 4
-
- long
-
-
-
- 21
-
- number of items in array in item
-14
-
- 72
-
- 4
-
- long
-
-
-
-
-22
-
- duplicate of item 15
-
- 76
-
- 4
-
- long
-
-
-
-The array of child node
-locations is simply a list of long integers.
-
-controller structure:
-
-
-
-
-Total length of controller
-structure: 16 bytes
-
- #
-
- item
-
- offset
-
- size (bytes)
-
- data type
-
-
-
- 1
-
- controller type
-
- 0
-
- 4
-
- long
-
-
-
- 2
-
- unknown
-
- 4
-
- 2
-
- short
-
-
-
- 3
-
- number of rows of controller data
-
- 6
-
- 2
-
- short
-
-
-
- 4
-
- offset of first time key
-
- 8
-
- 2
-
- short
-
-
-
- 5
-
- offset of first data byte
-
- 10
-
- 2
-
- short
-
-
-
- 6
-
- columns of data
-
- 12
-
- 1
-
- char
-
-
-
-
-7
-
- unknown
-
- 13
-
- 3
-
- char
-
-
-
-controller data structure:
-Ok, the controller data structure is not fixed. It has to be
-figured out from the controller itself.
-
-Example:
-controller: 1) 8 -1 2 0 2 3
-
- 2) 20 -1 2 8 10 4
-
-data: 0 1 0 0 0 1 2 3 0 1 0 0 0 1 0 0 0 1
-
-dark green =
-controller 1 time keys, light
-green = controller 1 data, dark
-red = controller 2 time keys, light red = controller 2 data
-
-So, controller 1 is a position controller (8 = position). It has
-2 rows of data, first time key is at offset 0, first data byte is at
-offset 2, the data is 3 values long.
-Controller 2 is an
-orientation
-controller (20 = orientation). It has 2 rows of data, first time
-key is at
-offset 8, first data byte is at offset 10, the data is 4 values long.
-
-Taking the data string and
-formatting it according to the controller info gives:
-controller 1 data:
-
-
-
-
-
-
- time
-
- x position
-
- y position
-
- z position
-
-
-
- 0
-
- 0
-
- 0
-
- 0
-
-
-
-
-1
-
- 1
-
- 2
-
- 3
-
-
-controller 2 data:
-
-
-
-
-
-
- time
-
- x
-
- y
-
- z
-
- w
-
-
-
- 0
-
- 0
-
- 0
-
- 0
-
- 1
-
-
-
-
-1
-
- 0
-
- 0
-
- 0
-
- 1
-
-
-What the heck is that x,y,z,w for orientation? That is a
-quaternion. For some models oreintation (i.e. rotation) is stored
-as quaternions. Too much for me to explain, Google it.
-
-common mesh header
-
-
-
-Total length of common mesh header:
-332 bytes
-
- #
-
- item
-
- offset
-
- size (bytes)
-
- data type
-
-
-
- 1
-
- unknown
-
- 0
-
- 4
-
- long
-
-
-
- 2
-
- unknown
-
- 4
-
- 4
-
- long
-
-
-
- 3
-
- location of the face array
-
- 8
-
- 4
-
- long
-
-
-
- 4
-
- number of faces in the face array
-
- 12
-
- 4
-
- long
-
-
-
- 5
-
- duplicate of item 4
-
- 16
-
- 4
-
- long
-
-
-
- 6
-
- bounding box min X
-
- 20
-
- 4
-
- float
-
-
-
- 7
-
- bounding box min Y
- 24
-
- 4
-
- float
-
-
- 8
-
- bounding box min Z
- 28
-
- 4
-
- float
-
-
- 9
-
- bounding box max X
- 32
-
- 4
-
- float
-
-
- 10
-
- bounding box max Y
-
- 36
-
- 4
-
- float
-
-
- 11
-
- bounding box max Z
-
- 40
-
- 4
-
- float
-
-
- 12
-
- mesh radius
-
- 44
-
- 4
-
- float
-
-
- 13
-
- mesh points average X
-
- 48
-
- 4
-
- float
-
-
- 14
-
- mesh points average Y
-
- 52
-
- 4
-
- float
-
-
- 15
-
- mesh points average Z
-
- 56
-
- 4
-
- float
-
-
- 16
-
- diffuse red
-
- 60
-
- 4
-
- float
-
-
- 17
-
- diffuse green
-
- 64
-
- 4
-
- float
-
-
- 18
-
- diffuse blue
-
- 68
-
- 4
-
- float
-
-
- 19
-
- ambient red
-
- 72
-
- 4
-
- float
-
-
- 20
-
- ambient green
-
- 76
-
- 4
-
- float
-
-
- 21
-
- ambient blue
-
- 80
-
- 4
-
- float
-
-
- 22
-
- unknown
-
- 84
-
- 4
-
- float?
-
-
- 23
-
- name for texture map 1
-
- 88
-
- 32
-
- null terminated string
-
-
-
- 24
-
- name for texture map 2
-
- 120
-
- 32
-
- null terminated string
-
-
- 25
-
- unknown
-
- 152
-
- 24
-
- ???
-
-
-
- 26
-
- location of number of verts
-
- 176
-
- 4
-
- long
-
-
-
- 27
-
- number of items in array 10
-(always 1)
-
- 180
-
- 4
-
- long
-
-
-
- 28
-
- duplicate of item 11
-
- 184
-
- 4
-
- long
-
-
-
- 29
-
- location of location of verts
-
- 188
-
- 4
-
- long
-
-
-
- 30
-
- number of items in array 13
-(always 1)
-
- 192
-
- 4
-
- long
-
-
-
- 31
-
- duplicate of item 14
-
- 196
-
- 4
-
- long
-
-
-
- 32
-
- location of unknown array
-
- 200
-
- 4
-
- long
-
-
-
- 33
-
- number of items in array 16
-(always 1)
-
- 204
-
- 4
-
- long
-
-
-
- 34
-
- duplicate of item 17
-
- 208
-
- 4
-
- long
-
-
-
- 35
-
- unknown (always -1)
-
- 212
-
- 4
-
- long
-
-
-
- 36
-
- unknown (always -1)
-
- 216
-
- 4
-
- long
-
-
-
- 37
-
- unknown (always 0)
-
- 220
-
- 4
-
- long
-
-
-
- 38
-
- unknown (always 3)
-
- 224
-
- 4
-
- long
-
-
-
- 39
-
- unknown (always 0)
- 228
-
- 4
-
- long
-
-
- 40
-
- unknown (always 0)
- 232
-
- 4
-
- long
-
-
- 41
-
- unknown
-
- 236
-
- 16
-
- long?
-
-
-
- 42
-
- size of 1 MDX structure
-
- 252
-
- 4
-
- long
-
-
-
- 43
-
- unknown (has something to do
-with textures)
-
- 256
-
- 4
-
- long
-
-
- 44
-
- unknown (always 0)
-
- 260
-
- 4
-
-
-
-
-
- 45
-
- offset to vertex normals in MDX
-data in bytes (always 12)
-
- 264
-
- 4
-
- long
-
-
- 46
-
- unknown (always -1)
-
- 268
-
- 4
-
- long
-
-
- 47
-
- offset to UV coordinates in MDX
-data in bytes (24 if present)
-
- 272
-
- 4
-
- long
-
-
- 48
-
- unknown (each value always -1)
-
- 276
-
- 28
-
-
-
-
-
- 49
-
- number of vertices
-
- 304
-
- 2
-
- short
-
-
-
- 50
-
- number of textures
-
- 306
-
- 2
-
- short
-
-
-
- 51
-
- unknown
-
- 308
-
- 2
-
- short
-
-
-
- 52
-
- shadow flag (value of 256 = cast
-shadow)
-
- 310
-
- 2
-
- short
-
-
- 53
-
- render flag (value of 256 =
-render this node)
- 312
-
- 2
-
- short
-
-
- 54
-
- unknown
- 314
-
- 2
-
- short
-
-
- 55
-
- unknown
- 316
-
- 8
-
- long?
-
-
-
- 56
-
- location of this nodes data in
-mdx
-
- 324
-
- 4
-
- long
-
-
-
-
-57
-
- location of vertex coordinates
-array
-
- 328
-
- 4
-
- long
-
-
-
-skin mesh header
-
-
-
-Total length of skin mesh header:
-100 bytes
-
- #
-
- item
-
- offset
-
- size (bytes)
-
- data type
-
-
-
- 1
-
- unknown
-
- 0
-
- 20
-
- long?
-
-
-
- 2
-
- location of bone map array
-
- 20
-
- 4
-
- long
-
-
-
- 3
-
- number of items in array 2
-
- 24
-
- 4
-
- long
-
-
-
- 4
-
- location of an unknown array
-
- 28
-
- 4
-
- long
-
-
-
- 5
-
- number of items in array 4
-
- 32
-
- 4
-
- long
-
-
-
- 6
-
- duplicate of item 5
-
- 36
-
- 4
-
- long
-
-
-
- 7
-
- location of an unknown array
-
- 40
-
- 4
-
- long
-
-
-
- 8
-
- number of items in array 7
-
- 44
-
- 4
-
- long
-
-
-
- 9
-
- duplicate of item 8
-
- 48
-
- 4
-
- long
-
-
-
- 10
-
- location of an unknown array
-
- 52
-
- 4
-
- long
-
-
-
- 11
-
- number of items in array 10
-
- 56
-
- 4
-
- long
-
-
-
- 12
-
- duplicate of item 11
-
- 60
-
- 4
-
- long
-
-
-
- 13
-
- list of nodes that can affect
-verticies of this node (i.e. bones)
-
- 64
-
- 30
-
- short
-
-
-
-
-14
-
- unknown
-
- 94
-
- 6
-
- short?
-
-
-
-Bone maps work like this:
--For each vertex in the MDX
-there are 4 bone indexes and the corresponding bone weights
--You take the bone index from
-the MDX and match it to an entry in the bone map array
--The entry number that matches
-is the node number that affects the vertex
-
-Example:
-MDX data: 0.1 0.2 0.3
-0.4 0.5 0.6 0.7 0.8 0.5
-0.5 0 0 1 2 -1 -1
-
-Bone map array:
-0 => 1
-1 => -1
-2 => -1
-3 => 2
-
-The yellow numbers in the MDX
-data are the weights. The red numbers are the bone indicies. The
-white numbers are coordinates, uv map coordinates, etc.
-
-We take bone index 1 from the
-MDX and look for it in the bone map array. We see that it is at
-position 0 in the list. This means that node 0 has a bone weight
-of 0.5 when affecting the vertex described in the MDX data.
-Taking bone index 2 we see that it is at position 3 in the list.
-So, node 3 has a bone weight of 0.5 when affecting the vertex described
-in the MDX data. The remaining bone indexs in the MDX are -1,
-meaning no other nodes affect this vertex. The total of the
-bone weights for a vertex must equal 1.
-
-dangly mesh header
-
-
-
-
-Total length of dangly mesh header:
-28 bytes
-
-
diff --git a/doc/specs/nds_sdat.html b/doc/specs/nds_sdat.html
deleted file mode 100644
index e3267e899e..0000000000
--- a/doc/specs/nds_sdat.html
+++ /dev/null
@@ -1,941 +0,0 @@
-
-
-
-
-
- #
-
- item
-
- offset
-
- size
-(bytes)
-
- data
-type
-
-
-
- 1
-
- location
-of constraints
-
- 0
-
- 4
-
- long
-
-
-
- 2
-
- number
-of items in array 1
-
- 4
-
- 4
-
- long
-
-
-
- 3
-
- duplicate
-of item 2
-
- 8
-
- 4
-
- long
-
-
-
- 4
-
- displacement
-
- 12
-
- 4
-
- float
-
-
-
- 5
-
- tightness
-
- 16
-
- 4
-
- float
-
-
-
- 6
-
- period
-
- 20
-
- 4
-
- float
-
-
-
-
-7
-
- unknown
-
- 24
-
- 4
-
- long?
-
- Nitro Composer File (*.sdat) Specification
-
-Current status
-Acknowledgement
-Many thanks to the following persons whose works I have studied:
-
-
- Tables of Contents
-
-
-0. Introduction- |
"The DS SDK has all the tools in it to convert MIDI files to the DS format, and has text file templates to define the soundbanks." CptPiard from VGMix
- -The Nitro Composer packs various types of sound files in a single file (*.sdat) for use in DS games. Not all games involve the Nitro Composer. But it seems that it is very popular for creation of DS game music.
- -Inside the SDAT you will find: SSEQ (Sequence), SSAR (Sequence Archive), SBNK (Sound Bank), SWAR (Wave Archive), STRM (Stream).
- -SSAR is a collection of SSEQ, while SWAR is a collection of SWAV.
- --s8 1 byte // signed char -u8 1 byte // unsigned char -s16 2 byte // signed short -u16 2 byte // unsigned short -s32 4 byte // signed long -u32 4 byte // unsigned long -- -
-typedef struct tagNdsStdFile { - s8 type[4]; // i.e. 'SDAT' or 'SBNK' etc... - u32 magic; // 0x0100feff or 0x0100fffe - u32 nFileSize; // Size of this file ( include this structure ) - u16 nSize; // Size of this structure ( always 16 ) - u16 nBlock; // Number of Blocks -} NDSSTDF; -- -
The magic value can be 0x0002feff or 0x0001feff for non sound-related files.
- - -
-1. SDAT File Format- |
- -------------------------------- - | Header | - -------------------------------- - | Symbol Block | - -------------------------------- - | Info Block | - -------------------------------- - | File Allocation Table (FAT) | - -------------------------------- - | File Block | - -------------------------------- -- -
-typedef struct tagSDATHeader -{ - struct tagNdsStdFile { - s8 type[4]; // 'SDAT' - u32 magic; // 0x0100feff - u32 nFileSize; - u16 nSize; - u16 nBlock; // usually 4, but some have 3 only ( Symbol Block omitted ) - } file; - u32 nSymbOffset; // offset of Symbol Block = 0x40 - u32 nSymbSize; // size of Symbol Block - u32 nInfoOffset; // offset of Info Block - u32 nInfoSize; // size of Info Block - u32 nFatOffset; // offset of FAT - u32 nFatSize; // size of FAT - u32 nFileOffset; // offset of File Block - u32 nFileSize; // size of File Block - u8 reserved[16]; // unused, 0s -} SDATHEADER; -- -
-typedef struct tagSDATSymbol -{ - char type[4]; // 'SYMB' - u32 nSize; // size of this Symbol Block - u32 nRecOffset[8]; // offset of Records (note below) - u8 reserved[24]; // unused, 0s -} SDATSYMB; -- - - -
Record No. | Record Name | Description | -
0 | SEQ | Sequence (for music) | -
1 | SEQARC | Sequence Archive (for sound effect) | -
2 | BANK | Sound Bank | -
3 | WAVEARC | Wave Archive | -
4 | PLAYER* | Player (Group-related) | -
5 | GROUP | Group of SEQ/SEQARC/BANK/WAVEARC | -
6 | PLAYER2* | Player2 (Stream-related) | -
7 | STRM | Stream | -
* Records 4 and 5 do not appear in SMAP file. A SMAP File is generated by the Nitro Composer listing all sound files in the SDAT file. An example can be found from <<Zoids Saga DS - Legend of Arcadia>> |
-typedef struct tagSDATSymbolRec -{ - u32 nCount; // No of entries in this record - u32 nEntryOffset[1]; // Array of offsets of each entry -} SDATSYMBREC; -- -For Record 1 (SEQARC), it is a group which contains sub-records. The sub-record is of the same structure as SDATSYMBREC (above). Record 1 has the following structure: - -
-typedef struct tagSDATSymbolRec2 -{ - u32 nCount; // No of entries in this record - struct { - u32 nEntryOffset; // Offset of this Group's symbol - u32 nSubRecOffset; // Offset of the sub-record - } Group[1]; // Array of offsets of each entry -} SDATSYMBREC2; -- -Below is an example to access these records: - -
-SDATSYMB *symb; -int i, j; -char *szSymbol; -... -// access record 0 'SSEQ' -SDATSYMBREC *symb_rec = (SDATSYMBREC *) ( (u8 *)symb + symb->RecOffset[0] ); - -for ( i = 0; i < symb_rec->nCount; i++ ) -{ - // print out the symbol - szSymbol = (char *) ( (u8 *)symb + symb_rec->nEntryOffset[i] ); - printf( "%s\n", szSymbol ); -} -... - -// access record 1 'SSAR' -SDATSYMBREC2 symb_rec2 = (SDATSYMBREC *)( (u8 *)symb + symb->RecOffset[1] ); - -for ( i = 0; i < symb_rec2->nCount; i++ ) -{ - szSymbol = (char *) ( (u8 *)symb + symb_rec2->Group[ i ].nEntryOffset ); - printf( "%s\n", szSymbol ); - - SDATSYMBREC *symb_subrec = (SDATSYMBREC *) ( (u8 *)symb + symb_rec2->Group[i].nSubRecOffset ); - for ( j = 0; j < symb_subrec->nCount; j++ ) - { - // print out sub record's symbols - szSymbol = (char *) ( (u8 *)symb + symb_subrec->nEntryOffset[i] ); - printf( "%s\n", szSymbol ); - } -} -- -
-typedef struct tagSDATInfo -{ - char type[4]; // 'INFO' - u32 nSize; // size of this Info Block - u32 nRecOffset[8]; // offset of a Record - u8 reserved[24]; // unused, 0s -} SDATINFO; -- -
-typedef struct tagSDATInfoRec -{ - u32 nCount; // No of entries in this record - u32 nEntryOffset[1]; // array of offsets of each entry -} SDATINFOREC; -- - -
Record 0 "SEQ" - The Info Entry for SEQ contains playback information.
--typedef struct tagSDATInfoSseq -{ - u16 fileID; // for accessing this file - u16 unknown; - u16 bnk; // Associated BANK - u8 vol; // Volume - u8 cpr; - u8 ppr; - u8 ply; - u8 unknown[2]; -} SDATINFOSSEQ; -- -
-typedef struct tagSDATInfoSsar -{ - u16 fileID; - u16 unknown; -} SDATINFOSSAR; -- -Remarks: no info is available for SEQARC files. The info of each archived SEQ is stored in that SEQARC file. - -
-typdef struct tagSDATInfoBank -{ - u16 fileID; - u16 unknown; - u16 wa[4]; // Associated WAVEARC. 0xffff if not in use -} -- -Remarks: Each bank can links to up to 4 WAVEARC files. The wa[4] stores the WAVEARC entry number. - -
-typedef struct tagSDATInfoSwar -{ - u16 fileID; - u16 unknown; -} SDATINFOSwar; -- -Remarks: This is not a new structure. It is the same as SDATINFOSSAR above for Record 1. - -
-typedef struct tagSDATInfoPlayer -{ - u8 unknown; - u8 padding[3]; - u32 unknown2; -} SDATINFOPlayer; -- -Remarks: None - -
-typedef struct tagSDATInfoPlayer -{ - u32 nCount; // number of sub-records - struct { // array of Group - u32 type; - u32 nEntry; - } Group[1]; -} SDATINFOPlayer; -- -
Remarks: SDATINFOPlayer::Group::type can be one of the following values. nEntry is the entry number in the relevant Record (SEQ/SEQARC/BANK/WAVEARC).
- -Value | Type | -
0x0700 | SEQ |
0x0803 | SEQARC |
0x0601 | BANK |
0x0402 | WAVEARC |
-typedef struct SDATInfoPlayer2 -{ - u8 nCount; - u8 v[16]; // 0xff if not in use - u8 reserved[7]; // padding, 0s -} SDATINFOPLAYER2; -- -Remarks: The use is unknown. The first byte states how many of the v[16] is used (non 0xff). - -
-typedef struct SDATInfoStrm -{ - u16 fileID; // for accessing the file - u16 unknown; - u8 vol; // volume - u8 pri; - u8 ply; - u8 reserved[5]; -} SDATINFOSTRM; -- -Remarks: 'ply' means play?, 'pri' means priority? - -
-typedef struct tagSDATFAT -{ - char type[4]; // 'FAT ' - u32 nSize; // size of the FAT - u32 nCount; // Number of FAT records - SDATFATREC Rec[1]; // Arrays of FAT records -} SDATFAT; -- -
-typedef struct tagSDATFATREC -{ - u32 nOffset; // offset of the sound file - u32 nSize; // size of the Sound file - u32 reserved[2]; // always 0s, for storing data in runtime. -} SDATFATREC; -- -
-typedef struct tagSDATFILE -{ - char type[4]; // 'FILE' - u32 nSize; // size of this block - u32 nCount; // Mumber of sound files - u32 reserved; // always 0 -} SDATFILE; -- - - - - -
-2. SSEQ File Format- |
SSEQ stands for "Sound Sequence". It is a converted MIDI sequence. Linked to a BANK for instruments.
- - --typedef struct tagSseq -{ - struct tagNdsStdFile { - char type[4]; // 'SSEQ' - u32 magic; // 0x0100feff - u32 nFileSize; // Size of this SSEQ file - u16 nSize; // Size of this structure = 16 - u16 nBlock; // Number of Blocks = 1 - } file; - struct { - char type[4]; // 'DATA' - u32 nSize; // Size of this structure = nFileSize - 16 - u32 nDataOffset; // Offset of the sequence data = 0x1c - u8 data[1]; // Arrays of sequence data - } data; -} SSEQ; -- -
NB. For the details of the SSEQ file, please refer to loveemu's sseq2mid
- -The design of SSEQ is more programming-oriented while MIDI is hardware-oriented. In MIDI, to produce a sound, a Note-On event is sent to the midi-instrument and then after a certain time, a Note-Off is sent to stop the sound (though it is also acceptable to send a Note-On message with 0 velocity). -In SSEQ, a sound is produced by one event only which carries with data such as note, velocity and duration. So the SSEQ-sequencer knows exactly what and how to play and when to stop.
- -A SSEQ can have at maximum 16 tracks, notes in the range of 0..127 (middle C is 60). Each quartet note has a fixed tick length of 48. Tempo in the range of 1..240 BPM (Default is 120). The SSEQ will not be played correctly if tempo higher than 240.
-The SEQ player uses Arm7's Timer1 for timing. The Arm7's 4 Timers runs at 33MHz (approximately 2^25). The SEQ player sets Timer1 reload value to 2728, prescaler to F/64. So on about every 0.0052 sec (64 * 2728 / 33MHz) the SEQ Player will be notified ( 1 cycle ). As a quartet note has fixed tick value of 48, the highest tempo that SEQ Player can handle is 240 BPM ( 60 / (0.0052 * 48) ).
-During each cycle, the SEQ player adds the tempo value to a variable. Then it checks if the value exceeds 240. If it does, the SEQ player subtracts 240 from the variable, and process the SSEQ file. Using this method, the playback is not very precise but the difference is too small to be noticed.
-Take an example with tempo = 160 BPM, the SSEQ file is processed twice in 3 notifications.
-cycle | variable | action |
1 | 0 | Add 160 |
2 | 160 | Add 160 |
3 | 320 | Subtract 240, process once, add 160 |
4 | 240 | Subtract 240, process once, add 160 |
5 | 160 | Add 160 |
6 | 320 | Subtract 240, process once, add 160 |
7 | 240 | Subtract 240, process once, add 160 |
8 | 160 | Add 160 |
Status Byte | -Parameter | -Description | -
0xFE | 2 bytes It indicates which tracks are used. Bit 0 for track 0, ... Bit 15 for track 15. If the bit is set, the corresponding track is used. | Indication begin of multitrack. Must be in the beginning of the first track to work. A series of event 0x93 follows. | -
0x93 | 4 bytes 1st byte is track number [0..15] The other 3 bytes are the relative adress of track data. Add nDataOffset (usually 0x1C) to find out the absolute address. | SSEQ is similar to MIDI in that track data are stored one after one track. Unlike mod music. | -
0x00 .. 0x7f | Velocity: 1 byte [0..127] Duration: Variable Length | NOTE-ON. Duration is expressed in tick. 48 for quartet note. Usually it is NOT a multiple of 3. | -
0x80 | Duration: Variable Length | REST. It tells the SSEQ-sequencer to wait for a certain tick. Usually it is a multiple of 3. | -
0x81 | Bank & Program Number: Variable Length | bits[0..7] is the program number, bits[8..14] is the bank number. Bank change is seldomly found, so usually bank 0 is used. | -
0x94 | Destination Address: 3 bytes (Add nDataOffset (usually 0x1C) to find out the absolute address.) | JUMP. A jump must be backward. So that the song will loop forever. - |
0x95 | Call Address: 3 bytes (Add nDataOffset (usually 0x1C) to find out the absolute address.) | CALL. It's like a function call. The SSEQ-sequncer jumps to the address and starts playing at there, until it sees a RETURN event. | -
0xFD | NONE | RETURN. The SSEQ will return to the caller's address + 4 (a Call event is 4 bytes in size). | -
0xA0 .. 0xBf | See loveemu's sseq2mid for more details. | Some arithmetic operations / comparions. Affect how SSEQ is to be played. | -
0xC0 | Pan Value: 1 byte [0..127], middle is 64 | PAN | -
0xC1 | Volume Value: 1 byte [0..127] | VOLUME | -
0xC2 | Master Volume Value: 1 byte [0..127] | MASTER VOLUME | -
0xC3 | Value: 1 byte [0..64] (Add 64 to make it a MIDI value) | TRANSPOSE (Channel Coarse Tuning) | -
0xC4 | Value: 1 byte | PITCH BEND | -
0xC5 | Value: 1 byte | PITCH BEND RANGE | -
0xC6 | Value: 1 byte | TRACK PRIORITY | -
0xC7 | Value: 1 byte [0: Poly, 1: Mono] | MONO/POLY | -
0xC8 | Value: 1 byte [0: Off, 1: On] | TIE (unknown) | -
0xC9 | Value: 1 byte | PORTAMENTO CONTROL | -
0xCA | Value: 1 byte [0: Off, 1: On] | MODULATION DEPTH | -
0xCB | Value: 1 byte | MODULATION SPEED | -
0xCC | Value: 1 byte [0: Pitch, 1: Volume, 2: Pan] | MODULATION TYPE | -
0xCD | Value: 1 byte | MODULATION RANGE | -
0xCE | Value: 1 byte | PORTAMENTO ON/OFF | -
0xCF | Time: 1 byte | PORTAMENTO TIME | -
0xD0 | Value: 1 byte | ATTACK RATE | -
0xD1 | Value: 1 byte | DECAY RATE | -
0xD2 | Value: 1 byte | SUSTAIN RATE | -
0xD3 | Value: 1 byte | RELEASE RATE | -
0xD4 | Count: 1 byte (how many times to be looped) | LOOP START MARKER | -
0xFC | NONE | LOOP END MARKER | -
0xD5 | Value: 1 byte | EXPRESSION | -
0xD6 | Value: 1 byte | PRINT VARIABLE (unknown) | -
0xE0 | Value: 2 byte | MODULATION DELAY | -
0xE1 | BPM: 2 byte | TEMPO | -
0xE3 | Value: 2 byte | SWEEP PITCH | -
0xFF | NONE | EOT: End Of Track | -
-3. SSAR File Format- |
-typedef struct tagSsarRec { - u32 nOffset; // relative offset of the archived SEQ file, absolute offset = nOffset + SSAR::nDataOffset - u16 bnk; // bank - u8 vol; // volume - u8 cpr; // channel pressure - u8 ppr; // polyphonic pressure - u8 ply; // play - u8 reserved[2]; -} SSARREC; - -typedef struct tagSsar -{ - struct tagNdsStdFile { - char type[4]; // 'SSAR' - u32 magic; // 0x0100feff - u32 nFileSize; // Size of this SSAR file - u16 nSize; // Size of this structure = 16 - u16 nBlock; // Number of Blocks = 1 - } file; - struct { - char type[4]; // 'DATA' - u32 nSize; // Size of this structure - u32 nDataOffset; // Offset of data - u32 nCount; // nCount * 12 + 32 = nDataOffset - SSARREC Rec[1]; // nCount of SSARREC - } data; -} SSAR; -- -
NB. Archived SSEQ files are not stored in sequence (order). So Rec[0].nOffset may point to 0x100 but Rec[1].nOffset points to 0x40.
-NB. Archived SSEQ files cannot be readily extracted from SSAR file because data in one SSEQ may 'call' data in other SSEQ.
- - - - -
-4. SBNK File Format- |
SBNK stands for "Sound Bank". A bank is linked to up to 4 SWAR files which contain the samples. It define the instruments by which a SSEQ sequence can use. You may imagine SSEQ + SBNK + SWAR are similar to module music created by trackers.
- --typedef struct tagSbnkInstrument -{ - u8 fRecord; // can be either 0, 1..4, 16 or 17 - u16 nOffset; // absolute offset of the data in file - u8 reserved; // must be zero -} SBNKINS; - -typedef struct tagSbnk -{ - struct tagNdsStdFile { - char type[4]; // 'SBNK' - u32 magic; // 0x0100feff - u32 nFileSize; // Size of this SBNK file - u16 nSize; // Size of this structure = 16 - u16 nBlock; // Number of Blocks = 1 - } file; - struct { - char type[4]; // 'DATA' - u32 nSize; // Size of this structure - u32 reserved[8]; // reserved 0s, for use in runtime - u32 nCount; // number of instrument - SBNKINS Ins[1]; - } data; -} SBNK; -- -
So, after SBNK::data, there come SBNK::data::nCount of SBNKINS. After the last SBNKINS, there will be SBNK::data::nCount of instrument records. In each instrument records, we can find one or more wave/note definitions. - - - - -
If SBNKINS::fRecord = 0, it is empty. SBNKINS::nOffset will also = 0.
-If SBNKINS::fRecord < 16, the record is a note/wave definition. I have seen values 1, 2 and 3. But it seems the value does not affect the wave/note definition that follows. Instrument record size is 16 bytes.
-- swav number 2 bytes // the swav used - swar number 2 bytes // the swar used. NB. cross-reference to "1.3.2 Info Block - Entry, Record 2 BANK" - note number 1 byte // 0..127 - Attack Rate 1 byte // 0..127 - Decay Rate 1 byte // 0..127 - Sustain Level 1 byte // 0..127 - Release Rate 1 byte // 0..127 - Pan 1 byte // 0..127, 64 = middle --
If SBNKINS::fRecord = 16, the record is a range of note/wave definitions. The number of definitions = 'upper note' - 'lower note' + 1. The Instrument Record size is 2 + no. of definitions * 12 bytes.
-- lower note 1 byte // 0..127 - upper note 1 byte // 0..127 - - unknown 2 bytes // usually == 01 00 - swav number 2 bytes // the swav used - swar number 2 bytes // the swar used. - note number 1 byte - Attack Rate 1 byte - Decay Rate 1 byte - Sustain Level 1 byte - Release Rate 1 byte - Pan 1 byte - - ... - ... - ... - - unknown 2 bytes // usually == 01 00 - swav number 2 bytes // the swav used - swar number 2 bytes // the swar used. - note number 1 byte - Attack Rate 1 byte - Decay Rate 1 byte - Sustain Level 1 byte - Release Rate 1 byte - Pan 1 byte --
For example, lower note = 30, upper note = 40, there will be 40 - 30 + 1 = 11 wave/note definitions.
-The first wave/note definition applies to note 30.
-The second wave/note definition applies to note 31.
-The third wave/note definition applies to note 32.
-...
-The eleventh wave/note definition applies to note 40.
If SBNKINS::fRecord = 17, the record is a regional wave/note definition.
-- The first 8 bytes defines the regions. They divide the full note range [0..127] into several regions (max. is 8) - An example is: - 25 35 45 55 65 127 0 0 (So there are 6 regions: 0..25, 26..35, 36..45, 46..55, 56..65, 66..127) - Another example: - 50 59 66 83 127 0 0 0 (5 regions: 0..50, 51..59, 60..66, 67..84, 85..127) - - Depending on the number of regions defined, the corresponding number of wave/note definitions follow: - - unknown 2 bytes // usually == 01 00 - swav number 2 bytes // the swav used - swar number 2 bytes // the swar used. - note number 1 byte - Attack Rate 1 byte - Decay Rate 1 byte - Sustain Level 1 byte - Release Rate 1 byte - Pan 1 byte - ... - ... - - In the first example, for region 0..25, the first wave/note definition applies. - For region 26..35, the 2nc wave/note definition applies. - For region 36..45, the 3rd wave/note definition applies. - ... - For region 66..127, the 6th wave/note definition applies. -- - -
REMARKS: Unknown bytes before wave/defnition definition = 5, not 1 in -stage_04_bank.sbnk, stage_04.sdat, Rom No.1156
- - -The articulation data affects the playback of the SSEQ file. They are 'Attack Rate', 'Decay Rate', 'Sustain Level' and 'Release Rate' (all have a value in range [0..127])
- --amplitude (%) - -100% | /\ - | / \__________ - | / \ - | / \ -0% |/__________________\___ time (sec) - --
Imagine how the amplitude of a note varies from begin to the end.
-The graph above shows the amplitude envelope when a note is sound. The y-axis is Amplitude, x-asix is time.
- -Attack rate determines how fast the note reaches 100% amplitude. (See the first upward curve). Thus the highest value 127 means the sound reaches 100% amplitude in the shortest time; 0 means the longest time.
-Decay rate determines how fast the amplitude decays to 0% amplitude. Of course the sound will not drop to 0% but stops at sustain level. (See the first downward curve). Thus the highest value 127 means the sound reachs the sustain level in the shortest time; 0 means the longest time.
-Sustain level determines the amplitude at which the sound sustains. (See the horizonal part). Thus the highest value 127 means the sound sustains at 100% amplitude (no decay), while 0 means 0% (full decay).
-Release rate determines how fast the amplitude drops from 100% to 0%. Not from sustain level to 0%. (See the second downward curve). The value has the same meaning as Decay rate.
- -See this file for more details on how to interpret the articulation data. The raw data column is the transformed value used for calculation.
-The SEQ Player treats 0 as the 100% amplitude value and -92544 (723*128) as the 0% amplitude value. The starting ampltitude is 0% (-92544).
- -During the attack phase, in each cycle, the SSEQ Player calculates the new amplitude value: amplitude value = attack rate * amplitude value / 255. The attack phase stops when amplitude reaches 0.
-The times column shows how many cycles are needed to reach 100% amplitude value.
-The sec column shows the corresponding time needed to reach 100% amplitude value.
-The scale column is the corresponding value to feed in DLS Bank.
- -During the decay phase, in each cycle, the SSEQ Player calculates the new amplitude value: amplitude value = amplitude value - decay rate. Note the starting amplitude value is 0. The decay phase stops when amplitude reaches sustain level.
-The other columns are self-explanatory.
- -
-5. SWAV File Format- |
SWAV doesn't appear in SDAT. They may be found in the ROM elsewhere. They can also be readily extracted from a SWAR file (see below).
- - --// info about the sample -typedef struct tagSwavInfo -{ - u8 nWaveType; // 0 = PCM8, 1 = PCM16, 2 = (IMA-)ADPCM - u8 bLoop; // Loop flag = TRUE|FALSE - u16 nSampleRate; // Sampling Rate - u16 nTime; // (ARM7_CLOCK / nSampleRate) [ARM7_CLOCK: 33.513982MHz / 2 = 1.6756991 E +7] - u16 nLoopOffset; // Loop Offset (expressed in words (32-bits)) - u32 nNonLoopLen; // Non Loop Length (expressed in words (32-bits)) -} SWAVINFO; - -// Swav file format -typedef struct tagSwav -{ - struct tagNdsStdFile { - char type[4]; // 'SWAV' - u32 magic; // 0x0100feff - u32 nFileSize; // Size of this SWAV file - u16 nSize; // Size of this structure = 16 - u16 nBlock; // Number of Blocks = 1 - } file; - struct { - char type[4]; // 'DATA' - u32 nSize; // Size of this structure - SWAVINFO info; // info about the sample - u8 data[1]; // array of binary data - } data; -} SWAV; -- - - -
-6. SWAR File Format- |
-typedef struct tagSwar -{ - struct tagNdsStdFile { - char type[4]; // 'SWAR' - u32 magic; // 0x0100feff - u32 nFileSize; // Size of this SWAR file - u16 nSize; // Size of this structure = 16 - u16 nBlock; // Number of Blocks = 1 - } file; - struct { - char type[4]; // 'DATA' - u32 nSize; // Size of this structure - u32 reserved[8]; // reserved 0s, for use in runtime - u32 nSample; // Number of Samples - } data; - u32 nOffset[1]; // array of offsets of samples -} SWAR; -- -
NB. After the array of offsets, the binary samples follow. Each sample has a SWAVINFO structure before the sample data. Therefore, it is easy to make a SWAV from the samples in SWAR.
- - - - -
-7. STRM File Format- |
-typedef struct tagSTRM -{ - struct tagNdsStdFile { - char type[4]; // 'STRM' - u32 magic; // 0x0100feff - u32 nFileSize; // Size of this STRM file - u16 nSize; // Size of this structure = 16 - u16 nBlock; // Number of Blocks = 2 - } file; - struct { - char type[4]; // 'HEAD' - u32 nSize; // Size of this structure - u8 nWaveType; // 0 = PCM8, 1 = PCM16, 2 = (IMA-)ADPCM - u8 bLoop; // Loop flag = TRUE|FALSE - u8 nChannel; // Channels - u8 unknown; // always 0 - u16 nSampleRate; // Sampling Rate (perhaps resampled from the original) - u16 nTime; // (1.0 / rate * ARM7_CLOCK / 32) [ARM7_CLOCK: 33.513982MHz / 2 = 1.6756991e7] - u32 nLoopOffset; // Loop Offset (samples) - u32 nSample; // Number of Samples - u32 nDataOffset; // Data Offset (always 68h) - u32 nBlock; // Number of Blocks - u32 nBlockLen; // Block Length (Per Channel) - u32 nBlockSample; // Samples Per Block (Per Channel) - u32 nLastBlockLen; // Last Block Length (Per Channel) - u32 nLastBlockSample; // Samples Per Last Block (Per Channel) - u8 reserved[32]; // always 0 - } head; - struct { - char type[4]; // 'DATA' - u32 nSize; // Size of this structure - u8 data[1]; // Arrays of wave data - } data; -} SDATSTRM; -- -
A Block is the same as SWAV Wave Data.
- -Mono (SWAV)
-Block 1Stereo (STRM)
-Block 1 LIt isn't too shocking that a game with the complexity of Neverwinter Nights -(NWN) requires a large assortment of different data files. These files -define everything from the basic mechanics of the game all the way to the videos -played during the introduction.
-Assuming that you installed the game in the default directories, the data -files are spread out in the following directories.
-When NWN starts, it has available several methods to locate the data -files. Depending on the working directory or more probably the directory -of the executable, NWN can locate three key files, "chitin.key", -"dialog.tlk", and "nwn.ini".
-Chitin.key contains a listing of all the resources available to NWN at -runtime. Given a resource name, chitin.key can be used to locate the name -of the master data file (.BIF) containing the resource.
-Dialog.tlk is textual resource file. Given an number, dialog.tlk can -return the text associated with that number. This method has at least two benefits. -First, common strings can be stored in a central location instead of spread out amongst -many script files. This makes it possible to change the text without -having to modify or recompile the scripts that reference the string. The -second benefit is that depending on the language of the user, a different -dialog.tlk can be installed. For the French, the French dialog.tlk is -installed. (Note: I haven't actually seen exactly how Bioware does -language support. It is an assumption on my part that they just use different -dialog.tlk files. They could have dialog.tlk reserved as the common English -and then a different file name for each of the other languages.)
-Nwn.ini is a standard format Windows ini file. It contains much of the -game configuration information. The section of most interest to us however -is the "[Alias]" section. This section provides a mapping -between logical directory names and their physical counterparts. This -allowed the developers to not have to worry about the how the NWN installation -would look at release time. As long as the group producing the -installation system properly set the different keys in the "[Alias]" -section, NWN will file the data files without modification.
-For add on programs such as my NWN Explorer, Bioware stored NWN's -installation directory in the registry. The registry key -"HKEY_LOCAL_MACHINE\SOFTWARE\BioWare\NWN\Neverwinter\Location" -contains the installation directory. However, I would like to add that -anyone who wishes to develop 3rd party application for NWN should also allow the -user to specify the location of NWN. Even though I don't foresee Bioware -removing this registry key, there is always the chance that it might be missing -or invalid. Thus, it would be a shame if a user couldn't use your 3rd -party application because you were too lazy to add this simple feature.
- -NWN has a wide range of resource types. The following table lists most -of these types. (Many of these resource types might not be used by NWN but -were present in earlier Bioware games.)
- -Resource Name | -Resource Type | -
---|---|
RES | 0x0000 |
BMP | 0x0001 |
MVE | 0x0002 |
TGA | 0x0003 |
WAV | 0x0004 |
PLT | 0x0006 |
INI | 0x0007 |
BMU | 0x0008 |
MPG | 0x0009 |
TXT | 0x000A |
PLH | 0x07D0 |
TEX | 0x07D1 |
MDL | 0x07D2 |
THG | 0x07D3 |
FNT | 0x07D5 |
LUA | 0x07D7 |
SLT | 0x07D8 |
NSS | 0x07D9 |
NCS | 0x07DA |
MOD | 0x07DB |
ARE | 0x07DC |
SET | 0x07DD |
IFO | 0x07DE |
BIC | 0x07DF |
WOK | 0x07E0 |
2DA | 0x07E1 |
TLK | 0x07E2 |
TXI | 0x07E6 |
GIT | 0x07E7 |
BTI | 0x07E8 |
UTI | 0x07E9 |
BTC | 0x07EA |
UTC | 0x07EB |
DLG | 0x07ED |
ITP | 0x07EE |
BTT | 0x07EF |
UTT | 0x07F0 |
DDS | 0x07F1 |
UTS | 0x07F3 |
LTR | 0x07F4 |
GFF | 0x07F5 |
FAC | 0x07F6 |
BTE | 0x07F7 |
UTE | 0x07F8 |
BTD | 0x07F9 |
UTD | 0x07FA |
BTP | 0x07FB |
UTP | 0x07FC |
DTF | 0x07FD |
GIC | 0x07FE |
GUI | 0x07FF |
CSS | 0x0800 |
CCS | 0x0801 |
BTM | 0x0802 |
UTM | 0x0803 |
DWK | 0x0804 |
PWK | 0x0805 |
BTG | 0x0806 |
UTG | 0x0807 |
JRL | 0x0808 |
SAV | 0x0809 |
UTW | 0x080A |
4PC | 0x080B |
SSF | 0x080C |
HAK | 0x080D |
NWM | 0x080E |
BIK | 0x080F |
PTM | 0x0811 |
PTT | 0x0812 |
ERF | 0x270D |
BIF | 0x270E |
KEY | 0x270F |
NWN has built-in support for different languages. Each of these -languages also has a male and female version. These languages are commonly -used in names, descriptions, and dialogs.
-Language | -ID | -
---|---|
English | 0 |
French, Male | 2 |
French, Female | 3 |
German, Male | 4 |
German, Female | 5 |
Italian, Male | 6 |
Italian, Female | 7 |
Spanish, Male | 8 |
Spanish, Female | 9 |
- - - \ No newline at end of file diff --git a/doc/specs/torlack/bif.html b/doc/specs/torlack/bif.html deleted file mode 100644 index f655e0e5ad..0000000000 --- a/doc/specs/torlack/bif.html +++ /dev/null @@ -1,103 +0,0 @@ - - -
BIF files contain the actual data files referenced in KEY files.
-- The BIF file begins with a header.
-- Offset | -- Type | -- Description | -
---|---|---|
0x0000 | -CHAR [4] | -File type signature (usually "BIFF") | -
0x0004 | -CHAR [4] | -Version number (usually "V1 ") | -
0x0008 | -UINT32 | -Number of resources in the file | -
0x000C | -UINT32 | -- Unknown value | -
0x0010 | -UINT32 | -Offset from the start of file to the first resource structure | -
0x0014 | -Total size of the structure | -
For each resource contained in a BIF, there is a corresponding entry in the - resource list. This list begins in the file at the offset specified in - the header. The resource structures are stored sequentially in the BIF - file. The BIF header specifies the number of resources.
-- Offset | -- Type | -- Description | -
---|---|---|
0x0000 | -UINT32 | -Key file ID of the resource | -
0x0004 | -UINT32 | -Offset from the start of the file to the given resource | -
0x0008 | -UINT32 | -Length of the resource in bytes | -
0x000C | -UINT32 | -Type of the resource | -
0x0010 | -Total size of the structure | -
The binary format of the model files contains 3 main sections, the header, -the model data and the vertex or raw data.
-The header is a only twelve bytes long. It provides us with the offset -and size of the raw data, and a 32 bit value of 0. The value of 0 is -important since it can be used to tell the difference between an ASCII model -file and a binary one. The chances of an ASCII model file starting with 4 -bytes of 0 is somewhere between zero and none.
-Offset | -Type | -Description | -
---|---|---|
0x0000 | -UINT32 | -Value of 0 for binary models | -
0x0004 | -UINT32 | -Offset to the raw data/Size of the model data | -
0x0008 | -UINT32 | -Size of the raw data | -
0x000C | -Total length of the structure | -
The model data follows the header in the file. Immediately following -the model data is the raw data. Thus, the second value in the header can -be either the model size or the offset from the start of the model data to the -raw data. Either interpretation works since they are the exact same value.
-The structure of the model is reasonably complex. Not only does it -contain structures of data, but those structures reference other -structures. This is accomplished using arrays and pointers.
-There are two types of pointers inside of a model file, model data pointer -and raw data pointer. Each of these pointers are stored as a 32 bit -value. In the case of model data pointers, the pointer will contain an -offset from the start of the model data to the data in question. A value -of zero represents a "NULL" pointer or a pointer that doesn't -reference anything. For raw data pointers, the pointer will contain an -offset from the start of the raw data to the data in question. A value of -0xFFFFFFFF (unsigned) or -1 (signed) represents a "NULL" pointer or a -pointer that doesn't reference anything. The reason the raw data uses a -value of -1 is that an offset of zero is a valid pointer into the raw -data. Excluding one special case, this isn't true for model data -pointers. (Only one element in a binary model file points to the data at -offset zero in the model data. However, this value is transient and isn't -actually stored in the model file.)
-Some of you might be wondering why I am referring to these offsets as -pointers. After all, in the binary model format, they are always offsets -and never actually a real pointer. That is very true for the disk image of -a model. However, on 32 bit address processors (or processors such as the -Alpha that can run in 32 bit address mode with sign extend), after the model is -loaded from disk, all the offsets can be converted to pointers. This -improves greatly the run time performance.
-Arrays in models are a slightly more complicated beast. They -consist of the following three elements.
-Offset | -Type | -Description | -
---|---|---|
0x0000 | -UINT32 | -Pointer/Offset to the first elements of the array | -
0x0004 | -UINT32 | -Number of used entries in the array | -
0x0008 | -UINT32 | -Number of allocated entries in the array | -
0x000C | -Total length of the structure | -
For binary model files, the number of used entries and number of allocated -entries will always be the same. During run time or complication time, -these value will usually differ since these arrays by nature will grow as more -elements are added.
- -Arrays can contain most anything as long as the elements are all the same -type. Examples of common arrays in model files would be arrays of vertices, -faces, and even pointers. In the case of pointers, these arrays are -commonly used to represent a model hierarchy.
- -Each node (to be defined later), in a model can contain zero or more -controllers. Controllers can be considered as attributes of a node. -They defined certain aspects of the node. One of the most common -controller is the position controller. This controller dictates the -position of the node relative to the parent node.
- -One of the first obvious questions about controllers is why isn't this -information included as part of the standard node structures. There are -two reasons for this. The first reason is that controllers are -optional. In the case of an emitter node, there are around 50 different -controllers that can be specified. Having to dedicate storage space to all -of these controllers, used or not, would be a waste of space. The second -and more important reason is that controllers can be animated.
- -To animate a model, the model must change over time. The way to do this -is with time keyed controllers. All animations take a given amount of time -from start to finish. For example, the swing of a sword might take 1 -second of total animation time. In order to draw the model properly, -controllers have different that are time keyed. For example, normally, the -position controller would be specified as follows.
- -- -- -position 0.2 1.0 0.124- -
However, in the case of a time keyed position, it would be specified as -follows.
- -- -- -positionkey 3 - 0.0 0.2 1.0 0.124 - 0.4 0.4 1.0 0.510 - 0.8 0.6 1.0 0.516- -
When specifying a time keyed controller, the first value is the start time -for that value. Following the start time is the actual value. In -this case, during animation time 0.0 through 0.4, the first position will be -used. Between 0.4 and 0.8, the second position will be used. Between -0.8 and the animation time for the given animation, the 3rd value will be used.
- -To provide smoother animations, the values will be interpolated. -For example, given our previous data, if the current animation time was 0.2, -then that would be half way between the first and second positions. Thus -each position will contribute equally to the actual position used. If the -animation time was earlier, then the first position would be given more -weight. The opposite is true if the animation time was later.
- -To provide an even smoother animation, a second style of interpolation is -available. It is know as "bezier" interpolation. Bezier -interpolation is used when you specify "bezierkey" as the suffix to -the controller name. (Note: At this time, I have not verified that any -Bioware model uses bezier interpolation. I don't even know if the -rendering engine supports this option.)
- -Inside a binary model file, controllers are stored as two arrays in the model -data. The first array is an array of a controller structure. The -second array is a simple array of floating point numbers. The second array -contains the actual controller data while the first tells us about all the -controllers in the array. The controller structure is as follows.
- -Offset | -Type | -Description | -
---|---|---|
0x0000 | -INT32 | -Type of controller | -
0x0004 | -INT16 | -Number of rows of controller data | -
0x0006 | -INT16 | -Index into the float array of the first time key | -
0x0008 | -INT16 | -Index into the float array of the first controller data value | -
0x000A | -INT8 | -Number of columns excluding the time key column | -
0x000B | -INT8 | -Pad, not used | -
0x000C | -Total length of the structure | -
There are a few important notes about the controller structure. The -first thing of note is that for controllers that aren't time keyed, they are -still stored as if they are time keyed but with a single row and a time key -value of zero. Thus, it is impossible to tell the difference between a -controller that isn't time keyed, and a time keyed controller with a single row -and a time key value of zero. The second important note is that if the -controller is actually bezier keyed, then the value of 0x10 is ORed in with the -number of columns. This is how you can tell the difference between a -normal keyed controller and a bezier keyed controller. Finally, all key -values are stored continuously and all the data values are stored -contiguously. Thus, if a keyed controller had 3 rows with the time keys -starting at floating point value 5, then the time keys for the other two rows -would be value 6 and value 7. Also, it appears that for some models, the -controller "detonate" when used as a key controller doesn't even list -a time key. Thus, the number of columns listed is -1.
-Following is a list of all controllers:
-Name | -Value | -Used in nodes | -
---|---|---|
Position | -8 | -All | -
Orientation | -20 | -All | -
Scale | -36 | -All | -
Color | -76 | -Light | -
Radius | -88 | -Light | -
ShadowRadius | -96 | -Light | -
VerticalDisplacement | -100 | -Light | -
Multiplier | -140 | -Light | -
AlphaEnd | -80 | -Emitter | -
AlphaStart | -84 | -Emitter | -
BirthRate | -88 | -Emitter | -
Bounce_Co | -92 | -Emitter | -
ColorEnd | -96 | -Emitter | -
ColorStart | -108 | -Emitter | -
CombineTime | -120 | -Emitter | -
Drag | -124 | -Emitter | -
FPS | -128 | -Emitter | -
FrameEnd | -132 | -Emitter | -
FrameStart | -136 | -Emitter | -
Grav | -140 | -Emitter | -
LifeExp | -144 | -Emitter | -
Mass | -148 | -Emitter | -
P2P_Bezier2 | -152 | -Emitter | -
P2P_Bezier3 | -156 | -Emitter | -
ParticleRot | -160 | -Emitter | -
RandVel | -164 | -Emitter | -
SizeStart | -168 | -Emitter | -
SizeEnd | -172 | -Emitter | -
SizeStart_Y | -176 | -Emitter | -
SizeEnd_Y | -180 | -Emitter | -
Spread | -184 | -Emitter | -
Threshold | -188 | -Emitter | -
Velocity | -192 | -Emitter | -
XSize | -196 | -Emitter | -
YSize | -200 | -Emitter | -
BlurLength | -204 | -Emitter | -
LightningDelay | -208 | -Emitter | -
LightningRadius | -212 | -Emitter | -
LightningScale | -216 | -Emitter | -
Detonate | -228 | -Emitter | -
AlphaMid | -464 | -Emitter | -
ColorMid | -468 | -Emitter | -
PercentStart | -480 | -Emitter | -
PercentMid | -481 | -Emitter | -
PercentEnd | -482 | -Emitter | -
SizeMid | -484 | -Emitter | -
SizeMid_Y | -488 | -Emitter | -
SelfIllumColor | -100 | -All Meshes | -
Alpha | -128 | -All Meshes | -
All nodes in a model begin with six values which have also been called -"tokens". During the early process of decoding the binary -models, many people including myself made the mistake that these tokens were -used to identify the different types of nodes. As silly as it sounds, this -was the best we could do at the time. These six tokens did uniquely -identify each of the nodes. However, I and I would imagine most others -knew there had to be a deeper meaning to these tokens. Nobody uses 6 -4-byte values to uniquely identify a handful of different nodes. All of -these tokens were values in the range of 0x00400000 and 0x00500000. There -was no apparent bit mask to the values. However, the difference between -the token values was interesting since it was usually either 0x10 or 0x20. -Now, if someone was really had everything on the ball and had a reasonable -knowledge of the Win32 image loader, they would have realized something that -eluded everyone, including myself for the longest time. These tokens were -not tokens, they were routine addresses. You see, the Win32/NT image -loader loads images at 0x0041000. Thus, the funny start to all the -numbers.
-So, as of now, these "tokens" should be consider unreliable as a -method of identifying model node types. What if Bioware releases new -models using a new build of their model compiler and these routine addresses -change. All the existing software that utilizes these "tokens" -would fail.
-Luckily, the proper way to identify the node type has been located. -Every node contains a 32 bit bit mask that identifies which structures make up -the node. Following is a list of all the flags.
-Name | -Value | -
---|---|
HasHeader | -0x00000001 | -
HasLight | -0x00000002 | -
HasEmitter | -0x00000004 | -
HasReference | -0x00000010 | -
HasMesh | -0x00000020 | -
HasSkin | -0x00000040 | -
HasAnim | -0x00000080 | -
HasDangly | -0x00000100 | -
HasAABB | -0x00000200 | -
Every node contains a node header. In the case of a dummy node, only a -node header is required. All mesh nodes also contain a mesh structure. In -the case of a trimesh node, only the node header and the mesh header is -required. By looking at a combination of flags, not only do we know what -structures make up the node, but we know what the node type is.
-Name | -Value | -
---|---|
Dummy | -0x00000001 | -
Light | -0x00000003 | -
Emitter | -0x00000005 | -
Reference | -0x00000011 | -
TriMesh | -0x00000021 | -
SkinMesh | -0x00000061 | -
AnimMesh | -0x000000A1 | -
DanglyMesh | -0x00000121 | -
AABBMesh | -0x00000221 | -
As you can see, each of the different node types contains one or more flags.
- -Part numbers are values assigned to nodes as the model compiler creates -them. However, after the complete geometry has been compiled, these values -are adjusted.
- -If a model has a super model, then the geometry for the model is compared -against the geometry for the super model. Any node that matches the name -of a node in the super model will be given the part number assigned to the node -in the super model. If a node in the model isn't found in the super model, -then it receives a part number of -1. If a model doesn't have a super -model, then the part numbers are left as is.
- -After the geometry for an animation has been compiled, the same process is -used to match the nodes in the animation with the nodes in the main model -geometry. It is important to note that the animation geometry is compare -against the model's geometry and not the model's super model geometry.
- -The basic layout of the binary model file is as follows:
-File Header | -|
Model - Data |
- Model Geometry Header | -
Node 1 | -|
Node 2 | -|
... | -|
Node N | -|
Animation Geometry Header 1 | -|
Node 1 | -|
Node 2 | -|
... | -|
Node N | -|
Animation Geometry Header 2 | -|
Node 1 | -|
Node 2 | -|
... | -|
Node N | -|
Animation Geometry Header N | -|
Raw Data | -
Not all models contain animation headers. Also, in many models, there -might be no raw data. It is also important to remember that this diagram -is a simplification of the real model layout. For example, to fully -defined a node, it might take 100 bytes of data or 10,000 bytes of data. -This information might be scattered in sections throughout the model data.
-All models contain at least one geometry header. This header is part of -the larger model geometry header. If the model contains animations, then -there will be a geometry header in each of the animation geometry headers. -
-The format of the geometry header is as follows:
-Offset | -Type | -Description | -
---|---|---|
0x0000 | -Function Pointer | -Pointer to a function | -
0x0004 | -Function Pointer | -Pointer to the function to parse a ASCII model line | -
0x0008 | -CHAR [64] | -Geometry Name (model or animation name) | -
0x0048 | -Node Header Pointer | -Pointer/Offset to the root node of the geometry | -
0x004C | -UINT32 | -Number of nodes in the geometry. In the case of the - model geometry, if the model has a super mode defined, then this value - also includes the number of nodes in the super model plus one. | -
0x0050 | -Pointer Array | -Array of unknown data (probably runtime only) | -
0x005C | -Pointer Array | -Array of unknown data (probably runtime only) | -
0x0068 | -UINT32 | -Reference count, initialized to 0. When another - model references this model, then this value is incremented. When - the referencing model dereferences this model the count is - decremented. When this count goes to zero, the model can be - deleted since it is no longer needed. | -
0x006C | -UINT8 | -Geometry Type - 0x01 = Basic geometry header (not in models) - 0x02 = Model geometry header - 0x05 = Animation geometry header - 0x80 = If bit is set, then model is a compiled binary model loaded from - disk and converted to absolute addresses. |
-
0x006D | -UINT8 [3] | -Padding | -
0x0070 | -Total length of the structure | -
As noted, the two arrays at 0x50 and 0x5C, and the data at 0x68 is unknown at -this time.
-There is only one model header per model file. This header always -starts at offset 0 in the model data section or offset 12 from the start of the -file.
-Offset | -Type | -Description | -
---|---|---|
0x0000 | -Geometry Header | -Geometry Header | -
0x0070 | -UINT8 | -Unknown value initialized to 0 | -
0x0071 | -UINT8 | -Unknown value initialized to 1 | -
0x0072 | -UINT8 | -Model classification: - 0x01 = Effect - 0x02 = Tile - 0x04 = Character - 0x08 = Door |
-
0x0073 | -UINT8 | -If non-zero, model should be fogged | -
0x0074 | -UINT32 | -Unknown value initialized to 0 | -
0x0078 | -Animation Header Pointer Array | -Array of pointers to all the animation geometries | -
0x0084 | -Pointer to parent model | -Pointer to the parent model, always 0 | -
0x0088 | -FLOAT [3] | -Bounding box min for the model, defaults to (-5, -5, -1) | -
0x0094 | -FLOAT [3] | -Bounding box max for the model., defaults to (5, 5, 10) | -
0x00A0 | -FLOAT | -Radius of the model, defaults to 7.0 | -
0x00A4 | -FLOAT | -Animation scale, defaults to 1.0 | -
0x00A8 | -CHAR [64] | -Super model name, defaults to "" | -
0x00E8 | -Total length of the structure | -
There are zero or more animation headers per model, one header for each -animation. All animations contain their own geometry information. -However, this usually consists of dummy nodes containing controller information.
-Offset | -Type | -Description | -
---|---|---|
0x0000 | -Geometry Header | -Geometry Header | -
0x0070 | -FLOAT | -Animation length, defaults to 1.0 | -
0x0074 | -FLOAT | -Trans time, defaults to 0.25 | -
0x0078 | -CHAR [64] | -Animation root, defaults to "" | -
0x00B8 | -Animation Event Array | -Array of all the events associated with this animation | -
0x00C4 | -Total length of the structure | -
Each animation can have zero or more events. Unlike other arrays that -contain pointers to the structures, the animation event array is an array of the -actual structure. The structure is as follows:
-Offset | -Type | -Description | -
---|---|---|
0x0000 | -FLOAT | -After | -
0x0004 | -CHAR [32] | -Event name | -
0x0024 | -Total length of the structure | -
Currently, there are nine different nodes types that make up a model's -geometry. These nodes specify such elements as lighting, animated graphics -emitters, and different types of meshes. Each node type share a common -header that supplies us with enough information to tell what type of node it is -and information about controllers and children.
-Offset | -Type | -Description | -
---|---|---|
0x0000 | -Function Pointer | -Unknown function | -
0x0004 | -Function Pointer | -Function to parse a line of an ASCII model file | -
0x0008 | -Function Pointer | -Function to perform post node processing | -
0x000C | -Function Pointer | -Unknown function | -
0x0010 | -Function Pointer | -Unknown function | -
0x0014 | -Function Pointer | -Unknown function | -
0x0018 | -UINT32 | -Inherit color flag | -
0x001C | -UINT32 | -Part number/Node number | -
0x0020 | -CHAR [32] | -Node name | -
0x0040 | -Geometry Pointer | -Pointer to the parent geometry, always zero | -
0x0044 | -Parent Node Pointer | -Pointer to the parent node, always zero | -
0x0048 | -Node Header Pointer Array | -Array of pointer to the children nodes | -
0x0054 | -Controller Key Array | -Array of controller key structures | -
0x0060 | -FLOAT Array | -Array of controller data values | -
0x006C | -UINT32 | -Node flags/type | -
0x0070 | -Total length of the structure | -
All nodes that contain mesh information share a common header. The -header is as follows:
-Offset | -Type | -Description | -
---|---|---|
0x0000 | -Node Header | -Common node header | -
0x0070 | -Function Pointer | -Function to prepare the mesh information | -
0x0074 | -Function Pointer | -Function to cleanup after mesh has been built | -
0x0078 | -Face Array | -Array of face structures | -
0x0084 | -FLOAT [3] | -Bounding box min, defaults to (0, 0, 0), computed | -
0x0090 | -FLOAT [3] | -Bounding box max, defaults to (0, 0, 0), computed | -
0x009C | -FLOAT | -Mesh radius, defaults to 0, computed | -
0x00A0 | -FLOAT [3] | -Average of all points in the mesh, defaults to (0, 0, 0), computed | -
0x00AC | -FLOAT [3] | -Diffuse color, defaults to (0.8, 0.8, 0.8) | -
0x00B8 | -FLOAT [3] | -Ambient color, defaults to (0.2, 0.2, 0.2) | -
0x00C4 | -FLOAT [3] | -Specular color, defaults to (0, 0, 0) | -
0x00D0 | -FLOAT | -Shininess, defaults to 1 | -
0x00D4 | -UINT32 | -Shadow flag, defaults to 1 | -
0x00D8 | -UINT32 | -Beaming flag, defaults to 0 | -
0x00DC | -UINT32 | -Render flag, defaults to 1 excluding AABB mesh where it defaults to 0 | -
0x00E0 | -UINT32 | -Transparency hint, defaults to 0 excluding AABB mesh where it defaults - to 1 | -
0x00E4 | -UINT32 | -Unknown value, defaults to 0. Known values probably - 0, 1, 2, and 4. | -
0x00E8 | -CHAR [64] | -Texture0/Bitmap | -
0x0128 | -CHAR [64] | -Texture1 | -
0x0168 | -CHAR [64] | -Texture2 | -
0x01A8 | -CHAR [64] | -Texture3 | -
0x01E8 | -UINT32 | -Tile fade, defaults to 0 | -
0x01EC | -UINT32 Pointer Array | -Vertex Indices, compile only, not stored in binary | -
0x01F8 | -UINT32 Array | -Left over faces, compile only, not stored in binary?? | -
0x0204 | -UINT32 Array | -Vertex Indices count array | -
0x0210 | -Raw UINT16 Pointer Array | -Vertex Indices offset array (The pointers exist in the - model data, however, the list of UINT16 that they point to exist in the - raw data. | -
0x021C | -Raw Data Pointer | -Unknown, probably used with triangle strips, initialized to -1 | -
0x0220 | -UINT32 | -Unknown, probably used with triangle strips, initialized to 0 | -
0x0224 | -UINT8 | -Triangle mode - 0x03 = Triangle - 0x04 = Triangle Strips |
-
0x0225 | -UINT8 [3] | -Padding | -
0x0228 | -Pointer | -Pointer to a compile only structure, always zero | -
0x022C | -Raw FLOAT [3] Pointer | -Pointer to the vertex data, stored in the raw data region, -1 if not - present | -
0x0230 | -UINT16 | -Vertex count | -
0x0232 | -UINT16 | -Texture count, usually 1 | -
0x0234 | -Raw FLOAT [2] Pointer | -Pointer to the texture 0 vertex data, stored in the raw data region, - -1 if not present | -
0x0238 | -Raw FLOAT [2] Pointer | -Pointer to the texture 1 vertex data, stored in the raw data region, - -1 if not present | -
0x023C | -Raw FLOAT [2] Pointer | -Pointer to the texture 2 vertex data, stored in the raw data region, - -1 if not present | -
0x0240 | -Raw FLOAT [2] Pointer | -Pointer to the texture 3 vertex data, stored in the raw data region, - -1 if not present | -
0x0244 | -Raw FLOAT [3] Pointer | -Pointer to the vertex normals, stored in the raw data region, -1 if - not present | -
0x0248 | -Raw UINT32 Pointer | -Pointer to the vertex RGBA colors, stored in the raw data region, -1 - is not present | -
0x024C | -Raw FLOAT [3] Pointer | -Pointer to texture animation data, stored in the raw data region, -1 - if not present | -
0x0250 | -Raw FLOAT [3] Pointer | -Pointer to texture animation data, stored in the raw data region, -1 - if not present | -
0x0254 | -Raw FLOAT [3] Pointer | -Pointer to texture animation data, stored in the raw data region, -1 - if not present | -
0x0258 | -Raw FLOAT [3] Pointer | -Pointer to texture animation data, stored in the raw data region, -1 - if not present | -
0x025C | -Raw FLOAT [3] Pointer | -Pointer to texture animation data, stored in the raw data region, -1 - if not present | -
0x0260 | -Raw FLOAT? Pointer | -Pointer to texture animation data, stored in the raw data region, -1 - if not present | -
0x0264 | -UINT8 | -Light mapped flag, defaults to 0 | -
0x0265 | -UINT8 | -Rotate texture flag, defaults to 0 | -
0x0266 | -UINT16 | -Padding | -
0x0268 | -FLOAT | -Vertex normal sum divided by 2, initialized to 0 | -
0x026C | -UINT32/FLOAT | -Unknown, initialized to 0 | -
0x0270 | -Total length of structure | -
The two arrays at 0x0210 and 0x0204 are interrelated. The array at 0x0210 -isn't an array of UINT16s, it is an array of pointers to lists of UINT16. -The number of UINT16s in each of the lists is specified by the elements of the -array at 0x0204. For the second entry in both 0x0210 and 0x0204, the array -0x0204 might tell us the there are 14 vertices in the list while the 0x0210 -array gives us the pointer to the list.
-All the pointers 0x022C through 0x0248 point to lists of data. The -number of elements in these list is specified by the UINT16 at 0x0230 which is -the vertex count.
-The face structure is as follows:
-Offset | -Type | -Description | -
---|---|---|
0x0000 | -FLOAT [3] | -Plane normal | -
0x000C | -FLOAT | -Plane distance | -
0x0010 | -INT32 | -Surface ID | -
0x0014 | -INT16 [3] | -Adjacent face number or -1 | -
0x001A | -INT16 [3] | -Vertex indices | -
0x0020 | -Total length of structure | -
The dummy node is a default node in a geometry that only contains children -nodes and controller information. It has no other data associated with it.
-Offset | -Type | -Description | -
---|---|---|
0x0000 | -Node Header | -Common node header | -
0x0070 | -Total length of structure | -
The light node specifies light sources in the geometry of the model.
-Offset | -Type | -Description | -
---|---|---|
0x0000 | -Node Header | -Common node header | -
0x0070 | -FLOAT | -Flare radius | -
0x0074 | -UINT32 Array | -Array of unknown information | -
0x0080 | -FLOAT Array | -Flare sizes | -
0x008C | -FLOAT Array | -Flare positions | -
0x0098 | -FLOAT [3] Array | -Flare color shifts | -
0x00A4 | -CHAR Pointer Array | -Array of pointers to the flare texture names | -
0x00B0 | -UINT32 | -Light priority, defaults to 5 | -
0x00B4 | -UINT32 | -Ambient only flag, defaults to 0 | -
0x00B8 | -UINT32 | -Dynamic type, defaults to 1 | -
0x00BC | -UINT32 | -Affect dynamic flag, defaults to 1 | -
0x00C0 | -UINT32 | -Shadow flag, defaults to 1 | -
0x00C4 | -UINT32 | -Generate flare flag, defaults to 0 | -
0x00C8 | -UINT32 | -Fading light flag, defaults to 1 | -
0x00CC | -Total length of structure | -
The emitter node specifies dynamic graphical elements that are emitted from -the model such as smoke or sparkles.
-Offset | -Type | -Description | -
---|---|---|
0x0000 | -Node Header | -Common node header | -
0x0070 | -FLOAT | -Dead space | -
0x0074 | -FLOAT | -Blast radius, defaults to 0 | -
0x0078 | -FLOAT | -Blast length, defaults to 0 | -
0x007C | -UINT32 | -X grid | -
0x0080 | -UINT32 | -Y grid | -
0x0084 | -UINT32 | -Space type, defaults to 0 | -
0x0088 | -CHAR [32] | -Update | -
0x00A8 | -CHAR [32] | -Render | -
0x00C8 | -CHAR [32] | -Blend | -
0x00E8 | -CHAR [64] | -Texture | -
0x0128 | -CHAR [16] | -Chunk name | -
0x0138 | -UINT32 | -Two sided texture flag, defaults to 0 | -
0x013C | -UINT32 | -Loop flag, defaults to 0 | -
0x0140 | -UINT16 | -Render order, defaults to 0 | -
0x0142 | -UINT16 | -Padding | -
0x0144 | -UINT32 | -Emitter flags - 0x0001 = P2P - 0x0002 = P2P Sel - 0x0004 = Affected by Wind - 0x0008 = Is Tinted - 0x0010 = Bounce - 0x0020 = Random - 0x0040 = Inherit - 0x0080 = Inherit Vel - 0x0100 = Inherit Local - 0x0200 = Splat - 0x0400 = Inherit Part |
-
0x0148 | -Total length of structure | -
The reference node... TBD
-Offset | -Type | -Description | -
---|---|---|
0x0000 | -Node Header | -Common node header | -
0x0070 | -CHAR [64] | -Ref model | -
0x00B0 | -UINT32 | -Reattachable flag | -
0x00B4 | -Total Length of structure | -
The trimesh node provides the basic drawing mesh used to render elements of -the game.
-Offset | -Type | -Description | -
---|---|---|
0x0000 | -Mesh Header | -Common mesh header | -
0x0270 | -Total Length of structure | -
The skin mesh node provides a specialized mesh where the texture is stretched -and contorted as the model moves to provide a more realistic look to skin. -It is mostly used just for things such as dragon wings.
-Offset | -Type | -Description | -
---|---|---|
0x0000 | -Mesh Header | -Common mesh header | -
0x0270 | -Weight Array | -Used during compile time to store weight information | -
0x027C | -Raw FLOAT [4] Pointer | -Compiled weight information for each vertex | -
0x0280 | -Raw UINT16 [4] Pointer | -Reference index for bones | -
0x0284 | -Raw UINT16 Pointer | -Bone reference mapping array | -
0x0288 | -UINT32 | -Number of entries in the mapping array | -
0x028C | -Quaternion Array | -QBone ref inv | -
0x0298 | -FLOAT [3] Array | -TBome ref inv | -
0x02A4 | -UINT32 Array | -Bone constant indices | -
0x02B0 | -UINT16 [17] | -Bone part numbers | -
0x02D2 | -UINT16 | -Spare | -
0x02D4 | -Total length of structure | -
Most all skin data is computed from the weights array.
-The animmesh nodes are used for the game's GUI
-Offset | -Type | -Description | -
---|---|---|
0x0000 | -Mesh Header | -Common mesh header | -
0x0270 | -FLOAT | -Sample Period | -
0x0274 | -FLOAT [3] Array | -Animation vertices, not stored in binary | -
0x0280 | -FLOAT [3] Array | -Animation texture vertices, not stored in binary | -
0x028C | -FLOAT [3] Array | -Animation vertex normals, not stored in binary | -
0x0298 | -FLOAT [3] Pointer | -Pointer to the stored animation vertex information | -
0x029C | -FLOAT [2] Pointer | -Pointer to the stored animation texture vertex - information | -
0x02A0 | -UINT32 | -Number of vertex sets | -
0x02A4 | -UINT32 | -Number of texture vertex sets | -
0x02A8 | -Total length of structure | -
The stored arrays are much like the other stored vertex arrays. There -size is the number of sets times the number of mesh vertices. There is -also a difference between how this information is parsed from the ASCII version -and stored in the binary. In the ASCII version, each vertex is listed sequentially -for each vertex or texture vertex sets. However, in the binary -version, each vertex is store with the different sets store sequentially.
-The danglymesh node provides a model with the look of movement by allowing -faces to move due to momentum even after the whole model has stopped. Thus -is much like how a car passenger jerks forward in a car when it stops suddenly.
-Offset | -Type | -Description | -
---|---|---|
0x0000 | -Mesh Header | -Common mesh header | -
0x0270 | -FLOAT Array | -Vertex constraints | -
0x027C | -FLOAT | -Displacement value | -
0x0280 | -FLOAT | -Tightness value | -
0x0284 | -FLOAT | -Period value | -
0x0288 | -Total length of structure | -
Much like the vertex information for the mesh, the constrains are expanded to -match the vertex list stored in the model.
-The aabb node provides the game with the ability to test for collisions.
-Offset | -Type | -Description | -
---|---|---|
0x0000 | -Mesh Header | -Common mesh header | -
0x0270 | -AABB Entry Pointer | -AABB table root pointer | -
0x0274 | -Total length of structure | -
The following is the layout of the AABB entry structure.
-Offset | -Type | -Description | -
---|---|---|
0x0000 | -FLOAT [3] | -Min bounding box | -
0x000C | -FLOAT [3] | -Max bounding box | -
0x0018 | -AABB Entry Pointer | -Left node | -
0x001C | -AABB Entry Pointer | -Right node | -
0x0020 | -INT32 | -Leaf face part number or -1 if not a leaf | -
0x0020 | -UINT32 | -Most significant plane??? - 0x01 = Positive X - 0x02 = Positive Y - 0x04 = Positive Z - 0x08 = Negative X - 0x10 = Negative Y - 0x20 = Negative Z |
-
0x0024 | -Total length of structure | -
I wanted to thank Zaddix and Revinor. Their information about the -binary model formats provided an excellent starting point for my work.
- - - - diff --git a/doc/specs/torlack/itp.html b/doc/specs/torlack/itp.html deleted file mode 100644 index fbdf00324b..0000000000 --- a/doc/specs/torlack/itp.html +++ /dev/null @@ -1,618 +0,0 @@ - - -(Note: ITP files are more correctly known as the GFF and BioWare's - documentation can be found here.)
-An ITP file can be thought of as a hierarchical collection variables.
-That cleared it up, didn't it.
-In an ITP file, you have a series of what can be considered variable assignments - such as 'PlayerName = "Francis"'. There can practically be an infinite - number of variable assignments in one file. Also, ITP files allow you to - nest variable assignments much the way a programmer might nest structures.
-ITP files are very common in NWN. The format is used for a wide collection - of files such as; ITP, BIC, DLG, GIT, GFF, FAC, UTI, UTC, UTT, UTS, UTE, UTD, - UTP, UTM, and UTW. All of these different files share the same common - file format. So in reality calling the file format ITP is inaccurate, but - it is the name we all know best.
-ITP files contain seven sections of data. The sections are as follows:
-- Offset | -- Type | -- Description | -
---|---|---|
0x0000 | -char [4] | -4 byte signature. | -
0x0004 | -char [4] | -4 byte version. | -
0x0008 | -UINT32 | -Offset from start of the file to the first entry | -
0x000C | -UINT32 | -Number of entries in the file | -
0x0010 | -UINT32 | -Offset from start of the file to the first element | -
0x0014 | -UINT32 | -Number of elements in the file | -
0x0018 | -UINT32 | -Offset from start of the file to the first variable name | -
0x001C | -UINT32 | -Number of names in the variable name block | -
0x0020 | -UINT32 | -Offset from start of the file to the first variable data | -
0x0024 | -UINT32 | -Number of bytes in the variable data block | -
0x0028 | -UINT32 | -Offset from start of the file to the first multimap | -
0x002C | -UINT32 | -Number of bytes in the multimap table | -
0x0030 | -UINT32 | -Offset from start of the file to the first list | -
0x0034 | -UINT32 | -Number of bytes in the list table | -
0x0038 | -Total length of the structure | -
All offsets in the file header are from the start of the file. The file - header is always at offset zero. It seems that the offset to the first - entry is always 0x0038. But please note that for entries and elements, we - are given the number of entries or elements. For the four remaining data - sections, the total section length is given in bytes.
-The entity table is an array of structures of the following form:
-- Offset | -- Type | -- Description | -
---|---|---|
0x0000 | -UINT32 | -Entity code (Use unknown) | -
0x0004 | -UINT32 | -Element index or MultiMap offset | -
0x0008 | -UINT32 | -Number of elements in this entry | -
0x000C | -Total length of the structure | -
The first entry in the entry table is the root of whole hierarchy. From - that one entry, all other entries and elements can be accessed in a logical - form.
-Entries only serve one function, to contain one or more elements. - Depending on the number of elements contained in an entry, accessing the - elements can either be easy or require indirect referencing. When an - entry contains only one element, and thus the value at offset 0x0008 is one, - then the value at offset 0x0004 is the index in the element table of the only - child. When an entry contains more than one element, then the value at - offset 0x0004 contains a byte offset into the multimap table. This offset - points to an array of element numbers stored as UINT32 values. -
-Here is an example of how you might iterate through the list of elements for an - entity. This code assumes that the whole file is resident in memory in a - contiguous buffer.
---char *pFileData = AddressOfTheITPDataInMemory; -Header *pHeader = (Header *) pFileData; -Entry *pEntryTable = (Entry *) &pFileData [pHeader ->EntryOffset]; -Element *pElementTable = (Element *) &pFileData [pHeader ->ElementOffset]; - -Entry *pEntry = &pEntryTable [0]; // For this example, use root entry - -if (pEntry ->Count == 1) // We have one element -{ - Element *pElement = &pElementTable [pEntry ->Offset]; - // Do something with the element -} -else //more than one -{ - UINT32 *pMMap = (UINT32 *) &pFileData [pHeader ->MultiMapOffset + pEntry ->Offset]; - for (int i = 0; i < pEntry ->Count; i++) - { - Element *pElement = &pElementTable [pMMap [i]]; - // Do something with the element - } -}-
There is one trick you can use to reduce duplicated code. I use this trick - in my software.
---char *pFileData = AddressOfTheITPDataInMemory; -Header *pHeader = (Header *) pFileData; -Entry *pEntryTable = (Entry *) &pFileData [pHeader ->EntryOffset]; -Element *pElementTable = (Element *) &pFileData [pHeader ->ElementOffset]; - -Entry *pEntry = &pEntryTable [0]; // For this example, use root entry - -UINT32 *pMMap; -if (pEntry ->Count == 1) - pMMap = &pEntry ->Offset; -else - pMMap = (UINT32 *) &pFileData [pHeader ->MultiMapOffset + pEntry ->Offset];-for (int i = 0; i < pEntry ->Count; i++) -{ - Element *pElement = &pElementTable [pMMap [i]]; - // Do something with the element -}-
The element table is an array of structures of the following form: -
-- Offset | -- Type | -- Description | -
---|---|---|
0x0000 | -UINT32 | -Variable type (0-15) | -
0x0004 | -UINT32 | -Variable name index | -
0x0008 | -VARIES | -Data for the variable | -
0x000C | -Total length of the structure | -
As you can see, the element structure is very basic. From the structure we - know the name of the variable, the type of the variable, and the assigned value - of the variable. The only difficult part is extracting the value from the - structure. -
-There are 16 know variable types supported by the ITP format. They are as - follows: -
-- Value | -- Type | -- Access | -- Data | -
---|---|---|---|
0 | -UINT8 | -Direct | -Unsigned byte | -
1 | -INT8 | -Direct | -Signed byte | -
2 | -UINT16 | -Direct | -Unsigned word | -
3 | -INT16 | -Direct | -Signed word | -
4 | -UINT32 | -Direct | -Unsigned longword | -
5 | -INT32 | -Direct | -Signed longword | -
6 | -UINT64 | -Indirect | -Unsigned quadword | -
7 | -INT64 | -Indirect | -Signed quadword | -
8 | -FLOAT | -Indirect | -Four byte floating point value | -
9 | -DOUBLE | -Indirect | -Eight byte floating point value | -
10 | -STRING | -Indirect | -Counted string | -
11 | -RESREF | -Indirect | -Counted resource name | -
12 | -STRREF | -Complex | -Multilingual capable string | -
13 | -DATREF | -Complex | -Counted binary data | -
14 | -CAPREF | -Complex | -List of child elements | -
15 | -LIST | -Complex | -List of child entries | -
For the simple data types, UINT8, INT8, UINT16, INT16, UINT32, INT32 and FLOAT, - the value is just stored directly into offset 0x0008. Since NWN is for - Intel systems, all the data values are stored in little endian format. - Thus, for UINT8 and INT8, the value is a single byte stored literally at offset - 0x0008 in the element structure. A UINT16 or INT16 takes up the first two - bytes. The remaining three basic data types take up all four bytes. - Access to the different values of the element can be done with this structure. -
---struct Element -{ - UINT32 Type; - UINT32 NameIndex; - union - { - UINT8 ui8; - INT8 si8; - UINT16 ui16; - INT16 si16; - UINT32 ui32; - INT32 si32; - FLOAT flt; - UINT32 Offset; - }; -};-Note: The "Offset" member can be used to access the indirect and complex - data stored in the variable data section.. -
-
- In the case of UINT64, INT64 and DOUBLE, the value stored at offset 0x0008 is a - byte offset into the variable data region. Starting at that address would - be stored the value in question. -
---char *pFileData = AddressOfTheITPDataInMemory; -Header *pHeader = (Header *) pFileData; -Element *pElementTable = (Element *) &pFileData [pHeader ->ElementOffset]; - -Element *pElement = &pElementTable [0]; // For this example, use first element-if (pElement ->Type == 6) -{ - UINT64 ul64 = *((UINT64 *) &pFileData [ - pHeader ->VarDataOffset + pElement ->Offset]); -} -else if (pElement ->Type == 7) -{ - INT64 l64 = *((INT64 *) &pFileData [ - pHeader ->VarDataOffset + pElement ->Offset]); -} -else if (pElement ->Type == 9) -{ - double d = *((double *) &pFileData [ - pHeader ->VarDataOffset + pElement ->Offset]); -}-
The STRING and RESREF types are two more indirect types but require a bit more - work to access. For both the STRING and RESREF the actual data is stored - in the variable data section starting at the given offset. They both - being with the length of string. Following the length, are the actual - bytes of the string. The string is not NULL terminated. However, - STRING and RESREF do differ. In the case of STRING, the string length is - stored as a UINT32 value. In the case of RESREF, the string length is - stored as a UINT8 value.
---char *pFileData = AddressOfTheITPDataInMemory; -Header *pHeader = (Header *) pFileData; -Element *pElementTable = (Element *) &pFileData [pHeader ->ElementOffset]; - -Element *pElement = &pElementTable [0]; // For this example, use first element-if (pElement ->Type == 10) //STRING -{ - UINT32 Length = *((UINT32 *) &pFileData [ - pHeader ->VarDataOffset + pElement ->Offset]); - char *String = (char *) &pFileData [ - pHeader ->VarDataOffset + pElement ->Offset + - sizeof (UINT32)] -} -else if (pElement ->Type == 11) //RESREF -{ - UINT8 Length = *((UINT8 *) &pFileData [ - pHeader ->VarDataOffset + pElement ->Offset]); - char *String = (char *) &pFileData [ - pHeader ->VarDataOffset + pElement ->Offset + - sizeof (UINT8)] -}-
The STRREF has two uses. First, it references a string in the dialog.tlk - file. Second, it provides localized (human language specific) version of - the string. The offset in the element points to a variable length - structure that begins with the following 12 bytes of data. -
-- Offset | -- Type | -- Description | -
---|---|---|
0x0000 | -UINT32 | -Number of bytes included in the STRREF not including this count. | -
0x0004 | -INT32 | -ID of the string in the in the dialog.tlk file. If none, then -1. | -
0x0008 | -UINT32 | -Number of language specific strings. This value is usually zero. | -
0x000C | -Total length of the structure | -
If the number of language specific strings is zero, then the length of the total - STRREF is only 12 bytes. The text of the string can be retrieved - from dialog.tlk. The value stored as the size of the STRREF will be 8 - since the 4 bytes in the count aren't included. However, if the number of - language specific strings is not zero, then there will be the given number of - the following structure following the initial STRREF structure. -
-- Offset | -- Type | -- Description | -
---|---|---|
0x0000 | -UINT32 | -Language of the string (values unknown) | -
0x0004 | -UINT32 | -Number of bytes in the following string | -
0x0008 | -CHAR [] | -Variable length string | -
VARIES | -Total length of the structure will always be 8 plus the length of - the string | -
The DATREF associates a block of arbitrary binary data with the element in - question. At the offset in the variable data section given in the element - is a UINT32 that has the number of bytes in the DATREF. Following the - UINT32 is the binary data. -
-The CAPREF element type allows for an element to contain an array of other - elements by referencing a single entry. The offset in the element - structure specifies the entry number. All the elements that entry - references can be considered as the children of the element. -
-The LIST element type allows for an element to contain an array of other - entries. For a LIST type, the offset in the element structure specifies - an offset into the list table. This is a byte offset even though the - table itself is just a series of UINT32 values. At the first UINT32 - pointed to by the offset will be the number of entries referenced by the - element. Following this count will be the actual entry - numbers. -
---char *pFileData = AddressOfTheITPDataInMemory; -Header *pHeader = (Header *) pFileData; -Element *pElementTable = (Element *) &pFileData [pHeader ->ElementOffset]; - -Element *pElement = &pElementTable [0]; // For this example, use first element-if (pElement ->Type == 15) //LIST -{ - UINT32 *List = *((UINT32 *) &pFileData [ - pHeader ->ListDataOffset + pElement ->Offset]); - UINT32 EntryCount = List [0]; - for (int i = 0; i < (int) EntryCount; i++) - { - UINT32 EntryIndex = List [i + 1]; - // do something with Entry - } -}-
The variable name table is a series of variable names stored in 16 byte long - character strings. Care should be taken when processing the variable name - strings. If the string is less than 16 characters in length, it will be - NULL terminated. However, if the variable name is 16 characters long, - then it will not. The easiest thing to do is copy the string into a 17 - byte character string and then set the 17th character to NULL. Thus, if - the string is 16 characters long, the 17th character will force a NULL - termination.
-All other data tables are purely subservient to the entry and element - tables. See the section on the elements to see how this information is - interpreted.
-Even though I was able to decode much of the ITP format soon after the game was - released, I want to thank Logxen, Seg Falt and Chanteur - for the information they published about the file format. Their - information filled in some very important missing elements such as CAPREF, - DATREF and elements of STRREF.
- - diff --git a/doc/specs/torlack/key.html b/doc/specs/torlack/key.html deleted file mode 100644 index a7ab63cc00..0000000000 --- a/doc/specs/torlack/key.html +++ /dev/null @@ -1,175 +0,0 @@ - - - - - - - -The KEY file in Neverwinter Nights (NWN) is used to provide the game with a -centralized location for locating resources contained in the BIF files. To the -best of my knowledge, only one file, "chitin.key" uses this file -format.
-The KEY file format is very basic. It consists a header and two large -tables. At the start of the file is the header. It provides -information about the file format, the file format version, offset and size -information about the two tables.
-Offset | -Type | -Description | -
---|---|---|
0x0000 | -char [4] | -4 byte signature ("KEY ") | -
0x0004 | -char [4] | -4 byte version ("V1 ") | -
0x0008 | -UINT32 | -Number of BIF files referenced in the key file | -
0x000C | -UINT32 | -Number of resources (RES) contained in the key file | -
0x0010 | -UINT32 | -Offset from the start of the file to the first BIF entry | -
0x0014 | -UINT32 | -Offset from the start of the file to the first RES entry | -
0x0018 | -UINT32 [10] | -Unknown | -
0x0040 | -Total Structure Size | -
One of the two tables of interest to us is the BIF table. This table -lists the all of the BIF files contained in the NWN data directory.
-Offset | -Type | -Description | -
---|---|---|
0x0000 | -UINT32 | -Length of the BIF file in bytes | -
0x0004 | -UINT32 | -Offset from the start of the KEY file to the BIF file name | -
0x0008 | -UINT16 | -Length of the BIF file name in bytes. Not including the - terminating 0. | -
0x000A | -UINT16 | -Unknown | -
0x000C | -Total Structure Size | -
The final table lists all of the resources contained within the BIF -files.
-Offset | -Type | -Description | -
0x0000 | -char [16] | -Name of the resource | -
0x0010 | -UINT16 | -Type of the resource | -
0x0012 | -UINT32 | -BIF id of the resource | -
0x0016 | -Total Structure Size | -
NOTE: It is very important that the structure packing for this structure is -set to BYTE or WORD alignment. Failure to do so will cause the UINT32 at -offset 0x0012 to be placed at 0x0014 and thus yield buggy functionality. -On non-Intel platforms, this alignment will cause alignment faults unless the -compiler has a "unaligned" type or special care is made when accessing -the UINT32.
-When NWN needs to locate a resource, it can be done just using the resource -name. If the name is used by more than one resource type, then the type -would also be required to locate the resource. To locate the resource, the -RES table is be searched for a match. Once a match has been located, the -BIF id of the resource gives the exact location of the resource.
-A BIF id is actually two numbers combined into one UINT32. The first 20 -bits starting from bit 0 specify the resource index inside the bif. The -final 12 bits specify the BIF in the BIF table contained within the KEY -file.
-Example: Suppose NWN needed to locate the resource -"IT_GOLD001". It would start by searching the RES table for the -entry "IT_GOLD001". Once located in the RES table, the BIF id is -examined. Suppose with BIF id is 0x00400029. The lower 20 bits of -the BIF id tell NWN that the "IT_GOLD001" resource is the 0x29th or -41st resource in the BIF file. From the upper 12 bits, NWN knows that the -4th BIF file contains the resource. So, the 4th record is examined in the -BIF table. This yields the file name for the BIF. The BIF can then -be opened and the 41st resource read from the file. (Information on how -the 41st resource in the BIF file is located will be covered in the BIF file -paper.)
- -For more information on the resource types, see NWN -Data File Basics.
- - - - diff --git a/doc/specs/torlack/mod.html b/doc/specs/torlack/mod.html deleted file mode 100644 index ff2fbe66a8..0000000000 --- a/doc/specs/torlack/mod.html +++ /dev/null @@ -1,235 +0,0 @@ - - - - - - - -ERF Format Document: http://nwn.bioware.com/developers/erf.html
-BioWare's "For Developers" site: http://nwn.bioware.com/developers/
First off, the ERF file format is a file format used by many different -files in NWN. This include files such as saved games (SAV), HAK packs (HAK), -exported resource files (ERF), Neverwinter Nights modules (NWM), and of course, -module files (MOD). ERF stands for Encapsulated Resource File.
-ERF files are relatively simple files that contain a collection of other -game resources. They also provide space for a textual description of the -contents of the file. In the case of modules, this is the module -description.
-Like almost all data files in NWN, the ERF file begins with a header.
-Offset | -Type | -Description | -
---|---|---|
0x0000 | -CHAR [4] | -File type signature. Depending on the file type, - this value varies. | -
0x0004 | -CHAR [4] | -Version number | -
0x0008 | -UINT32 | -Number of strings in the description | -
0x000C | -UINT32 | -Total length of the strings in bytes | -
0x0010 | -UINT32 | -Number of resources in the file | -
0x0014 | -UINT32 | -Offset from the start of file to the first string | -
0x0018 | -UINT32 | -Offset from the start of file to the first resource - structure | -
0x001C | -UINT32 | -Offset from the start of file to the first position - structure | -
0x0020 | -UINT32 | -Year the file was created with 1900 being 0 | -
0x0024 | -UINT32 | -Day of the year the file was created with Jan 1st being 0 | -
0x0028 | -UINT32 | -String reference for the description. - Varies depending on the file type: - MOD = -1, SAV = 0, NWM = -1 - For ERF and HAK, this value is unpredictable |
-
0x002C | -UINT32 [29] | -Spare values all initialized to 0 | -
0x00A0 | -Total size of the structure | -
Utilities such as the module editing tool and HAK pack editor from Bioware -allow the user to specify strings that describe the contents of the module or -HAK pack. These utilities also allow the user to supply this information -in multiple languages. Each string is stored sequentially starting at the -offset specified in the ERF file header.
- -Offset | -Type | -Description | -
---|---|---|
0x0000 | -UINT32 | -Language Identifier (See the document on data file - basics) | -
0x0004 | -UINT32 | -Length of the string in characters | -
0x0008 | -CHAR [*] | -String data | -
0x0008+Length | -Total size of the structure | -
For each resource contained in an ERF, there is a corresponding entry in -the resource list. This list begins in the file at the offset specified in -the header. The resource structures are stored sequentially in the ERF file. The -ERF header specifies the number of resources.
-Offset | -Type | -Description | -
---|---|---|
0x0000 | -CHAR [16] | -Name of the resource | -
0x0010 | -UINT32 | -Index of the resource | -
0x0014 | -UINT16 | -Resource type (See the document on data file basics) | -
0x0016 | -UINT16 | -Reserved and zero | -
0x0018 | -Total size of the structure | -
The name of the resource is padded with NULLs however they are not -necessarily NULL terminated. In the case of a resource name that is 16 -characters long, no NULL will exist. It can be mixed case, but most all resources -names are lowercase.
-For each resource, there is a corresponding position structure that defines -where the resource is located in the ERF. This list begins in the file -at the offset specified in the header. It is also sequentially stored in -the ERF file.
-Offset | -Type | -Description | -
---|---|---|
0x0000 | -UINT32 | -Offset from the start of the file to the given resource | -
0x0004 | -UINT32 | -Length of the resource in bytes | -
0x0008 | -Total size of the structure | -
The people at the OpenKnights -project noticed that for MOD and NWM files only, there exists a strange block of data -between the resource structures and the position structures. The size of -the block seems to be eight bytes per resource. In my tests, all the data -seemed to be NULL. What is strange about this data is that there doesn't -exist an offset in the ERF file header. Having a block of data that -contains no offset in the file header is very uncharacteristic for Bioware.
- - - - \ No newline at end of file diff --git a/doc/specs/torlack/ncs.html b/doc/specs/torlack/ncs.html deleted file mode 100644 index a4721ba08e..0000000000 --- a/doc/specs/torlack/ncs.html +++ /dev/null @@ -1,1845 +0,0 @@ - - - - - - - -Before we can really being discussing the actual contents of the NWScript -Compiled Script (NCS) file, we first must go over some of the basic concepts of -the NWScript engine.
-NWScript is a small instruction set byte code engine. This means that -instead of compiling the script into x86 machine instructions, the compiler -generates a series of platform independent commands. Languages such as -Forth or Java use similar techniques to store their compiled source. When -a script needs to be executed, current byte code is fetched from the compiled -script and then depending on the value of the byte code, the script engine -executes some predefined operation.
-In a real machine code program, local variables can be stored in specific memory -locations, memory relative to a stack pointer, or even in the CPU registers. -Byte code engines don't have the luxury of using CPU registers. Thus they -are limited to variables being stored in specific memory locations or relative -to a stack pointer. In the case of NWScript, all variables are accessed -relative to a stack pointer. Global variables don't exist in the -traditional sense.
-Since variables are all accessed off the stack without CPU registers, then -operators such as addition must operate differently. In machine code, if -you wished to add two values, the values would be loaded into registers and then -the operator is executed. (Note: That is a drastic simplification) With NWScript, operators always use the top most variable or variables on the stack. -Once the operation is complete, the variables are removed and the result is -placed on the stack. Thus, if you have a variable called "nValue" that you -wished to negate but not lose "nValue" on the stack, you would first have make a -copy of the variable onto the top of the stack and then invoke the operator.
-Let us look at an example program:
---void main () -{ - int i = 12; - int j = 1; - i = i + j; -}-
The first two lines of the program declare two variables "i" and "j". -Once these two statements are complete, the stack looks as follows:
-Top of Stack (SP) | -|
Offset | -Contents | -
-4 | -j: 1 | -
-8 | -i: 12 | -
Bottom of Stack | -
It is important to note that the NWScript stack builds up in increments of 4. -Thus when accessing values on the stack, they must be referenced using negative -offsets where "-4" points to the top most element on the stack.
-The next step is to make a copy of "i" so that we can operate on it.
-Top of Stack (SP) | -|
Offset | -Contents | -
-4 | -i: 12 | -
-8 | -j: 1 | -
-12 | -i: 12 | -
Bottom of Stack | -
Next, we need to make a copy of "j".
-Top of Stack (SP) | -|
Offset | -Contents | -
-4 | -j: 1 | -
-8 | -i: 12 | -
-12 | -j: 1 | -
-16 | -i: 12 | -
Bottom of Stack | -
Now that we have the two values on the top of the stack, we can invoke the -operator to compute the results.
-Top of Stack (SP) | -|
Offset | -Contents | -
-4 | -results: 13 | -
-8 | -j: 1 | -
-12 | -i: 12 | -
Bottom of Stack | -
The final step is the assignment. To do this, we copy the top of the -stack down to the variable and then remove the top of the stack.
-Top of Stack (SP) | -|
Offset | -Contents | -
-4 | -j: 1 | -
-8 | -i: 13 | -
Bottom of Stack | -
The current top of stack is also known as the stack pointer (SP).
-As stated previously, NWScript does not have global variables in the -tradition sense where the values a stored in a known region of memory. In -NWScript, global variables are placed onto the stack by a dummy shell routine. -This routine wraps the "main" or "StartingConditional" routine. So when a -script is executed with global variables, "main" and "StartingConditional" are -not the first routines to be invoked. The "#globals" routine is invoked to -place the globals onto the stack and then it invokes "main" or "StartingConditional".
-However, placing global variables on the stack is only half the problem. -Routines inside the script must be able to know how to reference the variables. -For a routine such as "main" that is invoked directly from "#globals", it knows -how deep down in the stack the global variables would be. If it had two -local variables and needed to access the top global variable, it could use an -offset of -12 (3 variables down time -4). However, subroutines called by -"main" would have no idea how deep down the stack the global variables exist. -
-To solve this problem, Bioware created a second stack pointer called "BP" -which is traditionally called base pointer for Intel processors. Inside -the "#globals" routine just prior to invoking "main" or "StartingConditional", -the current stack pointer (SP) is saved and becomes the new value of BP. -Then when "main" or and subroutine needs to access a global variable, it just -needs to access them relative to BP.
-For simplicity, there are not many operations that can be done to a variable -relative to BP. A copy of a variable can be placed on the top of the -stack. The current top of stack can be assigned to a variable relative to -BP. And a variable relative to BP can be incremented or decremented.
-Invoking subroutines or engine routines is done basically in the same manner. -Arguments are placed on the stack in reverse order. The call is then made -and the callee removes all the arguments from the stack prior to returning.
-However, return values are handled differently. In the case of a script -subroutine that returns a value, space for the return value is reserved, then -the arguments are placed on the stack and finally the subroutine is invoked. -In the case of an engine routine, it is the job of the engine routine to place -the return value on the stack after the calling arguments are removed.
-Here is an example of a call to a subroutine:
---int j = DoSomeScriptSubroutine (12, 14);-
Prior to the call, the stack looks as follows:
-Top of Stack (SP) | -|
Offset | -Contents | -
-4 | -Arg1: 12 | -
-8 | -Arg2: 14 | -
-12 | -Return: ?? | -
-16 | -j: ?? | -
Bottom of Stack | -
After the call, the stack looks as follows:
-Top of Stack (SP) | -|
Offset | -Contents | -
-4 | -Return: ?? | -
-8 | -j: ?? | -
Bottom of Stack | -
Here is an example of a call to an engine routine:
---int j = DoSomeEngineRoutine (12, 14);-
Prior to the call, the stack looks as follows:
-Top of Stack (SP) | -|
Offset | -Contents | -
-4 | -Arg1: 12 | -
-8 | -Arg2: 14 | -
-12 | -j: ?? | -
Bottom of Stack | -
After the call, the stack looks as follows:
-Top of Stack (SP) | -|
Offset | -Contents | -
-4 | -Return: ?? | -
-8 | -j: ?? | -
Bottom of Stack | -
All NWScript byte codes start with two bytes. The first byte is the -instruction such as "RETN" or "JSR". The second byte is the type of the -instruction such as an integer or floating point operation.
-Following is a list of all the different types:
-Unary Types | -|
---|---|
Value | -Type | -
3 (0x03) | -Integer (I) | -
4 (0x04) | -Float (F) | -
5 (0x05) | -String (S) | -
6 (0x06) | -Object (O) | -
16-31 - (0x10-0x1F) |
- Engine Types - 16 = Effect - 17 = Event - 18 = Location - 19 = Talent |
-
Binary Types | -|
Value | -Type | -
32 (0x20) | -Integer, Integer (II) | -
33 (0x21) | -Float, Float (FF) | -
34 (0x22) | -Object, Object (OO) | -
35 (0x23) | -String, String (SS) | -
36 (0x24) | -Structure, Structure (TT) | -
37 (0x25) | -Integer, Float (IF) | -
38 (0x26) | -Float, Integer (FI) | -
48-57 - (0x30-0x39) |
- Engine Types - 48 = Effect, Effect - 49 = Event, Event - 50 = Location, Location - 51 = Talent, Talent |
-
58 (0x3A) | -Vector, Vector (VV) | -
59 (0x3B) | -Vector, Float (VF) | -
60 (0x3C) | -Float, Vector (FV) | -
The value listed in parenthesis next to the type name is the short hand name -used to identify different byte codes. For example ADDII would add two -integer values.
-The TT opcode type is used to compare ranges of elements on the stack. -More specifically, it is used for structures and vectors.
-Following is a list and description of all the known byte codes.
-NOTE: All multi-byte values are stored in big endian order.
-Copy the given number of bytes from the top of the stack down to the location -specified.
-The value of SP remains unchanged.
-Bytes | -Value | -Description | -
---|---|---|
0 | -0x01 | -Byte Code | -
1 | -0x01 | -Type | -
2-5 | -Offset | -Destination of the copy relative to the top of the stack. | -
6-7 | -Size | -Number of bytes to copy | -
Reserve space on the stack for the given variable type.
-The value of SP is increased by the size of the type reserved. (Always -4)
-Bytes | -Value | -Description | -
---|---|---|
0 | -0x02 | -Byte Code | -
1 | -0x03 - 0x04 - 0x05 - 0x06 |
- RSADDI type - RSADDF type - RSADDS type - RSADDO type |
-
Add the given number of bytes from the location specified in the stack to the -top of the stack.
-The value of SP is increased by the number of copied bytes.
-Bytes | -Value | -Description | -
---|---|---|
0 | -0x03 | -Byte Code | -
1 | -0x01 | -Type | -
2-5 | -Offset | -Source of the copy relative to the top of the stack. | -
6-7 | -Size | -Number of bytes to copy | -
Place the constant integer onto the top of the stack.
-The value of SP is increased by the size of the type reserved. (Always -4)
-Bytes | -Value | -Description | -
---|---|---|
0 | -0x04 | -Byte Code | -
1 | -0x03 | -Type | -
2-5 | -Integer | -Integer value of the constant | -
Place the constant float onto the top of the stack.
-The value of SP is increased by the size of the type reserved. (Always -4)
-Bytes | -Value | -Description | -
---|---|---|
0 | -0x04 | -Byte Code | -
1 | -0x04 | -Type | -
2-5 | -Float | -Float value of the constant | -
Place the constant string onto the top of the stack.
-The value of SP is increased by the size of the type reserved. (Always -4)
-Bytes | -Value | -Description | -
---|---|---|
0 | -0x04 | -Byte Code | -
1 | -0x05 | -Type | -
2-3 | -String Length | -Length of the string | -
4-n | -String Data | -Text of the string | -
Place the constant object ID onto the top of the stack.
-The value of SP is increased by the size of the type reserved. (Always -4)
-Bytes | -Value | -Description | -
---|---|---|
0 | -0x04 | -Byte Code | -
1 | -0x06 | -Type | -
2-5 | -Object | -When the type is an object, these bytes contain the OID | -
Invoke the engine routine specified. All arguments must be placed on -the stack in reverse order prior to this byte code. The arguments will be -removed by the engine routine and any return value then placed on the stack.
-The value of SP is increased by the size of the return value and decreased by -the total size of the arguments. It is important to note that the total -size of the arguments might be different than the number of arguments. -Structures and vectors are take up more space than normal types.
-Bytes | -Value | -Description | -
---|---|---|
0 | -0x05 | -Byte Code | -
1 | -0x00 | -Type | -
2-3 | -Routine # | -Number of the action routine. NWSCIPT.NSS lists engine routines - in order starting at 0 | -
4 | -Arg Count | -Number of arguments | -
Compute the logical AND of two integer values.
-The value of SP is increased by the size of the result while decreased by the -size of both operands.
-Bytes | -Value | -Description | -
---|---|---|
0 | -0x06 | -Byte Code | -
1 | -0x20 | -Type | -
Compute the logical OR of two integer values.
-The value of SP is increased by the size of the result while decreased by the -size of both operands.
-Bytes | -Value | -Description | -
---|---|---|
0 | -0x07 | -Byte Code | -
1 | -0x20 | -Type | -
Compute the inclusive OR of two integer values.
-The value of SP is increased by the size of the result while decreased by the -size of both operands.
-Bytes | -Value | -Description | -
---|---|---|
0 | -0x08 | -Byte Code | -
1 | -0x20 | -Type | -
Compute the exclusive OR of two integers.
-The value of SP is increased by the size of the result while decreased by the -size of both operands.
-Bytes | -Value | -Description | -
---|---|---|
0 | -0x09 | -Byte Code | -
1 | -0x20 | -Type | -
Compute the boolean AND of two integers.
-The value of SP is increased by the size of the result while decreased by the -size of both operands.
-Bytes | -Value | -Description | -
---|---|---|
0 | -0x0A | -Byte Code | -
1 | -0x20 | -Type | -
Test the two operand for logical equality. This operator supports the -comparison or all the basic types and then engine types as long as both operands -have the same type.
-The value of SP is increased by the size of the result while decreased by the -size of both operands.
-Bytes | -Value | -Description | -
---|---|---|
0 | -0x0B | -Byte Code | -
1 | -0x20 - 0x21 - 0x22 - 0x23 - 0x30-0x39 |
- EQUALII Type - EQUALFF Type - EQUALOO Type - EQUALSS Type - For engine types |
-
Test the two operand for logical equality. This operator supports the -comparison or all the basic types and then engine types as long as both operands -have the same type.
-The value of SP is increased by the size of the result while decreased by the -size of both operands.
-Bytes | -Value | -Description | -
---|---|---|
0 | -0x0B | -Byte Code | -
1 | -0x24 | -Type | -
2-3 | -Size | -Size of structure | -
Test the two operand for logical inequality. This operator supports the -comparison or all the basic types and then engine types as long as both operands -have the same type.
-The value of SP is increased by the size of the result while decreased by the -size of both operands.
-Bytes | -Value | -Description | -
---|---|---|
0 | -0x0C | -Byte Code | -
1 | -0x20 - 0x21 - 0x22 - 0x23 - 0x30-0x39 |
- EQUALII Type - EQUALFF Type - EQUALOO Type - EQUALSS Type - For engine types |
-
Test the two operand for logical inequality. This operator supports the -comparison or all the basic types and then engine types as long as both operands -have the same type.
-The value of SP is increased by the size of the result while decreased by the -size of both operands.
-Bytes | -Value | -Description | -
---|---|---|
0 | -0x0C | -Byte Code | -
1 | -0x24 | -Type | -
2-3 | -Size | -Size of the structure | -
Test the two operand for logically greater than or equal.
-The value of SP is increased by the size of the result while decreased by the -size of both operands.
-Bytes | -Value | -Description | -
---|---|---|
0 | -0x0D | -Byte Code | -
1 | -0x20 - 0x21 |
- GEQII Type - GEQFF Type |
-
Test the two operand for logically greater than.
-The value of SP is increased by the size of the result while decreased by the -size of both operands.
-Bytes | -Value | -Description | -
---|---|---|
0 | -0x0E | -Byte Code | -
1 | -0x20 - 0x21 |
- GTII Type - GTFF Type |
-
Test the two operand for logically less than.
-The value of SP is increased by the size of the result while decreased by the -size of both operands.
-Bytes | -Value | -Description | -
---|---|---|
0 | -0x0F | -Byte Code | -
1 | -0x20 - 0x21 |
- LTII Type - LTFF Type |
-
Test the two operand for logically less than or equal.
-The value of SP is increased by the size of the result while decreased by the -size of both operands.
-Bytes | -Value | -Description | -
---|---|---|
0 | -0x10 | -Byte Code | -
1 | -0x20 - 0x21 |
- LEQII Type - LEQFF Type |
-
Shift the value left be the given number of bits. Operand one is the -value to shift while operand two is the number of bits to shift.
-The value of SP is increased by the size of the result while decreased by the -size of both operands.
-Bytes | -Value | -Description | -
---|---|---|
0 | -0x11 | -Byte Code | -
1 | -0x20 | -Type | -
Shift the value right be the given number of bits. Operand one is the value to shift while operand two is the -number of bits to shift.
-The value of SP is increased by the size of the result while decreased by the -size of both operands.
-Bytes | -Value | -Description | -
---|---|---|
0 | -0x12 | -Byte Code | -
1 | -0x20 | -Type | -
Shift the value right be the given number of bits as if it was an unsigned -integer and not a signed integer. Operand one is the value to shift while operand two is the number of bits to -shift.
-The value of SP is increased by the size of the result while decreased by the -size of both operands.
-Bytes | -Value | -Description | -
---|---|---|
0 | -0x13 | -Byte Code | -
1 | -0x20 | -Type | -
Add the two operands.
-The value of SP is increased by the size of the result while decreased by the -size of both operands.
-Bytes | -Value | -Description | -
---|---|---|
0 | -0x14 | -Byte Code | -
1 | -0x20 - 0x25 - 0x26 - 0x21 - 0x23 - 0x3A |
- ADDII Type - ADDIF Type - ADDFI Type - ADDFF Type - ADDSS Type - ADDVV Type |
-
Subtract the two operands.
-The value of SP is increased by the size of the result while decreased by the -size of both operands.
-Bytes | -Value | -Description | -
---|---|---|
0 | -0x15 | -Byte Code | -
1 | -0x20 - 0x25 - 0x26 - 0x21 - 0x3A |
- SUBII Type - SUBIF Type - SUBFI Type - SUBFF Type - SUBVV Type |
-
Multiply the two operands.
-The value of SP is increased by the size of the result while decreased by the -size of both operands.
-Bytes | -Value | -Description | -
---|---|---|
0 | -0x16 | -Byte Code | -
1 | -0x20 - 0x25 - 0x26 - 0x21 - 0x3B - 0x3C |
- MULII Type - MULIF Type - MULFI Type - MULFF Type - MULVF Type - MULFV Type |
-
Divide the two operands.
-The value of SP is increased by the size of the result while decreased by the -size of both operands.
-Bytes | -Value | -Description | -
---|---|---|
0 | -0x17 | -Byte Code | -
1 | -0x20 - 0x25 - 0x26 - 0x21 - 0x3B |
- DIVII Type - DIVIF Type - DIVFI Type - DIVFF Type - DIVVF Type |
-
Computes the modulus of two values.
-The value of SP is increased by the size of the result while decreased by the -size of both operands.
-Bytes | -Value | -Description | -
---|---|---|
0 | -0x18 | -Byte Code | -
1 | -0x20 | -Type | -
Computes the negation of a value.
-The value of SP remains unchanged since the operand and result are of the -same size.
-Bytes | -Value | -Description | -
---|---|---|
0 | -0x19 | -Byte Code | -
1 | -0x03 - 0x04 |
- NEGI Type - NEGF Type |
-
Computes the one's complement of a value.
-The value of SP remains unchanged since the operand and result are of the -same size.
-Bytes | -Value | -Description | -
---|---|---|
0 | -0x1A | -Byte Code | -
1 | -0x03 | -Type | -
Add the value specified in the instruction to the stack pointer.
-The value of SP is adjusted by the value specified.
-Bytes | -Value | -Description | -
---|---|---|
0 | -0x1B | -Byte Code | -
1 | -0x00 | -Type | -
2-5 | -Offset | -Value to add to the stack pointer. | -
Obsolete instruction to store the state of the stack and save a -pointer to a block of code to later be used as an "action" argument. This -byte code is always followed by a JMP and then a block of code to be executed by -a later function such as a DelayCommand.
-The value of SP remains unchanged.
-Bytes | -Value | -Description | -
---|---|---|
0 | -0x1C | -Byte Code | -
1 | -0x08 | -Offset to the block of code for an "action" argument | -
Change the current execution address to the relative address given in the -instruction.
-The value of SP remains unchanged.
-Bytes | -Value | -Description | -
---|---|---|
0 | -0x1D | -Byte Code | -
1 | -0x00 | -Type | -
2-5 | -Offset | -Offset to the new program location from the start of this instruction | -
Jump to the subroutine at the relative address given in the instruction. -If the routine returns a value, the RSADDx instruction should first be used to -allocate space for the return value. Then all arguments to the subroutine -should be pushed in reverse order.
-The value of SP remains unchanged. The return value is NOT placed on -the stack.
-Bytes | -Value | -Description | -
---|---|---|
0 | -0x1E | -Byte Code | -
1 | -0x00 | -Type | -
2-5 | -Offset | -Offset to the new program location from the start of this instruction | -
Change the current execution address to the relative address given in the -instruction if the integer on the top of the stack is zero.
-The value of SP is decremented by the size of the integer.
-Bytes | -Value | -Description | -
---|---|---|
0 | -0x1F | -Byte Code | -
1 | -0x00 | -Type | -
2-5 | -Offset | -Offset to the new program location from the start of this instruction | -
Return from a JSR. All arguments used to invoke the subroutine should -be removed prior to the RETN. This leaves any return value on the top of -the stack. The return value must be allocated by the caller prior to -invoking the subroutine.
-The value of SP remains unchanged. The return value is NOT placed on -the stack.
-Bytes | -Value | -Description | -
---|---|---|
0 | -0x20 | -Byte Code | -
1 | -0x00 | -Type | -
Given a stack size, destroy all elements in that size excluding the given -stack element and element size.
-The value of SP decremented by the given stack size minus the element size.
-Bytes | -Value | -Description | -
---|---|---|
0 | -0x21 | -Byte Code | -
1 | -0x01 | -Type | -
2-3 | -Size | -Total number of bytes to remove off the top of the stack | -
4-5 | -Offset | -Offset from the start of the bytes to remove to the element not to - destroy | -
6-7 | -Size | -Size of the element not to destroy | -
Computes the logical not of the value.
-The value of SP remains unchanged since the operand and result are of the -same size.
-Bytes | -Value | -Description | -
---|---|---|
0 | -0x22 | -Byte Code | -
1 | -0x03 | -Type | -
Decrements an integer relative to the current stack pointer.
-The value of SP remains unchanged.
-Bytes | -Value | -Description | -
---|---|---|
0 | -0x23 | -Byte Code | -
1 | -0x03 | -Type | -
2-5 | -Offset | -Offset of the integer relative to the stack pointer | -
Increments an integer relative to the current stack pointer.
-The value of SP remains unchanged.
-Bytes | -Value | -Description | -
---|---|---|
0 | -0x24 | -Byte Code | -
1 | -0x03 | -Type | -
2-5 | -Offset | -Offset of the integer relative to the stack pointer | -
Change the current execution address to the relative address given in the -instruction if the integer on the top of the stack is non-zero.
-The value of SP is decremented by the size of the integer.
-Bytes | -Value | -Description | -
---|---|---|
0 | -0x25 | -Byte Code | -
1 | -0x00 | -Type | -
2-5 | -Offset | -Offset to the new program location from the start of this instruction | -
Copy the given number of bytes from the base pointer down to the location -specified. This instruction is used to assign new values to global variables.
-The value of SP remains unchanged.
-Bytes | -Value | -Description | -
---|---|---|
0 | -0x26 | -Byte Code | -
1 | -0x01 | -Type | -
2-5 | -Offset | -Destination of the copy relative to the base pointer | -
6-7 | -Size | -Number of bytes to copy | -
Add the given number of bytes from the location specified relative to the -base pointer to the -top of the stack. This instruction is used to retrieve the current value -of global variables.
-The value of SP is increased by the number of copied bytes.
-Bytes | -Value | -Description | -
---|---|---|
0 | -0x27 | -Byte Code | -
1 | -0x01 | -Type | -
2-5 | -Offset | -Source of the copy relative to the base pointer | -
6-7 | -Size | -Number of bytes to copy | -
Decrements an integer relative to the current base pointer. This -instruction is used to decrement the value of global variables.
-The value of SP remains unchanged.
-Bytes | -Value | -Description | -
---|---|---|
0 | -0x28 | -Byte Code | -
1 | -0x03 | -Type | -
2-5 | -Offset | -Offset of the integer relative to the base pointer | -
Increments an integer relative to the current base pointer. This -instruction is used to increment the value of global variables.
-The value of SP remains unchanged.
-Bytes | -Value | -Description | -
---|---|---|
0 | -0x29 | -Byte Code | -
1 | -0x03 | -Type | -
2-5 | -Offset | -Offset of the integer relative to the base pointer | -
Save the current value of the base pointer and set BP to the current stack -position.
-The value of SP remains unchanged.
-Bytes | -Value | -Description | -
---|---|---|
0 | -0x2A | -Byte Code | -
1 | -0x00 | -Type | -
Restore the BP from a previous SAVEBP instruction.
-The value of SP remains unchanged.
-Bytes | -Value | -Description | -
---|---|---|
0 | -0x2B | -Byte Code | -
1 | -0x00 | -Type | -
Store the state of the stack and save a -pointer to a block of code to later be used as an "action" argument. This -byte code is always followed by a JMP and then a block of code to be executed by -a later function such as a DelayCommand.
-The value of SP remains unchanged.
-Bytes | -Value | -Description | -
---|---|---|
0 | -0x2C | -Byte Code | -
1 | -0x10 | -Offset to the block of code for an "action" argument | -
2-5 | -Size | -Size of the variables to save relative to BP. This would be all - the global variables. | -
6-9 | -Size | -Size of the local routine variables to save relative to SP. | -
Perform no program function. This opcode is used as a placeholder for -the debugger.
-The value of SP remains unchanged.
-Bytes | -Value | -Description | -
---|---|---|
0 | -0x2D | -Byte Code | -
1 | -0x00 | -Type | -
This byte code isn't a real instruction and is always found at offset 8 in -the NCS file.
-The value of SP remains unchanged.
-Bytes | -Value | -Description | -
---|---|---|
0 | -0x42 | -Byte Code | -
1-4 | -Size | -Size of the NCS file | -
A texture palette file is a variant on a standard texture. However, -instead of being a fixed texture where all the colors are constant, a texture -palette file allows the content creator to select from a wide range of color -palettes for preset areas in the texture.
- -There are four basic elements that go into converting a PLT to a real texture -at runtime. Some elements are supplied by the PLT file while others are -supplied by the game itself and the content creator.
-There are a total of ten different palette groups. The palette name is a -human readable name displayed in the user interface. The group index is -the index of the palette group. This matches the indices found in the PLT -files. The UI graphic is the palette as it is presented to the content -creator. Each UI graphic contains 256 different selections that corresponds -directly to a row in the actual palette file in the last column of the table.
- -Name | -Group Index | -UI | -Palette File | -
---|---|---|---|
Skin | -0 | -![]() |
- ![]() |
-
Hair | -1 | -![]() |
- ![]() |
-
Metal 1 | -2 | -![]() |
- ![]() |
-
Metal 2 | -3 | -![]() |
- ![]() |
-
Cloth 1 | -4 | -![]() |
- ![]() |
-
Cloth 2 | -5 | -![]() |
- ![]() |
-
Leather 1 | -6 | -![]() |
- ![]() |
-
Leather 2 | -7 | -![]() |
- ![]() |
-
Tattoo 1 | -8 | -![]() |
- ![]() |
-
Tattoo 2 | -9 | -![]() |
- ![]() |
-
The PLT file beings with a fixed header that defines the attributes of the -texture. Following the header is pixel information.
-Offset | -Type | -Description | -
---|---|---|
0x0000 | -char [4] | -4 byte signature ("PLT ") | -
0x0004 | -char [4] | -4 byte version ("V1 ") | -
0x0008 | -UINT32 | -Unknown | -
0x000C | -UINT32 | -Unknown | -
0x0010 | -UINT32 | -Width of the texture in pixels | -
0x0014 | -UINT32 | -Height of the texture in pixels | -
0x0018 | -Total Structure Size | -
The actual pixel data is an array of the following structure. There are -(width X height) instances of this structure in a palette file.
-Offset | -Type | -Description | -
---|---|---|
0x0000 | -UINT8 | -Color Index | -
0x0001 | -UINT8 | -Palette Group Index | -
0x0002 | -Total Structure Size | -
Imagine one of the body textures used to skin a model. From this PLT -file, we have the width and height of the texture. When NWN started, it -loads the palette files into memory. Finally, for a specific creature, we -have 10 different values, one for each of the different palette groups. -These values specify which palette is to be used. These values are -supplied by the content creator.
-For each of the pixels in the PLT texture, we have a color index and a -palette group index. To locate the actual color value for that pixel, the -following process is used.
-I have no idea who originally decoded the PLT file format. It wasn't -me. I read a very sketchy description on the Bioware forums and then -filled in the blanks. Thanks whoever you are.
- - - -