Crash Bandicoot: The Wrath of Cortex HGO

From XentaxWiki
Jump to: navigation, search

Back to index | Edit this page

HGO

  • Format Type : 3D Model
  • Endian Order : Big Endian
  • Signature : HGOF


Format Specifications

;;; Structure of GameCube HGO files for TWOC.
; All number fields are big endian, with the exception of in .hgo.blk files.
; The game exectuable comes with function name symbols, which were an aid in deciphering the structures.
	
struct matrix ; This is a 4x4 matrix, of size 0x40.
	float m11, m12, m13, m14
	float m21, m22, m23, m24
	float m31, m32, m33, m34
	float m41, m42, m43, m44
endstruct

struct vector3d
	float x, y, z
endstruct

struct vector2d
	float x, y
endstruct

struct chunk
	i32 type
	i32 size ; Size in bytes. Self-inclusive; TSH0 with only 1 contained i32 is size 0xC.
	; The type field contains 4 ASCII characters as a name for the structure contained.
	; These are all possible values for the type field, adjusted for clarity:
	;   HGOF - Root
	;   NTBL - NameTable
	;   TST0 - TextureSet
	;   TSH0 - TextureSet Counter
	;   TXM0 - TextureSet Material
	;   MS00 - MaterialSet
	;   TAS0 - TexAnimSet
	;   HGO0 - HGobjSet
	; The field is stored with chars in reverse order,
	; for example HGOF would appear as FOGH in a hex editor.
	; When read with big endianness,
	; chunk.type == 0x464F4748 should be true for the HGOF chunk.
	;;; For convenience, let this struct have an attribute END that points to the end of its data.
endstruct

struct blk ; This is an array of chunk headers from the HGO it's named after, like a summary.
	; The fields in this struct are THE OPPOSITE ENDIANNESS, they are little endian.
	for struct until EOF
		i32LE type ; An example of the endianness' char order is HGOF appearing as HGOF, rather than FOGH.
		i32LE offset ; This is a file offset to the chunk's size field, such that HGOF's is 4. Stops matching after a bitmap chunk.
	endfor
	; The offsets after the bitmap chunks appear broken, this file may not be fully used, if at all.
endstruct

struct hgo_geom ; Defines a 3D model. Used many times inside the HGO struct.
	i32 models_n
	for struct in [models_n] ; Only occurs as 1.
		i32 type
		if type == 0
			i32 unknown0
			i32 unknown1
			i32 unknown2
			i32 meshes_n ; The model is split into meshes according to its materials.
			for struct in [meshes_n]
				i32 material_id
				i32 vertices_n
				for struct in [vertices_n]
					vector3d position
					vector3d normals
					i32 colour ; ARGB format.
					vector2d uv
				endfor
				
				i32 geom_cntrl ; Only 0.
				i32 primitives_n
				for struct in [primitives_n]
					i32 primtype
					i32 indices_n
					i16 indices [indices_n]
					;;; Explanation:
					; If primtype == 5, then every grouping of 3 indices is 1 polygon.
					; If primtype == 6, then the indices describe triangle strips. Uncertain parsing method.
				endfor
				
				i32 geomskin_present ; Yes, this is a 32-bit boolean.
				if geomskin_present != 0 ; This is known in Blender lingo as bone weights.
					i8 type
					if type == 0 ; This type is unused.
						i32 unknown
						i32 unknown_len
						i32 unknown_n
						i32 unknown_a [unknown_n]
						i32 unknown_b [unknown_len] [unknown_n]
					else
						for struct in [vertices_n]
							f32 influence0
							f32 influence1
							f32 influence2
							i8 bone_id0
							i8 bone_id1
							i8 bone_id2
							i8 unused
						endfor
					endif
					;;; Explanation:
					; This stuff describes bone weights, how far a bone has to travel to move a vertex.
					; For type != 0, take each bone_id and connect the bone to the vertex with the corresponding influence.
					; Ignore bone_id values that are 0.
					; The limitation of this structure is that only 3 bones can have influence over a given vertex.
					;
					; I have not tested the type == 0 path, as it's unused, but it seems likely to me that it's an
					; extended version of the same, to have the option of having more than 3 bone influences on a vertex.
				endif
				
				i32 blendshapes_n
				if blendshapes_n != 0 ; Known in Blender lingo as shape keys.
					i32 blendshapes_ids [blendshapes_n]
					i32 blendshape_len
					i8 blendshape [blendshape_len]
					i8 blendshape_presence [blendshapes_n]
					;;; Explanation:
					; The numbers in blendshapes_ids are unique identification numbers (not indices) for the blendshapes involved,
					; and it dictates the order in which these blendshapes will be defined here.
					;
					; The blendshape buffer stores vectors for all the mesh's vertices, for each new blendshape defined.
					; blendshape_presence determines which blendshapes are included in the buffer, and which are omitted.
					; This saves a lot of space for meshes that are not involved in the new shape.
					; For that reason, blendshape_len == sizeof(vector)*vertices_n*sum(blendshape_presence).
					; Alternatively, blendshape can be defined as: vector blendshape [vertices_n] [sum(blendshape_presence)]
				endif
			endfor
		elseif type == 1 ; Unused.
			i32 unknown_n
			for struct in [unknown_n]
				i32 unknown0
				i32 unknown1_n
				i32 unknown2
				f32 unknown3
				i8 unknown1 [0x18] [unknown1_n]
			endfor
		endif
	endfor
endstruct

struct hgo
	chunk rootchunk
	; This is the HGOF chunk, it envelops the entire file.
	; Its size is padded to the 4 byte boundary,
	; despite the file not being padded, and likely being shorter.
	; Contained is an array of chunks:
	for chunk hgochunk until EOF
		elseif hgochunk.type == NTBL
			i32 table_len ; Size in bytes of the buffer just ahead.
			i8 table [table_len] ; A buffer of concatenated, null-terminated strings, such as bone names.
			; Everything that uses the name table stores offset value relative to the start of the name table,
			; but 1 too far; subtract 1 and it will match.
		elseif hgochunk.type == TST0 ; Chunk array.
			for chunk taschunk until hgochunk.END
				if hgochunk.type == TSH0
					i32 images_n ; The amount of bitmaps packed.
				elseif hgochunk.type == TXM0 ; Bitmaps.
					i32 bitmap_type ; 0x80 for DXT1, 0x81 for RGB5A3, 0x82 for an unknown tiled format.
					i32 bitmap_width  ; In pixels.
					i32 bitmap_height ; In pixels.
					i32 bitmap_len ; Size in bytes of the buffer just ahead.
					i8 bitmap [bitmap_len]
					; All formats follow a pattern of 4 tiles in a Z-shape.
				endif
				; The TSH0 chunk is unnecessary, but may have been more convenient with the in-house chunk utilities.
			endfor
		elseif hgochunk.type == MS00 ; Material definitions, indexes into bitmaps.
			i32 materials_n
			for struct in [materials_n] ; Struct size 0x54.
				i32 unknown0
				i32 unknown1
				i32 unknown2
				i32 unknown3
				i32 unknown4
				f32 diffuse_r
				f32 diffuse_g
				f32 diffuse_b
				f32 unknown8
				f32 unknown9
				i32 unknown10
				i32 unknown11
				f32 unknown12
				f32 unknown13
				i32 bitmap_id ; Negative if no bitmap, and uses diffuse colours. Otherwise an index into the bitmaps.
				f32 unknown15
				f32 unknown16
				f32 unknown17
				f32 unknown18
				f32 unknown19
				f32 unknown20
			endfor
		elseif hgochunk.type == TAS0 ; Completely unknown.
			i32 anims_n
			i32 unknown
			for struct in [anims_n] ; Size 0x20.
				i32 unknown0
				i32 unknown1
				i32 unknown2
				i32 unknown3
				i32 unknown4
				i32 unknown5
				i32 unknown6
				i32 unknown7
			endfor
			i32 shorts_n
			i16 shorts [anim_shorts_n]
		elseif hgochunk.type == HGO0 ; Contains all the 3D stuff.
			i32 bones_n
			for struct in [bones_n]
				i8 unknown
				matrix rotation
				matrix position
				matrix scale ; Conjecture.
				i32 unknown0
				f32 unknown1
				f32 unknown2
				i8 parent
				i32 name_offset ; Bone name in the name table.
			endfor
			i8 unknown0_len
			i8 unknown0 [unknown0_len]
			i8 unknown1_len
			i8 unknown1 [unknown1_len]
			i8 layers_n
			for struct in [layers_n]
				name_offset ; Layer name in the name table.
				
				i8 primary_bone_meshes_present
				if primary_bone_meshes_present != 0
					for - in range(bones_n)
						i8 primary_bone_mesh_present
						if primary_bone_mesh_present != 0
							hgo_geom
						endif
					endfor
				endif
				i8 primary_mesh_present
				if primary_mesh_present != 0
					hgo_geom
				endif
				
				i8 secondary_bone_meshes_present
				if secondary_bone_meshes_present != 0
					for - in range(bones_n)
						i8 secondary_bone_mesh_present
						if secondary_bone_mesh_present != 0
							hgo_geom
						endif
					endfor
				endif
				i8 secondary_mesh_present
				if secondary_mesh_present != 0
					hgo_geom
				endif
			endfor
			i8 points_n
			for struct in [points_n]
				i8 bone_id
				matrix position
				i32 name_offset ; Point name in the name table.
			endfor
			i8 unknown3_n
			for struct in [unknown3_n]
				i8 unknown0_n
				i8 unknown0 [0x30] [unknown0_n]
				i8 unknown1_n
				i8 unknown1 [0x30] [unknown1_n]
				i8 unknown2_n
				for struct in [unknown2_n]
					i32 unknown0_n
					i8 unknown0 [0x10] [unknown0_n]
					i32 unknown1_n
					i8 unknown1 [0x10] [unknown1_n]
				endfor
				i8 unknown3
			endfor
			f32 unknown_f0
			f32 unknown_f1
			f32 unknown_f2
			f32 unknown_f3
			f32 unknown_f4
			f32 unknown_f5
			f32 unknown_f6
			f32 unknown_f7
			f32 unknown_f8
			f32 unknown_f9
			f32 unknown_f10
		endif
	endfor
endstruct

MultiEx BMS Script

Not written yet.

Notes and Comments

None.

Games

List of games using this file format:

  • Crash Bandicoot: The Wrath of Cortex (*.HGO)

Compatible Programs

  • Blender