11 //Make sure everything is nice and together
16 // these index into the mesh's vert[origMeshVertID]'s bones
17 unsigned char boneWeightIndex[3];
18 unsigned char numBones;
20 unsigned short origMeshVertID;
22 // for sw skinned verts, these are indices into the global list of bones
23 // for hw skinned verts, these are hardware bone indices
29 STRIPGROUP_IS_FLEXED = 0x01,
30 STRIPGROUP_IS_HWSKINNED = 0x02,
31 STRIPGROUP_IS_DELTA_FLEXED = 0x04,
32 STRIPGROUP_SUPPRESS_HW_MORPH = 0x08, // NOTE: This is a temporary flag used at run time.
35 // A strip is a piece of a stripgroup which is divided by bones
50 int numBoneStateChanges;
51 int boneStateChangeOffset;
55 // a single vertex buffer
56 // a single index buffer
57 struct StripGroupHeader
59 // These are the arrays of all verts and indices for this mesh. strips index into this.
75 int stripGroupHeaderOffset;
89 // This maps one to one with models in the mdl file.
93 int numLODs; //This is also specified in FileHeader_t
106 // file version as defined by OPTIMIZED_MODEL_FILE_VERSION (currently 7)
109 // hardware params that affect how the model is to be optimized.
111 unsigned short maxBonesPerStrip;
112 unsigned short maxBonesPerTri;
115 // must match checkSum in the .mdl
118 int numLODs; // Also specified in ModelHeader_t's and should match
120 // Offset to materialReplacementList Array. one of these for each LOD, 8 in total
121 int materialReplacementListOffset;
123 //Defines the size and location of the body part array
130 =============================================
138 L VerticesTable[StudioMDL.Vertex]
139 L IndicesTable[UINT16]
149 class vtx_mesh : public util::verboseControl
152 std::vector<unsigned short> vertexSequence;
153 vtx::FileHeader header;
155 vtx_mesh(std::string filepath, bool verbose = false)
157 this->use_verbose = verbose;
160 std::ifstream reader(filepath, std::ios::in | std::ios::binary);
163 throw std::exception("VTX::LOAD FAILED"); return;
167 reader.read((char*)&this->header, sizeof(this->header));
168 this->debug("VTX version:", this->header.version);
169 this->debug("Num LODS:", this->header.numLODs);
171 /* Read bulk of .VTX file */
173 /* Body part array */
174 reader.seekg(header.bodyPartOffset);
175 int abs_body_base_offset = reader.tellg();
177 for (int body = 0; body < header.numBodyParts; body++)
179 //Move to current body part array item
180 reader.seekg(abs_body_base_offset);
181 reader.seekg(body * sizeof(vtx::BodyPartHeader), std::ios::cur);
184 vtx::BodyPartHeader BODY;
185 reader.read((char*)&BODY, sizeof(BODY));
188 reader.seekg(BODY.modelOffset - sizeof(vtx::BodyPartHeader), std::ios::cur);
189 int abs_model_base_offset = reader.tellg();
192 //NOTE: Total verts may need to be initialized outside the body array
194 for (int model = 0; model < BODY.numModels; model++)
196 //Move to current model array item
197 reader.seekg(abs_model_base_offset);
198 reader.seekg(model * sizeof(vtx::ModelHeader), std::ios::cur);
201 vtx::ModelHeader MODEL;
202 reader.read((char*)&MODEL, sizeof(MODEL));
205 reader.seekg(MODEL.lodOffset - sizeof(vtx::ModelHeader), std::ios::cur);
206 int abs_lod_base_offset = reader.tellg();
208 for (int lod = 0; lod < MODEL.numLODs; lod++){
209 if (lod > 0) goto IL_EXIT; // Skip all the other lods for now
211 //Move to the current LOD header array item
212 reader.seekg(abs_lod_base_offset);
213 reader.seekg(lod * sizeof(vtx::ModelLODHeader), std::ios::cur);
215 //Read the LOD header
216 vtx::ModelLODHeader LOD;
217 reader.read((char*)&LOD, sizeof(LOD));
220 reader.seekg(LOD.meshOffset - sizeof(vtx::ModelLODHeader), std::ios::cur);
221 int abs_mesh_base_offset = reader.tellg();
223 for (int mesh = 0; mesh < LOD.numMeshes; mesh++)
225 //Move to the current mesh array item
226 reader.seekg(abs_mesh_base_offset);
227 reader.seekg(mesh * sizeof(vtx::MeshHeader), std::ios::cur);
229 //Read the Mesh header
230 vtx::MeshHeader MESH;
231 reader.read((char*)&MESH, sizeof(MESH));
233 /* Strip Group array */
234 reader.seekg(MESH.stripGroupHeaderOffset - sizeof(vtx::MeshHeader), std::ios::cur);
235 int abs_strip_group_base_offset = reader.tellg();
237 for (int sgroup = 0; sgroup < MESH.numStripGroups; sgroup++)
239 //Move to the current stripgroup array item
240 reader.seekg(abs_strip_group_base_offset);
241 reader.seekg(sgroup * sizeof(vtx::StripGroupHeader), std::ios::cur);
243 //Read the strip group header
244 vtx::StripGroupHeader SGROUP;
245 reader.read((char*)&SGROUP, sizeof(SGROUP));
247 int base_location = (int)reader.tellg() - sizeof(vtx::StripGroupHeader);
248 int location_vertex_array = base_location + SGROUP.vertOffset;
249 int location_indices_array = base_location + SGROUP.indexOffset;
252 std::vector<vtx::Vertex> vertexTable;
253 reader.seekg(location_vertex_array);
254 for (int i = 0; i < SGROUP.numVerts; i++)
257 reader.read((char*)&vert, sizeof(vert));
258 vertexTable.push_back(vert);
262 std::vector<unsigned short> indicesTable;
263 reader.seekg(location_indices_array);
264 for (int i = 0; i < SGROUP.numIndices; i++)
266 unsigned short index;
267 reader.read((char*)&index, sizeof(index));
268 indicesTable.push_back(index);
272 reader.seekg(base_location);
273 reader.seekg(SGROUP.stripOffset, std::ios::cur);
274 int abs_strip_base_offset = reader.tellg();
276 for (int strip = 0; strip < SGROUP.numStrips; strip++)
278 //Move to current strip array item
279 reader.seekg(abs_strip_base_offset);
280 reader.seekg(strip * sizeof(vtx::StripHeader), std::ios::cur);
283 vtx::StripHeader STRIP;
284 reader.read((char*)&STRIP, sizeof(STRIP));
286 //Virtual vertices pool
287 std::vector<vtx::Vertex> v_verts;
288 for (int i = 0; i < STRIP.numVerts; i++)
289 if ((STRIP.vertOffset + i) >= vertexTable.size())
290 throw std::exception("VTX::DECOMPILE::VERT_TABLE OUT OF RANGE");
292 v_verts.push_back(vertexTable[STRIP.vertOffset + i]);
294 //Virtual indices pool
295 std::vector<unsigned short> v_indices;
296 for (int i = 0; i < STRIP.numIndices; i++)
297 if ((STRIP.indexOffset + i) >= indicesTable.size())
298 throw std::exception("VTX::DECOMPILE::INDEX_TABLE OUT OF RANGE");
300 v_indices.push_back(indicesTable[STRIP.indexOffset + i]);
302 for (int i = 0; i < v_indices.size(); i++)
304 this->vertexSequence.push_back(v_verts[v_indices[i]].origMeshVertID + total_verts);
308 total_verts += SGROUP.numVerts;
320 vtx_mesh(std::ifstream* stream, unsigned int offset, bool verbost = false){
321 this->use_verbose = verbost;
322 stream->seekg(offset);
325 stream->read((char*)&this->header, sizeof(this->header));
326 this->debug("VTX version:", this->header.version);
327 this->debug("Num LODS:", this->header.numLODs);
329 /* Read bulk of .VTX file */
331 /* Body part array */
332 stream->seekg(offset + header.bodyPartOffset);
333 int abs_body_base_offset = stream->tellg();
335 for (int body = 0; body < header.numBodyParts; body++){
336 //Move to current body part array item
337 stream->seekg(abs_body_base_offset);
338 stream->seekg(body * sizeof(vtx::BodyPartHeader), std::ios::cur);
341 vtx::BodyPartHeader BODY;
342 stream->read((char*)&BODY, sizeof(BODY));
345 stream->seekg(BODY.modelOffset - sizeof(vtx::BodyPartHeader), std::ios::cur);
346 int abs_model_base_offset = stream->tellg();
349 //NOTE: Total verts may need to be initialized outside the body array
351 for (int model = 0; model < BODY.numModels; model++){
352 //Move to current model array item
353 stream->seekg(abs_model_base_offset);
354 stream->seekg(model * sizeof(vtx::ModelHeader), std::ios::cur);
357 vtx::ModelHeader MODEL;
358 stream->read((char*)&MODEL, sizeof(MODEL));
361 stream->seekg(MODEL.lodOffset - sizeof(vtx::ModelHeader), std::ios::cur);
362 int abs_lod_base_offset = stream->tellg();
364 for (int lod = 0; lod < MODEL.numLODs; lod++){
365 if (lod > 0) goto IL_EXIT; // Skip all the other lods for now
367 //Move to the current LOD header array item
368 stream->seekg(abs_lod_base_offset);
369 stream->seekg(lod * sizeof(vtx::ModelLODHeader), std::ios::cur);
371 //Read the LOD header
372 vtx::ModelLODHeader LOD;
373 stream->read((char*)&LOD, sizeof(LOD));
376 stream->seekg(LOD.meshOffset - sizeof(vtx::ModelLODHeader), std::ios::cur);
377 int abs_mesh_base_offset = stream->tellg();
379 for (int mesh = 0; mesh < LOD.numMeshes; mesh++){
380 //Move to the current mesh array item
381 stream->seekg(abs_mesh_base_offset);
382 stream->seekg(mesh * sizeof(vtx::MeshHeader), std::ios::cur);
384 //Read the Mesh header
385 vtx::MeshHeader MESH;
386 stream->read((char*)&MESH, sizeof(MESH));
388 /* Strip Group array */
389 stream->seekg(MESH.stripGroupHeaderOffset - sizeof(vtx::MeshHeader), std::ios::cur);
390 int abs_strip_group_base_offset = stream->tellg();
392 for (int sgroup = 0; sgroup < MESH.numStripGroups; sgroup++){
393 //Move to the current stripgroup array item
394 stream->seekg(abs_strip_group_base_offset);
395 stream->seekg(sgroup * sizeof(vtx::StripGroupHeader), std::ios::cur);
397 //Read the strip group header
398 vtx::StripGroupHeader SGROUP;
399 stream->read((char*)&SGROUP, sizeof(SGROUP));
401 int base_location = (int)stream->tellg() - sizeof(vtx::StripGroupHeader);
402 int location_vertex_array = base_location + SGROUP.vertOffset;
403 int location_indices_array = base_location + SGROUP.indexOffset;
406 std::vector<vtx::Vertex> vertexTable;
407 stream->seekg(location_vertex_array);
408 for (int i = 0; i < SGROUP.numVerts; i++)
411 stream->read((char*)&vert, sizeof(vert));
412 vertexTable.push_back(vert);
416 std::vector<unsigned short> indicesTable;
417 stream->seekg(location_indices_array);
418 for (int i = 0; i < SGROUP.numIndices; i++)
420 unsigned short index;
421 stream->read((char*)&index, sizeof(index));
422 indicesTable.push_back(index);
426 stream->seekg(base_location);
427 stream->seekg(SGROUP.stripOffset, std::ios::cur);
428 int abs_strip_base_offset = stream->tellg();
430 for (int strip = 0; strip < SGROUP.numStrips; strip++)
432 //Move to current strip array item
433 stream->seekg(abs_strip_base_offset);
434 stream->seekg(strip * sizeof(vtx::StripHeader), std::ios::cur);
437 vtx::StripHeader STRIP;
438 stream->read((char*)&STRIP, sizeof(STRIP));
440 //Virtual vertices pool
441 std::vector<vtx::Vertex> v_verts;
442 for (int i = 0; i < STRIP.numVerts; i++)
443 if ((STRIP.vertOffset + i) >= vertexTable.size())
444 throw std::exception("VTX::DECOMPILE::VERT_TABLE OUT OF RANGE");
446 v_verts.push_back(vertexTable[STRIP.vertOffset + i]);
448 //Virtual indices pool
449 std::vector<unsigned short> v_indices;
450 for (int i = 0; i < STRIP.numIndices; i++)
451 if ((STRIP.indexOffset + i) >= indicesTable.size())
452 throw std::exception("VTX::DECOMPILE::INDEX_TABLE OUT OF RANGE");
454 v_indices.push_back(indicesTable[STRIP.indexOffset + i]);
456 for (int i = 0; i < v_indices.size(); i++)
458 this->vertexSequence.push_back(v_verts[v_indices[i]].origMeshVertID + total_verts);
462 total_verts += SGROUP.numVerts;
471 virtual ~vtx_mesh() {}