-
Notifications
You must be signed in to change notification settings - Fork 12
DZB File Format (Collision)
pho edited this page Jan 13, 2014
·
5 revisions
This is a dump of Sage of Mirrors and I's experimental work in reading DZB Files. Putting it here until I get time to re-write it properly. Some information is incorrect/oudated. Sorry!
Fun Fact: DZB probably stands for "Zelda Butsukaru Data", where Butsukaru is Romaji for Bump Into/Collide With.
/*-------------------------------------------------------------------------
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
Version 2, December 2004
Copyright (C) 2004 Sam Hocevar <[email protected]>
Everyone is permitted to copy and distribute verbatim or modified
copies of this license document, and changing it is allowed as long
as the name is changed.
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. You just DO WHAT THE FUCK YOU WANT TO.
--------------------------------------------------------------------------*/
#ifndef DZBFORMAT_H
#define DZBFORMAT_H
#include "datatypes.h"
#include "geometry.h"
#include <intrin.h>
//-------------------------------------------------------------------------
// Length: 2 bytes
//
//
// Description:
// Discovered thanks to Sage of Mirror causing Wind Waker to throw
// an exception while he was modifying *.dzb files. Credit goes to
// Devbug for the final piece of the puzzle.
//
// SpatialList_t::Index is an index into the Face_t array. It it
// goes through a form of compression, resulting in a pseudo triangle
// strip. You look at the SpatialList_t array as pairs and take
// the delta between the next index and the current. This gives
// you the number of Face_t triangles to draw starting at
// the current index and drawing up that many. Then you go onto
// the next pair.
//
// Purpose:
// Until custom collision files are working in game there is no
// definite purpose for this. It appears to be that each pair
// of indexes specifies a small group of triangles which never
// repeat and are grouped together physically.
//-------------------------------------------------------------------------
struct SpatialList_t
{
U16 Index;
inline void Byteswap()
{
Index = _byteswap_ushort(Index);
}
};
//-------------------------------------------------------------------------
// Purpose: Unknown struct. Length: 14 bytes
// Appears to be related to the SpatialList_t
//-------------------------------------------------------------------------
struct FaceGroupData_t
{
U16 Type; //Either 01 01 or 01 00 - "Data" or "Guides"
U16 Unknown2; //Appears to be a "group" identifier for both 01 01 and 01 00 groups. Marking them as zero doesn't seem to crash the game! //On "Data" it's used to group FaceGroupData_t's together. Can be completely 00'd out and doesn't seem to break. Sweet!
U16 SpatialListIndex; //For a 01 01 entry, this is the index into the Spatial List of which triangle it is.
U16 Unknown4;
U16 Unknown5;
U16 Unknown6;
U16 Unknown7;
U16 Unknown8;
U16 Unknown9;
U16 Unknown10;
inline void Byteswap()
{
Unknown1 = _byteswap_ushort(Unknown1);
Unknown2 = _byteswap_ushort(Unknown2);
Unknown3 = _byteswap_ushort(Unknown3);
Unknown4 = _byteswap_ushort(Unknown4);
Unknown5 = _byteswap_ushort(Unknown5);
Unknown6 = _byteswap_ushort(Unknown6);
Unknown7 = _byteswap_ushort(Unknown7);
Unknown8 = _byteswap_ushort(Unknown8);
Unknown9 = _byteswap_ushort(Unknown9);
Unknown10 = _byteswap_ushort(Unknown10);
}
};
//-------------------------------------------------------------------------
// Length: 16 bytes
//
//
// Description:
// Discovered by Sage of Mirrors. The following byte patterns are known:
//
// 07 FF xx FF 00 yy yy FF FF FF FF 00 00 00 00 00
//
// Where "xx" defines the walking sound effect (water, sand, etc.)
// and item interaction (sword collision, arrows, etc.)
//
// yy yy defines collision type. Known values:
// 03 10 Results in Link sliding down a slope, but still standing.
//
// Purpose:
// Defines the surface property of each triangle. The way these
// are indexed is not entirely known at this time.
//-------------------------------------------------------------------------
struct SurfaceProperty_t
{
U16 Unknown1;
byte hitEffect; //See "xx" above
byte Unknown2;
U16 collisionType; //See "yy yy" above
U16 Unknown3; //FF FF
U16 Unknown4; //FF FF
U16 Unknown5; //Sometimes Different
U16 Unknown6;
U16 Unknown7;
inline void ConvertToLE()
{
Unknown1 = _byteswap_ushort(Unknown1);
collisionType = _byteswap_ushort(collisionType);
Unknown3 = _byteswap_ushort(Unknown3);
Unknown4 = _byteswap_ushort(Unknown4);
Unknown5 = _byteswap_ushort(Unknown5);
Unknown6 = _byteswap_ushort(Unknown6);
Unknown7 = _byteswap_ushort(Unknown7);
}
};
//-------------------------------------------------------------------------
// Length: 10 bytes
//
//
// Description:
// 3 indexes into the Vertex array, followed by two indexes into
// what is theorized as the Type_t array. The values are never the
// same, and on simple maps Unknown1 will be "0" for every entry,
// while in the same map Unknown2 points from anything from 1-5.
//
// Purpose:
// Appears to link triangles to information about the surface type.
//-------------------------------------------------------------------------
struct Face_t
{
U16 verts[3];
U16 SurfacePropertyIndex;
U16 StringGroupIndex; //Can be any value with no ill effects. Seems to just be used by Nintendo's tool to easily map to which String Group it is but isn't used by the game.
inline void Byteswap()
{
verts[0] = _byteswap_ushort(verts[0]);
verts[1] = _byteswap_ushort(verts[1]);
verts[2] = _byteswap_ushort(verts[2]);
SurfacePropertyIndex = _byteswap_ushort(SurfacePropertyIndex);
StringGroupIndex = _byteswap_ushort(StringGroupIndex);
}
};
//-------------------------------------------------------------------------
// Purpose: Appears to define properties about the surface material.
// Length: 52 bytes.
//-------------------------------------------------------------------------
struct StringGroup_t
{
//Offset from start of file. This contains Romanji names for objects, things like
//"floor" "wall" "water" "surfacePoly" etc. My guess is these were the original
//names in Nintendo's editor and can be reused to re-create them in the OBJ.
U32 nameOffset;
//This value is 1,1,1 for every Type_t on some maps, or ~94% of them on others
//When the map does have some non-1,1,1 the values normally range between 0.5 and 2
Vector3 Scale; //Unknown1 might be a scale, but doesn't make a lot of sense.
U16 Unknown1;
U16 Unknown2;
U16 Unknown3;
U16 Padding;
//This value is 0,0,0 for every Type_t on some maps, or ~98% of them on others
//When the map does have some non-0,0,0 the values range between -5000 and 5000
Vector3 Translation;
/*
7:05 PM - Zeal of 12000BC: "Top/Upper level" = string group entries with no actual faces assigned to them
7:06 PM - Zeal of 12000BC: "Bottom/Lower level" = string groups with faces assigned to them */
U16 ChildOf; //Ex: Child of Entry 0, Sibling of Entry 3, Parent of Entry 32
U16 SiblingOf; //These are indexes into other Type_t groups. If it doesn't
U16 ParentOf; //have one then it's a null byte (FF FF)
U16 Unknown8; //Seem to always be FF FF - Padding
U16 Unknown9; //Possibly a Flags Field? Seems to not do anything, maybe it's something else for Nintendo's tools.
/*
7:06 PM - Zeal of 12000BC: The faces are assigned through a 01 00 entry, whose index is given in the two bytes at 46 dec
7:07 PM - Zeal of 12000BC: The 01 00 entry in turn has the indicies of all the 01 01 entries that, IN TURN, give the indicies of the appropriate spatial list faces
7:08 PM - Zeal of 12000BC: It looks like sometimes the 01 00 entries might give the index of another 01 00 entry, but I'm not sure if that's a fact*/
U16 FaceGroupIndex;
//Either 256, 'Default' is 0
U32 IsWater; //If it's set to 256 IT'S FUCKING WATER JESUS CHRIST. If it's not it's FUCKING SOLID. CHRIST!
//Unknown1/Unknown2 are curious. They don't seem to correspond to anything. If they're positions
//in the world, they aren't near where their associated triangles are. If they're some sort of
//physics property override, they don't make much sense. It's my belief that it'd be best to just
//write them in as 1,1,1 and 0,0,0 since some maps have these values so the engine can obviously
//load them like that. In theory at least.
inline void Byteswap()
{
nameOffset = _byteswap_ulong(nameOffset);
UnknownVec3_1.ConvertToLE();
Unknown2 = _byteswap_ushort(Unknown2);
Unknown3 = _byteswap_ushort(Unknown3);
Unknown4 = _byteswap_ushort(Unknown4);
UnknownVec3_2.ConvertToLE();
Unknown5 = _byteswap_ushort(Unknown5);
Unknown6 = _byteswap_ushort(Unknown6);
Unknown7 = _byteswap_ushort(Unknown7);
Unknown8 = _byteswap_ushort(Unknown8);
Unknown9 = _byteswap_ushort(Unknown9);
Unknown2GroupIndex = _byteswap_ushort(Unknown2GroupIndex);
Unknown10 = _byteswap_ushort(Unknown10);
}
};
//-------------------------------------------------------------------------
// Purpose: dzbHdr_t is 48 bytes in length, contains no MAGIC, ID, or other
// identifying information, just a pure count/offset gig.
//-------------------------------------------------------------------------
struct dzbHdr_t
{
U32 vertexCount;
U32 vertexOffset;
U32 triangleCount;
U32 triangleOffset;
U32 SpatialListCount;
U32 SpatialListOffset;
U32 FaceGroupDataCount;
U32 FaceGroupDataOffset;
U32 TypeCount;
U32 TypeOffset;
U32 SurfacePropertyCount;
U32 SurfacePropertyOffset;
//Is always set to 0
U32 padding;
Vector3 *Vertex(U32 i);
Face_t *Face(U32 i);
Type_t *Type(U32 i);
SpatialList_t *SpatialList(U32 i);
FaceGroupData_t *FaceGroupData(U32 i);
SurfaceProperty_t *SurfaceProperty(U32 i);
inline void Byteswap()
{
vertexCount = _byteswap_ulong(vertexCount);
vertexOffset = _byteswap_ulong(vertexOffset);
triangleCount = _byteswap_ulong(triangleCount);
triangleOffset = _byteswap_ulong(triangleOffset);
SpatialListCount = _byteswap_ulong(SpatialListCount);
SpatialListOffset = _byteswap_ulong(SpatialListOffset);
FaceGroupDataCount = _byteswap_ulong(FaceGroupDataCount);
FaceGroupDataOffset = _byteswap_ulong(FaceGroupDataOffset);
SurfacePropertyCount = _byteswap_ulong(SurfacePropertyCount);
SurfacePropertyOffset = _byteswap_ulong(SurfacePropertyOffset);
TypeCount = _byteswap_ulong(TypeCount);
TypeOffset = _byteswap_ulong(TypeOffset);
}
};
inline Vector3 *dzbHdr_t::Vertex(U32 i)
{
return (Vector3 *)(((byte *)this) + vertexOffset) + i;
}
inline Face_t *dzbHdr_t::Face(U32 i)
{
return (Face_t *)(((byte *)this) + triangleOffset) + i;
}
inline Type_t *dzbHdr_t::Type(U32 i)
{
return (Type_t *)(((byte *)this) + TypeOffset) + i;
}
inline SpatialList_t *dzbHdr_t::SpatialList(U32 i)
{
return (SpatialList_t*)(((byte *)this) + SpatialListOffset) + i;
}
inline FaceGroupData_t *dzbHdr_t::FaceGroupData(U32 i)
{
return (FaceGroupData_t *)(((byte *)this) + FaceGroupDataOffset) + i;
}
inline SurfaceProperty_t *dzbHdr_t::SurfaceProperty(U32 i)
{
return (SurfaceProperty_t *)(((byte *)this) + SurfacePropertyOffset) + i;
}
#endif //DZBFORMAT_H