The TDDD file is stored in Amiga (680x0) format, and conforms to the "IFF" file format on that computer. On IBM (80x86) based machines, much of the data refered to below will have to be byte reversed before it makes sense.
The IFF (interchange file format) format stores data in packets called "chunks." Each chunk begins with a long word identifier <ID> in ascii format. This identifier is immediately followed by a long word data-size. The data-size is measured in bytes and descrbes how much data, following the data-size long word, is part of the chunk identified by the <ID>. Imagine's IFF structure supports nesting of these chunks. For more info on the IFF standard, see the "Amiga ROM Kernal Reference Manual: Devices (3rd Edition)."
Currently, in "standard IFF" terms, a FORM TDDD has only one supported chunk type: an OBJ chunk describing the object heirarchy.
The OBJ chunk, in turn, is made up of smaller chunks with the standard IFF structure: <ID> <data-size> <data>.
The OBJ "sub-chunks" support object heirarchies. Currently, there are 2 types of supported OBJ sub-chunks: A DESC chunk, describing one node of a heirarchy; and a TOBJ chunk marking the end of a heirarchy chain. For each DESC chunk, there must be a corresponding TOBJ chunk.
In Imagine, the structure of the object heirarchy is as follows: Each heirarchy has a head (parent) object. The parent may have child objects. The children may have grandchildren, and so on. An object with children is a "grouped" object within Imagine.
Each object heirarchy is written in an OBJ chunk, along with all its descendants. The descendant heirarchy is supported as follows:
1) A DESC chunk is written, describing the object.
2) If the object in 1) has children, steps 1) thru 3) are performed
for each child.
3) A TOBJ chunk is written, marking the end of the object description.
Reader software WILL FOLLOW the standard IFF procedure of skipping over any un-recognized chunks -- and "sub-chunks" or "sub-sub-chunks". The <data-size> field indicates how many bytes to skip. In addition it WILL OBSERVE the IFF rule that an odd <data-size> may appear, in which case the corredponding <data> field will be padded at the end with one extra byte to give it an even size.
Second, there are several color (or RGB) fields in the data. They are always stored as three UBYTEs representing the red, green and blue components of the color. Red is always first, followed by green, and then blue. For some of the data chunks, Imagine reads the color field into the 24 LSB's of a LONGword. In such cases, the 3 RGB bytes are preceded by a zero byte in the file.
BYTE : a single byte of data (char)A "U" (ie. UBYTE) means unsigned.
WORD : a two byte data field (short)
LONG : a four byte data field (long)
The following "typedef"s are used below:
typedef LONG FRACT; /* 4 bytes */
typedef UBYTE COLOR[3]; /* 3 bytes */
typedef struct vectors {
BYTE Name[18] ; a name for the object.Object's name as it appears in the attributes requester. Used for tracking, etc.
WORD Shape; ; number indicating object typeValid shape numbers are:
WORD Lamp; ; bit field indicating lamp type
Lamp numbers are composed of several bit fields:
Bit 0 - Point light source.
Bit 1 - Parallel light source.
Bit 2 - Round shape.
Bit 3 - Rectangular shape.
Bit 4 - No Lens Flare FX flag.
Bit 5 - 1/R Diminishing intensity.
Bit 6 - Controlled falloff.
Bit 7 - Cast Shadows.
Bits 8 to 14 - reserved.
Bit 15 - Bright object.
For a light casting object, bit 0 or 1 must be set - all other bits are optional. All lights emminate from the object's axes (see POSI, SIZE, and AXIS chunk) and shadow casting lights will be blocked by faces that have neither fog nor transparent attributes.
VECTOR Position; ; the object's position.This is the position (in world coordinates) of the object's axes. Legal coordinates are in the range -32768 to 32767 and 65535/65536.
VECTOR XAxis;These are direction vectors for the object coordinate system. They must be "orthogonal unit vectors" (ortho-normal) - i.e. the sum of the squares of the vector components must equal one (or close to it), and the vectors must be perpendicular.
VECTOR YAxis;
VECTOR ZAxis;
VECTOR Size; ; object size infoSee SHP2 chunk above. The sizes are used in a variety of ways depending on the object shape. For custom objects and lights, they are the lengths of the coordinate axes drawn in the editor.
FRACT bounds[6]; ;bounding box dataThe descriptions of the bounds array is as follows:
bounds[0] - negative X boundary (relative to object axis position)
bounds[1] - negative Y boundary
bounds[2] - negative Z boundary
bounds[3] - posative X boundary
bounds[4] - posative Y boundary
bounds[5] - posative Z boundary
This chunk contains the objects bounding box info for use in improving redraw and loading speed when using Imagine's quick stage mode.
This is Imagine's state data chunk. There is a STND chunk for each (named) state in an object. Each STND chunk will contain a STID (state ID) chunk followed by one or several STDT (state data) chunks. (see STID and STDT chunks)
BYTE stid[18]; ; state nameThis chunk contains the state name and a description of the type of data assiciated with this state. This chunk will only appear within a STND chunk and is usually followed by one or more STDT chunks.
UWORD stFlags; ; state flags
; Bit 0 - contains axis data (group)
; Bit 1 - contains shape data (points)
; Bit 2 - contains color/properties data
; Bits 3 thru 15 - reserved
WORD tag; ; state data type tagsThis is the state data chunk. The tag value describes what kind of information is actually stored within the stateData[] array. This chunk will only appear within a STND chunk and will be preceded by either a STID chunk or another STDT chunk. The stateData[] array is interpreted as follows depending upon the tag type:
; tag values are as follows:
; 101 - contains object axis info
; 102 - contains point (vertex) data
; 103 - contains path data
; 104 - contains axis size data
; 105 - contains face color data (CLIST)
; 106 - contains face filter data (TLST)
; 107 - contains face reflect data (RLST)
; 108 - contains object attribute data
; all other values are reserved
WORD flags; ; state data flags
BYTE stateData[size]; ; state data - variable size
VECTOR axis_r; ; axis position vector(48 bytes total)
MATRIX axis_m; ; axis alignment vectors
tag = 102 - contains point (vertex) data - saved with shape
VECTOR obj_points[point_count]; ; object's points in 3 space(12 * point_count bytes total)
point_count = point count for object - e.g. from PNTS chunk
tag = 103 - contains path data - saved with shape
PTHD pdata[ACount]; ; path data for object(68 * ACount bytes total)
ACount = axis count for object - e.g. from PTH2 chunk
tag = 104 - contains axis size data - saved with shape
VECTOR size; ; object size info(12 bytes total)
See SIZE chunk.
tag = 105 - contains face color data (CLST) - saved with properties
COLOR colors[face_count]; ; color values(face_count * 3 bytes total)
face_count = face count for object - e.g. from FACE/CLST,...
tag = 106 - contains face filter data (TLST) - saved with properties
COLOR filter[face_count]; ; filter values(face_count * 3 bytes total)
face_count = face count for object
tag = 107 - contains face reflect data (RLST) - saved with properties
COLOR reflect[face_count]; ; reflect values(face_count * 3 bytes total)
face_count = face count for object
tag = 108 - contains object attribute data - saved with properties
UBYTE props[8]; ; object properties (PRP1 chunk)(44 bytes total) Note that the properties state does not save texture/brush info, only object base attributes. See PRP1, SHP2, INT1, FOGL, COLR, REFL, TRAN, SPC1 chunks.
UWORD lamp; ; bit field - lamp type (SHP2 chunk)
UWORD flags; ; reserved
VECTOR intensity; ; light intensity (INT1 chunk)
FRACT foglen; ; value of foglength (FOGL chunk)
UBYTE color[4]; ; object color (COLR chunk)
UBYTE reflect[4]; ; object reflectance (REFL chunk)
UBYTE filter[4]; ; object transparency (TRAN chunk)
UBYTE specular[4]; ; object specularity (SPC1 chunk)
UWORD PCount; ; point countThis chunk has all the points for custom (type 2 - axis) objects. point_count is the total number of points on the object. Edges will refer to these points by thier position in the Points[] array (i.e. the point numbers appearing below run from 0 through point_count - 1).
VECTOR Points[point_count]; ; points
UWORD ECount; ; edge countThis chunk contins the edge list for custom objects. The Edges[][2] array is pairs of point numbers that are connected by the edges. The values of Edges[n][0] and Edges[n][1] will thus be between 0 and point_count - 1, and the Points[] array will have to be refered to to find the endpoint positions of this edge. Faces will refer to these edges by thier position in the Edges[][] array (i.e. the edge numbers appearing below run from from 0 to edge_count - 1). (See PNTS chunk)
UWORD Edges[edge_count][2]; ; edges
UWORD FCount; ; face countThis chunk contains the triangle (face) list for custom objects. The Faces[][3] array is triples of edge numbers that are connected to form triangles. This Back references through the Edge list and then through the Point list to find the 3 space coordinates of the face's vertexes. (See EDGE and PNTS chunks) Note: it is possible that the edge numbers given for a face would use more than 3 point numbers all together ... this should be considered as an error ... however, Imagine doesn't enforce the desired constsistency when objects are loaded. This can lead to some confusion when testing "first time" code, since Imagine sometimes uses only the first two edge numbers, assumeing that the 3rd edge is constsient with the 1st two.
UWORD Faces[][3]; ; faces
UWORD ACount; ; axis countThis chunk contains the axis data for Imagine "path" objects. ACount is the number of axes in the path object. The PData array contains a bit of data for each point (axis) along the path. A closed path is made by setting the value of the inFrom[] variable of the first axis to the number of the last axis, and setting the outTo[] variable of the last axis to the number of the first axis (1). An open path will have to have the flags[] bits 1 (or 2) clear, showing that the first (or last) axis is only connected on one side ... the 1st axis should show a "connected out" flag, and the last axis should show a "connected in" flag only.
PTHD PData[ACount]; ; path (axis) data
BYTE pad; ; pad byte - must beThese are the main object RGB color, and reflection, transmission and specularity coefficients.
COLOR col; ; RGB color
UWORD face_count; ; number of facesThese are the color, reflection and transmission coefficients for each face in custom (type 2 - axis) objects. The face_count has to match the face count in the FACE chunk. The ordering corresponds to the face order. When the objects main attributes are altered, the new color values are copied into the whole colors[] array. Modifying color values in face mode or choosing "randomize colors" from the attributes requester will independantly alter the values in the colors[][] array. This chunk appears in all custom (type 2 - axis) objects.
COLOR colors[face_count]; ; colors
UWORD Flags; ; texture flags:This chunk contains the texture data necessary for the renderer to communicate with Imagine's procedural texture modules and for positioning textures on objects. Subgr[], if used, restricts the texture application to the named subgroup. LockState[], if used, will lock (tack) the texture to the object's faces for object morphing without texture sliding. The values in Params[] are tweened (interpolated) internally by Imagine when morphing/animating textures. A TXT3 chunk appears for each texture applied to an object.
; Bit 0 - apply to child objs
; Bits 1 thru 15 - reserved
TFORM TForm; ; local coordinates of texture axes.
FRACT Params[16]; ; texture parameters
UBYTE PFlags[16]; ; parameter flags for texture requester
; Bit 0 - alter red color in color chip
; Bit 1 - alter green color in color chip
; Bit 2 - alter blue color in color chip
; Bit 3 - alter parameter when resizing object
; Bits 4 thru 7 - reserved
BYTE SubGr[18]; ; Subrgoup to restrict texture to
BYTE LockState[18]; ; State name for "texture tacking"
UBYTE Length; ; length of texture file name
UBYTE Name[Length]; ; texture file name (not NULL terminated)
UBYTE optionalpad; ; appears only if the name string has an even
; length -- so the total length of the name
; "block" (length + name + pad?) comes out even
UWORD Flags; ; brush type:This chunk contains the brush data necessary for the renderer to load and position brush maps (texture maps) on objects. FullScale is used to map the highest color value within a brush map to full-scale 255 for Imagine's internal interpritation of the brush. Subgr[], if used, restricts the brush application to the named subgroup. LockState[], if used, will lock (tack) the brush to the object's faces for object morphing without texture sliding. The value in MaxSeq is tweened (interpolated) internally, from 1 to MaxSeq, by Imagine when animating brushes - this way, brush morphing can be accomplished. A BRS4 chunk appears for each brush map applied to an object.
; 0 - Color
; 1 - Reflectivity
; 2 - Filter
; 3 - Altitude
; 4 - Reflection
UWORD WFlags; ; brush wrapping flags:
; Bit 0 - wrap x
; Bit 1 - wrap z
; Bit 2 - apply to children
; Bit 3 - repeat brush
; Bit 4 - mirror with repeats
; Bit 5 - inverse video
; Bit 6 - Use genlock
TFORM TForm; ; local coordinates of brush axes.
UWORD FullScale; ; full scale value
UWORD MaxSeq; ; highest number for sequenced brushes
BYTE SubGr[18]; ; Subrgoup to restrict brush to
BYTE LockState[18]; ; Brush lockstate
UBYTE Length; ; length of brush file name
UBYTE Name[Length]; ; brush file name (not NULL terminated)
UBYTE optionalpad ; if name has even length (see TXT3 description)
This is the object foglength set in Imagine's attributes requester.
UBYTE IProps[8]; ; more object propertiesThe discriptions of the IProps array is as follows:
IProps[0] - dithering factor (0-255)
IProps[1] - hardness factor (0-255)
IProps[2] - roughness factor (0-255)
IProps[3] - shinyness factor (0-255)
IProps[4] - index of refraction - ir = (float)IProps[4] / 100.0 + 1.0;
IProps[5] - quickdraw type: 0=none, 1=bounding box, 2=quick edges
IProps[6] - flag - Phong shading on/off
IProps[7] - flag - Genlock on/off
The dithering factor controls the amount of color dithering used on the object - 255 is fully dithered. The hardness factor controls how tight the specular spot should be - 0 is a big soft spot, 255 is a tight hot spot The roughness factor controls how rough the object should appear - 0 is smooth, 255 is max roughness. The shiny factor in interaction with the object's filter values controls how shiny the object appears. Setting it to anything but zero forces the object to be non-transparent since then the filter values are used in the shiny (reflection) calculations. A value of 255 means maximum shinyness.
VECTOR Intensity; ; light intensityThis has seperate R, G & B intensities for the light objects. Note that these color values are stored as FRACT's and are not limited to the 0 to 255 range of the usual UBYTE color values so lights can be brighter than 255 255 255.
LONG Cellno; ; cell number ("key" cell)For Imagine's "Cycle" objects, within EACH DESC chunk in the file - that is, for each object of the group, there will be a series of ANID chunks. The cell number sequences of each part of the group must agree with the sequence for the head object, and the first cell number must be zero.
TFORM TForm; ; object position/axes/size in that cell.
WORD NumC; ; number of cross section pointsFor Imagine's "Forms" objects, the "PNTS" chunk above is not written out, but this structure is written instead. The object's real points are then calculated from these using a proprietary algorithm. The tranformation parameters above allow the axes of the real object be moved around relative to the "Forms" points. The value, PC, is calculated as follows:
WORD NumF; ; number of slices
WORD Flags; ; forms object type flag
; Bit 0 - X-Y Cross Section
; Bit 1 - One Former View
; Bit 2 - One Spacer View
; Bits 3 thru 15 - reserved
; (bit 0 off means Y-Z Cross Section)
; (bits 1 and 2 off means Two Former Views)
WORD keys; ; number of defined key sections
MATRIX TForm; ; object rotation/scaling transformation
VECTOR Shift; ; object translation
VECTOR Points[PC]; ; "Forms" editor points
WORD sexions[keys]; ; list of key sections by number
WORD type; ; tells what type of particles to useThis is the main object particalization parameters. This chunk describes the geometry of the particles to be used in place of the objects faces. The PTFN chunk contains the file name of the "use object file" type of particles, and the FGR2 chunk contains the particle geometry info for specific sub groups. Particles only work on custom (type 2 - axis) objects with faces. (see PTFN and FGR2 chunks)
; bits 0-3: shape
; 0x0000 - faces (no particles)
; 0x0001 - tetrahedrons
; 0x0002 - pyramids
; 0x0003 - octahedrons
; 0x0004 - cubes
; 0x0005 - blocks
; 0x0006 - dodecahedrons
; 0x0007 - spheres
; 0x0008 - random
; 0x0009 - use object file
; bits 4-7: centering
; 0x0000 - inscribed
; 0x0010 - circumscribed
; 0x0020 - interpolated
; 0x0030 - barycentric
; bits 8-11: size
; 0x0000 - small
; 0x0100 - large
; 0x0200 - random
; 0x0300 - specify
; bits 12-15: alignment
; 0x0000 - to object
; 0x1000 - to face
; 0x2000 - random
FRACT size; ; used with specify size
BYTE length; ; number of characters in the file nameFor Imagine's particalized objects. This is the filename for the "use
BYTE PartFileName[length]; ; particle file name (not null terminated)
BYTE optionalpad; ; appears only if name has an even length
; (see TXT3 description)
UWORD faceCount; ; the number of faces in this subgroupThis is the Subgroup info for Imagine's custom (type 2 - axis) objects which have subgroups - the mnemonic, FGR2, stands for face group. pType, pSize, pFNSize, and pFName all deal with particalized subgroups. The faceNums[] array is a list of faces by numerical position in the face list as described in the FACE chunk. Valid face numbers run from zero through object_face_count - 1.
BYTE subGrName[18]; ; the name of the subgroup
UWORD faceNums[faceCount]; ; the list of faces in this subgroup
UWORD pType; ; subgroup particle type - see PART chunk
FRACT pSize; ; subgroup particle size - see PART chunk
UBYTE pFNSize; ; character count in the particle file name
BYTE pFName[pFNSize]; ; particle filename - see PTFN chunk
BYTE optionalpad; ; appears only if name has an even length
BYTE bbsg[18]; ; big bone subgroup nameThis is the Big Bone SubGroup name used with the bones function in Imagine. By design, BBSG will appear in the DESC chunk of a particular bone (usually an axis), and will refer to a subgroup name in a FGR2 chunk of the parent object of this entire group. (note: the "Bones" functions also assume that a state named DEFAULT appears in the state list of the group's parent object, containing at least "shape" and "grouping" data) (also, see SBSG chunk below)
BYTE sbsg[18]; ; small bone subgroup nameThis is the Small Bone SubGroup name used with the bones function in Imagine. By design, SBSG will appear in the DESC chunk of a particular bone (usually an axis), and will refer to a subgroup name in a FGR2 chunk of the parent of this entire group. (see BBSG chunk above)
WORD edge_count; ; the number of edges on the objectThis chunk contains the flag values for all the edges of custom (type 2 - axis) objects with edges. These flags currently support the quick edge and sharp edge flags. (Note: Imagine writes this chunk only if one or more edges in the object actually has bit 6 or 7 set)
UBYTE edgeFlag[edge_count]; ; array of edge flags for each edge
; Bits 0 thru 5 - reserved
; Bit 6 - quick edge
; Bit 7 - sharp edge
Again, most of these fields are optional, and some defaults are supplied. However, if there is a FACE chunk, there must also be a CLST chunk, an RLST chunk and a TLST chunk -- all with matching "count" fields. The SHP2 chunk is not optional.
Your best bet in understanding the relationship between chunks (what's required, and what's not) will probably be through creating objects within Imagine, saving them out, and then interrogating and comparing the TDDD files.
The order in which the chunks appear is somewhat irrelevant. Some of the chunks contain a point count, or something similar, and some of them (STDT chunks) don't actually contain a count, but are based on a count. Imagine assigns the appropriate count based on the first occurence of a chunk whose size would depend on the count, and then enforces consitency as succeding chunks are processed.
For TXT3 and BRS4 (texture and brush) chunks, the order in which the chunks appear in the file determines the order they are listed in Imagine, and also the order in which they are applied during rendering.
For Imagine's "Quick Stage" mode, the DESC chunks are processed only until a certain minimum amount of data has been read in, and then it skips to the end of the DESC chunk. The "required" fields (in order to skip to the end) are NAME, POSI, ALGN, SIZE, SHP2 and BBOX. If state data (i.e. Bones data) is required from the object for stage animation, then it must appear before at least one of the "required" fields listed above, or it will be ignored -- similarly for cycle editor data (ANID chunks), and path (PTH2) data. For example, Imagine does the following: 1) writes all of the "required" chunks listed above except for the BBOX chunk, 2) writes ANID chunks (if any), 3) writes STND chunks (if any), 4) writes a PTH2 chunk (if reqd), 5) writes a BBOX chunk, and finally, 6) writes the rest of the data.
Unfortunately, Impulse does not have the support staff available to answer technical questions about the information included in this document. Hopefully, this will be a good starting point. How far you get with it will, most likely, be dependent upon hard work and perseverance.
Good Luck and Enjoy.
The IFF file format originated on machines in which the byte order for LONG (4 byte) and WORD (2 byte) data is "most significant byte first". This concept has been preserved in the "PC" versions of Imagine.
What it means, is that if you are writing code for the "other" type of CPU (80386 code, for example), you will need to reverse the byte ordering in (U)LONG, FRACT, and (U)WORD data wherever it appears (e.g. the FRACTs in a VECTOR structure must be (separatly) byte reversed ... the size field following a chunk identifier is another good example)
In case you are unfamiliar with the IFF file structure, the TDDD files have the following (simple, "single FORM") IFF structure:
form_ID 4 characters: 'F','O','R','M'
form_size LONG size : -- MSB(yte) first
form_type 4 characters: 'T','D','D','D'
chunks:
chunk_ID 4 characters: e.g. 'O','B','J',' '
chunk_size LONG size : -- byte reversed if appropriate
chunk_data 'size' bytes:
chunk_pad 0 or 1 bytes: -- pad to even length if 'size' is odd