Sie sind auf Seite 1von 92

Interchangeable World Format v2.

Interchangeable World Format v2.0


Standards Documentation - Rev 0
Copyright 2002 Daedalus Developments. All Rights Reserved.

Table of Contents
1. Introduction...........................................................3 1.1. Purpose............................................................3 1.2. Intended Audience..................................................4 1.3. Compliance.........................................................4 1.4. Changes............................................................4 1.5. Definitions........................................................4 2. What is the Interchangeable World Format?..............................4 2.1. Data Chunks........................................................5 2.2. Chunk Hierarchy....................................................5 2.3. Additional Features................................................6 2.3.1. Compression....................................................6 2.3.2. Error Detection................................................7 2.3.3. Custom Chunk Collision Prevention..............................8 2.3.4. Chunk Encryption...............................................9 2.3.5. Chunk Summary Information.....................................10 3. IWF Structure Layout..................................................10 3.1. File Header.......................................................10 3.1.1. Version System................................................12 3.2. Chunk Header......................................................12 3.2.1. Calculating and Using Chunk Sizes.............................14 3.2.2. Using Author-IDs..............................................14 3.3. Chunk Data Area...................................................16 3.4. Chunk Footer......................................................16 3.5. Chunk Types.......................................................18 3.6. Putting it All Together...........................................19 3.6.1. Providing Forward References..................................24 3.6.1.1. File Header - Flags......................................25 3.6.1.2. File Header - Checksum...................................25 3.6.1.3. Chunk Header - ChunkLength................................25 3.6.1.4. Chunk Header - DataLength.................................26 3.6.1.5. Chunk Footer - EOCValue...................................26 3.7. Supporting Chunk Encryption.......................................27 3.8. Supporting File Compression.......................................27 3.9. Calculating a Valid Checksum......................................27

Copyright 2002 Daedalus Developments. All Rights Reserved. Page 1 of 92.

Interchangeable World Format v2.0

Table of Contents (cont)


4. Standardised Chunk Specifications.....................................28 4.1. Common Types, Structures and Processes............................28 4.1.1. Vectors.......................................................28 4.1.2. Matrices......................................................29 4.1.3. Bounding Boxes................................................30 4.1.4. Palettes, Colours and Blend Modes.............................30 4.1.5. Scripts, Shaders and Effect Files.............................34 4.1.6. Object Component Architecture.................................35 4.2. Summary Chunk.....................................................37 4.2.1. Processing Chunk Statistics...................................38 4.3. Thumbnail Chunk...................................................40 4.3.1. Palettes and Image Data Formatting............................41 4.4. Group Chunk.......................................................43 4.5. Object Meshes.....................................................45 4.6. Polygon Data......................................................49 4.7. Vertex Components.................................................54 4.7.1. Vertex Pools..................................................59 4.7.1.1. Surface Pools.............................................60 4.7.1.2. Mesh Pools................................................61 4.7.1.3. Global Pools..............................................61 4.7.1.4. Mixing Vertex Pools.......................................62 4.7.2. Vertex Arrangement............................................64 4.8. Vertex Indices....................................................68 4.8.1. Index Values..................................................70 4.9. Decal Meshes......................................................72 4.10. Entities.........................................................73 4.10.1 Standard Entity Types.........................................74 4.10.1.1. Lights...................................................75 4.10.1.2. Simple Point.............................................77 4.10.1.3. Spawn Point..............................................78 4.11. Materials........................................................80 4.12. Textures.........................................................83 4.13. Shaders..........................................................87 4.14. Coordinate System Information....................................89 4.15. Standard Chunk Arrangements......................................91 4.16. Application Compliance...........................................91 5. IWF File Toolkit Version 2.0..........................................92

Copyright 2002 Daedalus Developments. All Rights Reserved. Page 2 of 92.

Interchangeable World Format v2.0

1. Introduction

The interchangeable world format, or IWF for short, is an Interchange File Format as its name suggests, in the sense that, much like Microsofts RIFF (Resource Interchange File Format) the IWF structure is designed to store data of any custom type, and is not strictly limited to any predefined layout or design, with the exception of the interchange structure itself. While the format does not prohibit the introduction of custom data within the file itself, and in fact can be utilised to store data pertaining to almost any application, the primary design goal of the interchangeable world format (IWF) is to provide a convenient means by which to store and retrieve data, commonly utilised by interactive multimedia applications such as computer games and any manner of associated content creation tools. For this reason, the IWF is an ideal candidate for such a task, not only because of the inherent features within file structure itself, but also due to the fact that many objects and data types, associated with such applications, have been standardised within the specification. This provides massive potential for cross-application support and content sharing, with minimal effort. This standards document is essentially split into three distinct sections. The first covers the actual properties, and intended use of the IWF specification. The second covers the actual structure and layout of the IWF file itself, whilst the third focuses more on the objects and data types implemented within the standards specification. Please bear in mind that this specification is designed as a reference to be used alongside the example import / export source code provided. There is a vast amount of information provided here that may become overwhelming should you be attempting to develop an import or export procedure based upon this specifications document alone. Unless otherwise noted, all aspects of this specifications document are Copyright 2002 Daedalus Developments, All Rights Reserved.
1.1. Purpose

The purpose of this specification is to define a flexible means by which to store a wide variety of information, including but not limited to, that used by applications involved in the field of interactive multimedia software, such as computer games, which:
Allows easy access to all, or simply portions, of the information stored within the file. Defines a content standard to provide support for multiple applications between nonassociated developers. Provides as much functionality as possible, for use within a wide range of situations. Does not restrict developers to only that which is defined by the standard. Provides support for constantly modernising technology.

Copyright 2002 Daedalus Developments. All Rights Reserved. Page 3 of 92.

Interchangeable World Format v2.0

1.2. Intended Audience

This specification is intended for use by developers of software intending to either export to, or import from the interchangeable world format, and assumes at least a basic knowledge of programming and the development of file input / output procedures.
1.3. Compliance

Unless otherwise noted, a compliant IWF import procedure must be able to successfully import any data set that conforms to all the specifications presented within this document with the exception of the standardised data chunk types. Likewise a compliant IWF export procedure must produce data sets that conform to all the specifications presented within this document with that same exception. Please refer to section 4.16. Application Compliance for more information about the implications of, and requirements for, building a compliant import procedure.
1.4. Changes

Revision 0. There are currently no changes to list.


1.5. Definitions Hex Hexadecimal. Pertaining to a number system having 16 as its base. Values specified in hexadecimal always begin with the characters 0x within this specification. A linear list of identically typed data items distinguished by their indices. Variable. An object of a certain type, used to store an arbitrary value.

Array Var

2. What is the Interchangeable World Format?

The format itself is not an all encompassing multimedia file format, but is in fact a hierarchical structure, designed primarily for ease of use rather than focusing on the storage of any particular type of object or data. To speak metaphorically, this structure can be thought of as being a library full of books. Each of these books has a contents page, which contains information about exactly what is contained within that particular book and also how to access it, by page number for instance. Put in the terms used by the format itself, the file is the library, and each book is what is known as a chunk. Each chunk has a header, essentially the contents page in our previous example, which contains information about the data contained within that chunk and how it should be accessed.

Copyright 2002 Daedalus Developments. All Rights Reserved. Page 4 of 92.

Interchangeable World Format v2.0

2.1. Data Chunks

Due to the fact that the structure itself is not reliant in any way on the data stored within each chunk, this allows us to essentially store any type of data we wish within the file. However, as previously mentioned, the primary design goal of this format is to provide a convenient method for storing and retrieving information, commonly utilised by interactive multimedia applications, in such a way that it can be retrieved and understood by a wide range of software, not simply the application for which it was designed. For this reason, the IWF implements the concept of Standard and Custom data chunks. Custom data chunks are developer defined, and can contain any object or data that is required. This could be in absolutely any form ranging from image or audio data, to scripts which control characters within the world. Standard data chunks however, are defined by the IWF standard. These chunks contain information such as mesh data, polygons, vertex information, certain types of world entities such as lights and player spawn points, height-maps and many other types of objects which relate to the creation of a three dimensional scenes. While these chunks are provided within the IWF standard, their use is not mandatory. However, should you choose not to utilise the format of this standardised information, third parties will be unable to read the information stored within the file, without making available the specifications of your own custom data chunks. This of course may be desirable; however other methods are available for protecting the data stored within an IWF file, discussed later in this document, other than using strictly custom data chunks (see section 2.3.4. Chunk Encryption). Both types of data chunk are made up of both the actual chunk data itself and a chunk header which precedes it. This header contains various pieces of information such as a chunk type-id (i.e. is this a mesh or a piece of terrain), a signature which informs the software whether this is a standard or custom chunk, and also the various chunk data size information which allows us to iterate through, or skip over, certain chunks without having to read or understand the data stored within them. Unlike the IWF version 1.0 specification, version 2.0 is now a fully realised hierarchical file format, and for this reason data chunks now also contain a chunk footer. This footer provides us with an additional End of Chunk code which informs the import procedure of whether there are additional chunks at this level in the hierarchy, or if it should step out of this level, and back up to the parent that owns it. While this could be achieved simply by using file position monitoring, the use of the exit code allows extremely intricate recursive procedures to be implemented with incredible ease.
2.2. Chunk Hierarchy

As mentioned, the v2.0 IWF is a hierarchical format. This means that all chunks within the file can be arranged in such a way that certain chunks can become children of other chunks. As an example, the polygon chunk may be a child of the mesh chunk, and many chunk types may be a child of the group chunk. The

Copyright 2002 Daedalus Developments. All Rights Reserved. Page 5 of 92.

Interchangeable World Format v2.0

usefulness of these hierarchical properties extends far beyond simple arrangement of individual object components however. Take a look at figure 1 below:
Body

Head

Arms

Legs

Mouth

Eyes

Hands

Feet

Fingers

Toes

Figure 1. Object Hierarchy

Hopefully, using the above diagram, you can see that even individual parts of a character model can be arranged such that certain limb meshes are stored as children of other parent limb meshes. In the above case, we could say that the objects fingers are children of that objects hand, or that the objects mouth is a child of the objects head. Due to the fact that the objects have physically been stored in this manner, there is no requirement for any additional information outlining the parent child hierarchy of specific model components. This not only applies merely to models of course, your entire scene graph information could be stored simply by writing the graph components out in this way. As we go on to discuss individual chunk types and their relationships later in this document, it should become clear how this form of hierarchical design can be achieved easily and efficiently.
2.3. Additional Features

There are many additional features built into the v2.0 IWF specifications in addition to the benefits gained using the chunk structure system itself (not including the features built into the standardised chunk types outlined later on), just some of which include compression, write corruption / read error detection and recovery, custom chunk collision prevention, chunk encryption and chunk summary information. All of these features are of course optional, but serve to provide extremely comprehensive support, whatever the situation. Although these features will be discussed in greater detail later in this document, here is a quick summary of what these features provide:
2.3.1. Compression

The compression support built into this specification is the primary means by which to reduce the overall size of the output IWF file. As the size and content of interactive worlds increase exponentially the amount of storage required for this information also increases. However, because of the ever increasing popularity of
Copyright 2002 Daedalus Developments. All Rights Reserved. Page 6 of 92.

Interchangeable World Format v2.0

online content, this no longer means that the only consideration is storage space, we must also now take into account the amount of bandwidth required to send and receive this information. Although there are many space saving features built into the individual standardised chunk types themselves, there is only so much space which can by saved by simply rearranging and merging the information within the file. This is why compression of data is becoming more and more important within this medium. The compression system utilised by the IWF is a lossless data-compression algorithm (very similar to that used in PKWAREs PKZIP 2.x and above) and has been designed around the extremely popular ZLib library (v1.1.4) developed by Jean-loup Gailly (compression) and Mark Adler (decompression). This library is used in the creation and decoding of many popular formats such as the PNG image format and GZIP / ZIP compressed volumes. ZLib is open source under the GPL and the library used is available completely free of charge from the following address: http://www.gzip.org/zlib/
2.3.2. Error Detection

Again, due to the ever increasing popularity of online content, file corruptions are an unfortunate reality even though many safeguards exist within the various internet traffic protocols. For this reason, the early detection of file corruptions is fast becoming an even more important aspect of any import procedure, if you are to prevent application-fatal protection faults. The IWF specification includes its own safeguards to help detect such errors, both before and during the import procedure. The first of these safeguards is a 32 bit checksum, or CRC, stored in the main header of the IWF file itself. This checksum is somewhat like a unique key, built using each individual byte of the file itself. By attempting to build this checksum again at load time, and then matching the resulting checksum against the original stored within the file, it is possible to tell whether or not the file has changed since it was written. Note: This checksum is not intended as a file content protection scheme. It is purely optional and should not be used to verify the existence of file tampering. As mentioned, this checksum value is optional, and may not be provided in the file header. Even if this value is provided, it may be advantageous to step through the file regardless of the fact that the checksum did not match. For this reason additional error detection is provided in the form of chunk signatures. Each chunk header and footer contains a 4 byte signature which can be examined to determine not only whether any corruption exists, but also to allow attempted recovery of the import process itself. This signature is not a checksum value however; it is intended to determine whether or not the attempted read operation of the current chunk is in fact valid. When reading the chunk header, if this signature is invalid, it is normally indicative of one of two things: either the chunk itself or this portion of the file is
Copyright 2002 Daedalus Developments. All Rights Reserved. Page 7 of 92.

Interchangeable World Format v2.0

entirely or partially corrupt, or an invalid value stored within the file caused the read operation to become out of sync with the file contents. Either of these two situations is of course a catastrophic event. In the case of the latter however, it is possible to attempt to recover the situation by ignoring this chunk. Even if the chunk itself is completely corrupt, or contains invalid values, it is usually the case that using the value stored in the chunk header will allow you to continue on to the next chunk. If this next chunk signature is also found to be invalid then using certain values stored in the Parent Level chunk can allow recovery back up to the level above. This does mean however that, if the latter is the case, all chunks found at the same level as that of the corrupt chunk will have to be discarded. However this does mean that the remaining contents of the file outside of the corrupted level can be recovered.
2.3.3. Custom Chunk Collision Prevention

All chunks are identified using a single two byte value, which informs the import procedure about what type of data this chunk contains. For example, the standards defined mesh chunk has a type-id code of 0x0020(hex) which identifies it as such. Because true globally unique identification (GUID) values are so large, combined with the fact that the same chunk headers are used for both standard and custom chunks, the IWF introduces the concept of Author ID fields. It is commonplace for two or more non-associated developers to choose the same id code for a custom chunk. Therefore, to prevent a collision of any such custom chunks, a developer defined author-id is appended to the chunk header as a means of identifying who created the chunk itself. Far from a simple watermark (although nonetheless very useful as such) the author-id field serves as a filter to allow an import procedure to skip over any custom chunks which are not intended for use in that application, regardless of the fact that they share the same chunk type-id code. This is extremely useful information for a developer in many cases, where for example Application A is searching through the file for a custom chunk with a typeid code of 0x0100(hex) which, as far as it is concerned is an empty chunk simply used to determine if this is a file from which it can read / understand. Whereas Application B (the software which originally exported the file), used the type-id code of 0x0100(hex) to hold a script file. Because both applications use that same type-id code, Application A in our example will now assume that it is a valid file, and no doubt get into trouble later on. As a second example, a third-party application may well be developed which appends a custom chunk with a specific type-id code to a certain (or in fact any) IWF file. The developer of that application has no way of knowing if the developer, whose application originally exported the file, presently uses, or will at any point in the future use, a custom chunk type-id with that same code. With the author-id field in place, chunks using the same type-id code can coexist within the same file without issue. The author-id field can even be used to signify differing versions of that same chunk. As an example, you could provide the same information within your file, perhaps structured differently or with extra fields, for both versions 1.0 and 2.0 of your application by providing different author-id
Copyright 2002 Daedalus Developments. All Rights Reserved. Page 8 of 92.

Interchangeable World Format v2.0

codes for each. Reading back in is then simply a case of filtering out the chunks not intended for that particular version, therefore providing support for all of your userbase, within the same IWF file.
2.3.4. Chunk Encryption

As mentioned in earlier sections, file content protection is possible without having to resort to strictly using custom chunks, and guarding your file specifications from being leaked (although even in this case, file format analysis procedures exist to attempt to gain that information regardless). This protection comes in the form of chunk encryption, and can be put into use where the external viewing or tampering of the file contents is to be prohibited. As an example: encryption could be used to prevent modifications to scripts for use online, in an attempt to prevent certain types of cheating for instance. The encryption scheme utilised by the IWF specification is a symmetric stream cipher known as ARCfour (an RC4 derivative). This cipher is a simple yet extremely effective algorithm used in many applications and systems today. These include various internet browsers (SSL), Lotus Notes and many cryptographic libraries. In this system, each individual chunks data is encrypted as it is written, using a variable length key provided by the developer, which must also be used to decrypt the data on import. With the exception of the author-id however, the chunk header remains plaintext. Although this is a secure system, there are various considerations which should be taken into account when using any encryption scheme. Just one of these is to bear in mind that using the same key for multiple files, increases the chance that a proficient crypto-analyst will be able to calculate the key used to encode them, and consequently freely decode that file. Therefore choosing a random key for each file increases the security of the encryption substantially. This is a consideration you should take with all encryption schemes and is not specific to ARCfour. Note: The encryption provided by this specification is not intended to be used as a secure transport method for sensitive data, it is merely a means to prevent the average user from being able to view or tamper with the contents of the file. The authors of this specification take no responsibility for the interception, or loss of sensitive data due to the use of the encryption provided. In addition to this warning, please also note that there are many laws in place, in various regions, which strictly prohibit certain levels of encryption (as an example, under U.S. law, you may only export files encrypted with ARCfour if they were encoded using keys of no more than 40 bits in length). It is your responsibility to ensure that you conform to your regions laws regarding encryption!

Copyright 2002 Daedalus Developments. All Rights Reserved. Page 9 of 92.

Interchangeable World Format v2.0

2.3.5. Chunk Summary Information

It is often advantageous to know in advance how many, of each type of object, are stored within your file prior to reading its contents. These include cases where for instance you wish to allocate memory for a certain number of light maps stored within your file, without having to reallocate storage space each time a new one is encountered. The summary information is stored in a standard chunk and is always found at, or near to, the end of the file. The information is stored in a table providing a chunk type-id, an author-id and a field specifying how many of these particular chunks are stored within the file. There is also a dedicated positional reference value stored within the file header itself, allowing you to seek straight to the beginning of this summary chunk, if required, prior to reading the remaining file contents.
3. IWF Structure Layout

This section of the specification details the actual layout of the various different components which go to make up the structure of the IWF itself. This includes items such as the file and chunk headers, and how they relate to one another. This section also covers exactly how each of these individual components is to be arranged, both when reading from and writing to the file. Note: Information on the structure of the separate standardised chunks can be found later in this document (see 4. Standardised Chunk Specifications).
3.1. File Header

The IWF File Header is the primary means by which to identify not only the format of the file itself, but also the file version number and various other pieces of related information which describe how the file is laid out. The header is always found at the beginning of the file and is mandatory. The Layout of the file header is as follows:
Table 1a. Layout File Header Type unsigned char (array) unsigned long unsigned long unsigned long unsigned long unsigned long

Name Signature Version Flags Checksum Reserved1 Reserved2

Size (In Bytes) 4 4 4 4 4 4

Copyright 2002 Daedalus Developments. All Rights Reserved. Page 10 of 92.

Interchangeable World Format v2.0

Table 1b. Variable Descriptions File Header Name Signature Description A four byte array that stores a set of pre-defined values used to identify the file as being that of a valid IWF file. A three component version number (Major, Minor, Revision) which has been built using the MAKEVERSION macro, outlined below. This value is used to identify which version of the IWF standard was used to create the file. Stores either 0, or a combination of one or more of the flags specified in Table 1c. Specifies various optional features in use within the file. Stores any valid 32 bit CRC checksum value, built using a polynomial of 0xEDB88320. This checksum is calculated using all of the data, within the file, which directly follows the header. This value is optional, store 0 if not in use. Four bytes of reserved space for future use. Four bytes of reserved space for future use. Valid Values 0x49, 0x49, 0x57, 0x46 { I, I, W, F } 0x2000000 to 0x200FFFF

Version

3.1.1. Version System IWF_COMPRESSED IWF_CHUNKSUMMARY IWF_CRYPT_ARCFOUR

Flags

Checksum

3.9. Calculating a Valid Checksum

Reserved1 Reserved2

N/A N/A

Table 1c. Flags Definitions File Header Name Value Description If this flag is specified, it signals to the import procedure that compression is currently in use within the IWF file. The file is compressed from the end of the file header onwards. For more information see 3.8. Supporting File Compression If this flag is specified, it signals to the import procedure that a summary chunk is available for import. For more information see 4.2. Summary Chunk The presence of this flag signals to the import procedure that the physical chunk data is encrypted using the ARCfour encryption scheme. If both this, and IWF_COMPRESSED are specified, the encryption will be applied first, prior to the file being compressed. For more information see 3.7. Supporting Chunk Encryption

IWF_COMPRESSED

0x1

IWF_FILESUMMARY

0x2

IWF_CRYPT_ARCFOUR

0x4

Copyright 2002 Daedalus Developments. All Rights Reserved. Page 11 of 92.

Interchangeable World Format v2.0

3.1.1. Version System

As mentioned above, the file header version variable is calculated using a macro labelled MAKEVERSION. This macro simply takes three components, namely major, minor and revision values, which are then used to build up a single 4 byte unsigned long value. For completeness, this macro is shown below.
#define MAKEVERSION( Major, Minor, Revision ) \ ((Major & 0xFF) << 24) + \ ((Minor & 0xFF) << 16) + \ (Revision & 0xFFFF)

When importing an IWF file, you can check to ensure that the version number is supported by your application, using this macro. To do this, you simply compare the value generated by this macro, with the value stored inside the file header itself, for example:
// Return if this is an unsupported version. if ( FileHeader.Version != MAKEVERSION( 2, 0, 0 ) ) return false;

Although comparing in this manner is supported, you must bear in mind that future versions of the specification may well increase this version number, and still provide full backwards compatibility. Typically, minor modifications made to the specification that do not require code revising, or additional support, will simply increase the revision value. In all other cases, the major or minor version number components will be increased. Therefore, it is best to test for version support using the following method:
// Return if this is an unsupported version. if ( FileHeader.Version < MAKEVERSION( 2, 0, 0 ) || FileHeader.Version > MAKEVERSION( 2, 0, 65535 ) ) return false;

This is made possible due to the fact that increasing any individual component passed to the macro will increase the overall value of the final version number in a linear fashion. The major and minor version components both have a maximum value of 255 or 0xFF(hex), whilst the revision component has a maximum value of 65535 or 0xFFFF(hex). All components have a minimum value of zero, that is to say no signed / negative values are permitted.
3.2. Chunk Header

The Chunk Header is the primary means by which the import procedure identifies the contents of the chunk data area. It contains several variables used to identify various properties, such as the length of the data area, the type of data following the header and so on. This same header is used for both standard and custom chunk types, and always precedes the physical chunk data although empty chunks are allowed. All aspects of the chunk header, unless otherwise noted, are mandatory.
Copyright 2002 Daedalus Developments. All Rights Reserved. Page 12 of 92.

Interchangeable World Format v2.0

The Layout of the chunk header is as follows:


Table 2a. Layout Chunk Header Type unsigned char (array) unsigned short unsigned long unsigned long unsigned char unsigned char (array)

Name Signature ChunkTypeID ChunkLength DataLength AuthorIDLength AuthorID

Size (In Bytes) 4 2 4 4 1 AuthorIDLength (var)

Table 2b. Variable Descriptions Chunk Header Name Signature Description A four byte array that stores a set of predefined values used to identify this structure as being that of a valid IWF chunk header. Used as a means of identification, this variable specifies the type of data stored within this chunk. This could be either a standard or a custom chunk type-id. This variable specifies the length, if any, of this particular chunk including any children. This variable is used to skip straight to the footer belonging to this chunk. This variable specifies the length, if any, of this chunks data area only, i.e. excluding any children. This variable is used to step straight to the next child-level chunk within the file. Specifies the length, if any, of the author-id which directly follows this variable. It allows the import procedure to pre-allocate any memory required, and to read in the correct amount of bytes from the file. Note: This field should have a value of zero when writing / reading standard chunks. A simple array of bytes or characters, defined by the developer, used to identify the author of any particular custom chunk. This field is optional. See the section regarding author-ids for more information. Note: This field should not be used when writing / reading standard chunks. Valid Values 0x48, 0x45, 0x41, 0x44 { H, E, A, D }

ChunkTypeID

3.5. Chunk Types

ChunkLength

3.2.1. Calculating and Using Chunk Sizes

DataLength

As Above

AuthorIDLength

3.2.2. Using Author-IDs

AuthorID

As Above

Copyright 2002 Daedalus Developments. All Rights Reserved. Page 13 of 92.

Interchangeable World Format v2.0

3.2.1. Calculating and Using Chunk Sizes

There are two sizes provided by the chunk header, the first of these being the ChunkLength variable. The value stored within this variable describes the total length of the chunk, following the header itself, up to the start of that particular chunks footer. Since all children, contained within that chunk, precede the chunk footer itself; this value includes the length of any children, and allows the import procedure to seek straight to the end of that particular chunk, and on to the next, at that same hierarchy level. The second length provided by the chunk header is the DataLength variable. Unlike ChunkLength, this variable describes only the length of that chunks physical data area. This means that seeking forwards by the amount specified within that variable will result in a file position which is placed directly at the start of either: the first childs header or, should no children exist, the footer of that particular chunk. This allows the import procedure to step into any particular chunk at will, and retrieve information from any other hierarchy level which may be available at that point. This variable also provides enormous scope for providing additional chunk data area components with future versions of the specification, without sacrificing compatibility. Should no children exist within the current chunk; both variables will contain identical values. This is due to the fact that the current chunks physical data area is all that is stored prior to the chunk footer. Both variables store a length specifying the total number of bytes to seek forwards, and are both relative to the end of the chunk header which contains them. These values are mandatory and can contain a value between 0 and any 32 bit integer number (i.e. up to 0xFFFFFFF(hex)). Note: It is important when reading an IWF file, to always seek to the next chunk header stored within the file, rather than simply continuing to read. By seeking in this way your application will be able to skip over any additional variables that may be added to the end of a chunks data area in later revisions of the specification. For information on the relationships between chunk headers, data areas and parent / child hierarchies, please refer to section 3.6. Putting it All Together.
3.2.2. Using Author-IDs

Summary: 2.3.3. Custom Chunk Collision Prevention. As mentioned in the section outlining the mechanism used for custom chunk collision prevention, the author-id is the primary means by which to prevent custom chunks, each of differing types and possibly defined by un-associated developers, from being misidentified should they happen to share the same chunk type-id. Even though this was its original design intention, it also has many uses outside of this

Copyright 2002 Daedalus Developments. All Rights Reserved. Page 14 of 92.

Interchangeable World Format v2.0

situation, and can be an invaluable tool even when the risk of third-party involvement is not necessarily a factor. In its most basic form, the author-id mechanism is simply an array of bytes / characters of any description, and a variable storing the length of this corresponding set. Put into context however, this array of characters serves as a way of identifying and filtering out any custom chunk not understood by the import procedure which may encounter it. As an example, one developer may define a custom chunk which stores raw light-mapping information, whereas another developer may use the same type-id as this chunk to store game-scripts. In cases where either partys application may be required to parse the others file, compatibility would be severely compromised. However, had these developers stored an author-id along with their custom chunks, both applications would have passed over this unrecognised data without issue, even though both custom chunks share the same type-id. It is even possible to store multiple differently-formatted custom chunks, which share the same type-id, within the same file as long as different author-id values are used for each format. This caters for a wide variety of possibilities such as differently formatted custom-chunks which technically store the same data, but may be intended for different versions of a single application. The author-id that is chosen by the developer, when writing the file, can be anything ranging from a series of random numeric values, to an ASCII string denoting a company, or developer name, but should be as unique as possible. Technically speaking, it is entirely feasible to assign a different author-id to each individual chunk; however it is usually only necessary to use a single author-id for all custom chunks, which in turn also reduces the complexity of comparing the identifier on import. If the developer chooses not to write an author-id, within the chunk header, the AuthorIDLength variable must be set to 0 signalling that the AuthorID variable need not be created or initialised due to the fact that no data is available or required. When the import procedure begins reading the IWF file, filtering out unrecognised custom chunks becomes as simple as comparing the author-id, stored within each chunks header, against the original. Any custom chunk containing an ID which does not match this original value can be passed over without further processing. Although the author-id is purely optional, it is recommended that this information be written, if only to provide interoperability with third-party files and applications. The author-id itself, if written, must be between 1 and 255 bytes in length, although an ID of no less than 4 bytes in length is recommended. Standard chunks do not utilise this information, and therefore should not write any additional information after the AuthorIDLength variable, which in itself must always store a value of 0, signifying that no AuthorID is in use. Whilst this array is not technically designed to store a string, any value may be assigned to each element, including ASCII character values. If a string ID is used, no terminating character need be stored. If a terminator is required, the AuthorIDLength variable must also include the length of this character.
Copyright 2002 Daedalus Developments. All Rights Reserved. Page 15 of 92.

Interchangeable World Format v2.0

3.3. Chunk Data Area

This portion of the IWF is technically the single most important aspect of the format structure; in the sense that this area is reserved for storing the physical file data, of which the various headers describe. The layout of the data area itself is variable, and largely depends on whether the chunk itself is a standard or custom chunk. When this data area is written within the confines of a standard chunk, it is vitally important that the formatting of the data area follows the design set out within this specification. The data stored within a custom chunk data area however is entirely developer defined, and therefore no restrictions are placed upon the layout. The chunk data area is used to store the various assets, used by the application for which it is intended, which may include objects such as meshes, entities, images, texture and lighting information or any custom data that may be required. Whilst this area is used as the sole means by which to store data within the IWF file itself, it is often advantageous to store an empty chunk, a chunk with a zerolength data area, within the hierarchy of the file. For this reason, the chunk data area is entirely optional and may be omitted, even when that chunk may contain many children with or without their own data areas. In this case, the DataLength variable, stored within the chunk header, would contain a value of 0. Should any such data be required, it must always be written directly following the chunk header.
3.4. Chunk Footer

The chunk footer, much like the chunk header, provides information about how the file should be processed, and is mandatory. In this particular case however, its primary function is to provide information about how the import procedure should proceed once the chunk data has been processed. It provides this information via an End of Chunk value, which specifies whether or not any additional chunks exist at the current chunk hierarchy level. If additional chunks do exist, then the application can continue on, reading the next header and its associated data. If there are no further chunks at that particular hierarchy level, then the application can step back out to the parent level and continue processing there. While this may seem technically obsolete given the presence of the various chunk sizes, provided by the chunk header, the footer itself does in fact fill other, extremely crucial, roles within the structure. The first of these is to provide information about the chunk hierarchy within the file. Many such hierarchical file formats, require the developer to know in advance whether any particular chunk type has children, and also when to step out of that level of the hierarchy. Since, within these formats, chunks are essentially sequentially positioned it can become somewhat difficult to analyse the hierarchy of the file. The chunk footer however, encloses the chunk (much like you would find with HTML tags) allowing the developer to determine easily if a particular chunk is a child or not. Should the import procedure encounter a new chunk header during the processing of another chunk, prior to that chunk being closed by the footer, we know that this newly encountered chunk is a child of the original.
Copyright 2002 Daedalus Developments. All Rights Reserved. Page 16 of 92.

Interchangeable World Format v2.0

The second benefit we gain from using chunk footers is that of being able to design intricate recursive import systems, where each level throughout the recursion is provided with all the information it needs at the point of reading, such as when to step out of the call, and which encountered chunks are children. Because it is made much easier to design completely self-contained chunk processing functions in this way, the developer need not worry about the logistics of transferring and storing chunk information whilst children, below the current chunk, are processed. It is in fact possible, in part due to the chunk footer, to simply use the function stack to store this information until all children have been processed, at which point that function will automatically regain control and can then go on to handle the data after having been provided with all the information stored within its children. The third and final major benefit we gain from the use of a chunk footer, is that of support for error detection and recovery. As mentioned in previous sections of this document, the footer contains a signature which allows the import procedure to test not only for file or chunk corruption, but also for determining whether the chunk was read correctly. If this signature does not exist, or does not contain the correct value when read, the import procedure then knows that something has gone wrong, and can act appropriately. Note: For more information on using the methods outlined above, please see section 3.6. Putting it All Together. The layout of the chunk footer is as follows:
Table 3a. Layout Chunk Footer Type unsigned char (array) unsigned short

Name Signature EOCValue

Size (In Bytes) 4 2

Table 3b. Variable Descriptions Chunk Footer Name Signature Description A four byte array that stores a set of predefined values used to identify this structure as being that of a valid IWF chunk footer. The End Of Chunk Value is used to inform the import procedure about how it should proceed, once the chunk data has been processed. May only store one of the values specified within Table 3c. Valid Values 0x46, 0x4F, 0x4F, 0x54 { F, O, O, T }

EOCValue

CHUNK_EOC CHUNK_EOC_EXIT

Copyright 2002 Daedalus Developments. All Rights Reserved. Page 17 of 92.

Interchangeable World Format v2.0

Table 3c. EOCValue Definitions Chunk Footer Name Value Description If this flag is specified, it signals to the import procedure that more chunks exist at this level in the chunk hierarchy. For more information see 3.6. Putting it All Together If this flag is specified, it signals to the import procedure that there are no further chunks contained within this level of the chunk hierarchy, and can therefore step back out to the parent level. For more information see 3.6. Putting it All Together

CHUNK_EOC

0xF000

CHUNK_EOC_EXIT

0xF001

3.5. Chunk Types

As mentioned there are two types of chunks, standard and custom, which are identified by a ChunkTypeID value stored within each chunk header. This variable has a minimum value of 0 and a maximum of 65535 or 0xFFFF(hex). The method used to identify whether a chunk is of a standard or custom type is simple. A standard chunk always has a type-id value of between 0 and 511 or 0x01FF(hex) inclusive, whereas a custom type-id must have a type-id value of between 512 or 0x0200(hex), and that maximum value inclusive. Because those initial 512 (0 through 511) values are reserved for standard chunks, it is extremely important that no custom chunk uses these values. Should any custom chunk contain a type-id value of less than 512, it may well be mistaken for a standard chunk, and would most likely result in the complete failure of the import process at that point. Although the type-id itself is extremely important, it serves no higher purpose other than allowing the import procedure to identify the type of information stored within the chunk data area. It is important to understand that type-id values are not unique identifiers (i.e. one for each chunk within the structure), but are in fact only unique to a specific type of data which may occur at many points throughout the file. With the exception of standard chunks, the developer may choose any type-id they wish for a specific chunk type, as long as the value chosen does not encroach on those reserved for use with standard chunk types. As an example of this, a developer may define their own custom texture chunk as having a value of 0x20FF(hex), and then go on to write thirty of these texture chunks to the file. This would in turn mean that; during the import of this file, thirty separate chunk headers, all with type-ids containing exactly this same value (0x20FF(hex)), would be encountered.

Copyright 2002 Daedalus Developments. All Rights Reserved. Page 18 of 92.

Interchangeable World Format v2.0

3.6. Putting it All Together

This section focuses on the structure of an interchangeable world formatted file as a whole. Whilst the main focus will be on writing the structure, the information contained here is equally useful to those wishing to develop an import procedure. In its most basic form, the IWF file itself is simply a collection of chunk headers and footers, which may contain any arbitrary data, and can be arranged in such a way that it provides information on the hierarchical layout of any content within that file. While this is of course a simplified example, it is in essence all we need to get started. So with this on board we can move on to discussing exactly how we arrange these separate components when we are writing our IWF formatted file. First, take a look at the following diagram:

File Header Chunk Header Chunk Data Chunk Footer Chunk Header Chunk Data (A) (A) (A) (B) (B) Chunk Header Chunk Data Chunk Footer Chunk Footer (B) (C) (C) (C)

Figure 2. File Structure Layout.

Looking at the above diagram you can hopefully see more clearly what is meant by hierarchical arrangement when discussed in the context of the individual components, which go to make up chunks stored within the file. Lets now go into more detail about exactly what the above diagram represents. As always, similar to almost every other file format, the IWF structure begins with the file header. This contains various pieces of information about the file, such as an identifying signature, and various other fields. However, we can largely disregard this area of the file for the purposes of this explanation (see 3.1. File Header for more information about writing / reading the file header). Directly following the file header we then write the chunk header belonging to the first chunk
Copyright 2002 Daedalus Developments. All Rights Reserved. Page 19 of 92.

Interchangeable World Format v2.0

we would like to store within the file. We have labelled this portion of our example file structure Chunk Header (A). You should be able to see that chunk A, coloured orange in the above diagram, has no children or rather no child chunks. It is simply made up of the chunk header, the actual chunk data, and finally the chunk footer. Lets just assume for a moment that chunk A is a custom chunk, whose data area contains 100 bytes of raw image data. Given the fact that this chunk has no children, the chunk header would contain values similar to those described in the following table.
Table 4a. Example Chunk Header Chunk A Name Type Signature 0x48, 0x45, 0x41, 0x44 {H, E, A, D } ChunkTypeID 0x20FF CHUNK_CTM_IMAGERAW ChunkLength DataLength AuthorIDLength AuthorID 100 100 4 0x4D, 0x59, 0x49, 0x44 {M, Y, I, D} (Example) (Example) (Example) (Example) (Example)

Of course, many of the above values are application specific, however the two values of interest here are those contained within both the ChunkLength and DataLength variables. As described in section 3.2.1. Calculating and Using Chunk Sizes, the ChunkLength variable must specify the total length of the chunk up to, but not including, the corresponding chunk footer, whereas the DataLength variable must specify the length of the chunk data area only. Due to the fact that chunk A has no children; the data chunk will directly precede the chunk footer and therefore both of these length variables will contain the same value. At this point, having written out the chunk header, we would then proceed onto writing out the actual chunk data in whatever form we require. In our example case, we will write out our 100 bytes of raw image data. Because there are no children to be written for this particular chunk, we would then finish by writing our chunk footer which, in a sense, closes the chunk. The footer, as previously mentioned, informs the applications import procedure about one of two things at this point. The first is whether there are more chunks to follow at this hierarchy level and that it should continue to process, or secondly, that no more chunks exist at this hierarchy level and it can step out to the parent, or in fact finish reading the file if that chunk was at the top of the hierarchy. In our example file structure there are of course more chunks to follow at this root level, so lets take a look at an example of what values this chunks footer would contain.

Copyright 2002 Daedalus Developments. All Rights Reserved. Page 20 of 92.

Interchangeable World Format v2.0

Table 4b. Example Chunk Footer Chunk A Name Type Signature 0x46, 0x4F, 0x4F, 0x54 { F, O, O, T } EOCValue 0xF000 CHUNK_EOC

As you can see, the footer contains the code CHUNK_EOC, which is designed to inform the import procedure that more chunks follow. At this point, we now move onto writing chunk B, shown in green in Figure 2 above. Chunk B is slightly different when compared to chunk A in that it contains a child chunk, shown in blue. We know that this is a child due to the fact that it is written prior to the footer, belonging to chunk B. Although this chunk contains a child, the same rules apply when writing our chunk header, so lets once again assume that chunk B is a custom chunk, but this time its data area contains 350 bytes of custom mesh data. Lets also assume for a moment that chunk C, the child of this chunk, contains a data area of 223 bytes in length. So following those same rules regarding the length variables stored in our header, lets take a look at the values which will be written for the header belonging to chunk B.
Table 4c. Example Chunk Header Chunk B Name Type Signature 0x48, 0x45, 0x41, 0x44 {H, E, A, D } ChunkTypeID 0x2100 CHUNK_CTM_MESH ChunkLength DataLength AuthorIDLength AuthorID 598 350 4 0x4D, 0x59, 0x49, 0x44 {M, Y, I, D} (Example) (Example) (Example) (Example) (Example)

You can see in Table 4c that the two length variables now contain different values from one another. The DataLength variable obviously stores the length of the data area only, but the ChunkLength variable contains the position in bytes, relative to the end of this chunks header, at which the current chunks footer will be written. It may not be immediately clear how we arrived at the number 598, so lets take a look at exactly how we came up this seemingly arbitrary value.

Copyright 2002 Daedalus Developments. All Rights Reserved. Page 21 of 92.

Interchangeable World Format v2.0

Chunk Chunk Chunk Chunk

B C C C

Data Area Header Data Area Footer Total Size

350 19 223 6 598

+ + +

Hopefully you can see now why we arrive at this value, and why each of the individual components is the size outlined above (dont forget to include the length of the various signatures in your calculations). This value will now allow the import procedure to skip over this entire chunk including any and all children it may contain. This is extremely useful in cases where, for instance, the import procedure does not include support for this chunk type and does not wish to interpret its children in this situation, whereas; the DataLength variable allows us to step into this chunk, down to the first child, regardless of whether the import procedure can interpret this chunks data (and therefore its length), or not. Next in the process is chunk Bs data area, which as mentioned is 350 bytes in length. Looking at our description of the process used for writing chunk A, we would then, after writing the data area, write the chunk footer, but due to the fact that chunk B has children, this step is deferred until those children have been written. At this point we actually begin to write chunk C, the child chunk, to the IWF file. This chunk is very much like chunk A in that it contains no children and would be handled in much the same way, however for completeness the tables containing the various chunk components are shown below:
Table 4d. Example Chunk Header Chunk C Name Type Signature 0x48, 0x45, 0x41, 0x44 {H, E, A, D } ChunkTypeID 0x2101 CHUNK_CTM_POLYGONS ChunkLength DataLength AuthorIDLength AuthorID 223 223 4 0x4D, 0x59, 0x49, 0x44 {M, Y, I, D} (Example) (Example) (Example) (Example) (Example)

Table 4e. Example Chunk Data Area Chunk C Name Length {Custom Data} 223 Bytes

Copyright 2002 Daedalus Developments. All Rights Reserved. Page 22 of 92.

Interchangeable World Format v2.0

Table 4f. Example Chunk Footer Chunk C Name Type Signature 0x46, 0x4F, 0x4F, 0x54 { F, O, O, T } EOCValue 0xF001 CHUNK_EOC_EXIT

It should be clear by now exactly what each of these components role is and why they contain the specified values, however; one thing that you may have noticed with regards this chunks footer, is that it contains the code CHUNK_EOC_EXIT, unlike chunk As footer which contains the code CHUNK_EOC. Referring back to Table 3c EOCValue Definitions, you will see that this code informs the import procedure that no further chunks exist at this hierarchy level. This code allows the import procedure to step back out of this chunk, and carry on processing its parent, which in this case is chunk B. After writing all of chunk Bs children, we can now close off this chunk by writing the corresponding chunk footer. Somewhat like chunk C, chunk B is the last chunk at this hierarchy level, so will contain the code CHUNK_EOC_EXIT but in this case, because this chunk is at the root level, the import procedure is informed that it has finished reading the file in its entirety. For completeness, the table below shows chunk Bs footer:
Table 4g. Example Chunk Footer Chunk B Name Type Signature 0x46, 0x4F, 0x4F, 0x54 { F, O, O, T } EOCValue 0xF001 CHUNK_EOC_EXIT

The IWF structure does of course support far more individual hierarchy levels than the two shown in this simple example, however; implementing such a structure is no more complex than the relationship between chunk B and chunk C in the scenario we have given. Although we have only demonstrated the hierarchy of custom chunks, exactly the same concepts are utilised for standard chunk types. This means that it is entirely possible to mix custom and standard chunks where, for example, you may specify that a custom chunk containing additional, application specific, information is the child of a standard mesh chunk. Note: It is vitally important to understand that any and all children belonging to a specific chunk must strictly be written after the chunk data area itself. No child must be written inside the data area, i.e. in-between two separate variables. One thing that is taken for granted in the above examples, that doesnt necessarily follow within a real world situation, is that we know in advance what
Copyright 2002 Daedalus Developments. All Rights Reserved. Page 23 of 92.

Interchangeable World Format v2.0

values certain variables will contain, such as the chunk and data length variables or even the EOCValue code, when they are quite clearly describing chunks or objects which we have not yet written or processed. In some real world cases, we may not know what value each of these variables should contain until such time as we have physically written those objects, and in other, more frequent, cases it is simply more convenient to calculate these values as we actually write or process those objects or chunks. These types of variables are what we call Forward References. Tips on how best to deal with these situations, are covered in the following section.
3.6.1. Providing Forward References

There are cases, as outlined in the previous section, where the IWF chunk structure requires information which may not presently be available. We call these values Forward References and there are five such references, within the various IWF chunk components, which contain vital information required by any import procedure. The first of these is the Flags variable, stored within the file header (see section 3.1. File Header). This variable contains various pieces of information about how the file itself is formatted, and also whether it contains certain standard chunks types. This variable is considered to be a forward reference because it may not be known, at the point of writing the file header itself, whether these specified chunks will be written or not. The second forward reference is the Checksum value, contained within the file header, and provides error detection information to the application. The checksum requires the entire contents of the file to be written before being calculated. The third and fourth forward references within the structure are the ChunkLength and DataLength variables, stored within the chunk header (see section 3.2. Chunk Header). The former specifies the length of the chunk as a whole, including all its children, whilst the latter specifies only the length of the chunk data area. The fourth and final forward reference is the code specified by the EOCValue variable, stored within the chunk footer (see section 3.4. Chunk Footer). This variable specifies whether or not there are any further chunks at the current hierarchy level. As you can see, all of these variables describe in some way how various portions of the file are to be interpreted by the import procedure, and each precedes the information for which it is describing. This can present a problem during the export of the file. If we were required to determine the contents of all of these variables in advance, it would no doubt involve a complex series of iterations through various data structures, calculating sizes and working out in advance the hierarchy, which could, in some cases, greatly increase the amount of code required to write even a simple file. Due to the fact that these variables describe information not yet written, it is logical that we would want to write these values after that information has been written to file. The listings below describe solutions for the logistical issues involved in the calculation and export of the values contained within each of these four forward references. Note: The tips outlined below are not part of the specification itself. It is not required that your implementation follow these guidelines in order for the
Copyright 2002 Daedalus Developments. All Rights Reserved. Page 24 of 92.

Interchangeable World Format v2.0

application to be considered compliant. Therefore you may use any technique which works best in your given situation, as long as the output provides an accurate description of the contents stored within the interchangeable world formatted file. These guidelines are discussed merely to help provide you with solutions to certain problems which you may or may not encounter during the implementation of your IWF export procedure. Example code, and demonstrations of the techniques outlined below are included in the IWF File Toolkit (see section 5.0. IWF File Toolkit Version 2.0).
3.6.1.1. File Header - Flags

When initially writing this variable to file, it should only contain those flags for which you know will be made available at the time of writing the header. These are normally formatting values such as the IWF_COMPRESSED flag or the encryption flag, IWF_CRYPT_ARCFOUR. It may not be known however, at the point of writing the file header, whether or not a summary chunk will be written. Therefore, it is logical that we would want to alter these set of flags should we begin to write a summary chunk to file. To do this; we must store the current file position into a 4 byte application variable (which we will refer to as FilePos) just prior to writing the summary chunk header. Once we have stored the current file position, we can then seek back to the Flags variable, which will always be positioned 8 bytes from the beginning of the file. Once we are positioned at the start of the Flags variable, we can then re-write our initial flags, combined with the IWF_CHUNKSUMMARY flag, overwriting the previously stored data. Finally we must perform an absolute seek, back to the position stored within our FilePos application variable, and continue writing the summary chunk itself.
3.6.1.2. File Header - Checksum

For more information on when and how the checksum should be calculated, please refer to section 3.9. Calculating a Valid Checksum.
3.6.1.3. Chunk Header - ChunkLength

When initially writing this variable to file, it should either be skipped (seek forward relatively by 4 bytes) or should contain a value of zero. Just prior to writing the header that contains this variable however, we must make sure that we store the current file position into a 4 byte application variable, which we will refer to as HeaderPos. After writing the header itself, we can now continue on writing the chunk data area and all children belonging to this chunk, as we would under normal circumstances. Once we reach the point where we are about to write the footer belonging to the current chunk, we once again store the current file position into a separate 4 byte application variable, which we will refer to as FilePos. We can now, as with our summary position, seek back to the ChunkLength variable and write this final value. This variable will always be positioned 6 bytes forward, starting from the position we stored within our HeaderPos variable. The actual value we store here is calculated simply by subtracting the value stored in our HeaderPos variable from
Copyright 2002 Daedalus Developments. All Rights Reserved. Page 25 of 92.

Interchangeable World Format v2.0

that stored in our FilePos variable. Once we have written our chunk length we can then seek back to the position stored within FilePos and continue writing the chunk footer from that point.
3.6.1.4. Chunk Header - DataLength

The process of calculating and storing the DataLength variable is very similar to the process used for writing the chunk length. The only real difference here is that whereas previously the application variable FilePos stored the position just prior to the chunk footer, in this case FilePos will store the position directly following the chunk data, not including any children. Of course, if no children exist within the current chunk, these values will be identical due to the fact that the chunk data will directly precede the chunk footer, which is as we would expect given our earlier examples.
3.6.1.5. Chunk Footer - EOCValue

As mentioned throughout this specification, the End of Chunk value, contained within all chunk footers, provides information to the import procedure about how it should proceed after reading that particular chunk. Because it is not always clear, at the point of writing the chunk footer, whether more chunks exist at that level in the hierarchy, this variable should always be written to file containing an initial value of CHUNK_EOC_EXIT. There are two steps which must be taken before writing the footer itself however, the first of these is to step back to any previous footer written at that hierarchy level, and adjust its exit code from CHUNK_EOC_EXIT, to simply CHUNK_EOC. To do this, we require a 4 byte application variable which we will refer to as FooterPos. This variable will contain the position, within the file, of any footers previously written at that hierarchy level only, the reason for which will be made clear shortly. Obviously, whenever we are writing the first footer at any particular level, there are no previous footers to be altered, so defaulting the FooterPos variable to a value which represents this fact (such as 0 or -1) is a good idea. The second of these two steps is to update the FooterPos variable itself with the current file position, just prior to writing the actual footer. So lets assume we are just about to write the second chunk footer to file, at that hierarchy level. Our FooterPos variable will currently contain the position of the previous (first) footer written to file. At this point we should store the current file position into a temporary application variable, which we will refer to as TempPos, and then seek back to the EOCValue variable written for that previous footer. This variable will always be positioned 4 bytes forward starting from the position stored within our FooterPos application variable. We can then overwrite that portion of the file with the altered CHUNK_EOC code. At this point we would seek forward once again to the position stored within our TempPos variable and, finally, update FooterPos with the current file position (assigning FooterPos to the value stored inside our TempPos variable will suffice). This allows us at a later stage to step back and alter this second chunk footer, should we actually continue on to write a third. Once we have updated our FooterPos variable, we can then continue on writing the current chunk footer which will, as before, contain the code CHUNK_EOC_EXIT.

Copyright 2002 Daedalus Developments. All Rights Reserved. Page 26 of 92.

Interchangeable World Format v2.0

If you followed this process through, you will hopefully see that we will be left with all of our individual chunk footers containing the value CHUNK_EOC, informing the import procedure that more chunks follow, with the exception of the last chunk at any particular hierarchy level. This final chunk footer will contain the value CHUNK_EOC_EXIT and will inform the import procedure that it can now step out of that level, and back up to the parent. The reason why it is important that you store multiple FooterPos variables, one for each individual active hierarchy level, is due to the fact that a value of CHUNK_EOC_EXIT should occur exactly once for each run of chunks at any hierarchy level within the file. If we were to have only one FooterPos variable for the entire file, we would in fact be stepping back and altering every single footer written, until we were left with only the last chunk in our file storing the CHUNK_EOC_EXIT code. All other chunks, at any and all levels within the file, would simply contain the value CHUNK_EOC. Although the generic procedures used to handle all of these forward references seem relatively complex, the practical implementations of these techniques are in fact fairly simple. For more information, including example source code, please refer to section 5.0. IWF File Toolkit Version 2.0.
3.7. Supporting Chunk Encryption

Summary: 2.3.4. Chunk Encryption. As mentioned in the section outlining the mechanism used for chunk encryption, the method used to encrypt the data stored within each individual chunk data area is an RC4 derivative known as ARCFour. This technique is a very simple, efficient and yet extremely secure system which is similar to that utilised by various internet browser technologies such as the Secure Sockets Layer, more commonly referred to by its acronym SSL.
Not yet supported within revision 0. 3.8. Supporting File Compression

Summary: 2.3.1. Compression.


Not yet supported within revision 0. 3.9. Calculating a Valid Checksum

Summary: 2.3.2. Error Detection.


Not yet supported within revision 0.

Copyright 2002 Daedalus Developments. All Rights Reserved. Page 27 of 92.

Interchangeable World Format v2.0

4. Standardised Chunk Specifications

The following sections of the file discuss the many different types of standard chunks, provided by the current interchangeable world format specification. The standardised chunk specification includes many useful structures such as, meshes, surfaces, textures, materials, shaders, images and much more, all of which are commonly used by interactive multimedia applications today. As mentioned earlier in this document, the primary goal of this particular section of the specification, is to provide a standardised means by which to store data in such a way that it is made easy to both read and write all, or simply portions, of the file, whilst providing as much functionality as possible, for use within a wide range of situations and applications. One of the other main benefits that is gained by utilising a standardised form of storage is of course the possibility for interapplication support, between non-associated developers. It should be made clear at this point that while making use of the standard chunk definitions set out in the following sections is recommended, it is not mandatory. It is entirely possible to use the IWF structure outlined in the previous sections, to store any arbitrary custom data chunks.
For more information on how to put all of the standardised chunks together, and how the hierarchy should be arranged, please refer to section 4.15. Standard Chunk Arrangements. 4.1. Common Types, Structures and Processes

The following sections detail both the structures and processes commonly used within the chunk data area of several current and possibly future chunk types. More specific details about the use of each individual item can be found in the various sections which describe the chunk data area in which they are used.
4.1.1. Vectors

Vectors are commonly used to describe both positional and directional values based upon the coordinate system to which they are applied. As an example, two dimensional vectors (VECTOR2) are commonly used to describe positions or directions within a two dimensional coordinate system such as Screen Space, where the vector origin is located at the top-left hand corner of the screen. The following structure outlines the two dimensional vector:
Table 5. Structure Layout VECTOR2 Type Size (Bytes) Description float float 4 4 The X axis component of the two dimensional vector. The Y axis component of the two dimensional vector.

Name x y

Copyright 2002 Daedalus Developments. All Rights Reserved. Page 28 of 92.

Interchangeable World Format v2.0

Three dimensional vectors (VECTOR3) are used more commonly throughout the IWF specification in general. They are primarily used to describe positions and directions within the world set out in the file as a whole. All positions and directions specified by these three dimensional vectors must always be based on the left handed Cartesian coordinate system (as used in Direct3D by default) unless noted otherwise. For more information on coordinate systems and how they are used within the IWF specification, please refer to section 4.14. Coordinate System Information. The following structure outlines the three dimensional vector:
Table 6. Structure Layout VECTOR3 Type Size (Bytes) Description float float float 4 4 4 The X axis component of the three dimensional vector. The Y axis component of the three dimensional vector. The Z axis component of the three dimensional vector.

Name x y z

4.1.2. Matrices

Matrices can be used for many things, ranging from transformations (translation, rotation and scaling among others) to N-dimensional projections. The matrices used within the IWF is a two-dimensional array containing 64 elements utilising a standard 4x4 arrangement, as with most popular APIs. As with vectors, IWF matrices must always be based on the left handed Cartesian coordinate system (as used in Direct3D by default) unless noted otherwise. It is also of great importance to note that each matrix is Row Major and is designed to be compatible with the ordering system used by the popular Microsoft Direct3D API. Bearing in mind that the numbering system used for referencing elements in an array is zero based, Row Major means that when we are referring to an individual row or column within the matrix, for example third column across, second row down, we are in fact referencing the array element [1][2] (i.e. [Row][Column]). While all matrices used by the standard chunk types within the IWF greatly resemble that used by Direct3D, converting matrices to and from any coordinate system utilised by your application is usually a trivial process. For more information on coordinate systems and how they are used within the IWF specification, please refer to section 4.14. Coordinate System Information.

Copyright 2002 Daedalus Developments. All Rights Reserved. Page 29 of 92.

Interchangeable World Format v2.0

The following structure outlines the two-dimensional 4x4 matrix:


Table 7. Structure Layout MATRIX4 Type Size (Bytes) Description float [4][4] (array) 64 The entire matrix is described as a two-dimensional array specifying a 4x4 block of floats.

Name val

4.1.3. Bounding Boxes

Figure 3.

There are various types of bounding volumes which serve to provide a rough depiction of an objects position, size, orientation and often its shape. The most commonly used bounding volume is the bounding box, or more specifically the axis-aligned bounding box. This type of bounding volume is described as being axis-aligned due to the fact that each of the 6 planes of the Box that it is describing, are exactly aligned to one of the world axes. Because we know that this Box will always be axis-aligned, we can in fact describe it in as little as two separate three-dimensional vectors, one specifying its minimum extents and the other specifying the maximum, as depicted in the above diagram. The following structure outlines the three-dimensional axis-aligned bounding box:
Table 8. Structure Layout AA_BBOX Type Size (Bytes) Description VECTOR3 VECTOR3 12 12 The minimum, local space, extents of the axis aligned bounding box. The maximum, local space, extents of the axis aligned bounding box.

Name Min Max

4.1.4. Palettes, Colours and Blend Modes

Most images which use an 8 bit image format use a palette as a lookup table to specify the resulting colour of any pixel when displaying that image. A palette usually consists of up to 256 entries, each of which contain the individual primary colour components, red, green and blue, which are eventually combined to produce the final colour value.

Copyright 2002 Daedalus Developments. All Rights Reserved. Page 30 of 92.

Interchangeable World Format v2.0

The following structure outlines an individual palette entry:


Table 9. Structure Layout PAL_ENTRY Type Size (Bytes) Description unsigned char unsigned char unsigned char 1 1 1 The red colour component for the final pixel value. The green colour component for the final pixel value. The blue colour component for the final pixel value.

Name Red Green Blue

There are also many cases, where a colour value is represented by a single 32 bit unsigned long value. This format can be found in such cases as the Diffuse and Specular vertex colouring components (See 4.7. Vertex Components), where each colour component is specified within each byte (8 bits) contained within that value, and is usually formatted in the order Alpha, Red, Green, Blue. Lets take a look at an example of how we would build and / or extract the individual colour values from this type of variable. In the following example, we have highlighted each individual colour component using the same colour as their matching positions within the SrcColour value.
unsigned long SrcColour = 0xFF326C94; unsigned long DestColour = 0; // Lets extract each individual colour component unsigned char Alpha = (SrcColour & 0xFF000000) >> 24; unsigned char Red = (SrcColour & 0x00FF0000) >> 16; unsigned char Green = (SrcColour & 0x0000FF00) >> 8; unsigned char Blue = (SrcColour & 0x000000FF);

// // // //

0xFF 0x32 0x6C 0x94

// Lets now take each of these values and rebuild it DestColour = (Alpha << 24) | (Red << 16) | (Green << 8) | (Blue);

As you can see, the colour component is extracted simply by masking off the byte in which that component is contained, and then shifting that value to the right by the required number of bits to bring it into the range of 0 - 255. To demonstrate the reasons behind why we are masking and shifting in this manner, lets follow up with an example of what is happening, at the bit level, when we are extracting the Red colour component. Remember that there are 8 individual bits to each byte.
We begin with the bit level definition of our SrcColor variable.

SrcColour

(Bit 32)...................(Bit1) = 11111111001100100110110010010100 // 0xFF326C94

At this point in our example, we want to extract the red colour component. To do this we used the code Red = (SrcColour & 0x00FF0000) >> 16. Lets break this down and see exactly whats happening. First of all we mask the component out by &ing the value with a bit mask of 0x00FF0000, so lets do this here. Copyright 2002 Daedalus Developments. All Rights Reserved. Page 31 of 92.

Interchangeable World Format v2.0

BitMask = 00000000111111110000000000000000 // 0x00FF0000 (And) SrcColour = 11111111001100100110110010010100 // 0xFF326C94 (Equals) TempColour = 00000000001100100000000000000000 // 0x00320000

You can see that all we are left with after these two values have been combined, is the definition of our red colour component. All of the values contained within the alpha, green and blue components have been stripped and set to 0. The value now stored in the variable TempColour has a hex value of 0x00320000. We can already see that this variable contains the value we are required to extract, the number 32(hex), however we have a problem: there are still 16 empty bits to the right of our red component value. This complete hex value of course corresponds to the decimal value of 3,276,800 which is clearly far outside of the range in which we require it to be (0 - 255). So what we need to do next is move the red component so that it lines up with the bit locations 1 through 8 (the bits which describe values between 0 and 255). In our above example we do this by shifting our resulting colour value to the right by 16 places using the code >> 16 , lets see what happens when we do this.

TempColour = 00000000001100100000000000000000 // 0x00320000 ( >> 16 Equals ) Result = 00000000000000000000000000110010 // 0x00000032

As you can see, the green and blue components are stripped and essentially drop off the end. What we are now left with is a value of 0x00000032(hex) or 50 in decimal. This means that our red colour component specifies a value of 50. The same operation is applied to the other three colour components. The only differences between the processes used to extract the colour components is that they each utilise unique bit masks and bit shifting values required in order to extract that components information. Try out the remaining three for yourself and see what you come up with.

As well as palette entries storing colour values, there are also certain objects, such as materials and light entities, which often reference colours using floating point values. These values are usually found to be within the range of 0.0 to 1.0, however the use of floats not only allows a finer level of granularity for each colour component value, it also allow for Over Brightening or Burning colours (by specifying a value greater than 1.0) and, in the case of lights for instance, can even contain negative values which will result in light actually being removed from the scene. The latter method in particular is a great way to create cheap shadowed areas when using vertex lighting.
Copyright 2002 Daedalus Developments. All Rights Reserved. Page 32 of 92.

Interchangeable World Format v2.0

The following structure outlines a floating point colour value:


Table 10. Structure Layout COLOUR_VALUE Type Size (Bytes) Description float float float float 4 4 4 4 The red colour component for the light source, or material property. The green colour component for the light source, or material property. The blue colour component for the light source, or material property. The alpha component used by the light source, or material property.

Name Red Green Blue Alpha

As you can see, the above structure contains an Alpha value. This value is commonly used by most rendering applications to specify an object or surfaces level of opacity, i.e. the lower the alpha value, the more translucent those surfaces become. This technique is known as Alpha Blending. At its core, alpha blending is simply a rendering technique which takes two colours, one from the source image, and another from the destination image, and blends the two together (based on a weighting / alpha value) to produce the final output colour. There are many ways in which to perform alpha blending using many different formulae which can be applied to produce differing results. For this reason, most rendering APIs allow the developer to specify various flags to exact control over which blending techniques the API should use. These Blend Mode flags are often specified in the form of two separate Source and Destination modes which describe, among other things, how each colour component should be interpreted for use within the blending formulae. The IWF specification exposes the ability to store these blend modes, per surface, and is stored within the following BLEND_MODE structure. (For more information on how these blending modes are stored within the file, please refer to section 4.6. Polygon Data) The following structure outlines the storage of the two blending modes:
Table 11a. Structure Layout BLEND_MODE Type Size (Bytes) Description unsigned char 1 The source blending mode. Contains one of the values described in Table 11b. The destination blending mode. Contains one of the values described in Table 11b.

Name SrcBlendMode

DestBlendMode

unsigned char

Copyright 2002 Daedalus Developments. All Rights Reserved. Page 33 of 92.

Interchangeable World Format v2.0

The following table outlines the flags used within each of the above variables:
(The descriptions provided below are quoted directly from the Microsoft DirectX 8.1 SDK.) Table 11b. SrcBlendMode & DestBlendMode Definitions BLEND_MODE Name BLEND_NONE BLEND_ZERO BLEND_ONE BLEND_SRCCOLOR BLEND_INVSRCCOLOR BLEND_SRCALPHA BLEND_INVSRCALPHA BLEND_DESTALPHA BLEND_INVDESTALPHA BLEND_DESTCOLOR BLEND_INVDESTCOLOR Value 0x0 0x1 0x2 0x3 0x4 0x5 0x6 0x7 0x8 0x9 0xA Description No blending is to be applied. Blend factor is (0, 0, 0, 0). Blend factor is (1, 1, 1, 1). Blend factor is (Rs, Gs, Bs, As). Blend factor is (1Rs, 1Gs, 1Bs, 1As). Blend factor is (As, As, As, As). Blend factor is (1As, 1As, 1As, 1As). Blend factor is (Ad, Ad, Ad, Ad). Blend factor is (1Ad, 1Ad, 1Ad, 1Ad). Blend factor is (Rd, Gd, Bd, Ad). Blend factor is (1Rd, 1Gd, 1Bd, 1Ad).

4.1.5. Scripts, Shaders and Effect Files

With the recent surge in the use of, and API support for, pixel and vertex shaders; file based support for this information has become increasingly important. The IWF structure supports both external and internal script resources which can be referenced using the SCRIPT_REF structure. This structure is used in several places throughout the various standard chunk types that are available, in particular CHUNK_SURFACES and CHUNK_SHADERS. (Please note that the term script is used loosely, and refers to any piece of executable code such as that provided by shaders or Microsoft Direct3D Effect files as well as application specific scripting files). Although the SCRIPT_REF structure allows the application to reference script files, it is the responsibility of the application to determine the type of script being referenced whether that script is a vertex or pixel shader or an application specific script.

Copyright 2002 Daedalus Developments. All Rights Reserved. Page 34 of 92.

Interchangeable World Format v2.0

The following structure outlines an individual script reference entry:


Table 12a. Structure Layout SCRIPT_REF Type Size (Bytes) Description A combination of one or more of the flags set out in Table 12b. Specifies how the following variables should be interpreted and where the script should be loaded from. The length of the ScriptData area in bytes (not characters). Contains string data which specifies either an external filename or the array contains the physical script code (compiled or otherwise). No string terminator is required, however if one is included, the ScriptSize variable must also reflect this additional character.

Name

ScriptSource

unsigned char

ScriptSize

unsigned short

ScriptData

char (array)

ScriptSize(var)

Name

Table 12b. ScriptSource Definitions SCRIPT_REF Value Description 0x1 The ScriptData array contains an external resource or file name used to reference the script, shader or effect file. This flag can be combined with the SCRIPT_COMPILED flag, but must not be combined with SCRIPT_INTERNAL. The ScriptData array contains the physical script, shader or effect code itself. This flag can be combined with the SCRIPT_COMPILED flag, but must not be combined with SCRIPT_EXTERNAL. This flag allows you to specify whether the external or internal script, shader or effect code is in its compiled form. If this bit is set, the code referenced is compiled, otherwise it is simply raw source.

SCRIPT_EXTERNAL

SCRIPT_INTERNAL

0x2

SCRIPT_COMPILED

0x4

4.1.6. Object Component Architecture

Several chunk types, such as CHUNK_MESH and CHUNK_SURFACES, adopt the object component architecture. Despite its fancy name, it is an extremely simple system which provides the ability to save large amounts of space within the file by not writing components, inside the chunk data area, that are not required instead of simply writing empty values which can take up a significant amount of space. In its most basic form, the component system is made up of a single 4 byte variable, contained within the layout of the chunk data area itself. This variable is always referred to with the label Components, and contains various flags specifying whether or not up to 32 individual components are available. Using CHUNK_SURFACES as an example, when reading the surfaces contained within the data area, the first thing we must do is read in any mandatory variables. In this case there is only the Components variable. At this point we can test each bit to determine which

Copyright 2002 Daedalus Developments. All Rights Reserved. Page 35 of 92.

Interchangeable World Format v2.0

components are stored within the file. As an example, we can test to see if the surface normal is contained within the data area using the following code:
if ( Components & SCOMPONENT_NORMAL ) ReadNormal();

As you can see, if the surface normal bit is set, within the components variable, then we know that the normal is contained within the file and can continue to read it. If the bit is not set, then we simply do nothing and continue on to the next component. Obviously when writing the components variable, the same applies. Lets just imagine for a moment that we are only planning to write out the normal component and the render effect component. In this case, the only bits which would be set within the variable would be the normal, and effect bits:
Components = SCOMPONENT_NORMAL | SCOMPONENT_EFFECT;

An alternative example is one where we would like to write all components, or possibly all components but one. Rather than specifying every component, which can be a little laborious, we can in fact specify the components by simply modifying the relevant *_ALL definition. The following two examples demonstrate these two cases in action:
// Example 1: We will be writing out all components Components = SCOMPONENT_ALL; // Example 2: We are writing all except the normal component. Components = SCOMPONENT_ALL; Components &= ~SCOMPONENT_NORMAL;

The first example simply sets all bits, currently defined by the revision of the standard being used, to 1. Likewise, the second example also sets all bits currently defined by the revision of the standard being used to 1, however it then sets the Normal component bit to 0. Information on both the actual data component flags and the use of each component can be found throughout all of the various sections covering the individual chunk data areas in which they are used.

Copyright 2002 Daedalus Developments. All Rights Reserved. Page 36 of 92.

Interchangeable World Format v2.0

4.2. Summary Chunk


Type Identifier Name:

CHUNK_FILESUMMARY
Type Identifier Value:

0x0002(hex)
Restrictions:

Strictly one instance of this chunk per file. Must be written at the root hierarchy level (i.e. cannot be used as a child).

Recommendations:

None.
Standard Children:

None.
Data Area Layout: Table 13a. Data Area Layout CHUNK_FILESUMMARY Type Size (In Bytes) unsigned short 2
Section Repeated for N Iterations - N = EntryCount (var)

Name EntryCount

ChunkTypeID AuthorIDLength AuthorID UsageCount

unsigned short unsigned char unsigned char (array) unsigned long


End Repeat

2 1 AuthorIDLength (var) 4

Table 13b. Variable Descriptions CHUNK_FILESUMMARY Name EntryCount Description The number of entries stored in this chunk summary table. The type identifier to which the value stored in UsageCount applies. Specifies the length, if any, of the author-id which directly follows this variable. Valid Values 4.2.1. Processing Chunk Statistics 3.5. Chunk Types.

ChunkTypeID

AuthorIDLength

3.2.2. Using Author-IDs.

Copyright 2002 Daedalus Developments. All Rights Reserved. Page 37 of 92.

Interchangeable World Format v2.0

Table 13b. Variable Descriptions CHUNK_FILESUMMARY Name Description The author-id signature, used for correct identification of the value stored within ChunkTypeID, to which the value stored in UsageCount applies. The total number of the specified chunk type found to be stored within the IWF file. Valid Values

AuthorID

As Above

UsageCount

4.2.1. Processing Chunk Statistics

Description:

The file summary chunk provides information about how many of each individual standard, or custom, chunk type are stored within the IWF file. This information can be used by an application to perform many tasks, just one of which is to pre-allocate memory for a certain type of object, instead of having to resize the memory block, each time a new chunk of that type is encountered within the file. This chunk is entirely optional (due to the fact that it is possible to build this information at the point of loading by stepping through the file manually), however with large data sets this can prove to be inefficient and may increase loading times, therefore it is recommended that this information is made available. If this chunk is to be written, then it is important to also inform the loading application that a summary chunk exists within the file. This allows the import procedure to instantly handle any situation where the summary chunk has not been provided without first having to perform a lengthy search for a chunk containing the CHUNK_FILESUMMARY type id value. This can be achieved by adjusting the Flags variable, stored within the file header, and combining the value stored there with the IWF_FILESUMMARY flag. For more information on this subject please refer to sections 3.1. File Header and 3.6.1. Providing Forward References.
4.2.1. Processing Chunk Statistics

Providing this summary information is relatively simple, and can be built during the export of the file. Put simply, each time a new chunk header is written, the information to be stored is compared against any summary information already built. If both ChunkTypeID and the AuthorID match any items entries already contained within the summary table, then the UsageCount value for that chunk type is simply increased. If that chunk type is not currently contained within the summary table, then it is appended. It is for the above reasons that the standard summary chunk will usually be found at, or close to, the end of the file.

Copyright 2002 Daedalus Developments. All Rights Reserved. Page 38 of 92.

Interchangeable World Format v2.0

The following table demonstrates an example summary chunk:


Table 14. Example Chunk Summary Table Name Type EntryCount 3
Entry 0

ChunkTypeID AuthorIDLength UsageCount

CHUNK_FILESUMMARY 0 1
Entry 1

ChunkTypeID AuthorIDLength UsageCount

CHUNK_MESH 0 12
Entry 2

ChunkTypeID AuthorIDLength AuthorID UsageCount

CHUNK_CTM_RAWIMAGE 4 M, Y, I, D 6

This example summary consists of four entries which categorise each of the 13 standard and 6 custom chunks contained within the file being described. You can see that each entry contains the ChunkTypeID and AuthorID which matches the various chunk headers and that the UsageCount variable describes how many of each chunk type was written to file. It is important to remember to include the summary entry itself when writing the table (shown here as Entry 0) because the summary may be extracted by a third party application used to display information about the exact contents of the file. Providing this entry unifies the process of displaying this chunk information without having to implement a special case for a once only insertion of the summary chunk itself. In addition, if you are developing a third party application which may append new chunks to the IWF file, you must strip the summary information already contained there. Once the append operation is completed, you must then rebuild and write the table including the newly appended chunks. Note: An example for the implementation of this process is included in the IWF file toolkit. For more information see 5.0. IWF File Toolkit Version 2.0.

Copyright 2002 Daedalus Developments. All Rights Reserved. Page 39 of 92.

Interchangeable World Format v2.0

4.3. Thumbnail Chunk


Type Identifier Name:

CHUNK_THUMBNAIL
Type Identifier Value:

0x0003(hex)
Restrictions:

Strictly one instance of this chunk per file. Must be written at the root hierarchy level (i.e. cannot be used as a child).

Recommendations:

For the purposes of optimisation, it is recommended that this chunk be written as close to the beginning of the file as possible to allow an application to seek to this chunk without being required to search the entire file.

Standard Children:

None.
Data Area Layout: Table 15a. Data Area Layout CHUNK_THUMBNAIL Type Size (In Bytes) unsigned short 2 unsigned short unsigned short PAL_ENTRY (array)(8bpp only) (array) 2 2 768 (256 Entries * 3) (Width * Height) * (BitsPerPixel / 8)

Name Width Height BitsPerPixel Palette ImageData

unsigned char

Table 15b. Variable Descriptions CHUNK_THUMBNAIL Name Width Description Specifies the width, in pixels, of the image stored within the image data array. Specifies the height, in pixels, of the image stored within the image data array. The colour resolution for the image itself. This specifies how many bits are used to describe each pixel stored within the image data array. Valid Values 0 - 65535

Height

0 65535

BitsPerPixel

8 or 24

Copyright 2002 Daedalus Developments. All Rights Reserved. Page 40 of 92.

Interchangeable World Format v2.0

Table 15b. Variable Descriptions CHUNK_THUMBNAIL Name Description An array of 256 individual palette entries which describe the colour of each pixel stored within the image data array. Palette Note: This array will only be written when BitsPerPixel is set to 8, i.e. the image data array holds 8 bit palette indices. Stores the physical image pixel data. This array stores a series of either palette indices, or physical colour data depending on the value specified in the BitsPerPixel field. Valid Values

4.3.1. Palettes and Image Data Formatting

ImageData

As Above

Description:

The thumbnail chunk is a specialised chunk designed to hold image data which depicts a graphical representation of the contents of the file. This chunk is commonly used by developers who wish to display a preview image, whenever a user selects an IWF file via the applications common file open dialog, or any other file preview utility. Any image, of any size, may be stored within this chunk; however, because no image compression is applied, it is recommended that you limit the dimensions of this image to a maximum of approximately 128x128. This chunk is entirely optional.
4.3.1. Palettes and Image Data Formatting

There are two colour depth dependant image formats which can be stored within this chunk. The first of these is the 8 bit format which can store an image utilising a maximum of 256 individual colours via the use of the colour palette. If the 8 bit format is to be used, the colour palette must be written just prior to the image data itself. The palette is made up of 256 entries with each palette entry containing 3 individual components. These components describe the colour of the palette entry by specifying each of the three primary colour values; red, green and blue. Each colour component is expressed with a value between 0 and 255 inclusive. Each palette entry uses a standard RGB colour space model where black can be described using RGB( 0, 0, 0 ) and white as RGB( 255, 255, 255 ). (Please refer to section 4.1.4. Palettes, Colours and Blend Modes for information on the layout of the PAL_ENTRY structure). As mentioned, the palette stores 256 individual colour entries in a linear array, each element being referenced by the index value 0 through 255. When the specified image depth is set to a value of 8, each byte within the image data array stores an 8 bit index value which references the specified element within the palette and therefore the colour in which this pixel should be drawn.

Copyright 2002 Daedalus Developments. All Rights Reserved. Page 41 of 92.

Interchangeable World Format v2.0

Note: You are required to write all 256 entries regardless of the number of physical colours used within the image. The second image format which can be contained within the thumbnail chunk, is that used by 24 bit colour depth images. Unlike the 8 bit format, no palette information is stored prior to the image data, and each pixel in the ImageData array occupies 3 bytes instead of 1. The colour of each pixel is expressed in much the same way as it is stored within a palette entry. In this case, the first byte within each pixel specifies the red colour component, the second specifies the green colour component and the third specifies the blue. As with the standard palette entries, this is a standard RGB colour space model. When writing the image data array itself, it is important that your image be written using a coordinate system whose origin is set at the top-left corner (scan lines are written from the top down). This differs from windows bitmaps for instance, whose base coordinate system originates from the bottom-left and is interpreted from the bottom upwards. This raw image data need not be padded, or aligned with any boundary; it is simply a continuous stream of scan lines whose pitch exactly matches the width of the image itself, multiplied by the number of bytes used per pixel. The following series of examples shows how the same 3x3 image is laid out in both 8 and 24 bits per pixel.

Entry 0 Entry 1 Entry 2

Red 0xFF 0x00 0x00

Example Palette Green 0x00 0xFF 0x00

Blue 0x00 0x00 0xFF

Figure 4. 8 bpp Row 1 Row 2 Row 3

Example Image Data Area Column 1 Column 2 Palette Entry 0 Palette Entry 1 Palette Entry 2 Palette Entry 0 Palette Entry 1 Palette Entry 2

Column 3 Palette Entry 2 Palette Entry 1 Palette Entry 0

Example Image Data Area Column 1 Row 1 Row 2 Figure 5. 24 bpp


(No Palette)

Column 2 0, 255, 0 0x00FF00 255, 0, 0 0xFF0000 0, 0, 255 0x0000FF

Column 3 0, 0, 255 0x0000FF 0, 255, 0 0x00FF00 255, 0, 0 0xFF0000

255, 0, 0 0xFF0000 0, 0, 255 0x0000FF 0, 255, 0 0x00FF00

Row 3

Copyright 2002 Daedalus Developments. All Rights Reserved. Page 42 of 92.

Interchangeable World Format v2.0

4.4. Group Chunk


Type Identifier Name:

CHUNK_GROUP
Type Identifier Value:

0x0010(hex)
Restrictions:

Must contain at least two children.

Recommendations:

None.
Standard Children:

Any standard chunk, including CHUNK_GROUP, unless noted otherwise.


Data Area Layout: Table 16a. Data Area Layout CHUNK_GROUP Type Size (In Bytes) unsigned char 1 char (array) NameLength (var)

Name NameLength Name

Table 16b. Variable Descriptions CHUNK_GROUP Name NameLength Description The length, in bytes (not characters), of the string following this variable. The label associated with this group. No terminator is required. However should you include a terminator, the value stored within the NameLength variable must reflect the existence of this extra character. Valid Values 0 255

Name

Any valid, ANSI compatible, string no greater than 255 bytes in length.

Description:

There are many cases where multiple objects must, technically, be treated as one single object, whilst retaining their own independent properties such as position and orientation. Many design applications today support the concept of grouping multiple objects in this way. This allows the designer to, for example, easily position many objects as a whole rather than forcing them to move each individual object, which goes to make up a model, by hand.

Copyright 2002 Daedalus Developments. All Rights Reserved. Page 43 of 92.

Interchangeable World Format v2.0

The same concept can be adopted within the IWF, however; its scope extends far beyond merely grouping mesh objects and can in fact be applied to many standard or custom chunk types. To group two or more chunks together, simply insert a physical group chunk and then insert, as children of the group, those chunks you wish to be grouped together. As mentioned, groups can hold many types of chunks, standard or custom, including other groups. This provides an easy way to create multiple level grouped hierarchies where for instance you could have a group named Tank containing two child group chunks and a custom script chunk. The first child group could contain all of the meshes used to make up the base of the tank, and the second group contains the turret meshes. The script, contained as a custom child of the Tank group, can then modify these two child groups independently from one another. The following diagram demonstrates this grouped chunk hierarchy, utilising the group layout mentioned above.

Group - Tank Group - Base Mesh - Body Mesh - Left Track Mesh - 'Right Track Group - Turret Mesh - 'Turret Base Mesh Barrel Custom - Script

Figure 6. Example Grouped Hierarchy.

The chunk data area contains only a string label, which can be used as a form of identification for the group itself. The additional information about what objects the group contains is gained simply by stepping into the chunk, and reading the groups children.

Copyright 2002 Daedalus Developments. All Rights Reserved. Page 44 of 92.

Interchangeable World Format v2.0

4.5. Object Meshes


Type Identifier Name:

CHUNK_MESH
Type Identifier Value:

0x0020(hex)
Restrictions:

None.
Recommendations:

None.
Standard Children:

CHUNK_SURFACES CHUNK_MESH CHUNK_DECALMESH CHUNK_GROUP CHUNK_VERTEXCOMPONENTS

(Mesh Pool)

(Required) (Optional) (Optional) (Optional) (Optional)

Data Area Layout: Table 17a. Data Area Layout CHUNK_MESH Type Size (In Bytes) unsigned char 1 char (array) unsigned long unsigned long unsigned long MATRIX4 AA_BBOX unsigned long unsigned short (optional) (optional) (optional) (optional) NameLength (var) 4 4 4 64 24 4 2 CustomDataSize (var)

Name NameLength Name Reserved1 Reserved2 Components ObjectMatrix Bounds Style CustomDataSize CustomData

unsigned char (array)(optional)

Copyright 2002 Daedalus Developments. All Rights Reserved. Page 45 of 92.

Interchangeable World Format v2.0

Table 17b. Variable Descriptions CHUNK_MESH Name NameLength Description The length, in bytes (not characters), of the string following this variable. The label associated with this mesh object. No terminator is required however, should you include a terminator, the value stored within the NameLength variable must reflect the existence of this extra character. Four bytes of reserved space for future use. Four bytes of reserved space for future use. Stores either 0, or a combination of one or more of the flags specified in Table 17c. These flags describe which components are included within the file, for this particular mesh. This matrix describes how to transform the object, from object space, into its parents object space. This matrix provides a relative transformation between the parent and this object. An axis-aligned bounding box specifying the extents of the mesh in object space, i.e. if a world space bounding box is required, this box must be transformed along with the mesh data, or recalculated in world space. Stores either 0, or a combination of one or more of the flags specified in Table 17d. Specifies various features which apply to the mesh being described. Specifies the length, in bytes, of the CustomData array directly following this field. A custom data array which can be freely used to store any arbitrary information which may be relevant to the mesh object. This data area should be ignored by applications which do not have strict control over the source of the file containing this information. Child chunks are preferable however for non trivial information. Valid Values 0 255

Name

Any valid, ANSI compatible, string no greater than 255 bytes in length.

Reserved1 Reserved2

N/A N/A

Components

Refer to Table 17c.

ObjectMatrix

Any valid transformation matrix (See 4.14. Coordinate System Information)

Bounds

4.1.3. Bounding Boxes

Style

MESH_DETAIL MESH_DYNAMIC MESH_DESTRUCTIBLE

CustomDataSize

0 - 65535

CustomData

Developer Defined

Copyright 2002 Daedalus Developments. All Rights Reserved. Page 46 of 92.

Interchangeable World Format v2.0

Table 17c. Components Definitions CHUNK_MESH Name MCOMPONENT_OMATRIX Value 0x1 Description If this bit is set it informs the import application that the ObjectMatrix variable is included and should be read. If this bit is set it informs the import application that the Bounds variable is included and should be read. If this bit is set it informs the import application that the Style variable is included and should be read. If this bit is set it informs the import application that the CustomDataSize variable should be read and that the CustomData area is potentially available should CustomDataSize contain a value greater than zero. The definition which contains all currently defined component bits set to 1.

MCOMPONENT_BOUNDS

0x2

MCOMPONENT_STYLE

0x4

MCOMPONENT_CUSTOMDATA

0x8

MCOMPONENT_ALL

0xF

Table 17d. Style Definitions CHUNK_MESH Name Value Description Specifies that this mesh is a detail object. While having no effect on the format of the file, it can provide the application with information about which objects should or should not be considered as base architecture. Specifies that this mesh is dynamic. While having no effect on the format of the file, it can provide the application with information about which objects should be allowed to be moved by players, scripts or external forces. Specifies that this mesh is destructible. While having no effect on the format of the file, it can provide the application with information about which objects should be allowed to be destroyed by players, scripts or external forces.

MESH_DETAIL

0x1

MESH_DYNAMIC

0x2

MESH_DESTRUCTIBLE

0x4

Description:

The mesh chunk is the primary, standard, means by which to define geometry contained inside the world, set out within the file. Although this chunk does not physically contain any polygonal data itself, it defines the mesh properties and is the container for various other chunks which do. More specifically, the mesh chunk is the container for the surfaces chunk defined here with the name CHUNK_SURFACES. There can be an infinite number of individual meshes stored within the file, or as few as one mesh used to describe a single model or a generic soup of world polygons. As with all chunks, the mesh chunk can contain other children prior to its footer. These children can be anything from another mesh to a custom chunk containing the physical texture image data to be applied to its parent. This is the primary means by which to provide information about mesh hierarchies within the
Copyright 2002 Daedalus Developments. All Rights Reserved. Page 47 of 92.

Interchangeable World Format v2.0

IWF file. By inserting other meshes, or groups of meshes, as children of any particular chunk you can easily specify, for instance, scene graph information. Each mesh within the file should ideally be stored within its own local object space, relative to its parent. Each mesh may contain a matrix which allows the import procedure to transform the mesh data to and from its parents object space at any point. This is a vital concept within any hierarchical scene graph where, for instance, translating the parent object would effectively translate all children as well because their own object matrix is relative to its parents, now translated, matrix. If your meshes are defined in world space however, the MESH_OMATRIX component should not be written. Note: This chunk utilises the component mechanism set out in section 4.1.6. Object Component Architecture, whereby individual surface components may be discarded to save space within the output file if those components are deemed to be redundant.

Copyright 2002 Daedalus Developments. All Rights Reserved. Page 48 of 92.

Interchangeable World Format v2.0

4.6. Polygon Data


Type Identifier Name:

CHUNK_SURFACES
Type Identifier Value:

0x0030(hex)
Restrictions:

Can be used as a child of CHUNK_MESH or CHUNK_DECALMESH only. Only one instance of this child-chunk is allowed for each parent.

Recommendations:

None.
Standard Children:

CHUNK_VERTEXCOMPONENTS CHUNK_INDICES

(Surface Pool) (Optional) (Required if Surface Pool not provided)

Data Area Layout: Table 18a. Data Area Layout CHUNK_SURFACES Type Size (In Bytes) unsigned long 4

Name SurfaceCount

Section Repeated for N Iterations - N = SurfaceCount (var)

Components Normal ZBias Style RenderEffect ChannelCount TexIndices MatIndices ShaderIndices BlendModes CustomDataSize CustomData

unsigned long VECTOR3 unsigned char unsigned long SCRIPT_REF unsigned char short short short BLEND_MODE (optional) (optional) (optional) (optional) (optional) (array)(optional) (array)(optional) (array)(optional) (array)(optional) (optional)

4 12 1 4 8 + SCRIPT_REF::ScriptSize 1 2 * ChannelCount 2 * ChannelCount 2 * ChannelCount 2 * ChannelCount 2 CustomDataSize (var)

unsigned short

unsigned char (array)(optional)


End Repeat

Copyright 2002 Daedalus Developments. All Rights Reserved. Page 49 of 92.

Interchangeable World Format v2.0

Table 18b. Variable Descriptions CHUNK_SURFACES Name SurfaceCount Description The number of surfaces described by this chunk. that are physically Valid Values 0 0xFFFFFFFF

Components

Stores either 0, or a combination of one or more of the flags specified in Table 18c. These flags describe which components are included within the file, for this particular surface. Specifies the three-dimensional unit length vector describing the direction of the plane on which this surface lies. The Z-Bias value by which to offset this surface, specified within the range of 0 to 255. Because of this fixed range, it is possible to scale the value into whatever Z-Bias range you require, for example 016 when using Microsoft Direct3D. Stores either 0, or a combination of one or more of the flags specified in Table 18d. Specifies various features which apply to the surface being described. References a script, shader or effect file that should be used when rendering this surface. The number of Render Pass Channels used by this surface. The number of channels relates to the number of stages (single or multi-pass) to be applied when rendering. For example, a simple face with a base texture and a light map would specify two separate channels. Note: Please refer to the component table below for information on when this variable should be written and / or read. An array of one or more indices specifying an entry within the texture table (CHUNK_TEXTURES). Texture entries reference either: external texture files (by specifying a filename) or physical texture data stored within the file. An array of one or more indices specifying an entry within the materials table (CHUNK_MATERIALS). Material entries reference various properties primarily based around how light is reflected. An array of one or more indices specifying an entry within the shader table (CHUNK_SHADERS). Shader entries reference vertex and pixel shaders to be applied to each render stage of the surface.

Refer to Table 18c.

Normal

Any valid unit length directional vector. (See 4.14. Coordinate System Information)

ZBias

0 - 255

Style

Refer to Table 18d.

RenderEffect

4.1.5. Scripts, Shaders and Effect Files

ChannelCount

0 255

TexIndices

4.12. Textures

MatIndices

4.11. Materials

ShaderIndices

4.13. Shaders

Copyright 2002 Daedalus Developments. All Rights Reserved. Page 50 of 92.

Interchangeable World Format v2.0

Table 18b. Variable Descriptions CHUNK_SURFACES Name Description An array of BLEND_MODE structures, used to indicate both the source, and destination, alpha blending modes which should be applied to this surface, or this render pass. Specifies the length, in bytes, of the CustomData array directly following this field. A custom data array which can be freely used to store any arbitrary information which may be relevant to the surface. This data area should be ignored by applications which do not have strict control over the source of the file containing this information. Child chunks are preferable however for non trivial information. Valid Values 4.1.4. Palettes, Colours and Blend Modes

BlendModes

CustomDataSize

0 65535

CustomData

Developer Defined

Table 18c. Components Definitions CHUNK_SURFACES Name SCOMPONENT_NORMAL Value 0x1 Description If this bit is set it informs the import application that the Normal variable is included and can be read. If this bit is set it informs the import application that the ZBias variable is included and can be read. If this bit is set it informs the import application that the Style variable is included and can be read. If this bit is set it informs the import application that the RenderEffect variable is included and can be read. If this bit is set it informs the import application that the TexIndices array is available, and can be read. SCOMPONENT_TEXTURES 0x10 Note: If this component is included, the ChannelCount variable must also be written. If this bit is set it informs the import application that the MatIndices array is available, and can be read. SCOMPONENT_MATERIALS 0x20 Note: If this component is included, the ChannelCount variable must also be written. If this bit is set it informs the application that the ShaderIndices array is available, and can be read. SCOMPONENT_SHADERS 0x40 Note: If this component is included, the ChannelCount variable must also be written.

SCOMPONENT_ZBIAS

0x2

SCOMPONENT_STYLE

0x4

SCOMPONENT_EFFECT

0x8

Copyright 2002 Daedalus Developments. All Rights Reserved. Page 51 of 92.

Interchangeable World Format v2.0

Table 18c. Components Definitions CHUNK_SURFACES Name Value Description If this bit is set it informs the import application that the BlendModes array is available, and can be read. SCOMPONENT_BLENDMODES 0x80 Note: If this component is included, the ChannelCount variable must also be written. If this bit is set it informs the import application that the CustomDataSize variable should be read and that the CustomData area is potentially available should CustomDataSize contain a value greater than zero. The definition which contains all currently defined component bits set to 1.

SCOMPONENT_CUSTOMDATA

0x100

SCOMPONENT_ALL

0x1FF

Table 18d. Style Definitions CHUNK_SURFACES Name SURFACE_INVISIBLE Value 0x1 Description This surface is flagged as invisible, and as such should not be rendered. Specifies that this surface should be considered Full Bright. This means that no diffuse shading should be applied during, for instance, a light-mapping process. In a lot of cases, sky surfaces must be handled differently to normal surfaces whether thats merely during texture application, or the surface is being used as a stencil to mask off the sky areas. This flag informs the rendering application that this surface should be considered as a sky surface. This surface should be considered as being twosided, which means that no back-face culling should be applied either within the API or by the rendering application.

SURFACE _FULLBRIGHT

0x2

SURFACE _SKYTYPE

0x4

SURFACE _TWO_SIDED

0x8

Description:

The surfaces chunk itself must only be written once within any mesh or decalmesh chunk due to the fact that it houses information about every surface which goes to make up that mesh. This is not the case with certain other chunk types where an individual chunk describes only one object. The surfaces chunk may contain one surface, which describes the entire outer hull of that particular mesh object, or could in fact contain many surfaces, with each entry describing an individual polygon. Surfaces are the primary means by which to supply polygonal data used to make up each individual mesh within the scene. As with the mesh chunk, this chunk does not actually contain any physical vertex data, however it does serve as the container for either the vertices themselves, or the indices into a global or mesh
Copyright 2002 Daedalus Developments. All Rights Reserved. Page 52 of 92.

Interchangeable World Format v2.0

vertex pool. (See sections 4.7. Vertex Components and 4.8. Vertex Indices for more information on vertex pools.) As previously mentioned; each CHUNK_SURFACES data area may contain one or more surface, used to describe the outer hull of any particular mesh. It is not a requirement that each surface describes a single coplanar polygon. In actuality, it is possible, and often desirable, to provide one or more surfaces, stored as triangle strips for instance, where each surface defines a series of non-coplanar polygons. A good example of this case is where a mesh describes a portion of terrain or landscape data. In this particular example, the terrain may be divided into several patches, each one containing many vertices. In these cases it is important that the application is informed of this fact, to allow the import procedure to split if necessary. In this example, due to the fact that the surface is not strictly coplanar, the surface normal component is redundant and would not have been included. (For more information on providing this information, refer to section 4.7. Vertex Components) Under normal circumstances however, even where global or mesh vertex pools are in use, it is often advantageous to provide information about each individual polygon that goes to make up any particular mesh. In this case, the application would export information about each individual polygon, providing components such as surface normals and per surface texture or material information if so required. Note: This chunk utilises the component mechanism set out in section 4.1.6. Object Component Architecture, whereby individual surface components may be discarded to save space within the output file if those components are deemed to be redundant.

Copyright 2002 Daedalus Developments. All Rights Reserved. Page 53 of 92.

Interchangeable World Format v2.0

4.7. Vertex Components


Type Identifier Name:

CHUNK_VERTEXCOMPONENTS
Type Identifier Value:

0x0050(hex)
Restrictions (Surface Pool):

Can be used as a child of CHUNK_SURFACES only. Only one instance of this chunk is allowed for each parent. Must be written prior to any CHUNK_INDICES chunk.

Restrictions (Mesh Pool):

Can be used as a child of CHUNK_MESH or CHUNK_DECALMESH only. Only one instance of this chunk is allowed for each parent mesh. Must be written prior to the CHUNK_SURFACES chunk.

Restrictions (Global Pool):

Can be used at the root hierarchy level only. Only one instance of this chunk is allowed within the file. Must be written prior to any CHUNK_MESH or CHUNK_DECALMESH chunk.

Recommendations:

None.
Standard Children:

None.
Data Area Layout: Table 19a. Data Area Layout CHUNK_VERTEXCOMPONENTS Name Type Size (In Bytes) VertexPool unsigned char 1 TotalVertexCount SurfaceCount unsigned long unsigned long (VPOOL_SURFACE) (VPOOL_SURFACE) 4 4
N = SurfaceCount Occurs Once

(VertexPool = VPOOL_SURFACE)

Section Repeated for N Iterations No Repeat

(VertexPool = VPOOL_MESH or VPOOL_GLOBAL)

VertexFlags VertexCount Components

unsigned char unsigned short unsigned long

1 2 4

Copyright 2002 Daedalus Developments. All Rights Reserved. Page 54 of 92.

Interchangeable World Format v2.0

Table 19a. Data Area Layout CHUNK_VERTEXCOMPONENTS Name Type Size (In Bytes) TexChannelCount unsigned char (optional) 1 TexCoordSize unsigned char (array)(optional) TexChannelCount (var)

Section Repeated for N Iterations - N = VertexCount (var)

x y z rhw Normal PointSize Diffuse Specular

float float float float VECTOR3 float unsigned long unsigned long

(optional) (optional) (optional) (optional) (optional) (optional) (optional) (optional)

4 4 4 4 12 4 4 4

Section Repeated for N Iterations - N = TexChannelCount (var) (optional)

TexCoords
End Repeat for End Repeat for End Repeat for

float

(array)(optional)

TexCoordSize[N] * 4
(TexChannelCount) (VertexCount)

(VertexPool = VPOOL_SURFACE) (SurfaceCount)

Table 19b. Variable Descriptions CHUNK_VERTEXCOMPONENTS Name Description Informs the import procedure about what type of vertex pool this chunk is describing. This variable also defines, in part, how this chunk is to be interpreted. Note: Refer to section 4.7.1. Vertex Pools for more information on this value. The total number of vertices described by the individual vertex components stored inside all surfaces being described within this chunk. Note: This should not be read / written unless VertexPool contains the VPOOL_SURFACE flag. The number of surfaces, whose vertices are described by this chunk. SurfaceCount Note: This should not be read / written unless VertexPool contains the VPOOL_SURFACE flag. Informs the import procedure, among other things, about how the vertices are currently arranged within the chunk. Must contain at least one primitive flag. 0 0xFFFFFFFF Valid Values

VertexPool

VPOOL_SURFACE VPOOL_MESH VPOOL_GLOBAL

TotalVertexCount

0 0xFFFFFFFF

VertexFlags

4.7.2. Vertex Arrangement

Copyright 2002 Daedalus Developments. All Rights Reserved. Page 55 of 92.

Interchangeable World Format v2.0

Table 19b. Variable Descriptions CHUNK_VERTEXCOMPONENTS Name Description Specifies the number of vertices to be read by the import procedure. Depending on the value stored within VertexPool, this variable contains the number of vertices which make up the current surface (VPOOL_SURFACE), the number of vertices which make up the entire mesh (VPOOL_MESH) or the number of vertices which make up the entire file (VPOOL_GLOBAL). Stores either 0, or a combination of one or more of the flags specified in Table 19c. These flags describe which components are included for this set of vertices. The number of texture-coordinate channels that are contained with each vertex currently being described. This information is generally linked with the number of render stage channels stored within the surface, and describes a set of texture coordinates for each. Both the TexCoordSize and TexCoords arrays will contain the amount elements specified by this variable. This is an array of values which describes how many float components make up the texture coordinate in each channel. As an example, the standard U,V coordinate format utilises 2 components, whereas information pertaining to a volume texture may contain 3. The X axis component of the vertex currently being described. This value is generally expressed in object space unless using transformed vertices, in which case this value is expressed in screen space. The Y axis component of the vertex currently being described. This value is generally expressed in object space unless using transformed vertices, in which case this value is expressed in screen space. The Z axis component of the vertex currently being described. This value is generally expressed as a distance in object space, unless using transformed vertices, in which case this value is expressed as a depth value. The reciprocal homogeneous W value which is generally used to describe vertices which have already been transformed. Valid Values

VertexCount

4.7.1. Vertex Pools

Components

Refer to Table 19c.

TexChannelCount

0 255

TexCoordSize

0 - 255

4.14. Coordinate System Information

As Above

As Above

rhw

N/A

Copyright 2002 Daedalus Developments. All Rights Reserved. Page 56 of 92.

Interchangeable World Format v2.0

Table 19b. Variable Descriptions CHUNK_VERTEXCOMPONENTS Name Description The vertex normal. This value is commonly used by modern rendering APIs to calculate diffuse lighting values. However, this vector is also used in many other techniques such as, among others, environment mapping. Specifies the size of the Point Primitive to be rendered, in either camera space units, or screen space units when using transformed vertices. This value is generally used in conjunction with systems such as the Microsoft Direct3D point sprite mechanism, or used to specify the width of each line within a wireframe model under OpenGL for example. The diffuse colour component to be included in this vertex. This value is generally used in conjunction with pre-calculated lighting, or just to colour a surface in general. The specular colour component to be included in this vertex. This value is generally used in conjunction with pre-calculated lighting, or just to colour a surface in general. An array of texture coordinates of the type specified by the texture coordinate layout information. If no layout information is provided, this will always be a single element containing a two-dimensional coordinate (i.e. U & V). Valid Values Any valid unit length directional vector. (See 4.14. Coordinate System Information)

Normal

PointSize

N/A

Diffuse

4.1.4. Palettes, Colours and Blend Modes

Specular

As Above

TexCoords

Refer to TexChannelCount and TexCoordSize variables.

Table 19c. Components Definitions CHUNK_VERTEXCOMPONENTS Name VCOMPONENT_XYZ Value 0x1 Description Each of the X, Y and Z variables, stored within this chunk, are available and should be read by the import procedure. The RHW variable (reciprocal homogeneous W) stored within this chunk, is available and can be read by the import procedure. This is generally used in conjunction with transformed vertices. A combination of the VCOMPONENT_XYZ and VCOMPONENT_RHW flags. This vertex component flag is provided for convenience only. Specifies that the Normal variable associated with these vertices is available, and can be read by the import procedure.

VCOMPONENT_RHW

0x2

VCOMPONENT_XYZRHW

0x3

VCOMPONENT_NORMAL

0x4

Copyright 2002 Daedalus Developments. All Rights Reserved. Page 57 of 92.

Interchangeable World Format v2.0

Table 19c. Components Definitions CHUNK_VERTEXCOMPONENTS Name VCOMPONENT_POINTSIZE Value 0x8 Description Specifies that the PointSize variable associated with these vertices is available, and can be read by the import procedure. Specifies that the Diffuse variable associated with this vertex is available, and can be read by the import procedure. Specifies that the Specular variable associated with this vertex is available, and can be read by the import procedure. Informs the import procedure that one or more texture coordinates have been written to file for these vertices. VCOMPONENT_TEXCOORDS 0x40 Note: The availability of the texture coordinate layout variables is not determined using this flag. See VCOMPONENT_TEXCOORDLAYOUT. Specifies that the texture coordinate layout information is available, and should be read by the import procedure. This information is provided in the form of the TexChannelCount variable, and the TexCoordSize array. VCOMPONENT_TEXCOORDLAYOUT 0x80 Note: You need not include this component if you are using the default layout of only 1 channel, made up of two coordinate components (i.e. U and V). Note: This component should not be written if no texture coordinates are included. The definition which contains all currently defined component bits set to 1. This is provided purely for convenience.

VCOMPONENT_DIFFUSE

0x10

VCOMPONENT_SPECULAR

0x20

VCOMPONENT_ALL

0xFF

Description:

The Vertex Components chunk is where all of the individual points, which serve to make up a mesh surface, are stored. As you can no doubt see by the sheer amount of individual components and variables stored within this chunk, this is by far the most intricate and complex standardised chunk within the specification. There is of course several good reasons for this, one of the most important being the vast amount of different ways in which vertices are required to be expressed by so many different applications. As an example, one application may require diffuse colour values to be stored at each vertex, whilst another application does not. If the specification were to force that application to write the diffuse value regardless, the resulting file would contain 4 bytes of wasted space per vertex which, in a file with for example 60,000 vertices, results in approximately 234kb of wasted space on just the redundant diffuse value alone. Add onto that a redundant vertex normal component of 12 bytes per vertex and you can clearly see the amount of space wasted within
Copyright 2002 Daedalus Developments. All Rights Reserved. Page 58 of 92.

Interchangeable World Format v2.0

the file would grow exponentially for an application which does not require that these components be exported. In addition to the many ways in which a vertex can be formatted, there is also the issue of duplicated vertices. Taking a look at figure 7 to the left you can see that the front face of the cube is made up of two triangles (coloured in blue and red respectively), each of which is described by three vertices. If we were to describe each triangle separately within the file, we would be required to write all 6 vertices which go to make up the two triangles themselves. In this particular situation however, the vertices which are used by the connecting edge of each of these two triangles share exactly the same position meaning we have two sets of duplicated vertices. If we examine a standard cube more closely, we can see that in fact we can describe all of the cubes 6 faces in as little as 8 unique vertex positions, however in the above situation we would require 36 vertices (3 vertices x 12 triangles) which means that we would be writing 28 duplicated vertices in total, which is of course unacceptable in many cases. Taking the same ratio of duplicated vertices, using a scene which only requires 10,000 unique vertex positions, would result in a scene made up of 45,000 vertices with 35,000 such vertices duplicating information already available. For this reason the IWF adopts the concept of vertex pools. This is an extremely important topic, and is the one that probably requires the most thought before deciding how you will be formatting your scene information during export. (For more information on vertex pools, please refer to section 4.7.1. Vertex Pools.) Note: This chunk utilises the component mechanism set out in section 4.1.6. Object Component Architecture, whereby individual vertex components may be discarded to save space within the output file if those components are deemed to be redundant.
4.7.1. Vertex Pools
Figure 7.

As mentioned in the previous section, the duplication of vertices is a complex issue which involves a great deal of forethought into how your application presents its mesh information, when stored in memory or written to file. Vertex pools are the primary method, adopted by the IWF specification, by which to reduce or eliminate this issue. There are a total of three types of vertex pool which are available for use by an export application, each of which serve as a container for one or more vertex components, at different locations within the scene hierarchy. The three types of vertex pools available are shown in the following table:

Copyright 2002 Daedalus Developments. All Rights Reserved. Page 59 of 92.

Interchangeable World Format v2.0

Table 20. VertexPool Definitions CHUNK_* Name VPOOL_SURFACE Value 0x0 Description The vertices or vertex components stored, describe each individual surface separately, and cannot be referenced by an external source. The vertices or vertex components stored, describe all surfaces contained within the mesh in which the pool is contained. Any vertex stored here may be referenced by any child surface, but cannot be referenced by external mesh objects. The vertices or vertex components stored, describe every surface, of every mesh, contained within the file. Any vertex stored here may be referenced by any surface belonging to any mesh.

VPOOL_MESH

0x1

VPOOL_GLOBAL

0x2

The export procedure is not limited in any way to using just one type of vertex pool per file. It is often desirable, for instance, to allow certain meshes to use their own mesh pool (i.e. a complex detail object), whilst other meshes may require that each surface reference their own set of vertices (i.e. base architecture). There are many ways of combining each type of vertex pool within the file to provide the maximum amount of coverage for any situation which may be required. (For more information on mixing vertex pool types within the file please refer to section 4.7.1.4. Mixing Vertex Pools)
4.7.1.1. Surface Pools

Vertex component chunks that describe a surface pool will always be written to file as a child of the CHUNK_SURFACES chunk. In this particular case it, should be written prior to any CHUNK_INDICES chunk contained there. The surface pool form of the CHUNK_VERTEXCOMPONENTS chunk differs slightly from that used when writing mesh and global pool types. Referring back to Table 19a within section 4.7. Vertex Components, you will notice that not only are there two additional variables contained within the layout itself (TotalVertexCount and SurfaceCount), the chunk actually consists of a unique vertex pool for each surface, as opposed to a single pool per chunk when used in conjunction with the other types. The primary reason for this pool dependant layout is to save as much space within the file as possible. If we were to write out a unique chunk for each surface, the file would soon grow to an unmanageable size where each set of vertices, for each surface, is enveloped by a chunk header and chunk footer. While this may add a relatively small amount of complexity when reading or writing surface pools, the overall space saving gained is more than worth the extra effort. Surface pools are used to describe per surface vertex information, where the pool itself stores all of the vertices used by an individual surface alone. This means that no other surface, from either the parent or external mesh, can reference a vertex
Copyright 2002 Daedalus Developments. All Rights Reserved. Page 60 of 92.

Interchangeable World Format v2.0

within this pool. Although, because of this fact, using this type of vertex pool alone throughout the file is generally considered to be wasteful and is usually avoided, the surface pool serves an absolutely crucial purpose when used in conjunction with other pool types (see section 4.7.1.4. Mixing Vertex Pools)
4.7.1.2. Mesh Pools

Vertex component chunks that describe a mesh pool will always be written to file as a child of the CHUNK_MESH or CHUNK_DECALMESH chunks. In this particular case, it should be written prior to any CHUNK_SURFACES chunk contained there. The mesh pool is used to describe all of the vertices used by the child surfaces of any particular mesh within the file. This is the most commonly used method of all three pool types because it allows duplicate vertex information to be kept to a minimum, whilst allowing meshes to be described in their own local object space. This is achieved by providing a set of indices, within each surface, which reference vertices stored within the mesh level vertex pool. Because all surfaces contained within the mesh have access to the vertex information contained within the parent, this allows many different surfaces to simply reference the same vertex information, for example on a shared edge, instead of being required to simply duplicate such information as would be required with a surface pool. For this reason, whenever a mesh level pool is in use the CHUNK_INDICES chunk must be provided as a child of the surfaces chunk if any of those surfaces reference vertices from the meshs vertex pool. (For more information on providing indices refer to section 4.8. Vertex Indices) Although mesh pools are the recommended type for use during the export of vertex information; there are cases where duplicating at least portions of each vertex cannot be avoided. A classic example of such a case is the vertex normal. In many cases, where smooth shading between polygons should not be applied (for example: cube faces) it is necessary to provide a different normal for each vertex belonging to two or more surfaces, even though the vertex positions are identical. In this particular scenario there are two options. The first is to resort to using surface pools for each face of the cube, duplicating the vertex position, which is of course far from satisfactory in many cases. The second, recommended, approach is to make use of the mixed vertex pool support (see section 4.7.1.4. Mixing Vertex Pools) whereby each individual vertex component may be separated into individual mesh and surface level pools. In the latter case a surface can reference all the shared vertex component information stored within the mesh pool, such as the vertex position, whilst also having access to the unique vertex normal component stored within the surface pool.
4.7.1.3. Global Pools

Vertex component chunks which describe a global pool will always be written to file at the root hierarchy level. In this particular case, it should be written prior to any CHUNK_MESH or CHUNK_DECALMESH contained either at the root or as a child of any other chunk.
Copyright 2002 Daedalus Developments. All Rights Reserved. Page 61 of 92.

Interchangeable World Format v2.0

Global vertex pools are used to describe all the vertices, used by all surfaces of every mesh, stored within the IWF file as a whole. This type of pool is very similar to the mesh pool, with the exception that all vertices stored here must be expressed in world-space. For this reason, global vertex pools are probably the least used of the three pool types, mainly due to the fact that this type of restriction is generally unsuitable for scene-graph style hierarchies in particular. Although the space saving gained by using this type of pool over the standard mesh pool is at best negligible, there are in fact cases where the use of a global vertex pool can certainly be advantageous. As an example of one such case, imagine for a moment that the exported information is used to describe terrain data. In this case the global vertex pool may contain all of the vertices used to describe the terrain geometry itself, with each mesh simply indexing a small portion or patch of that terrain for level of detail calculations. As with the mesh chunk, whenever a global pool is in use the CHUNK_INDICES chunk must be provided as a child of the surfaces chunk if any of those surfaces reference vertices from the files global vertex pool. (For more information on providing indices refer to section 4.8. Vertex Indices)
4.7.1.4. Mixing Vertex Pools

As mentioned in previous sections, it is possible to mix the different types of vertex pools utilised by the different components stored within the exported IWF file. The classic example, as demonstrated earlier, is that of being required to provide more than one vertex normal for a single vertex position when flat shading of surfaces is required, even when gouraud shading is in use. Lets go into a little more detail with this example now to demonstrate exactly what components would be required in that situation. Shown in figure 8, to the left, there are four physical vertex locations depicted by the labels A, B, C & D. Focusing specifically on vertex A for the moment, we can see that this vertex is used by each of the three cube faces labelled 1, 2 & 3 respectively. In order to render the cube correctly however, we may in fact be required to provide one vertex normal for each of the three surfaces that reference vertex A. If we were to use only a mesh pool in this situation, we would be limited to just one vertex normal. When this type of multi-component support is required, we can in fact split the vertex components up into separate vertex pools. In this particular case for example, we would store the vertex normals, required to render each face correctly, within a surface pool, with all other vertex components remaining in tact within the mesh pool. This in fact allows us to specify per-surface vertex component information, without having to duplicate all other vertex
Figure 8. Vertex Components Copyright 2002 Daedalus Developments. All Rights Reserved. Page 62 of 92.

Interchangeable World Format v2.0

components. Smooth vs. Flat shading issues are of course only one of the problems which may require vertex components to be provided on a per-surface level. Another example of this type of situation is where different textures are applied to each surface of a mesh. In this case, we often require multiple texture coordinates for faces which are connected at a shared vertex. To demonstrate this, refer back once again to figure 8 above. Looking at the top edge of surface 3, we can imagine that we might need to specify texture coordinates whose U component ranges from 0.0f at the left-most vertex, to 1.0f at vertex A. When rendering surface 1 however, the U texture coordinate component of vertex A may well be expected to contain a value of 0.0f, with vertex B containing the value 1.0f. This is of course extremely difficult to achieve without requiring duplicate copies of vertex A to be stored within either surface 1 or 3. Add into the mix the V component, let alone all the other vertices and surfaces, and we find that the only realistic way to represent all this information with one pool alone would be to duplicate each vertex 3 times, once for each face that references it. However, once again, by using mixed vertex pools we can store, for example, the texture coordinate information (along with anything else that may be required) within the surface pool, leaving all other vertex components to be shared between all surfaces within the parent meshs vertex pool. The process of mixing the vertex pools used within a surface is relatively simple, the first thing we have to do is write our indices which reference the primary vertex components within the mesh level pool, specifying VPOOL_MESH within our indices VertexPool variable. This will allow the import procedure to determine exactly which vertices are being referenced, and in which order. Once the CHUNK_INDICES chunk has been written, we can then proceed onto writing the surface pool. In this case the import procedure determines which vertex, from the surface pool, belongs to which vertex, in the mesh pool, based on the order in which they are contained within the surfaces CHUNK_VERTEXCOMPONENTS child. As an example, lets imagine for a moment that the mesh contains a surface which is made up of 4 vertices whose vertex positions alone are stored within the mesh pool. The mesh pool in itself may contain many vertices, used by other surfaces within the mesh, and for this reason the surface itself is required to store a set of indices which reference the correct vertices from that mesh pool. For the moment, lets assume that the indices, contained within the surface, reference vertices 3, 6, 8 & 12 from our mesh pool, which allows our import procedure to reference the four vertex positions which make up the topology of the surface. In addition to the vertex coordinates, each vertex may be required to contain, for instance, a vertex normal which is specific to a particular surface, many of which may be referencing the same vertex (i.e. 3, 6, 8 & 12 in our example) within the mesh. Since this is not possible by using a mesh pool alone, our surface will be required to store the various vertex normal components itself by writing out a matching CHUNK_VERTEXCOMPONENTS chunk directly preceding the indices chunk. As mentioned earlier, the order in which the additional vertex components are written within the surface pool is critical, because the import procedure needs to know which vertices in the surface pool, match up with which vertices in the mesh pool. In our example, the indices stored within the surface, reference the mesh pool vertices 3, 6, 8 & 12 respectively. This means that the vertex normal component, that will be written to the surface pool, should be stored in the same order, that is the normal
Copyright 2002 Daedalus Developments. All Rights Reserved. Page 63 of 92.

Interchangeable World Format v2.0

associated with vertex 3 followed by the normal associated with vertex 6, then vertex 8 and finally vertex 12. On import, this now allows us to step through both the indices, to determine the ordering and position of each vertex used within the surface, and also to obtain the additional vertex components associated with the surface, simply by stepping through the information stored within the surface pool. Although mixed pools are fairly complex in nature, especially when the import procedure is required to cater for any and all situations which may arise, the amount of space saved, when mixing vertex pools in this manner, is more often than not worth the additional effort required.
4.7.2. Vertex Arrangement

There are several ways of arranging vertices, within a surface, in order to both specify how a surfaces vertex information should be interpreted and also to ensure that the most efficient method possible is used for either storage or rendering purposes. Take a look at the following table which describes the flags which can be used in conjunction with the vertex component chunks VertexFlags variable.
Table 21. VertexFlag Definitions CHUNK_VERTEXCOMPONENTS Name VERTICES_NON_PLANAR Value 0x1 Description
Descriptor Flag: Specifies that the vertices contained within

this chunk cannot be guaranteed as being coplanar with one another. This flag can be combined with all other flags.
Primitive Type Flag: Specifies that there is no particular order

VERTICES_INDEXED

0x2

to the vertices stored, and that they can only be referenced by the indices contained within each surface.
Primitive Type Flag: The primitives specified by the vertices

VERTICES_TRISTRIP

0x4

in the following array utilise triangle strip ordering.


Primitive Type Flag: The primitives specified by the vertices

VERTICES_TRILIST

0x8

in the following array utilise triangle list ordering.


Primitive Type Flag: The primitives specified by the vertices

VERTICES_TRIFAN

0x10

in the following array utilise triangle fan ordering.


Primitive Type Flag: The primitives specified by the vertices

VERTICES_LINESTRIP

0x20

in the following array are lines, ordered in a continuous strip.


Primitive Type Flag: The primitives specified by the vertices

VERTICES_LINELIST

0x40

in the following array are lines, ordered into lists.


Primitive Type Flag: The primitives specified by the vertices

VERTICES_POINTLIST

0x80

in the following array are rendered as separate points.

As you can see, this table consists primarily of the various primitive types which are exposed through many of todays popular three-dimensional rendering pipelines such as the one provided by the Microsoft Direct3D API. In case you are not familiar with the vertex arrangements commonly associated with each of
Copyright 2002 Daedalus Developments. All Rights Reserved. Page 64 of 92.

Interchangeable World Format v2.0

these primitive types, the following examples show the ordering in which the vertices should be written and also how many are required for each type:
Figure 9a. VERTICES_TRILIST The diagram, shown to the left, demonstrates the primitive type known as the Triangle List. This type of primitive is quite literally a list of vertices, which describe each individual triangle that makes up the surface being rendered. The first triangle in this relatively simple diagram (depicted using red arrows) is made up of the vertices 0, 1 & 2, whilst the second (depicted using yellow arrows) is made up of vertices 3, 4 & 5. The reason why the vertices which share identical positions are shown with differing vertex numbers is due to the fact that when using a standard triangle list arrangement, all vertices making up each individual triangle are physically separated. This means that vertices 1/3 and 2/5 are actually four separate vertices within the list. When writing the triangle list we would write the vertices in the order 0, 1, 2, 3, 4, 5 as shown in the diagram, resulting in six distinct and separate vertices. Which vertex comes first when ordering the vertices within each triangle is largely unimportant, as long as the resulting triangles vertices can be said to be using a clockwise winding order when viewed from its Front (the direction in which the triangle / surface normal points). The number of triangles contained within a list of this type can be calculated simply using the formula (VertexCount / 3).

Figure 9b. VERTICES_TRIFAN This primitive type is commonly referred to as the Triangle Fan. Although, based on the first diagram shown to the left, it may not be entirely clear exactly where this primitive type gets its name; the diagram directly underneath however, shows an octagon and its resulting triangles, at which point the reason for its name should become abundantly clear. The individual triangles, described by any primitive arranged as a triangle fan, each fan out from, or more specifically share, a single vertex (depicted in both of these diagrams as vertex 0). Focusing on the upper diagram for the moment, we can see that this surface is made up of only four vertices, as opposed to the six required when using VERTICES_TRILIST. Although we are not explicitly providing two distinct triangles when writing the vertices for this surface, this primitive type still in fact describes a surface containing exactly two triangles. Because of the rules governing the arrangement of triangle fans, it can be assumed that the first of the three vertices which make up all triangles in the fan is that of the first vertex in the list (Vertex 0) and that every other vertex following, make up the second and third vertex of each triangle alternately. So, using these rules we can accurately determine that the first triangle is made up of vertices 0, 1 & 2 whilst the second triangle uses vertices 0, 2 & 3. In our second diagram, following the same rules, we know that the first triangle is made up of vertices 0, 1 & 2, the second using 0, 2 & 3 and so on up to the last triangle which makes use of vertices 0, 6 & 7. The number of triangles contained within a fan of this type can be calculated simply using the formula (VertexCount - 2). The vertices should be written in the order shown in the above diagrams. Copyright 2002 Daedalus Developments. All Rights Reserved. Page 65 of 92.

Interchangeable World Format v2.0

Figure 9c. VERTICES_TRISTRIP Triangle strips are in many ways similar to triangle fans, with the exception being that no single vertex is shared between all triangles. This in fact allows for much greater scope with regards the type of surface which can be described. Most 3D rendering applications today make wide use of triangle strips because they can be used to describe complex surfaces in such a way that is extremely memory and CPU / GPU efficient. In our first diagram, you can instantly see the difference between how fans and strips are ordered. Unlike fans however, when using this primitive type, we can in fact provide one long, continuous, strip of triangles where theoretically speaking, the length of the strip is only limited by the number of vertices allowed by the rendering API, and the accuracy afforded by single precision floating points. The triangle strip in our first diagram also only requires 4 individual vertices to describe the two triangles which make up the surface. One thing which you may have noticed however is the strange ordering of the second triangle, where the arrows would seem to be travelling in a counter clockwise direction, and in fact youd be absolutely correct. However, as with the triangle fan, there are various fixed rules, known by the rendering API, governing the arrangement of the triangles within the list. In our first diagram, the first triangle would be interpreted as 0, 1 & 2 as we would expect, however the second triangle uses the vertices in the order 1, 3 & 2 to ensure a clockwise winding order. There is of course a distinct pattern to the order of these vertices, which can be calculated using something along the lines of the following expanded code:
for ( int i = 0; i < VertexCount - 2; i++ ) { // Starting with triangle 0. // Is this an Odd or Even triangle if ( (i % 2) == 0 ) { TriVertex[0] = Vertices[i]; TriVertex[1] = Vertices[i + 1]; TriVertex[2] = Vertices[i + 2]; } // End if Even else { TriVertex[0] = TriVertex[1] = TriVertex[2] = triangle

Vertices[i]; Vertices[i + 2]; Vertices[i + 1];

} // End if Odd triangle // Render the triangle (clockwise ordering) RenderTriangle( TriVertex ); } // Next vertex

Test this out for yourself using the second diagram as a guide. The number of triangles contained within a strip of this type can be calculated simply using the formula (VertexCount - 2) as demonstrated in the above code. The vertices should be written in the order shown in the above diagrams.

Copyright 2002 Daedalus Developments. All Rights Reserved. Page 66 of 92.

Interchangeable World Format v2.0

There are four additional types shown in the above table which are not associated with triangle primitives. These are: Line Lists, Line Strips, Point Lists and the final IWF specific primitive type named VERTICES_INDEXED. The first of these, Line Lists, is used to describe a list of straight lines to be rendered by the import application as a wire-frame portion of the mesh for instance. Much like the triangle list, this primitive type requires a separate set of vertices for each line segment where, for example, rendering 10 lines requires 20 unique vertices (one start point and one end point for each line). As with Line Lists, Line Strips are similar in theory to the triangle strip primitive type where each line segment follows on from the last (the end point of one line is the start point of the next) where, for example, rendering 10 concurrent lines requires only 12 unique vertices. Finally, Point Lists simply describe a set of points to be rendered in whatever form is required, either for plotting individual pixels in world space, or for use as point sprites. These primitive types are used to instruct the import application on various aspects of the vertices stored within this vertex pool. Typically the primitive type itself is used to inform the rendering API about the order in which the vertices are being passed for rasterisation. This is especially useful in cases where, for example, indices are not available within the file, or are not required by the application itself. Although the previously mentioned primitive types are commonly used within surface vertex pools, used to describe each surface to be rendered, the mesh and global vertex pools on the other hand will usually be written using the remaining primitive type: VERTICES_INDEXED. Unlike the previous flags, which are common to most rendering APIs, this primitive type is defined by the IWF specification, and is used to inform the import procedure that the vertices contained within this vertex pool are in no particular order and can only be referenced by index. This flag is typically found here due to the fact that in many cases it is not possible, or desirable, to describe an entire mesh or global vertex pool using only a single primitive list (i.e. a single strip). In these cases, the mesh vertices are usually referenced using the indices stored within the individual surfaces of the meshes themselves. (For more information on providing indices refer to section 4.8. Vertex Indices) The very last bit which may be set within the VertexFlags variable, is the VERTICES_NON_PLANAR descriptor flag. As discussed in section 4.6. Polygon Data, it is the responsibility of the export procedure to inform the end user developer if the triangles described by the vertices within any individual vertex pool cannot be guaranteed to be entirely coplanar with one another. If this is the case, then this flag must be set within the vertex pool for which it applies. This affords the import application the chance to split the surfaces if required.

Copyright 2002 Daedalus Developments. All Rights Reserved. Page 67 of 92.

Interchangeable World Format v2.0

4.8. Vertex Indices


Type Identifier Name:

CHUNK_INDICES
Type Identifier Value:

0x0040(hex)
Restrictions:

Can be used as a child of CHUNK_SURFACES only. Only one instance of this child-chunk is allowed for each parent. Must only be written following the parents CHUNK_VERTEXCOMPONENT child, if any.

Recommendations:

None.
Standard Children:

None.
Data Area Layout:

Table 22a. Data Area Layout CHUNK_INDICES Name Type Size (In Bytes) TotalIndexCount unsigned long 4 SurfaceCount unsigned long 4

Section Repeated for N Iterations - N = SurfaceCount (var)

IndexCount IndexFlags VertexPool Indices

unsigned short unsigned char unsigned char (see Indices description)


End Repeat

2 1 1 (see Indices description)

Copyright 2002 Daedalus Developments. All Rights Reserved. Page 68 of 92.

Interchangeable World Format v2.0

Table 22b. Variable Descriptions CHUNK_INDICES Name TotalIndexCount Description Total number of indices, required by all surfaces, contained within this chunk. The total number of surfaces, whose indices are described by this chunk. The number of individual indices which are contained within the following Indices array for the current surface. Informs the application about which format the indices are provided, and also informs the import procedure about how large each individual index, stored within the Indices array, is. This variable must contain either 0, or exactly one element size flag and one primitive type flag. Specifies the type of vertex pool, into which the following indices are referencing (See both sections 4.7.1. Vertex Pools and 4.8.1. Index Values for more information) This array is either a 16 bit array, or a 32 bit array, based upon the values provided by the IndexFlag variable. In the former case, each index will be stored as an unsigned short and in the latter, each index in the array will be stored as an unsigned long. The size of this array, in bytes, is therefore dependant on the format of the array elements themselves and can be calculated using either: 2 * Surface::IndexCount (16bits) or 4 * Surface::IndexCount (32bits) Valid Values 0 0xFFFFFFFF

SurfaceCount

0 0xFFFFFFFF

IndexCount

0 - 65535

4.8.1. Index Values Refer to Table 23.

IndexFlag

4.7.1. Vertex Pools Refer to Table 20.

VertexPool

Indices

4.8.1. Index Values

Description:

The indices chunk stores various index values, referencing each individual vertex, contained within a surface, mesh, or global vertex pool, which may be used to make up the surface / polygon being described. Indices are extremely useful, not only for reducing the amount of overall storage space required for each surface (by allowing many surfaces to reference the same vertices), but also to allow primitive rendering to be optimised both internally by the API, and also the developer, simply by adjusting integer index values rather than manipulating the ordering of the vertices themselves. For more information on what values must be written into the Indices array, please refer to section 4.8.1. Index Values.

Copyright 2002 Daedalus Developments. All Rights Reserved. Page 69 of 92.

Interchangeable World Format v2.0

4.8.1. Index Values

In many of todays graphics rendering APIs there are several ways in which to arrange the vertices used to make up a single surface, as discussed in section 4.7.2. Vertex Arrangement. Although this topic was primarily written with regards vertex ordering, the same mechanism by which to provide the order interpreted by the import procedure also applies to indices. Take a look at the following table which describes the flags which can be used in conjunction with the index chunks IndexFlags variable:
Table 23. IndexFlags Definitions CHUNK_INDICES Name INDICES_NONE Value 0x0 Description This value alone is used should there be no indices written for this particular surface.
Element Size Flag: Each element within the Indices array is stored as a 16 bit, unsigned short integer value. This flag

INDICES_16BIT

0x1

can be combined with all other flags, with the exception of


INDICES_32BIT. Element Size Flag: Each element within the Indices array is stored as a 32 bit, unsigned long integer value. This flag

INDICES_32BIT

0x2

can be combined with all other flags, with the exception of INDICES_16BIT.
Primitive Type Flag: The primitives specified by the indices in

INDICES_TRISTRIP

0x4

the following array utilise triangle strip ordering.


Primitive Type Flag: The primitives specified by the indices in

INDICES_TRILIST

0x8

the following array utilise triangle list ordering.


Primitive Type Flag: The primitives specified by the indices in

INDICES_TRIFAN

0x10

the following array utilise triangle fan ordering.


Primitive Type Flag: The primitives specified by the indices in

INDICES_LINESTRIP

0x20

the following array are lines, ordered in a continuous strip.


Primitive Type Flag: The primitives specified by the indices in

INDICES_LINELIST

0x40

the following array are lines, ordered into lists.


Primitive Type Flag: The primitives specified by the indices in

INDICES_POINTLIST

0x80

the following array are rendered as separate points.

With the exception of the element size flags, the remaining primitive type definitions hold exactly the same meaning as those provided during the export of the CHUNK_VERTEXCOMPONENTS chunk. When put in the context of the indices array however, it is the order in which the vertices are referenced by the index values themselves (based on the primitive type set within the IndexFlags variable) which dictates the arrangement of the surface used for rendering, rather than the order in which the vertices are stored.

Copyright 2002 Daedalus Developments. All Rights Reserved. Page 70 of 92.

Interchangeable World Format v2.0

As discussed in the previous section, the values stored within the Indices array may be referencing vertices from one of three pools, either the Surface Pool, the Mesh Pool or the Global Pool. The pool being referenced can be determined by testing the value contained within the VertexPool variable. Each surface (of whose index information is stored within this chunk) may reference a different vertex pool independently. For example the first surface may well contain indices that reference any vertices that are stored within the vertex components chunk (CHUNK_VERTEXCOMPONENTS) stored as a child of the current surfaces chunk (CHUNK_SURFACES), whilst the second surface might reference the set of vertices stored as a child of a mesh (CHUNK_MESH).

Copyright 2002 Daedalus Developments. All Rights Reserved. Page 71 of 92.

Interchangeable World Format v2.0

4.9. Decal Meshes


Type Identifier Name:

CHUNK_DECALMESH
Type Identifier Value:

0x0021(hex)
Restrictions:

None.
Recommendations:

None.
Standard Children:

CHUNK_SURFACES CHUNK_MESH CHUNK_DECALMESH CHUNK_GROUP CHUNK_VERTEXCOMPONENTS

(Mesh Pool)

(Required) (Optional) (Optional) (Optional) (Optional)

Data Area Layout:

The layout of the decal mesh chunk is currently identical to that of the standard mesh chunk (CHUNK_MESH). The decal mesh is provided in a separate chunk to allow for both future enhancement, and to distinguish between the two types easily without having to step into the chunk and read. More component and style flags may be added in later revisions, however for information on the current layout of the CHUNK_DECALMESH data area, including all component and style flags, please refer to section 4.5. Object Meshes.
Description:

Decal meshes are essentially standard mesh chunks which are designed primarily to store surfaces used to build decals that are to be placed within the world. These decals could be anything ranging from explosion or scorch marks, to graffiti or logos. The IWF specification uses a mesh based layout for its decals to provide support for as many different types of system as possible, such as that required by clipped multi-surface decals.

Copyright 2002 Daedalus Developments. All Rights Reserved. Page 72 of 92.

Interchangeable World Format v2.0

4.10. Entities
Type Identifier Name:

CHUNK_ENTITY
Type Identifier Value:

0x0080(hex)
Restrictions:

None.
Recommendations:

None.
Standard Children:

None.
Data Area Layout: Table 24a. Data Area Layout CHUNK_ENTITY Type Size (In Bytes) unsigned short 2 unsigned char unsigned char (array) unsigned long MATRIX4 unsigned long unsigned char (array) 1 NameLength (var) 4 64 4 4 * DataSize (var)

Name EntityTypeID NameLength Name Reserved ObjectMatrix DataSize DataArea

Table 24b. Variable Descriptions CHUNK_ENTITY Name EntityTypeID Description This value is used to identify the type of entity stored within this chunk data area. The length, in bytes (not characters), of the string following this variable. The reference name associated with this material. No terminator is required however, should you include a terminator, the value stored within the NameLength variable must reflect the existence of this extra character. Valid Values 4.10.1 Standard Entity Types

NameLength

0 - 255

Name

Any valid, ANSI compatible, string no greater than 255 bytes in length.

Copyright 2002 Daedalus Developments. All Rights Reserved. Page 73 of 92.

Interchangeable World Format v2.0

Table 24b. Variable Descriptions CHUNK_ENTITY Name Reserved Description Four bytes of reserved data. This matrix describes how to transform the entity, from object space, into its parents object space. This matrix provides a relative transformation between the parent and this object. The length, in bytes, of the entity data area array directly following this variable. An array of bytes containing the data associated with the entity stored within this chunk. For more information on the data which may be stored within this array, please refer to section 4.10.1 Standard Entity Types Valid Values N/A

ObjectMatrix

Any valid transformation matrix (See 4.14. Coordinate System Information)

DataSize

4.10.1 Standard Entity Types

DataArea

As Above

Description:

Entities are the primary means by which to store non-mesh data objects for use within the scene. These objects can be anything, ranging from light sources, particle emitters, simple point locators, player / enemy spawn points, item positions and billboards through to script triggers, door buttons, object linkage, audio sample positioning, portal entry / exit points and much more. Although there are several standardised entity types defined within this specification, there are of course many more uses for entities than is realistic to set out here. For this reason, many entities stored within IWF files in real world applications will be custom entities, designed purely for the purposes of the application for which it was designed. Custom entities, much like custom chunks, have an EntityTypeID of 0x0200 or above. All identifier values of 0 through 0x01FF are reserved for standard entity types. For more information on the standardised entity types which are available, please refer to section 4.10.1. Standard Entity Types.
4.10.1 Standard Entity Types

There are relatively few standardised entity types contained within this specification due to the fact that most entities are extremely application specific. However, more entity types may be added to the specification in future revisions to allow a wider application base to share entity information. The following multi-use entity types are currently defined:
Table 25. EntityTypeID Definitions CHUNK_ENTITIES Name ENTITY_LIGHT Value 0x10 Description Light entities are used to describe each individual light source contained within the scene. See section 4.10.1.1. Lights for more information on this entity type.

Copyright 2002 Daedalus Developments. All Rights Reserved. Page 74 of 92.

Interchangeable World Format v2.0

Table 25. EntityTypeID Definitions CHUNK_ENTITIES Name Value Description Spawn points describe locations in space which can be used to spawn either player or non-player characters. They can also be used as spawn points for player items such as health packs or ammo. For more information on this entity type, see section 4.10.1.3. Spawn Point. Used simply to describe a simple point in space which can be referenced by name by external scripts for instance. See section 4.10.1.2. Simple Point for more information on this entity type.

ENTITY_SPAWN_POINT

0x30

ENTITY_SIMPLE_POINT

0x31

4.10.1.1. Lights

Light entities are provided by the specification due to the fact that lighting information is one of the primary components required to render most scenes correctly. By ensuring that this lighting information is provided using a standard format; cross-application file rendering support is made possible for scenes which do not use other means by which to represent that information (i.e. light maps). The structure of the data area for light entities is shown in the following table:
Table 26a. Structure Layout LIGHT_ENTITY Type Size (Bytes) Description long 4 The type of light being described by the following properties. Refer to Table 26b for more information. Light emits diffuse light based on this components colour values. Refer to 4.1.4. Palettes, Colours and Blend Modes. Light emits specular light based on this components colour values. Refer to 4.1.4. Palettes, Colours and Blend Modes. Light emits ambient light based on this components colour values. Refer to 4.1.4. Palettes, Colours and Blend Modes. The maximum distance from the light source position, to which the emitted light reaches. (Does not apply to directional lights) The falloff, or gradient of the light between a spot lights inner and outer cone. (Applies to spot lights only) Single component of the lights attenuation which is used to specify how the light intensity affects the scene over distance. (Does not apply to directional lights).

Name LightType

Diffuse

COLOUR_VALUE

16

Specular

COLOUR_VALUE

16

Ambient

COLOUR_VALUE

16

Range

float

FallOff

float

Attenuation0

float

Copyright 2002 Daedalus Developments. All Rights Reserved. Page 75 of 92.

Interchangeable World Format v2.0

Name Attenuation1 Attenuation2 Theta

Table 26a. Structure Layout LIGHT_ENTITY Type Size (Bytes) Description float 4 As Above float float 4 4 As Above Specifies the angle of the inner cone, relative to the light direction. (Applies to spot lights only) Specifies the angle of the outer cone, relative to the light direction. (Applies to spot lights only)

Phi

float

Table 26b. LightType Definitions LIGHT_ENTITY Name LIGHTTYPE_POINT Value 0x0 Description The entity is a point light source. The light is simply expressed by a position, and the light effects surfaces in all directions around it. The entity is a spot light source. This type of light can be thought of like a cone of light, extending outwards from a position in space. Much like a point light source, this light type has a position, but also specifies a directional cone which restricts the light to only an area which falls inside the lights cone. The entity is a directional light source. Directional lights are very much like point light sources, with the exception that: with point light sources, the direction is calculated between any vertex it affects, and the lights position. Directional light sources however essentially just specify the direction in which the light travels (which is the same direction used in the light calculation of all vertices), and has no position. Ambient light types are not commonly provided by todays popular rendering APIs, but are in fact defined within the specification as a means to define global ambient illumination within your scene (which can be used for different areas of the level), or for reference within a script or shader source.

LIGHTTYPE_SPOT

0x1

LIGHTTYPE_DIRECTIONAL

0x2

LIGHTTYPE_AMBIENT

0x3

As with all entities, an object matrix is provided which can specify position, scale and orientation among other things. Most light types require at least a position and often a direction in order to correctly describe the light source itself. With light entities, this information can be extracted from the object matrix itself. This matrix is a standard transformation matrix where the translation (in this case the position) can be extracted from the bottom row, and the direction can be extracted from the 3rd column. This is extraction is demonstrated in the following code:

Copyright 2002 Daedalus Developments. All Rights Reserved. Page 76 of 92.

Interchangeable World Format v2.0

// Extract Light Position pos.x = Matrix.val[3][0]; pos.y = Matrix.val[3][1]; pos.z = Matrix.val[3][2]; // Extract Light Direction dir.x = Matrix.val[0][2]; dir.y = Matrix.val[1][2]; dir.z = Matrix.val[2][2];

(For more information on matrices, please refer to sections 4.1.2. Matrices and 4.14. Coordinate System Information)
4.10.1.2. Simple Point

The simple point entity type can be used for anything from AI waypoints, to map reference points which are linked to distinguishable meshes for display within a mini-map for instance. Although technically the information provided by this entity type does not extend much further than a simple position, reference name, and a list of items to which it is linked; scripts can easily reference these points by name for use within any process or algorithm that is required. The following structure outlines the layout of the SIMPLE_POINT entitys data area:
Table 27a. Structure Layout SIMPLE_POINT Type Size (In Bytes) unsigned char 1
Section Repeated for N Iterations - N = LinkCount (var)

Name LinkCount

NameLength Name

unsigned char unsigned char (array)


End Repeat

1 NameLength (var)

Table 27b. Variable Descriptions SIMPLE_POINT Name LinkCount Description The number of linked reference names contained within this entity data area. The length, in bytes (not characters), of the string following this variable. The reference name to which this simple point locator is associated. No terminator is required however, should you include a terminator, the value stored within the NameLength variable must reflect the existence of this extra character. 0 - 255 Valid Values

NameLength

Name

Any valid, ANSI compatible, string no greater than 255 bytes in length.

Copyright 2002 Daedalus Developments. All Rights Reserved. Page 77 of 92.

Interchangeable World Format v2.0

4.10.1.3. Spawn Point

The spawn point entity is used to provide the application with locations and orientations of objects and characters which must be spawned within the scene. These objects could be anything ranging from health pack or ammo items, to waves of enemy NPCs spawned in for the player to repel. These spawn points reference objects either by name, or by providing a script which is triggered at level start-up or optionally, if a respawn period is provided, each time the amount of milliseconds specified has elapsed. As with light entities, the entity object matrix is used to specify the location, orientation and optionally scale of the object being spawned. The following structure outlines the layout of the SPAWN_POINT entitys data area:
Table 28a. Structure Layout SPAWN_POINT Type Size (In Bytes) unsigned short 2 unsigned long unsigned long unsigned char (optional) (optional) 4 4 1 NameLength (var) 8 + SCRIPT_REF::ScriptSize

Name SpawnType Components RespawnTime RefNameLength RefName Script

unsigned char (array) (optional) SCRIPT_REF (optional)

Table 28b. Variable Descriptions SPAWN_POINT Name SpawnType Description The type of spawn point being described by this chunks data area. Stores either 0, or a combination of one or more of the flags specified in Table 28d. These flags describe which components are included within the file, for this particular spawn point. The recurring time period, in milliseconds, at which this entity will respawn the associated object. The length, in bytes (not characters), of the string following this variable. The reference name associated with this spawn point, allows the application to determine which object should be spawned. No terminator is required however, should you include a terminator, the value stored within the RefNameLength variable must reflect the existence of this extra character. A script, if any, which should be triggered when the object is spawned. Valid Values Refer to Table 28c.

Components

Refer to Table 28d.

RespawnTime

0 0xFFFFFFFF

RefNameLength

0 - 255

RefName

Any valid, ANSI compatible, string no greater than 255 bytes in length.

Script

4.1.5. Scripts, Shaders and Effect Files

Copyright 2002 Daedalus Developments. All Rights Reserved. Page 78 of 92.

Interchangeable World Format v2.0

Table 28c. SpawnType Definitions SPAWN_POINT Name Value Description This spawn point specifies that the referenced object / script should be respawned / triggered every time the number of milliseconds, specified by the RespawnTime variable, has passed. Can be combined with all other flag types (The remaining flags are mutually exclusive). The spawn point is a single player spawn point. The spawn point is a multiplayer spawn point. The spawn point references a non player character spawn point (NPC). The type of character spawned may be referenced by name, or by specifying a script. The spawn point references an item, i.e. health or ammo. The type of item to be spawned may be referenced by name, or by specifying a script.

SPAWNTYPE_RESPAWNABLE

0x1

SPAWNTYPE_SINGLEPLAYER SPAWNTYPE_MULTIPLAYER

0x2 0x4

SPAWNTYPE_NON_PLAYER

0x8

SPAWNTYPE_ITEM

0x10

Table 28d. Components Definitions SPAWN_POINT Name SPCOMPONENT_RESPAWN Value 0x1 Description If this bit is set, the RespawnTime variable is available and should be read by the import application. If this bit is set, both the RefNameLength variable and RefName array are available and should be read by the import application. If this bit is set, the Script variable is available and should be read by the import application. The definition which contains all currently defined component bits set to 1. This flag is provided convenience purposes only.

SPCOMPONENT_REFNAME

0x2

SPCOMPONENT_SCRIPT

0x4

SPCOMPONENT_ALL

0x7

Note: This entity data area utilises the component mechanism set out in section 4.1.6. Object Component Architecture, whereby individual components may be discarded to save space within the output file if those components are deemed to be redundant.

Copyright 2002 Daedalus Developments. All Rights Reserved. Page 79 of 92.

Interchangeable World Format v2.0

4.11. Materials
Type Identifier Name:

CHUNK_MATERIALS
Type Identifier Value:

0x0090(hex)
Restrictions:

Strictly one instance of this chunk per file. Must be written at the root hierarchy level (i.e. cannot be used as a child). Must be written prior to any chunk types which may reference materials stored here.

Recommendations:

None.
Standard Children:

None.
Data Area Layout: Table 29a. Data Area Layout CHUNK_MATERIALS Type Size (In Bytes) unsigned long 4

Name MaterialCount

Section Repeated for N Iterations - N = MaterialCount (var)

NameLength Name Diffuse Ambient Emissive Specular Power

unsigned char unsigned char (array) COLOUR_VALUE COLOUR_VALUE COLOUR_VALUE COLOUR_VALUE float
End Repeat

2 NameLength (var) 16 16 16 16 4

Table 29b. Variable Descriptions CHUNK_MATERIALS Name MaterialCount Description The total number of individual material entries contained within this chunk. The length, in bytes (not characters), of the string following this variable. Valid Values 0 0xFFFFFFFF

NameLength

0 - 255

Copyright 2002 Daedalus Developments. All Rights Reserved. Page 80 of 92.

Interchangeable World Format v2.0

Table 29b. Variable Descriptions CHUNK_MATERIALS Name Description The reference name associated with this material. No terminator is required however, should you include a terminator, the value stored within the NameLength variable must reflect the existence of this extra character. The diffuse material component which describes how the surface to which it is applied reflects diffuse light. The ambient material component which describes how the surface to which it is applied reflects ambient light. The emissive material component which describes the colour of the light that is emitted from the surface to which it is applied. The specular material component which describes how the surface to which it is applied reflects specular light. Specifies the sharpness of the specular highlights. This value must be 0 to disable specular highlights. Valid Values

Name

Any valid, ANSI compatible, string no greater than 255 bytes in length.

Diffuse

4.1.4. Palettes, Colours and Blend Modes

Ambient

As Above

Emissive

As Above

Specular

As Above

Power

0 FLOAT_MAX

Description:

Materials are often used in most rendering applications to describe how the light, contained within the scene, is reflected by any surface to which it may be applied. Diffuse light is by far the most common type of light found to be reflected by surfaces both within the real world, and within scenes designed for rendering in most of todays interactive multimedia applications. There are several types of material component which can be specified, that interact with the various types of light sources contained within the scene. The first such property is the diffuse component which reflects light that is often scaled based on both the angle between the surface normal and the light source, and also the distance between the two. The second property is the ambient component, which does not generally take into account range or angle of incidence, and is commonly used to set the base brightness, colour and, artistically speaking, the overall ambient mood of the scene. The emissive component differs from the other properties due to the fact that it does not generally specify how light is reflected, but does in fact specify the colour of the light emitted by the surface. When used in conjunction with standard vertex lighting however, this surface does not physically become a light source in itself (that is, other surfaces do not receive this emitted light) but can essentially be used to create objects which appear to glow in the dark even where no light source is currently within range. The last property is the specular component. This commonly interacts with any specular light emitted by any light sources within
Copyright 2002 Daedalus Developments. All Rights Reserved. Page 81 of 92.

Interchangeable World Format v2.0

range, and appears to make the surface shiny by lightening the resulting colour, at each vertex, based upon the position and direction of the world camera. This process can be relatively computationally expensive when compared with other, fake, texture based specular map solutions and therefore is not widely used in many of todays rendering applications. However, with the wide scale introduction of accelerated transformation and lighting hardware, specular vertex lighting is becoming an increasingly viable option. Many surfaces stored within the file may reference one or more individual materials, stored within this chunk, by providing a zero-based index value relative to the first material stored here. Additional unreferenced materials may also be stored here should the need arise, allowing user materials to be retained within an editing system for instance, for use during the next session.

Copyright 2002 Daedalus Developments. All Rights Reserved. Page 82 of 92.

Interchangeable World Format v2.0

4.12. Textures
Type Identifier Name:

CHUNK_TEXTURES
Type Identifier Value:

0x00A0(hex)
Restrictions:

Strictly one instance of this chunk per file. Must be written at the root hierarchy level (i.e. cannot be used as a child). Must be written prior to any chunk types which may reference textures stored here.

Recommendations:

None.
Standard Children:

None.
Data Area Layout:

Name TextureCount

Table 30a. Data Area Layout CHUNK_TEXTURES Type Size (In Bytes) unsigned long 4

Section Repeated for N Iterations - N = TextureCount (var)

TextureSource NameLength Name TextureFormat TextureSize TextureData

unsigned char unsigned short unsigned char (array) unsigned char unsigned long unsigned char (array)
End Repeat

1 2 NameLength (var) 1 4 TextureSize (var)

Copyright 2002 Daedalus Developments. All Rights Reserved. Page 83 of 92.

Interchangeable World Format v2.0

Table 30b. Variable Descriptions CHUNK_TEXTURES Name TextureCount Description The total number of individual texture entries contained within this chunk. A combination of one or more of the flags set out in Table 30c. Specifies how the following variables should be interpreted and where the texture should be loaded from. The length, in bytes (not characters), of the string following this variable. If TEXTURE_EXTERNAL is specified within TextureSource, this variable contains the external filename by which to identify the texture. If TEXTURE_INTERNAL is specified then this variable contains any arbitrary reference name which can be used to identify this texture. No terminator is required however should you include a terminator the value stored within the NameLength variable must reflect the existence of this extra character. Specifies the format of the internal texture data, if any, stored within the following variables. The length, in bytes of the TextureData array (if any) directly following this variable. If the TEXTURE_INTERNAL source flag is specified, this array will contain physical texture data, written in the format specified by the TextureFormat variable. Valid Values 0 0xFFFFFFFF

TextureSource

TEXTURE_EXTERNAL TEXTURE_INTERNAL

NameLength

0 - 65535

Any valid, ANSI compatible, string no greater than 65535 bytes in length. If TEXTURE_EXTERNAL is specified, this must be a valid texture filename (which may include a relative path if required).

Name

TextureFormat

Refer to Table 30d.

TextureSize

0 0xFFFFFFFF

TextureData

See Chunk Description.

Name

Table 30c. TextureSource Definitions CHUNK_TEXTURES Value Description 0x1 The Name array contains an external resource or file name used to reference the texture file. This flag cannot be combined with TEXTURE_INTERNAL. The TextureData array contains the physical texture data itself. This flag cannot be combined with TEXTURE_EXTERNAL.

TEXTURE_EXTERNAL

TEXTURE_INTERNAL

0x2

Copyright 2002 Daedalus Developments. All Rights Reserved. Page 84 of 92.

Interchangeable World Format v2.0

Table 30d. TextureFormat Definitions CHUNK_TEXTURES Name Value Description TEXFORMAT_RAW 0x1 The texture data contained within the TextureData array is formatted as a simple raw, uncompressed image. The TextureData array contains a custom data file the format of which is defined by the end user developer. Textures of this format should be ignored by any application which does not have strict control over the source of the input file. Windows or OS/2 Bitmap (BMP) JPEG JFIF Compilant (JPG) Truevision Targa (TGA) Portable Network Graphics (PNG) ZSoft Paintbrush (PCX) Compuserve Graphics Interchange (GIF) Photoshop (PSD) Tagged Image File Format (TIFF) Portable Pixelmap (PPM)

TEXFORMAT_CUSTOM

0x2

TEXFORMAT_BMP TEXFORMAT_JPEG TEXFORMAT_TGA TEXFORMAT_PNG TEXFORMAT_PCX TEXFORMAT_GIF TEXFORMAT_PSD TEXFORMAT_TIFF TEXFORMAT_PPM

0x3 0x4 0x5 0x6 0x7 0x8 0x9 0xA 0xB

Description:

Textures are often applied to surfaces within the scene to give the impression that those surfaces are detailed. Imagine a scenario where we could not use textures, and yet we wanted our scene to contain a relatively highly detailed brick wall. In this case, not only would the level designer be required to model each individual brick within the wall, but anything even remotely adventurous such as deformed or rough bricks would send the scene polygon count through the roof and consequently, our applications frame rate through the floor. If however we were to apply a brick texture to all of the walls in our scene, we can in fact get away with applying it to a single flat polygon, giving the appearance of a highly detailed scene, even where extremely low polygon counts must be enforced. The textures chunk contains the physical texture data or more commonly, external references to, all of the textures used by the surfaces within the scene. Many surfaces stored within the file may reference one or more individual textures, stored within this chunk, by providing a zero-based index value relative to the first texture stored here. As mentioned, each texture stored within this chunk may contain the physical texture data itself. This data may range from a raw uncompressed image format to internal storage of physical files such as the common Windows Bitmap, by specifying the appropriate texture format flag. The layout of the raw image data which may be stored within this chunk is very similar to the format described in the section 4.3.1. Palettes and Image Data Formatting, with the exception that within this context, you are also allowed to specify a 32 bit pixel format, which used the byte ordering: Alpha, Red, Green and Blue respectively. In addition, custom file or data structures may be
Copyright 2002 Daedalus Developments. All Rights Reserved. Page 85 of 92.

Interchangeable World Format v2.0

stored within each texture element, simply by specifying the TEXFORMAT_CUSTOM flag within the TextureFormat variable. More commonly however, developers will write out texture data in one of the common graphics file format specified in Table 30d. In this instance, it is recommended that the TextureFormat variable contain the associated TEXFORMAT_* flag to inform the import procedure in which format the texture data is stored, so that it can be loaded without having to determine this in advance. Although internal storage of texture data would not commonly be used within a large scale gaming application, where many textures may be shared between individual level files; the ability to store textures in this manner is ideal for scenes which contain and utilise associated light maps, and can also prove to be a huge advantage for the simple, rapid deployment of single file demonstrations scenes.

Copyright 2002 Daedalus Developments. All Rights Reserved. Page 86 of 92.

Interchangeable World Format v2.0

4.13. Shaders
Type Identifier Name:

CHUNK_SHADERS
Type Identifier Value:

0x00B0(hex)
Restrictions:

Strictly one instance of this chunk per file. Must be written at the root hierarchy level (i.e. cannot be used as a child). Must be written prior to any chunk types which may reference shaders stored here.

Recommendations:

None.
Standard Children:

None.
Data Area Layout:

Name ShaderCount

Table 31a. Data Area Layout CHUNK_SHADERS Type Size (In Bytes) unsigned long 4
Section Repeated for N Iterations - N = ShaderCount (var)

Components VertexShader PixelShader

unsigned long SCRIPT_REF SCRIPT_REF (optional) (optional)


End Repeat

4 4 4

Table 31b. Variable Descriptions CHUNK_SHADERS Name Description Stores either 0, or a combination of one or more of the flags specified in Table 31c. These flags describe which components are included within the file, for this particular shader. A script reference structure which specifies a vertex shader to be used for this surface rendering pass. Valid Values

Components

Refer to Table 31c.

VertexShader

4.1.5. Scripts, Shaders and Effect Files

Copyright 2002 Daedalus Developments. All Rights Reserved. Page 87 of 92.

Interchangeable World Format v2.0

Table 31b. Variable Descriptions CHUNK_SHADERS Name PixelShader Description A script reference structure which specifies a pixel shader to be used for this surface rendering pass. Valid Values As Above

Name

Table 31c. Components Definitions CHUNK_SHADERS Value Description 0x1 0x2 If this bit is set, the VertexShader variable is available and should be read by the import application. If this bit is set, the PixelShader variable is available and should be read by the import application.

SHCOMPONENT_VSHADER SHCOMPONENT_PSHADER

Description:

Shader files are becoming an important part of todays rendering applications. With support for shaders becoming more prevalent in hardware, they are now becoming a viable option for developers. This chunk stores a list of all of the pixel and vertex shaders used by any surface stored within the file. Many surfaces stored within the file may reference one or more individual shader element, stored within this chunk, by providing a zero-based index value relative to the first element stored here. Additional unreferenced shaders may also be stored here should the need arise, allowing user shaders to be retained within an editing system for instance, for use during the next session.

Copyright 2002 Daedalus Developments. All Rights Reserved. Page 88 of 92.

Interchangeable World Format v2.0

4.14. Coordinate System Information


Type Identifier Name:

CHUNK_COORDSYSINFO
Type Identifier Value:

0x00C0(hex)
Restrictions:

Strictly one instance of this chunk per file. Must be written at the root hierarchy level (i.e. cannot be used as a child). Must be written prior to any vertex data stored within the file.

Recommendations:

None.
Standard Children:

None.
Data Area Layout: Table 32a. Data Area Layout CHUNK_COORDSYSINFO Name Type Size (In Bytes) CoordSysMatrix MATRIX4 64 WindingOrder unsigned char 1

Table 32b. Variable Descriptions CHUNK_COORDSYSINFO Name Description A transformation matrix which can be used by an external application to transform vertices, normals and matrices from the coordinate system used to write these components, into the standard left handed Cartesian coordinate system. The vertex order, used by the surfaces stored within the file, in which the vertices wind. The winding order specified within this variable describes which side of any particular surface is said to be the front. Valid Values

CoordSysMatrix

See Chunk Description.

WindingOrder

WINDING_CCW WINDING_CW

Copyright 2002 Daedalus Developments. All Rights Reserved. Page 89 of 92.

Interchangeable World Format v2.0

Description:

To provide inter-application compatibility, the interchangeable world format is primarily based around the left handed Cartesian coordinate system (as used by Microsoft Direct3D by default) for storage of mesh vertex data. However, there are cases when this can be extremely restrictive where alternative coordinate systems may be required. Forcing an application to read and write data using a non native coordinate system can place an unnecessary load on the import / export procedures, which would consequently be required to convert between the two coordinate systems on the fly. For this reason, it is in fact possible to store the scene data using any arbitrary coordinate system, such as the right handed Cartesian coordinate system used by OpenGL, as long as the application which exports this file also writes the CHUNK_COORDSYSINFO chunk. This chunk provides any external application with information about the coordinate system in which various components within the file are expressed, such as vertex positions, surface and vertex normals and the various object matices. The following example demonstrates the values which would be stored within the CoordSysMatrix variable to convert between a right and left handed coordinate system (i.e. between OpenGL and Direct3D).
Table 33. Example Matrix CHUNK_COORDSYSINFO val[0][*] val[1][*] val[2][*] val[3][*] val[*][0] 1 0 0 0 val[*][1] 0 1 0 0 val[*][2] 0 0 -1 0 val[*][3] 0 0 0 1

The above matrix is essentially a standard identity matrix, with the exception that the matrix element [2][2] is negated. This has the effect of swapping the sign of the Z component of any vector that is transformed using these values. As mentioned earlier, it is of great importance to note that each matrix stored within the IWF, including the coordinate system matrix, are Row Major. Bearing in mind that the numbering system used for referencing elements in an array is zero based, Row Major means that when we are referring to an individual row or column within the matrix, for example third column across, second row down, we are in fact referencing the array element [1][2] (i.e. [Row][Column]). This means that even where the coordinate system information chunk is written, all matrices within the file should still use row major ordering. If the export application stores matrices designed for use in OpenGL for example, whose matrices are column major; these matrices must be re-ordered during the physical export of any object matrix. On import, if this chunk has been written, the application would transform all vertex coordinates, normals and matrices, using the CoordSysMatrix stored here, to convert that information to the base right handed coordinate system before processing. In addition the WindingOrder variable must be taken into account should the vertex winding order need to be adjusted for use during rendering. Note: This chunk need not be written if the default coordinate system is adopted.
Copyright 2002 Daedalus Developments. All Rights Reserved. Page 90 of 92.

Interchangeable World Format v2.0

4.15. Standard Chunk Arrangements

The following diagram serves as a reference table for common arrangements of the standard chunks specified within this standards document. Although not all combinations are contained within this table, additional information about which chunks can be used as a child of which other chunks, can be found underneath the Standard Children header of each individual chunks reference section.

4.16. Application Compliance

There are many different factors which contribute to how specification compliant the import application is required to be. Although the IWF specification provides many varied ways of storing and interpreting world data, an application need only implement a minor subset of the standard assuming that no support is required for third party files. As an example, the IWF structure may be used by an editing application, to export mesh data in a particular fixed manner. If the associated rendering application is only required to support files exported by that editor, then full specification compliance will not be required.

Copyright 2002 Daedalus Developments. All Rights Reserved. Page 91 of 92.

Interchangeable World Format v2.0

5. IWF File Toolkit Version 2.0 Not yet finalised in this document revision. Please refer to intermediate source code included for current beta toolkit information.

Copyright 2002 Daedalus Developments. All Rights Reserved. Page 92 of 92.

Das könnte Ihnen auch gefallen