forked from Sparagas/Silent-Hill
-
Notifications
You must be signed in to change notification settings - Fork 0
/
SH4 (PC) world mesh.bt
183 lines (159 loc) · 5.82 KB
/
SH4 (PC) world mesh.bt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
//------------------------------------------------
//--- 010 Editor v13.0.2 Binary Template
//
// File: SH4 World Mesh
// Authors: Hunter Stanton, roocker666, Sparagas
// Version:
// Purpose: A binary template for Silent Hill 4 PC world meshes (aka sgEMRenderModel). Intended for PC but might apply to Xbox and PS2.
// Category:
// File Mask:
// ID Bytes:
// History:
//------------------------------------------------
typedef struct ModelHead3 { // struct sgEMRenderModelTop
// unsigned int type_id;
// unsigned int version;
uint32 to_normal_group; // unsigned int to_normal_groupet;
uint32 to_overdraw_group; // unsigned int overdraw_group_offset;
uint32 to_trans_group; // unsigned int transparency_group_offset;
uint32 to_matrix_rts; // unsigned int matrices_offset;
uint32 num_matrix_rts; // unsigned int n_matrices; // I am not sure this is really used anymore, even in very complex scenes only one matrix is present and the values are always [[1.0 0 0 0] [0 1.0 0 0] [0 0 1.0 0] [0 0 0 1.0]]
uint32 unk_additional_data; // unsigned int additional_data;
uint32 reserved_08; // unsigned int reserved_08;
uint32 reserved_09; // unsigned int reserved_09;
uint32 reserved_0a; // unsigned int reserved_0a;
uint32 reserved_0b; // unsigned int reserved_0b;
uint32 reserved_0c; // unsigned int reserved_0c;
uint32 reserved_0d; // unsigned int reserved_0d;
uint32 reserved_0e; // unsigned int reserved_0e;
uint32 reserved_0f; // unsigned int reserved_0f;
} ModelHead3_t;
typedef struct MatrixRTS {
float matrix_rts[16];
} MatrixRTS_t;
typedef struct DrawBlockParams
{
// TODO: figure this out, this is presumably important in how these get drawn, perhaps it determines which shader to use and params passed to it or something?
// this isn't really important for extracting the mesh though
ubyte unk[0x40];
/*
// data is from PS2 debug data, not applicable to PC due to how this is intended for DMAing to the PS2 GPU
// leaving here for posterity
int64 dma_tag;
int64 part_giftag;
unsigned long tex0;
unsigned long clamp;
unsigned int tex1;
unsigned int alpha;
unsigned int prim;
unsigned int nb_parts;
*/
} drawBlockParams;
typedef struct VertPosColUV
{
float x;
float y;
float z;
ubyte b;
ubyte g;
ubyte r;
ubyte a;
float u;
float v;
} VertPosColUV;
typedef struct WrldPart
{
local uint64 start = FTell();
ubyte unk[32];
uint32 n_faces;
uint32 n_vertices;
ubyte unk2[64];
uint32 unk3;
uint32 unk4;
uint32 unk5;
uint32 faces_offset <format=hex>;
uint32 vertices_offset <format=hex>;
uint32 unk6;
FSeek(start + faces_offset);
uint16 faces[n_faces];
VertPosColUV vert_pos_col_uv[n_vertices];
} WrldPart;
typedef struct BoundingBox
{
float bmin[4]; //<bgcolor=cGreen>;
float bmax[4]; //<bgcolor=cGreen>;
};
// assuming it is split like this because of
typedef struct DrawBlock
{
local uint32 start = FTell();
uint32 next_block_offset <format=hex>;
uint32 params_offset <format=hex>;
uint32 parts_offset <format=hex>;
uint16 texture_id;
uint16 texture_bank; // not sure what this is considering the overwhelming majority of world meshes only have one single texture chunk
ubyte clut_id;
ubyte subtexture_id; // not 100% on this but it seems to line up?
uint16 palette_idx;
uint32 bounding_box_offset <format=hex>;
uint16 matrix_index;
ubyte backclip; // possibly related to backface culling?
ubyte pad0;
uint32 pad1;
FSeek(start + bounding_box_offset);
BoundingBox bounding_box;
FSeek(start + params_offset);
DrawBlockParams params;
FSeek(start + parts_offset);
WrldPart wrld_part;
} drawBlock;
typedef struct DrawGroup
{
local uint32 start = FTell();
local uint32 i = 0;
uint32 num_mesh;
if(num_mesh != 0)
{
uint32 to_mesh[num_mesh] <format=hex>;
for( i = 0; i < num_mesh; i++ )
{
FSeek(start + to_mesh[i]);
DrawBlock draw_block;
}
}
} drawGroup;
enum Version
{
Prototype = 1, // seen in some test .bins included with the final game (iwa_teststage.bin for example). structure is very different due to being from an earlier version of the game, might be similar to SH3
Prototype2 = 2, // closer to SH4's final version but not quite, found in the unused gtXX bin files and some others (this game has a *lot* of unused content, some of it still never seen before)
Final = 3 // what is actually used in Silent Hill 4's final version
};
//------------------------------------------------
// parsing sequance (the acutal reading of a file)
//------------------------------------------------
struct WorldModel { // SGEMRenderModel
local int start = FTell();
uint32 type_id;
Version version;
if(version == Final)
{
// normal group = the main mesh
// overdraw = mesh used for decals, shadows
// transparency = meshes specifically intended to be transparent or see through (tree leaves, etc.)
ModelHead3_t model_head3;
FSeek(start + model_head3.to_matrix_rts);
MatrixRTS_t matrix_rts[model_head3.num_matrix_rts];
if(model_head3.to_normal_group != 0)
{
FSeek(start + model_head3.to_normal_group);
DrawGroup normalDrawGroup;
}
if(model_head3.to_overdraw_group != 0)
{
FSeek(start + model_head3.to_overdraw_group);
DrawGroup overdrawDrawGroup;
}
} else {
Warning("Error: Template does not support non-final versioned world meshes");
}
} world_model_block;