In the previous post I described the overall structure of the .wdb file format, including the file header, the collision fence and the scene node hierarchy. This time I will go into the VCGeometry structure.
Structure VCGeometry
numPoints As UInt16 'number of 3D points in this geometry
points() As VCPoint 'series of numPoints VCPoint structures
numNormals As UInt16 'number of normals in this geometry
normals() As VCNormal 'series of numNormals VCNormal structures
numPolygons As UInt16 'number of polygons in this geometry
lenIFS As UInt16 'number of bytes in the Indexed Face/Line Set
polyDefs() As VCPolyDef 'series of numPolygons VCPolyDef structures
finalIFS As UInt16 'final word of Indexed Face/Line Set (always 0000)
w6 As UInt16 'render flags
texCoords() As VCTexCoord 'series of numPoints texture coordinates
ffs() As VCFFFlags 'series of numPoints 4-byte flag sets
numTexDefs As Byte 'number of texture definitions to follow
texDefs() As VCTexDef 'series of numTexDefs VCTexDef structures
materials() As UInt16 'series of numPolygons material indices
End Structure
The VCGeometry starts by defining a list of numPoints 3D points, held in the file as a series of VCPoint structures:
Structure VCPoint
x As Single
y As Single
z As Single
End Structure
Next comes a list of numNormals 3D vectors, held in the file as a series of VCNormal structures:
Structure VCNormal
x As Single
y As Single
z As Single
End Structure
The geometry is defined in the form of an Indexed Face Set, though a later flag allows the same data to be interpreted as an Indexed Line Set. The following description assumes the IFS mode.
numPolygons defines how many polygons (or line segments) are defined in the IFS. The lenIFS value is the length of the IFS table in bytes, allowing for faster parsing of the file (i.e. removing the need to unpack the whole IFS to find its end, for example allowing the correct amount of memory to be allocated before reading the IFS.
Structure VCPolyDef
numVerts As UInt16 'number of vertices in this polygon
vertices() As UInt16 'series of numVerts indices into points table
normals() As UInt16 'series of numVerts indices into normals table
End Structure
Each VCPolyDef structure defines a single polygon as a series of indices into the points() and normals() lists. The normals are therefore vertex normals – the renderer calculates face normals from the point data (points are in clockwise order when viewing the front of the face).
A zero word always follows the IFS.
The next word (w6) is at least partially a mystery. Across the set of published .wdb files this adopts one of four values: 0, 256, 768 or 1024.
w6=0 is he rarest, coinciding with “wirexx” nodes in the tabletop and lunarislands worlds (for the flower stems and walkway red edges respectively). This indicates that the geometry data should be rendered as an indexed line set.
w6=256 is by far the most common value. This seems to coincide in all cases with geometry that has a texture image.
w6=768 is used in VCGeometry nodes in outerworld, mall, lodge, lobby, homespace, hutchspace, hanami, and cartooncity and seems to be associated with flat-shaded geometry that does not use a texture image, though this is to be confirmed.
w6=1024 is used in VCGeometry nodes in compass, eurostadium, fishbowl, hanami, help, kivaunderground, lavalovelounge, littlehouse, lunarislands, nshof, paradiseisland and tabletop and appears to be associated with smooth-shaded objects that do not use texture images – again to be confirmed.
In practice, these last two values determine whether vertex normals or computed face normals are used by the renderer.
Texture coordinates are defined in texCoords(), which is a list of numPoints VCTexCoord structures. Each holds a (u,v) texture coordinate:
Structure VCTexCoord
u As Single 'normalised and scaled texture u coordinate
v As Single 'normalised and scaled texture v coordinate
End Structure
These are normalised and scaled to repeat the texture in both u- and v-directions.
The texCoords are followed by four bytes of &HFF.
Textures and materials are defined by a series of numTexDefs VCTexDef structures. These define an RGB colour, most also include the name of a texture image, and there are a couple of other bytes which have an unknown function:
Structure VCTexDef
txBlue As Byte 'face colour (blue component)
txGreen As Byte 'face colour (green component)
txRed As Byte 'face colour (red component)
txb3 As Byte 'unknown function, always &HFF
txName As String 'file name of texture image
txb4 As Byte 'unknown function
End Structure
txb4 is either &H00 or &H01. The &H01 value occurs much less often and only for (all) VCTexDef structures in cartooncity, hanami and lodge. They include VCTexDefs both with and without texture images, and include animated and non-animated items, so the purpose of this remains unclear. My guess at present is that this flags textures or materials that are not subject to lighting – more on this later.
Next comes a list of numPolygons material indices defining which material should be applied to each polygon. There is an oddity here in that numTexDefs is a Byte, but the members of materials() are UINT16. These nearly always range between 0 and 4, but there are a small number of entries in lodge that have the value 256 (associated with the wooden pillars). This indicates that perhaps the lower order byte identifies the material and the high order byte contains flags of unknown purpose.
That concludes the VCGeometry structure. Next time VCLight.