FILE STRUCTURE
Here is what I figured out about 0x12 file. This file contains information about models and structure is as follow:
It always starts with following header:
struct {
uint8 tag; // always 'DC'
uint8 model_count; // models count
int16 padd; // align to 32 bits - irrelevant data
} header;
After header there is an array of models infos. Lenght of this array == header.model_count
struct {
uint16 mesh_id; // 0x02 file id - mesh
uint16 default_animation_id; // 0x03 file id - animation ( this value can be -1, it means that there is no default animation )
uint8 materials_count; // materials count
uint24 materials_pointer; // pointer to materials array ( calculated from begining of stucture )
uint16 id_0x19; // 0x19 file id - ??? ( can be -1 )
uint8 unknown1; // possibly id of some file
uint8 unknown2; // unknown ( align to 32 bits? )
} model_info;
Materials:
First there is an array of tpage/clut values. Length == model_info.materials_count
struct {
uint16 tpage;
uint16 clut;
} tpage_clut;
Then array of textures windows (actually just x,y), this values should be added to tpage.x and tpage.y to obtain top-left corner of material texture. Length == model_info.materials_count
struct {
int16 x; // This value can be negative!
int16 y; // This value can be negative!
} tw;
Next there is an array that probably is face/eye position in VRAM. For fields models this values are quite ok but not for playable charachters.
For weapons it's always [0, 0, 0, 0] and for playable characters it's [2, 2, 0, 0] or [1, 1, 0, 0]. Length == model_info.materials_count
struct {
int16 x1; // x of face/eye ???
int16 y1; // y of face/eye ???
int16 x2; // very often this value is equal x1
int16 y2; // very often this value is equal y1
} eye_anim;
HOW TO READ MONSTERS
In all cases meshes (0x02) animations (0x03) and textures (0x04) are in the same cluster with 0x12 file. The only exception are monsters that are separated into two directories:
Directory 5 - Contains 0x12 file
Directory 7 - Contains 0x02, 0x03 and 0x04
To read monster first you need to read information from 0x12, when you got meshes id you can load corresponding clusters from directory 7. Id of cluster from directory 7 always match id of mesh that is inside this cluster. Some times there is more than one mesh in 0x12 file for monsters!
HOW TO DECODE TPAGE AND CLUT
Information about how to decode tpage/clut value can be found in Psy-Q SDK. In file: psx/include/LIBGPU.H we can find following macros:
#define getTPage(tp, abr, x, y) \
((((tp)&0x3)<<7)|(((abr)&0x3)<<5)|(((y)&0x100)>>4)|(((x)&0x3ff)>>6)| \
(((y)&0x200)<<2))
#define getClut(x, y) \
(((y)<<6)|(((x)>>4)&0x3f))
#define dumpTPage(tpage) \
GPU_printf("tpage: (%d,%d,%d,%d)\n", \
((tpage)>>7)&0x003,((tpage)>>5)&0x003, \
((tpage)<<6)&0x7c0, \
(((tpage)<<4)&0x100)+(((tpage)>>2)&0x200))
#define dumpClut(clut) \
GPU_printf("clut: (%d,%d)\n", (clut&0x3f)<<4, (clut>>6))
and from documentation:
u_short GetTPage(
int tp, // Texture mode
// 0: 4bitCLUT
// 1: 8bitCLUT
// 2: 16bitDirect
int abr, // Semitransparency rate
// 0: 0.5 x Back + 0.5 x Forward
// 1: 1.0 x Back + 1.0 x Forward
// 2: 1.0 x Back - 1.0 x Forward
// 3: 1.0 x Back + 0.25 x Forward
int x, int y) // Texture page address
That's all:) I hope that it will be useful for somebody.