| 1 | /* | 
|---|
| 2 |    orxonox - the future of 3D-vertical-scrollers | 
|---|
| 3 |  | 
|---|
| 4 |    Copyright (C) 2004 orx | 
|---|
| 5 |  | 
|---|
| 6 |    This program is free software; you can redistribute it and/or modify | 
|---|
| 7 |    it under the terms of the GNU General Public License as published by | 
|---|
| 8 |    the Free Software Foundation; either version 2, or (at your option) | 
|---|
| 9 |    any later version. | 
|---|
| 10 |  | 
|---|
| 11 |    ### File Specific: | 
|---|
| 12 |    main-programmer: Patrick Boenzli | 
|---|
| 13 | */ | 
|---|
| 14 |  | 
|---|
| 15 | #define DEBUG_SPECIAL_MODULE DEBUG_MODULE_IMPORTER | 
|---|
| 16 |  | 
|---|
| 17 | #include "md3_data.h" | 
|---|
| 18 |  | 
|---|
| 19 | #include "md3_bone_frame.h" | 
|---|
| 20 | #include "md3_tag.h" | 
|---|
| 21 | #include "md3_mesh.h" | 
|---|
| 22 |  | 
|---|
| 23 | #include "material.h" | 
|---|
| 24 |  | 
|---|
| 25 | #include "debug.h" | 
|---|
| 26 |  | 
|---|
| 27 | namespace md3 | 
|---|
| 28 | { | 
|---|
| 29 |  | 
|---|
| 30 | /******************************************************************************** | 
|---|
| 31 |  *   MD3Data                                                                    * | 
|---|
| 32 |  ********************************************************************************/ | 
|---|
| 33 |  | 
|---|
| 34 | /** | 
|---|
| 35 |   \brief simple constructor | 
|---|
| 36 | */ | 
|---|
| 37 | MD3Data::MD3Data(const std::string& modelFileName, const std::string& skinFileName, float scale) | 
|---|
| 38 | { | 
|---|
| 39 |  | 
|---|
| 40 |  | 
|---|
| 41 |  | 
|---|
| 42 |   this->loadModel(modelFileName); | 
|---|
| 43 | //   this->loadSkin(skinFileName); | 
|---|
| 44 | } | 
|---|
| 45 |  | 
|---|
| 46 |  | 
|---|
| 47 | /** | 
|---|
| 48 |   \brief simple destructor | 
|---|
| 49 |  | 
|---|
| 50 |   this will clean out all the necessary data for a specific md2model | 
|---|
| 51 | */ | 
|---|
| 52 | MD3Data::~MD3Data() | 
|---|
| 53 | { | 
|---|
| 54 |   delete this->header; | 
|---|
| 55 | } | 
|---|
| 56 |  | 
|---|
| 57 |  | 
|---|
| 58 |  | 
|---|
| 59 | /** | 
|---|
| 60 |   \brief this will load the whole model data (vertices, opengl command list, ...) | 
|---|
| 61 | * @param fileName: the name of the model file | 
|---|
| 62 |   \return true if success | 
|---|
| 63 | */ | 
|---|
| 64 | bool MD3Data::loadModel(const std::string& fileName) | 
|---|
| 65 | { | 
|---|
| 66 |   FILE *pFile;                            //file stream | 
|---|
| 67 | //  char* buffer;                           //buffer for frame data | 
|---|
| 68 |   int fileOffset = 0;                     // file data offset | 
|---|
| 69 |  | 
|---|
| 70 |  | 
|---|
| 71 |  | 
|---|
| 72 |   //! @todo this chek should include deleting a loaded model (eventually) | 
|---|
| 73 |   if (fileName.empty()) | 
|---|
| 74 |     return false; | 
|---|
| 75 |  | 
|---|
| 76 |   PRINTF(0)("opening file: %s\n", fileName.c_str()); | 
|---|
| 77 |   pFile = fopen(fileName.c_str(), "rb"); | 
|---|
| 78 |   if( unlikely(!pFile)) | 
|---|
| 79 |     { | 
|---|
| 80 |       PRINTF(1)("Couldn't open the MD3 File for loading. Exiting.\n"); | 
|---|
| 81 |       return false; | 
|---|
| 82 |     } | 
|---|
| 83 |   fileOffset += this->readHeader(pFile, fileOffset); | 
|---|
| 84 |   /* check for the header version: make sure its a md2 file :) */ | 
|---|
| 85 |   if( unlikely(this->header->version != MD3_VERSION) && unlikely(this->header->ident != MD3_IDENT)) | 
|---|
| 86 |     { | 
|---|
| 87 |       PRINTF(1)("Couldn't load file %s: invalid file format: stop loading\n", fileName.c_str()); | 
|---|
| 88 |       return false; | 
|---|
| 89 |     } | 
|---|
| 90 |  | 
|---|
| 91 |  | 
|---|
| 92 |     // check if the filesize is correct | 
|---|
| 93 |     if( this->header->fileSize > this->header->tagStart && | 
|---|
| 94 |         this->header->fileSize >= this->header->meshStart) | 
|---|
| 95 |     { | 
|---|
| 96 |       bool bBoneFrames, bTags, bMeshes; | 
|---|
| 97 |       bBoneFrames = ( this->header->boneFrameNum == 0); | 
|---|
| 98 |       bTags = ( this->header->tagNum == 0); | 
|---|
| 99 |       bMeshes = ( this->header->meshNum == 0); | 
|---|
| 100 |  | 
|---|
| 101 |       // read different parts of the model in correct order | 
|---|
| 102 |       while( !(bBoneFrames && bTags && bMeshes)) | 
|---|
| 103 |       { | 
|---|
| 104 |         printf("while, fileOffset = %i\n", fileOffset); | 
|---|
| 105 |         if( fileOffset == this->header->boneFrameStart && !bBoneFrames) | 
|---|
| 106 |         { | 
|---|
| 107 |           fileOffset += this->readBoneFrames(pFile, fileOffset); | 
|---|
| 108 |           bBoneFrames = true; | 
|---|
| 109 |         } | 
|---|
| 110 |         else if( fileOffset == this->header->tagStart && !bTags) | 
|---|
| 111 |         { | 
|---|
| 112 |           fileOffset += this->readTags(pFile, fileOffset); | 
|---|
| 113 |           bTags = true; | 
|---|
| 114 |         } | 
|---|
| 115 |         else if( fileOffset == this->header->meshStart && !bMeshes) | 
|---|
| 116 |         { | 
|---|
| 117 |           fileOffset += this->readMeshes(pFile, fileOffset); | 
|---|
| 118 |           bMeshes = true; | 
|---|
| 119 |         } | 
|---|
| 120 |       } | 
|---|
| 121 |  | 
|---|
| 122 |     } | 
|---|
| 123 |  | 
|---|
| 124 |   fclose(pFile); | 
|---|
| 125 |  | 
|---|
| 126 |   return true; | 
|---|
| 127 | } | 
|---|
| 128 |  | 
|---|
| 129 |  | 
|---|
| 130 | /** | 
|---|
| 131 |   \brief loads the skin/material stuff | 
|---|
| 132 | * @param fileName: name of the skin file | 
|---|
| 133 |   \return true if success | 
|---|
| 134 | */ | 
|---|
| 135 | bool MD3Data::loadSkin(const std::string& fileName) | 
|---|
| 136 | { | 
|---|
| 137 | //   if( fileName.empty()) | 
|---|
| 138 | //     { | 
|---|
| 139 | //       this->skinFileName = ""; | 
|---|
| 140 | //       return false; | 
|---|
| 141 | //     } | 
|---|
| 142 | // | 
|---|
| 143 | //   this->skinFileName = fileName; | 
|---|
| 144 | // | 
|---|
| 145 | //   this->material.setName("md2ModelMaterial"); | 
|---|
| 146 | //   this->material.setDiffuseMap(fileName); | 
|---|
| 147 | //   this->material.setIllum(3); | 
|---|
| 148 | //   this->material.setAmbient(1.0, 1.0, 1.0); | 
|---|
| 149 |  | 
|---|
| 150 |   return true; | 
|---|
| 151 | } | 
|---|
| 152 |  | 
|---|
| 153 |  | 
|---|
| 154 | /** | 
|---|
| 155 |  * read heaader | 
|---|
| 156 |  */ | 
|---|
| 157 | int MD3Data::readHeader(FILE* pFile, int fileOffset) | 
|---|
| 158 | { | 
|---|
| 159 |   PRINTF(0)("Reading Header\n"); | 
|---|
| 160 |  | 
|---|
| 161 |   this->header = new MD3Header; | 
|---|
| 162 |   fread(this->header, 1, sizeof(MD3Header), pFile); | 
|---|
| 163 |  | 
|---|
| 164 |     //header debug: | 
|---|
| 165 |   PRINTF(0)("MD3 Header debug section======================================\n"); | 
|---|
| 166 |   printf("ident: %i\n", this->header->ident); | 
|---|
| 167 |   printf("version: %i\n", this->header->version); | 
|---|
| 168 |   printf("filename: %s\n", this->header->filename); | 
|---|
| 169 |   printf("boneFrameNum: %i\n", this->header->boneFrameNum); | 
|---|
| 170 |   printf("tag number: %i\n", this->header->tagNum); | 
|---|
| 171 |   printf("mesh number: %i\n", this->header->meshNum); | 
|---|
| 172 |   printf("max tex num: %i\n", this->header->maxTexNum); | 
|---|
| 173 |   printf("bone frame start: %i\n", this->header->boneFrameStart); | 
|---|
| 174 |   printf("tag start: %i\n", this->header->tagStart); | 
|---|
| 175 |   printf("mesh start: %i\n", this->header->meshStart); | 
|---|
| 176 |   printf("fileSize: %i\n", this->header->fileSize); | 
|---|
| 177 |  | 
|---|
| 178 |   return sizeof(MD3Header); | 
|---|
| 179 | } | 
|---|
| 180 |  | 
|---|
| 181 |  | 
|---|
| 182 | /** | 
|---|
| 183 |  * read bone frames | 
|---|
| 184 |  */ | 
|---|
| 185 | int MD3Data::readBoneFrames(FILE* pFile, int fileOffset) | 
|---|
| 186 | { | 
|---|
| 187 |   PRINTF(0)("Reading Bone Frames\n"); | 
|---|
| 188 |  | 
|---|
| 189 |   this->boneFrames = new MD3BoneFrame*[this->header->boneFrameNum]; | 
|---|
| 190 |  | 
|---|
| 191 |   for( int i = 0; i < this->header->boneFrameNum; i++) | 
|---|
| 192 |   { | 
|---|
| 193 |     this->boneFrames[i] = new MD3BoneFrame(i); | 
|---|
| 194 |  | 
|---|
| 195 |     MD3BoneFrameData* md = new MD3BoneFrameData; | 
|---|
| 196 |     fread(md, 1, sizeof(MD3BoneFrameData), pFile); | 
|---|
| 197 |     this->boneFrames[i]->data = md; | 
|---|
| 198 |   } | 
|---|
| 199 |  | 
|---|
| 200 |   return this->header->boneFrameNum * sizeof(MD3BoneFrameData); | 
|---|
| 201 | } | 
|---|
| 202 |  | 
|---|
| 203 |  | 
|---|
| 204 | /** | 
|---|
| 205 |  * read the tags | 
|---|
| 206 |  */ | 
|---|
| 207 | int MD3Data::readTags(FILE* pFile, int fileOffset) | 
|---|
| 208 | { | 
|---|
| 209 |   PRINTF(0)("Reading Tags\n"); | 
|---|
| 210 |  | 
|---|
| 211 |   for( int i = 0; i < this->header->boneFrameNum; i++) | 
|---|
| 212 |   { | 
|---|
| 213 |     this->boneFrames[i]->tags = new MD3Tag*[this->header->tagNum]; | 
|---|
| 214 |  | 
|---|
| 215 |     for( int j = 0; j < this->header->tagNum; j++) | 
|---|
| 216 |     { | 
|---|
| 217 |       this->boneFrames[i]->tags[j] = new MD3Tag(); | 
|---|
| 218 |       MD3TagData* md = new MD3TagData; | 
|---|
| 219 |       fread(md, 1, sizeof(MD3TagData), pFile); | 
|---|
| 220 |       this->boneFrames[i]->tags[j]->data = md; | 
|---|
| 221 |     } | 
|---|
| 222 |   } | 
|---|
| 223 |  | 
|---|
| 224 |   return this->header->boneFrameNum * this->header->tagNum * sizeof(MD3TagData); | 
|---|
| 225 | } | 
|---|
| 226 |  | 
|---|
| 227 |  | 
|---|
| 228 | /** | 
|---|
| 229 |  * read meshes | 
|---|
| 230 |  */ | 
|---|
| 231 | int MD3Data::readMeshes(FILE* pFile, int fileOffset) | 
|---|
| 232 | { | 
|---|
| 233 |   PRINTF(0)("Reading Mesh Data\n"); | 
|---|
| 234 |  | 
|---|
| 235 |   fileOffset = 0; | 
|---|
| 236 |  | 
|---|
| 237 |   this->meshes = new MD3Mesh*[this->header->meshNum]; | 
|---|
| 238 |  | 
|---|
| 239 |   for( int i = 0; i < this->header->meshNum; i++) | 
|---|
| 240 |   { | 
|---|
| 241 |     this->meshes[i] = new MD3Mesh(); | 
|---|
| 242 |  | 
|---|
| 243 |     int localFileOffset = 0; | 
|---|
| 244 |     bool   bTriangles, bTexVecs, bVertices, bTextures;            //!< the parts that have been read so far | 
|---|
| 245 |  | 
|---|
| 246 |     //start reading mesh data | 
|---|
| 247 |     MD3MeshHeader* md = new MD3MeshHeader; | 
|---|
| 248 |     fread(md, 1, sizeof(MD3MeshHeader), pFile); | 
|---|
| 249 |     this->meshes[i]->header = md; | 
|---|
| 250 |     localFileOffset += sizeof(MD3MeshHeader); | 
|---|
| 251 |  | 
|---|
| 252 |     PRINTF(0)("MD3 Mesh Header debug section\n"); | 
|---|
| 253 |     printf("ident: %i\n", md->id); | 
|---|
| 254 |     printf("filename: %s\n", md->name); | 
|---|
| 255 |     printf("meshFrameNum: %i\n", md->meshFrameNum); | 
|---|
| 256 |     printf("textureNum: %i\n", md->textureNum); | 
|---|
| 257 |     printf("vertexNum: %i \n", md->vertexNum); | 
|---|
| 258 |     printf("triangleNum: %i\n", md->triangleNum); | 
|---|
| 259 |     printf("triangleStart: %i\n", md->triangleStart); | 
|---|
| 260 |     printf("textureStart: %i\n", md->textureStart); | 
|---|
| 261 |     printf("texVecStart: %i\n", md->texVecStart); | 
|---|
| 262 |     printf("vertexStart: %i\n", md->vertexStart); | 
|---|
| 263 |     printf("fileSize: %i\n", md->meshSize); | 
|---|
| 264 |  | 
|---|
| 265 |     if( unlikely(this->meshes[i]->header->id != MD3_IDENT)) | 
|---|
| 266 |     { | 
|---|
| 267 |       PRINTF(1)("Wrong MD3 mesh file tag, file %s could be corrupt\n", this->filename.c_str()); | 
|---|
| 268 |       return false; | 
|---|
| 269 |     } | 
|---|
| 270 |  | 
|---|
| 271 |     // check which parts to be loaded | 
|---|
| 272 |     bTriangles = ( this->meshes[i]->header->triangleNum == 0); | 
|---|
| 273 |     bTexVecs = ( this->meshes[i]->header->vertexNum == 0); | 
|---|
| 274 |     bVertices = ( this->meshes[i]->header->meshFrameNum == 0); | 
|---|
| 275 |     bTextures = ( this->meshes[i]->header->textureNum == 0); | 
|---|
| 276 |  | 
|---|
| 277 |     // now read the data block whise | 
|---|
| 278 |     while( !(bTriangles && bTexVecs && bVertices && bTextures)) | 
|---|
| 279 |     { | 
|---|
| 280 |       PRINTF(0)("while2: localOffset = %i\n", localFileOffset); | 
|---|
| 281 |       if( localFileOffset == this->meshes[i]->header->triangleStart  && !bTriangles) | 
|---|
| 282 |       { | 
|---|
| 283 |         localFileOffset += this->readMeshTriangles(pFile, localFileOffset, i); | 
|---|
| 284 |         bTriangles = true; | 
|---|
| 285 |       } | 
|---|
| 286 |       else if( localFileOffset == this->meshes[i]->header->textureStart && !bTextures) | 
|---|
| 287 |       { | 
|---|
| 288 |         localFileOffset += this->readMeshTextures(pFile, localFileOffset, i); | 
|---|
| 289 |         bTextures = true; | 
|---|
| 290 |       } | 
|---|
| 291 |       else if( localFileOffset == this->meshes[i]->header->texVecStart && !bTexVecs) | 
|---|
| 292 |       { | 
|---|
| 293 |         localFileOffset += this->readMeshTexVecs(pFile, localFileOffset, i); | 
|---|
| 294 |         bTexVecs = true; | 
|---|
| 295 |       } | 
|---|
| 296 |       else if( localFileOffset == this->meshes[i]->header->vertexStart && !bVertices) | 
|---|
| 297 |       { | 
|---|
| 298 |         localFileOffset += this->readMeshVertices(pFile, localFileOffset, i); | 
|---|
| 299 |         bVertices = true; | 
|---|
| 300 |       } | 
|---|
| 301 |     } | 
|---|
| 302 |     fileOffset += localFileOffset; | 
|---|
| 303 |     PRINTF(0)("finished reading mesh %i, got %i of %i byes\n", i, localFileOffset, md->meshSize); | 
|---|
| 304 |   } | 
|---|
| 305 |   return fileOffset; | 
|---|
| 306 | } | 
|---|
| 307 |  | 
|---|
| 308 |  | 
|---|
| 309 |  | 
|---|
| 310 | /** | 
|---|
| 311 |  * reading in the mesh triangles | 
|---|
| 312 |  */ | 
|---|
| 313 | int MD3Data::readMeshTriangles(FILE* pFile, int fileOffset, int mesh) | 
|---|
| 314 | { | 
|---|
| 315 |   PRINTF(0)("Reading Mesh Triangles\n"); | 
|---|
| 316 |   // create the memomry to save the triangles | 
|---|
| 317 |   this->meshes[mesh]->triangles = new MD3Triangle[this->meshes[mesh]->header->triangleNum]; | 
|---|
| 318 |   fread(this->meshes[mesh]->triangles, 1, sizeof(MD3Triangle) * this->meshes[mesh]->header->triangleNum, pFile); | 
|---|
| 319 |  | 
|---|
| 320 |   return this->meshes[mesh]->header->triangleNum * sizeof(MD3Triangle); | 
|---|
| 321 | } | 
|---|
| 322 |  | 
|---|
| 323 |  | 
|---|
| 324 | /** | 
|---|
| 325 |  * reading in the mesh textures | 
|---|
| 326 |  */ | 
|---|
| 327 | int MD3Data::readMeshTextures(FILE* pFile, int fileOffset, int mesh) | 
|---|
| 328 | { | 
|---|
| 329 |   PRINTF(0)("Reading Mesh Textures\n"); | 
|---|
| 330 |  | 
|---|
| 331 |   // create the textures | 
|---|
| 332 |   this->meshes[mesh]->material = new Material[this->meshes[mesh]->header->textureNum]; | 
|---|
| 333 |  | 
|---|
| 334 |   MD3Texture* tex = new MD3Texture[this->meshes[mesh]->header->textureNum]; | 
|---|
| 335 |   fread(tex, 1, sizeof(MD3Texture) * this->meshes[mesh]->header->textureNum, pFile); | 
|---|
| 336 |  | 
|---|
| 337 |   for( int i = 0; i < this->meshes[mesh]->header->textureNum; i++) { | 
|---|
| 338 |     PRINTF(0)(" texture file: %s\n", tex[i].fileName); | 
|---|
| 339 |     this->meshes[mesh]->material[i].setDiffuseMap(tex[i].fileName); | 
|---|
| 340 |     this->meshes[mesh]->material[i].setAmbient(1, 1, 1); | 
|---|
| 341 |   } | 
|---|
| 342 |  | 
|---|
| 343 |   return this->meshes[mesh]->header->textureNum * sizeof(MD3Texture); | 
|---|
| 344 | } | 
|---|
| 345 |  | 
|---|
| 346 |  | 
|---|
| 347 | /** | 
|---|
| 348 |  * reading in the mesh tex vecs | 
|---|
| 349 |  */ | 
|---|
| 350 | int MD3Data::readMeshTexVecs(FILE* pFile, int fileOffset, int mesh) | 
|---|
| 351 | { | 
|---|
| 352 |   PRINTF(0)("Reading Mesh TexVecs\n"); | 
|---|
| 353 |  | 
|---|
| 354 |   this->meshes[mesh]->texVecs = new MD3TexVecs[this->meshes[mesh]->header->vertexNum]; | 
|---|
| 355 |   fread(this->meshes[mesh]->texVecs, 1, sizeof(MD3TexVecs) * this->meshes[mesh]->header->vertexNum, pFile); | 
|---|
| 356 |  | 
|---|
| 357 |   return this->meshes[mesh]->header->vertexNum * sizeof(MD3TexVecs); | 
|---|
| 358 | } | 
|---|
| 359 |  | 
|---|
| 360 |  | 
|---|
| 361 | /** | 
|---|
| 362 |  * reading in the mesh vertices | 
|---|
| 363 |  */ | 
|---|
| 364 | int MD3Data::readMeshVertices(FILE* pFile, int fileOffset, int mesh) | 
|---|
| 365 | { | 
|---|
| 366 |   PRINTF(0)("Reading Mesh Vertices\n"); | 
|---|
| 367 |  | 
|---|
| 368 |   // reserver memory for the vertex informations | 
|---|
| 369 |   this->meshes[mesh]->meshFrames = new sVec3D[this->meshes[mesh]->header->meshFrameNum * this->meshes[mesh]->header->vertexNum]; | 
|---|
| 370 |   this->meshes[mesh]->normals = new MD3Normal[this->meshes[mesh]->header->meshFrameNum * this->meshes[mesh]->header->vertexNum]; | 
|---|
| 371 |  | 
|---|
| 372 |   for( int i = 0; i < this->meshes[mesh]->header->meshFrameNum * this->meshes[mesh]->header->vertexNum; i++) | 
|---|
| 373 |   { | 
|---|
| 374 |     // read out the compressed data | 
|---|
| 375 |     MD3VertexCompressed* vc = new MD3VertexCompressed; | 
|---|
| 376 |     fread(vc, 1, sizeof(MD3VertexCompressed), pFile); | 
|---|
| 377 |  | 
|---|
| 378 |     this->meshes[mesh]->meshFrames[i][0] = (float)vc->vector[0] / 64.0f; | 
|---|
| 379 |     this->meshes[mesh]->meshFrames[i][1] = (float)vc->vector[1] / 64.0f; | 
|---|
| 380 |     this->meshes[mesh]->meshFrames[i][2] = (float)vc->vector[2] / 64.0f; | 
|---|
| 381 |  | 
|---|
| 382 |     this->meshes[mesh]->normals[i].vertexNormal[0] = vc->vertexNormal[0]; | 
|---|
| 383 |     this->meshes[mesh]->normals[i].vertexNormal[1] = vc->vertexNormal[1]; | 
|---|
| 384 |  | 
|---|
| 385 |     delete vc; | 
|---|
| 386 |   } | 
|---|
| 387 |  | 
|---|
| 388 |   // delete the temp memory again | 
|---|
| 389 | //   delete vc; | 
|---|
| 390 |  | 
|---|
| 391 |   return this->meshes[mesh]->header->meshFrameNum * this->meshes[mesh]->header->vertexNum * sizeof(MD3VertexCompressed); | 
|---|
| 392 | } | 
|---|
| 393 |  | 
|---|
| 394 | } | 
|---|
| 395 |  | 
|---|
| 396 |  | 
|---|
| 397 |  | 
|---|
| 398 |  | 
|---|
| 399 |  | 
|---|
| 400 |  | 
|---|
| 401 |  | 
|---|