FORM TDDD --------- Imagine 3.0 Object File Format Rev 3.0 05-19-94 S.Kirvan Copyright 1994 Impulse Inc., Mpls, MN 55444 Disclaimer: All information contained herein is subject to change without notice. Knowledge is dangerous - use at your own risk. No warranties are made or implied, and no liability or responsibility is assumed. Good luck. SCOPE: ===== This text will describe Imagine 3.0's basic object file format. It is beyond the scope of this text to describe any of the file formats used for spline objects, deform tool, or any other object types not mentioned below. However, some of the data described below may apply to some of these undocumented object formats. It is also not the intent of this document to explain the implementation of the information contained in the TDDD files (ie. what equations we use to represent Imagine's paths - lighting models - forms geometry - tweening algorithms, etc.). GENERAL INFO: ============ FORM TDDD is used by Impulse's Imagine 3.0 for 3D rendering data. TDDD stands for "3D data description". The files contain 3D object definitions, and can be extended to describe different types of object information. 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 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 . 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: . 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: starting with the head (parent) object, 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. The TOBJ sub-chunks have zero size -- and no data. The DESC sub-chunks are made up of "sub-sub-chunks", again, with the standard IFF structure: . Reader software WILL FOLLOW the standard IFF procedure of skipping over any un-recognized chunks -- and "sub-chunks" or "sub-sub-chunks". The field indicates how many bytes to skip. In addition it WILL OBSERVE the IFF rule that an odd may appear, in which case the corredponding field will be padded at the end with one extra byte to give it an even size. DATA TYPES: ========== First, there are several numerical fields appearing in the data, describing object positions, rotation angles, scaling factors, etc. They are stored as "32-bit fractional" numbers, such that the true number is the 32-bit number divided by 65536. So as an example, the number 3.14159 is stored as (hexadecimal) 0x0003243F (ie. 0x0003243F / 65536 = 3.14159). This allows the data to be independant of any particular floating point format. Numbers stored in this format are typedef'ed as "FRACT"s below. 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. The three basic data types that will be refered to herein are: BYTE : a single byte of data (char) WORD : a two byte data field (short) LONG : a four byte data field (long) A "U" (ie. UBYTE) means unsigned. The following "typedef"s are used below: typedef LONG FRACT; /* 4 bytes */ typedef UBYTE COLOR[3]; /* 3 bytes */ typedef struct vectors { FRACT X; /* 4 bytes */ FRACT Y; /* 4 bytes */ FRACT Z; /* 4 bytes */ } VECTOR; /* 12 bytes total */ typedef struct matrices { VECTOR I; /* 12 bytes */ VECTOR J; /* 12 bytes */ VECTOR K; /* 12 bytes */ } MATRIX; /* 36 bytes total */ typedef struct _tform { VECTOR r; /* 12 bytes - position */ VECTOR a; /* 12 bytes - x axis */ VECTOR b; /* 12 bytes - y axis */ VECTOR c; /* 12 bytes - z axis */ VECTOR s; /* 12 bytes - size */ } TFORM; /* 60 bytes total */ typedef struct _pthd { TFORM PData; /* axis data */ UWORD inFrom; /* previous axis number */ UWORD outTo; /* next axis number */ UWORD flags; /* flags for this axis */ /* Bit 0 - reserved - zero for "Detail Editor" paths /* Bit 1 - an axis connects in to this axis /* Bit 2 - an axis connects out of this axis /* Bits 3 thru 15 - reserved UWORD pad; /* reserved */ } PTHD; DESC SUB-SUB-CHUNKS: =================== NAME - size 18 BYTE Name[18]; ; a name for the object. Object's name as it appears in the attributes requester. Used for tracking, etc. SHP2 - size 4 WORD Shape; ; number indicating object type WORD Lamp; ; bit field indicating lamp type Valid shape numbers are: 0 - Sphere 2 - Axis ; custom objects with points/faces 5 - Ground 1, 3, and 4 are reserved, and should never appear in TDDD files. Perfect spheres have thier radius set by the X size parameter (see SIZE chunk). A ground object is an infinte plane perpendicular to the world Z axis. Its Z coordinate sets its height, and the X and Y coordinates are only relevant to the position of the "hot point" used in selecting the object in the editor (see POSI chunk). Custom objects have points, edges and triangles associated with them. Imagine's primative objects are cumstom (type 2) objects. The size fields are relevant only for drawing the object axes in the editor. 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. POSI - size 12 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. AXIS - size 36 VECTOR XAxis; VECTOR YAxis; VECTOR ZAxis; 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. SIZE - size 12 VECTOR Size; ; object size info See SHAP 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. BBOX - size 24 FRACT bounds[6]; ;bounding box data The 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. STND - variable size The data in an STND chunk consists only of smaller sub-chunks. STID and STDT are the only types defined so far. 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) STID - size 20 BYTE stid[18]; ; state name 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 This 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. STDT - variable size WORD tag; ; state data type tags ; 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 (CLST) ; 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 This 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 = 101 - contains object axis info - saved with grouping VECTOR axis_r; ; axis position vector MATRIX axis_m; ; axis alignment vectors (48 bytes total) See AXIS and POSI chunks. 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) 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) (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. PNTS - size 2 + 12 * point count UWORD PCount; ; point count VECTOR Points[point_count]; ; points This 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). EDGE - size 2 + 4 * edge_count UWORD ECount; ; edge count UWORD Edges[edge_count][2]; ; edges This 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 PTNS chunk) FACE - size 2 + 6 * face count UWORD FCount; ; face count UWORD Faces[][3]; ; faces This 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. PTH2 - size 2 + 68 * axis count UWORD ACount; ; axis count PTHD PData[ACount]; ; path (axis) data This 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. COLR - size 4 REFL - size 4 TRAN - size 4 SPC1 - size 4 BYTE pad; ; pad byte - must be zero COLOR col; ; RGB color These are the main object RGB color, and reflection, transmission and specularity coefficients. CLST - size 2 + 3 * face_count RLST - size 2 + 3 * face_count TLST - size 2 + 3 * face_count UWORD face_count; ; number of faces COLOR colors[face_count]; ; colors These 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. TXT3 - variable size UWORD Flags; ; texture flags: ; 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 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. BRS4 - variable size UWORD Flags; ; brush type: ; 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 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. FOGL - size 4 FRACT foglen; ; value of foglength attribute This is the object foglength set in Imagine's attributes requester. PRP1 - size 8 UBYTE IProps[8]; ; more object properties The 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. INT1 - size 12 VECTOR Intensity; ; light intensity This 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. ANID - size 64 LONG Cellno; ; cell number ("key" cell) TFORM TForm; ; object position/axes/size in that 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. FOR2 - size 56 + 12 * PC + 2 * keys WORD NumC; ; number of cross section points 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 For 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: for Two Former Views: PC = keys * NumC + 4 * NumF; for One Former View: PC = keys * NumC + 2 * NumF; for One Spacer View: PC = keys * NumC + 1 * NumF; PART - size 6 WORD type; ; tells what type of particles to use ; 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 This 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) PTFN - variable size BYTE length; ; number of characters in the file name BYTE PartFileName[length]; ; particle file name (not null terminated) BYTE optionalpad; ; appears only if name has an even length ; (see TXT3 description) For Imagine's particalized objects. This is the filename for the "use object file" type of particlization. (see PART chunk) FGR2 - variable size UWORD faceCount; ; the number of faces in this subgroup 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 This 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. BBSG - size 18 BYTE bbsg[18]; ; big bone subgroup name This 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) SBSG - size 18 BYTE sbsg[18]; ; small bone subgroup name This 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) EFLG - 2 + edge_count WORD edge_count; ; the number of edges on the object UBYTE edgeFlag[edge_count]; ; array of edge flags for each edge ; Bits 0 thru 5 - reserved ; Bit 6 - quick edge ; Bit 7 - sharp edge This 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) DESC notes ---------- 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 SHAP 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,POSN,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. PC (80x86 CPU) notes ==================== 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) IFF file format notes --------------------- 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 Note: The "form_size" field appearing after the "form_ID" is the total length of the data that FOLLOWS it, INCLUDING the 4-byte (TDDD) id. Also the "chunk_size" fields list the size of the data in the "chunk_data" blocks that follow. In other words, the size fields when rounded up to an even number, always list the number of bytes (after the size field) to skip forward in the file if, based on the ID field preceding the size, the reader can not or does not wish to interpret the data ... so, in particular, the sizes that appear DO NOT include the length of the ID and size fields themselves, and the 'form_size' DOES include 4 bytes for the 'form_type' field that follows it. Imagine uses "extended sub-chunks" -- where for some chunk types, the data actually consists of a series of smaller chunks, in the same IFF form: ID/Size/Data/pad_byte_if_neccesary. In fact, the only "true" IFF chunk that imagine recognizes is the 'OBJ ' chunk -- which contains the complete data for a single heirarchy (group) of objects. Things are as they are, mainly for historical reasons ... once upon a time, TDDD files were also used to hold all the data for a single frame in an animation, and several 'OBJ ' chunks could appear, as well as more chunks giving data about the camera position, etc. Now, when Imagine writes a TDDD file, it contains only a single 'OBJ ' chunk. Imagine will still process a file containing multiple 'OBJ ' chunks, but in all cases, except when it loads a file into its "Detail Editor", it ignores all but the first object heirarchy.