vrshoot

annotate libs/assimp/MDLLoader.cpp @ 0:b2f14e535253

initial commit
author John Tsiombikas <nuclear@member.fsf.org>
date Sat, 01 Feb 2014 19:58:19 +0200
parents
children
rev   line source
nuclear@0 1 /*
nuclear@0 2 ---------------------------------------------------------------------------
nuclear@0 3 Open Asset Import Library (assimp)
nuclear@0 4 ---------------------------------------------------------------------------
nuclear@0 5
nuclear@0 6 Copyright (c) 2006-2012, assimp team
nuclear@0 7
nuclear@0 8 All rights reserved.
nuclear@0 9
nuclear@0 10 Redistribution and use of this software in source and binary forms,
nuclear@0 11 with or without modification, are permitted provided that the following
nuclear@0 12 conditions are met:
nuclear@0 13
nuclear@0 14 * Redistributions of source code must retain the above
nuclear@0 15 copyright notice, this list of conditions and the
nuclear@0 16 following disclaimer.
nuclear@0 17
nuclear@0 18 * Redistributions in binary form must reproduce the above
nuclear@0 19 copyright notice, this list of conditions and the
nuclear@0 20 following disclaimer in the documentation and/or other
nuclear@0 21 materials provided with the distribution.
nuclear@0 22
nuclear@0 23 * Neither the name of the assimp team, nor the names of its
nuclear@0 24 contributors may be used to endorse or promote products
nuclear@0 25 derived from this software without specific prior
nuclear@0 26 written permission of the assimp team.
nuclear@0 27
nuclear@0 28 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
nuclear@0 29 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
nuclear@0 30 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
nuclear@0 31 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
nuclear@0 32 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
nuclear@0 33 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
nuclear@0 34 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
nuclear@0 35 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
nuclear@0 36 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
nuclear@0 37 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
nuclear@0 38 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
nuclear@0 39 ---------------------------------------------------------------------------
nuclear@0 40 */
nuclear@0 41
nuclear@0 42 /** @file MDLLoader.cpp
nuclear@0 43 * @brief Implementation of the main parts of the MDL importer class
nuclear@0 44 * *TODO* Cleanup and further testing of some parts necessary
nuclear@0 45 */
nuclear@0 46
nuclear@0 47 // internal headers
nuclear@0 48 #include "AssimpPCH.h"
nuclear@0 49 #ifndef ASSIMP_BUILD_NO_MDL_IMPORTER
nuclear@0 50
nuclear@0 51 #include "MDLLoader.h"
nuclear@0 52 #include "MDLDefaultColorMap.h"
nuclear@0 53 #include "MD2FileData.h"
nuclear@0 54
nuclear@0 55 using namespace Assimp;
nuclear@0 56
nuclear@0 57 static const aiImporterDesc desc = {
nuclear@0 58 "Quake Mesh / 3D GameStudio Mesh Importer",
nuclear@0 59 "",
nuclear@0 60 "",
nuclear@0 61 "",
nuclear@0 62 aiImporterFlags_SupportBinaryFlavour,
nuclear@0 63 0,
nuclear@0 64 0,
nuclear@0 65 7,
nuclear@0 66 0,
nuclear@0 67 "mdl"
nuclear@0 68 };
nuclear@0 69
nuclear@0 70 // ------------------------------------------------------------------------------------------------
nuclear@0 71 // Ugly stuff ... nevermind
nuclear@0 72 #define _AI_MDL7_ACCESS(_data, _index, _limit, _type) \
nuclear@0 73 (*((const _type*)(((const char*)_data) + _index * _limit)))
nuclear@0 74
nuclear@0 75 #define _AI_MDL7_ACCESS_PTR(_data, _index, _limit, _type) \
nuclear@0 76 ((BE_NCONST _type*)(((const char*)_data) + _index * _limit))
nuclear@0 77
nuclear@0 78 #define _AI_MDL7_ACCESS_VERT(_data, _index, _limit) \
nuclear@0 79 _AI_MDL7_ACCESS(_data,_index,_limit,MDL::Vertex_MDL7)
nuclear@0 80
nuclear@0 81 // ------------------------------------------------------------------------------------------------
nuclear@0 82 // Constructor to be privately used by Importer
nuclear@0 83 MDLImporter::MDLImporter()
nuclear@0 84 {}
nuclear@0 85
nuclear@0 86 // ------------------------------------------------------------------------------------------------
nuclear@0 87 // Destructor, private as well
nuclear@0 88 MDLImporter::~MDLImporter()
nuclear@0 89 {}
nuclear@0 90
nuclear@0 91 // ------------------------------------------------------------------------------------------------
nuclear@0 92 // Returns whether the class can handle the format of the given file.
nuclear@0 93 bool MDLImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const
nuclear@0 94 {
nuclear@0 95 const std::string extension = GetExtension(pFile);
nuclear@0 96
nuclear@0 97 // if check for extension is not enough, check for the magic tokens
nuclear@0 98 if (extension == "mdl" || !extension.length() || checkSig) {
nuclear@0 99 uint32_t tokens[8];
nuclear@0 100 tokens[0] = AI_MDL_MAGIC_NUMBER_LE_HL2a;
nuclear@0 101 tokens[1] = AI_MDL_MAGIC_NUMBER_LE_HL2b;
nuclear@0 102 tokens[2] = AI_MDL_MAGIC_NUMBER_LE_GS7;
nuclear@0 103 tokens[3] = AI_MDL_MAGIC_NUMBER_LE_GS5b;
nuclear@0 104 tokens[4] = AI_MDL_MAGIC_NUMBER_LE_GS5a;
nuclear@0 105 tokens[5] = AI_MDL_MAGIC_NUMBER_LE_GS4;
nuclear@0 106 tokens[6] = AI_MDL_MAGIC_NUMBER_LE_GS3;
nuclear@0 107 tokens[7] = AI_MDL_MAGIC_NUMBER_LE;
nuclear@0 108 return CheckMagicToken(pIOHandler,pFile,tokens,8,0);
nuclear@0 109 }
nuclear@0 110 return false;
nuclear@0 111 }
nuclear@0 112
nuclear@0 113 // ------------------------------------------------------------------------------------------------
nuclear@0 114 // Setup configuration properties
nuclear@0 115 void MDLImporter::SetupProperties(const Importer* pImp)
nuclear@0 116 {
nuclear@0 117 configFrameID = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_MDL_KEYFRAME,-1);
nuclear@0 118
nuclear@0 119 // The
nuclear@0 120 // AI_CONFIG_IMPORT_MDL_KEYFRAME option overrides the
nuclear@0 121 // AI_CONFIG_IMPORT_GLOBAL_KEYFRAME option.
nuclear@0 122 if(static_cast<unsigned int>(-1) == configFrameID) {
nuclear@0 123 configFrameID = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_GLOBAL_KEYFRAME,0);
nuclear@0 124 }
nuclear@0 125
nuclear@0 126 // AI_CONFIG_IMPORT_MDL_COLORMAP - pallette file
nuclear@0 127 configPalette = pImp->GetPropertyString(AI_CONFIG_IMPORT_MDL_COLORMAP,"colormap.lmp");
nuclear@0 128 }
nuclear@0 129
nuclear@0 130 // ------------------------------------------------------------------------------------------------
nuclear@0 131 // Get a list of all supported extensions
nuclear@0 132 const aiImporterDesc* MDLImporter::GetInfo () const
nuclear@0 133 {
nuclear@0 134 return &desc;
nuclear@0 135 }
nuclear@0 136
nuclear@0 137 // ------------------------------------------------------------------------------------------------
nuclear@0 138 // Imports the given file into the given scene structure.
nuclear@0 139 void MDLImporter::InternReadFile( const std::string& pFile,
nuclear@0 140 aiScene* _pScene, IOSystem* _pIOHandler)
nuclear@0 141 {
nuclear@0 142 pScene = _pScene;
nuclear@0 143 pIOHandler = _pIOHandler;
nuclear@0 144 boost::scoped_ptr<IOStream> file( pIOHandler->Open( pFile));
nuclear@0 145
nuclear@0 146 // Check whether we can read from the file
nuclear@0 147 if( file.get() == NULL) {
nuclear@0 148 throw DeadlyImportError( "Failed to open MDL file " + pFile + ".");
nuclear@0 149 }
nuclear@0 150
nuclear@0 151 // This should work for all other types of MDL files, too ...
nuclear@0 152 // the quake header is one of the smallest, afaik
nuclear@0 153 iFileSize = (unsigned int)file->FileSize();
nuclear@0 154 if( iFileSize < sizeof(MDL::Header)) {
nuclear@0 155 throw DeadlyImportError( "MDL File is too small.");
nuclear@0 156 }
nuclear@0 157
nuclear@0 158 // Allocate storage and copy the contents of the file to a memory buffer
nuclear@0 159 std::vector<unsigned char> buffer(iFileSize+1);
nuclear@0 160 mBuffer = &buffer[0];
nuclear@0 161 file->Read( (void*)mBuffer, 1, iFileSize);
nuclear@0 162
nuclear@0 163 // Append a binary zero to the end of the buffer.
nuclear@0 164 // this is just for safety that string parsing routines
nuclear@0 165 // find the end of the buffer ...
nuclear@0 166 mBuffer[iFileSize] = '\0';
nuclear@0 167 const uint32_t iMagicWord = *((uint32_t*)mBuffer);
nuclear@0 168
nuclear@0 169 // Determine the file subtype and call the appropriate member function
nuclear@0 170
nuclear@0 171 // Original Quake1 format
nuclear@0 172 if (AI_MDL_MAGIC_NUMBER_BE == iMagicWord || AI_MDL_MAGIC_NUMBER_LE == iMagicWord) {
nuclear@0 173 DefaultLogger::get()->debug("MDL subtype: Quake 1, magic word is IDPO");
nuclear@0 174 iGSFileVersion = 0;
nuclear@0 175 InternReadFile_Quake1();
nuclear@0 176 }
nuclear@0 177 // GameStudio A<old> MDL2 format - used by some test models that come with 3DGS
nuclear@0 178 else if (AI_MDL_MAGIC_NUMBER_BE_GS3 == iMagicWord || AI_MDL_MAGIC_NUMBER_LE_GS3 == iMagicWord) {
nuclear@0 179 DefaultLogger::get()->debug("MDL subtype: 3D GameStudio A2, magic word is MDL2");
nuclear@0 180 iGSFileVersion = 2;
nuclear@0 181 InternReadFile_Quake1();
nuclear@0 182 }
nuclear@0 183 // GameStudio A4 MDL3 format
nuclear@0 184 else if (AI_MDL_MAGIC_NUMBER_BE_GS4 == iMagicWord || AI_MDL_MAGIC_NUMBER_LE_GS4 == iMagicWord) {
nuclear@0 185 DefaultLogger::get()->debug("MDL subtype: 3D GameStudio A4, magic word is MDL3");
nuclear@0 186 iGSFileVersion = 3;
nuclear@0 187 InternReadFile_3DGS_MDL345();
nuclear@0 188 }
nuclear@0 189 // GameStudio A5+ MDL4 format
nuclear@0 190 else if (AI_MDL_MAGIC_NUMBER_BE_GS5a == iMagicWord || AI_MDL_MAGIC_NUMBER_LE_GS5a == iMagicWord) {
nuclear@0 191 DefaultLogger::get()->debug("MDL subtype: 3D GameStudio A4, magic word is MDL4");
nuclear@0 192 iGSFileVersion = 4;
nuclear@0 193 InternReadFile_3DGS_MDL345();
nuclear@0 194 }
nuclear@0 195 // GameStudio A5+ MDL5 format
nuclear@0 196 else if (AI_MDL_MAGIC_NUMBER_BE_GS5b == iMagicWord || AI_MDL_MAGIC_NUMBER_LE_GS5b == iMagicWord) {
nuclear@0 197 DefaultLogger::get()->debug("MDL subtype: 3D GameStudio A5, magic word is MDL5");
nuclear@0 198 iGSFileVersion = 5;
nuclear@0 199 InternReadFile_3DGS_MDL345();
nuclear@0 200 }
nuclear@0 201 // GameStudio A7 MDL7 format
nuclear@0 202 else if (AI_MDL_MAGIC_NUMBER_BE_GS7 == iMagicWord || AI_MDL_MAGIC_NUMBER_LE_GS7 == iMagicWord) {
nuclear@0 203 DefaultLogger::get()->debug("MDL subtype: 3D GameStudio A7, magic word is MDL7");
nuclear@0 204 iGSFileVersion = 7;
nuclear@0 205 InternReadFile_3DGS_MDL7();
nuclear@0 206 }
nuclear@0 207 // IDST/IDSQ Format (CS:S/HL^2, etc ...)
nuclear@0 208 else if (AI_MDL_MAGIC_NUMBER_BE_HL2a == iMagicWord || AI_MDL_MAGIC_NUMBER_LE_HL2a == iMagicWord ||
nuclear@0 209 AI_MDL_MAGIC_NUMBER_BE_HL2b == iMagicWord || AI_MDL_MAGIC_NUMBER_LE_HL2b == iMagicWord)
nuclear@0 210 {
nuclear@0 211 DefaultLogger::get()->debug("MDL subtype: Source(tm) Engine, magic word is IDST/IDSQ");
nuclear@0 212 iGSFileVersion = 0;
nuclear@0 213 InternReadFile_HL2();
nuclear@0 214 }
nuclear@0 215 else {
nuclear@0 216 // print the magic word to the log file
nuclear@0 217 throw DeadlyImportError( "Unknown MDL subformat " + pFile +
nuclear@0 218 ". Magic word (" + std::string((char*)&iMagicWord,4) + ") is not known");
nuclear@0 219 }
nuclear@0 220
nuclear@0 221 // Now rotate the whole scene 90 degrees around the x axis to convert to internal coordinate system
nuclear@0 222 pScene->mRootNode->mTransformation = aiMatrix4x4(1.f,0.f,0.f,0.f,
nuclear@0 223 0.f,0.f,1.f,0.f,0.f,-1.f,0.f,0.f,0.f,0.f,0.f,1.f);
nuclear@0 224
nuclear@0 225 // delete the file buffer and cleanup
nuclear@0 226 AI_DEBUG_INVALIDATE_PTR(mBuffer);
nuclear@0 227 AI_DEBUG_INVALIDATE_PTR(pIOHandler);
nuclear@0 228 AI_DEBUG_INVALIDATE_PTR(pScene);
nuclear@0 229 }
nuclear@0 230
nuclear@0 231 // ------------------------------------------------------------------------------------------------
nuclear@0 232 // Check whether we're still inside the valid file range
nuclear@0 233 void MDLImporter::SizeCheck(const void* szPos)
nuclear@0 234 {
nuclear@0 235 if (!szPos || (const unsigned char*)szPos > this->mBuffer + this->iFileSize)
nuclear@0 236 {
nuclear@0 237 throw DeadlyImportError("Invalid MDL file. The file is too small "
nuclear@0 238 "or contains invalid data.");
nuclear@0 239 }
nuclear@0 240 }
nuclear@0 241
nuclear@0 242 // ------------------------------------------------------------------------------------------------
nuclear@0 243 // Just for debgging purposes
nuclear@0 244 void MDLImporter::SizeCheck(const void* szPos, const char* szFile, unsigned int iLine)
nuclear@0 245 {
nuclear@0 246 ai_assert(NULL != szFile);
nuclear@0 247 if (!szPos || (const unsigned char*)szPos > mBuffer + iFileSize)
nuclear@0 248 {
nuclear@0 249 // remove a directory if there is one
nuclear@0 250 const char* szFilePtr = ::strrchr(szFile,'\\');
nuclear@0 251 if (!szFilePtr) {
nuclear@0 252 if(!(szFilePtr = ::strrchr(szFile,'/')))
nuclear@0 253 szFilePtr = szFile;
nuclear@0 254 }
nuclear@0 255 if (szFilePtr)++szFilePtr;
nuclear@0 256
nuclear@0 257 char szBuffer[1024];
nuclear@0 258 ::sprintf(szBuffer,"Invalid MDL file. The file is too small "
nuclear@0 259 "or contains invalid data (File: %s Line: %i)",szFilePtr,iLine);
nuclear@0 260
nuclear@0 261 throw DeadlyImportError(szBuffer);
nuclear@0 262 }
nuclear@0 263 }
nuclear@0 264
nuclear@0 265 // ------------------------------------------------------------------------------------------------
nuclear@0 266 // Validate a quake file header
nuclear@0 267 void MDLImporter::ValidateHeader_Quake1(const MDL::Header* pcHeader)
nuclear@0 268 {
nuclear@0 269 // some values may not be NULL
nuclear@0 270 if (!pcHeader->num_frames)
nuclear@0 271 throw DeadlyImportError( "[Quake 1 MDL] There are no frames in the file");
nuclear@0 272
nuclear@0 273 if (!pcHeader->num_verts)
nuclear@0 274 throw DeadlyImportError( "[Quake 1 MDL] There are no vertices in the file");
nuclear@0 275
nuclear@0 276 if (!pcHeader->num_tris)
nuclear@0 277 throw DeadlyImportError( "[Quake 1 MDL] There are no triangles in the file");
nuclear@0 278
nuclear@0 279 // check whether the maxima are exceeded ...however, this applies for Quake 1 MDLs only
nuclear@0 280 if (!this->iGSFileVersion)
nuclear@0 281 {
nuclear@0 282 if (pcHeader->num_verts > AI_MDL_MAX_VERTS)
nuclear@0 283 DefaultLogger::get()->warn("Quake 1 MDL model has more than AI_MDL_MAX_VERTS vertices");
nuclear@0 284
nuclear@0 285 if (pcHeader->num_tris > AI_MDL_MAX_TRIANGLES)
nuclear@0 286 DefaultLogger::get()->warn("Quake 1 MDL model has more than AI_MDL_MAX_TRIANGLES triangles");
nuclear@0 287
nuclear@0 288 if (pcHeader->num_frames > AI_MDL_MAX_FRAMES)
nuclear@0 289 DefaultLogger::get()->warn("Quake 1 MDL model has more than AI_MDL_MAX_FRAMES frames");
nuclear@0 290
nuclear@0 291 // (this does not apply for 3DGS MDLs)
nuclear@0 292 if (!this->iGSFileVersion && pcHeader->version != AI_MDL_VERSION)
nuclear@0 293 DefaultLogger::get()->warn("Quake 1 MDL model has an unknown version: AI_MDL_VERSION (=6) is "
nuclear@0 294 "the expected file format version");
nuclear@0 295 if(pcHeader->num_skins && (!pcHeader->skinwidth || !pcHeader->skinheight))
nuclear@0 296 DefaultLogger::get()->warn("Skin width or height are 0");
nuclear@0 297 }
nuclear@0 298 }
nuclear@0 299
nuclear@0 300 #ifdef AI_BUILD_BIG_ENDIAN
nuclear@0 301 // ------------------------------------------------------------------------------------------------
nuclear@0 302 void FlipQuakeHeader(BE_NCONST MDL::Header* pcHeader)
nuclear@0 303 {
nuclear@0 304 AI_SWAP4( pcHeader->ident);
nuclear@0 305 AI_SWAP4( pcHeader->version);
nuclear@0 306 AI_SWAP4( pcHeader->boundingradius);
nuclear@0 307 AI_SWAP4( pcHeader->flags);
nuclear@0 308 AI_SWAP4( pcHeader->num_frames);
nuclear@0 309 AI_SWAP4( pcHeader->num_skins);
nuclear@0 310 AI_SWAP4( pcHeader->num_tris);
nuclear@0 311 AI_SWAP4( pcHeader->num_verts);
nuclear@0 312 for (unsigned int i = 0; i < 3;++i)
nuclear@0 313 {
nuclear@0 314 AI_SWAP4( pcHeader->scale[i]);
nuclear@0 315 AI_SWAP4( pcHeader->translate[i]);
nuclear@0 316 }
nuclear@0 317 AI_SWAP4( pcHeader->size);
nuclear@0 318 AI_SWAP4( pcHeader->skinheight);
nuclear@0 319 AI_SWAP4( pcHeader->skinwidth);
nuclear@0 320 AI_SWAP4( pcHeader->synctype);
nuclear@0 321 }
nuclear@0 322 #endif
nuclear@0 323
nuclear@0 324 // ------------------------------------------------------------------------------------------------
nuclear@0 325 // Read a Quake 1 file
nuclear@0 326 void MDLImporter::InternReadFile_Quake1( )
nuclear@0 327 {
nuclear@0 328 ai_assert(NULL != pScene);
nuclear@0 329 BE_NCONST MDL::Header *pcHeader = (BE_NCONST MDL::Header*)this->mBuffer;
nuclear@0 330
nuclear@0 331 #ifdef AI_BUILD_BIG_ENDIAN
nuclear@0 332 FlipQuakeHeader(pcHeader);
nuclear@0 333 #endif
nuclear@0 334
nuclear@0 335 ValidateHeader_Quake1(pcHeader);
nuclear@0 336
nuclear@0 337 // current cursor position in the file
nuclear@0 338 const unsigned char* szCurrent = (const unsigned char*)(pcHeader+1);
nuclear@0 339
nuclear@0 340 // need to read all textures
nuclear@0 341 for (unsigned int i = 0; i < (unsigned int)pcHeader->num_skins;++i)
nuclear@0 342 {
nuclear@0 343 union{BE_NCONST MDL::Skin* pcSkin;BE_NCONST MDL::GroupSkin* pcGroupSkin;};
nuclear@0 344 pcSkin = (BE_NCONST MDL::Skin*)szCurrent;
nuclear@0 345
nuclear@0 346 AI_SWAP4( pcSkin->group );
nuclear@0 347
nuclear@0 348 // Quake 1 groupskins
nuclear@0 349 if (1 == pcSkin->group)
nuclear@0 350 {
nuclear@0 351 AI_SWAP4( pcGroupSkin->nb );
nuclear@0 352
nuclear@0 353 // need to skip multiple images
nuclear@0 354 const unsigned int iNumImages = (unsigned int)pcGroupSkin->nb;
nuclear@0 355 szCurrent += sizeof(uint32_t) * 2;
nuclear@0 356
nuclear@0 357 if (0 != iNumImages)
nuclear@0 358 {
nuclear@0 359 if (!i) {
nuclear@0 360 // however, create only one output image (the first)
nuclear@0 361 this->CreateTextureARGB8_3DGS_MDL3(szCurrent + iNumImages * sizeof(float));
nuclear@0 362 }
nuclear@0 363 // go to the end of the skin section / the beginning of the next skin
nuclear@0 364 szCurrent += pcHeader->skinheight * pcHeader->skinwidth +
nuclear@0 365 sizeof(float) * iNumImages;
nuclear@0 366 }
nuclear@0 367 }
nuclear@0 368 // 3DGS has a few files that are using other 3DGS like texture formats here
nuclear@0 369 else
nuclear@0 370 {
nuclear@0 371 szCurrent += sizeof(uint32_t);
nuclear@0 372 unsigned int iSkip = i ? UINT_MAX : 0;
nuclear@0 373 CreateTexture_3DGS_MDL4(szCurrent,pcSkin->group,&iSkip);
nuclear@0 374 szCurrent += iSkip;
nuclear@0 375 }
nuclear@0 376 }
nuclear@0 377 // get a pointer to the texture coordinates
nuclear@0 378 BE_NCONST MDL::TexCoord* pcTexCoords = (BE_NCONST MDL::TexCoord*)szCurrent;
nuclear@0 379 szCurrent += sizeof(MDL::TexCoord) * pcHeader->num_verts;
nuclear@0 380
nuclear@0 381 // get a pointer to the triangles
nuclear@0 382 BE_NCONST MDL::Triangle* pcTriangles = (BE_NCONST MDL::Triangle*)szCurrent;
nuclear@0 383 szCurrent += sizeof(MDL::Triangle) * pcHeader->num_tris;
nuclear@0 384 VALIDATE_FILE_SIZE(szCurrent);
nuclear@0 385
nuclear@0 386 // now get a pointer to the first frame in the file
nuclear@0 387 BE_NCONST MDL::Frame* pcFrames = (BE_NCONST MDL::Frame*)szCurrent;
nuclear@0 388 BE_NCONST MDL::SimpleFrame* pcFirstFrame;
nuclear@0 389
nuclear@0 390 if (0 == pcFrames->type)
nuclear@0 391 {
nuclear@0 392 // get address of single frame
nuclear@0 393 pcFirstFrame = &pcFrames->frame;
nuclear@0 394 }
nuclear@0 395 else
nuclear@0 396 {
nuclear@0 397 // get the first frame in the group
nuclear@0 398 BE_NCONST MDL::GroupFrame* pcFrames2 = (BE_NCONST MDL::GroupFrame*)pcFrames;
nuclear@0 399 pcFirstFrame = (BE_NCONST MDL::SimpleFrame*)(&pcFrames2->time + pcFrames->type);
nuclear@0 400 }
nuclear@0 401 BE_NCONST MDL::Vertex* pcVertices = (BE_NCONST MDL::Vertex*) ((pcFirstFrame->name) + sizeof(pcFirstFrame->name));
nuclear@0 402 VALIDATE_FILE_SIZE((const unsigned char*)(pcVertices + pcHeader->num_verts));
nuclear@0 403
nuclear@0 404 #ifdef AI_BUILD_BIG_ENDIAN
nuclear@0 405 for (int i = 0; i<pcHeader->num_verts;++i)
nuclear@0 406 {
nuclear@0 407 AI_SWAP4( pcTexCoords[i].onseam );
nuclear@0 408 AI_SWAP4( pcTexCoords[i].s );
nuclear@0 409 AI_SWAP4( pcTexCoords[i].t );
nuclear@0 410 }
nuclear@0 411
nuclear@0 412 for (int i = 0; i<pcHeader->num_tris;++i)
nuclear@0 413 {
nuclear@0 414 AI_SWAP4( pcTriangles[i].facesfront);
nuclear@0 415 AI_SWAP4( pcTriangles[i].vertex[0]);
nuclear@0 416 AI_SWAP4( pcTriangles[i].vertex[1]);
nuclear@0 417 AI_SWAP4( pcTriangles[i].vertex[2]);
nuclear@0 418 }
nuclear@0 419 #endif
nuclear@0 420
nuclear@0 421 // setup materials
nuclear@0 422 SetupMaterialProperties_3DGS_MDL5_Quake1();
nuclear@0 423
nuclear@0 424 // allocate enough storage to hold all vertices and triangles
nuclear@0 425 aiMesh* pcMesh = new aiMesh();
nuclear@0 426
nuclear@0 427 pcMesh->mPrimitiveTypes = aiPrimitiveType_TRIANGLE;
nuclear@0 428 pcMesh->mNumVertices = pcHeader->num_tris * 3;
nuclear@0 429 pcMesh->mNumFaces = pcHeader->num_tris;
nuclear@0 430 pcMesh->mVertices = new aiVector3D[pcMesh->mNumVertices];
nuclear@0 431 pcMesh->mTextureCoords[0] = new aiVector3D[pcMesh->mNumVertices];
nuclear@0 432 pcMesh->mFaces = new aiFace[pcMesh->mNumFaces];
nuclear@0 433 pcMesh->mNormals = new aiVector3D[pcMesh->mNumVertices];
nuclear@0 434 pcMesh->mNumUVComponents[0] = 2;
nuclear@0 435
nuclear@0 436 // there won't be more than one mesh inside the file
nuclear@0 437 pScene->mRootNode = new aiNode();
nuclear@0 438 pScene->mRootNode->mNumMeshes = 1;
nuclear@0 439 pScene->mRootNode->mMeshes = new unsigned int[1];
nuclear@0 440 pScene->mRootNode->mMeshes[0] = 0;
nuclear@0 441 pScene->mNumMeshes = 1;
nuclear@0 442 pScene->mMeshes = new aiMesh*[1];
nuclear@0 443 pScene->mMeshes[0] = pcMesh;
nuclear@0 444
nuclear@0 445 // now iterate through all triangles
nuclear@0 446 unsigned int iCurrent = 0;
nuclear@0 447 for (unsigned int i = 0; i < (unsigned int) pcHeader->num_tris;++i)
nuclear@0 448 {
nuclear@0 449 pcMesh->mFaces[i].mIndices = new unsigned int[3];
nuclear@0 450 pcMesh->mFaces[i].mNumIndices = 3;
nuclear@0 451
nuclear@0 452 unsigned int iTemp = iCurrent;
nuclear@0 453 for (unsigned int c = 0; c < 3;++c,++iCurrent)
nuclear@0 454 {
nuclear@0 455 pcMesh->mFaces[i].mIndices[c] = iCurrent;
nuclear@0 456
nuclear@0 457 // read vertices
nuclear@0 458 unsigned int iIndex = pcTriangles->vertex[c];
nuclear@0 459 if (iIndex >= (unsigned int)pcHeader->num_verts)
nuclear@0 460 {
nuclear@0 461 iIndex = pcHeader->num_verts-1;
nuclear@0 462 DefaultLogger::get()->warn("Index overflow in Q1-MDL vertex list.");
nuclear@0 463 }
nuclear@0 464
nuclear@0 465 aiVector3D& vec = pcMesh->mVertices[iCurrent];
nuclear@0 466 vec.x = (float)pcVertices[iIndex].v[0] * pcHeader->scale[0];
nuclear@0 467 vec.x += pcHeader->translate[0];
nuclear@0 468
nuclear@0 469 vec.y = (float)pcVertices[iIndex].v[1] * pcHeader->scale[1];
nuclear@0 470 vec.y += pcHeader->translate[1];
nuclear@0 471 //vec.y *= -1.0f;
nuclear@0 472
nuclear@0 473 vec.z = (float)pcVertices[iIndex].v[2] * pcHeader->scale[2];
nuclear@0 474 vec.z += pcHeader->translate[2];
nuclear@0 475
nuclear@0 476 // read the normal vector from the precalculated normal table
nuclear@0 477 MD2::LookupNormalIndex(pcVertices[iIndex].normalIndex,pcMesh->mNormals[iCurrent]);
nuclear@0 478 //pcMesh->mNormals[iCurrent].y *= -1.0f;
nuclear@0 479
nuclear@0 480 // read texture coordinates
nuclear@0 481 float s = (float)pcTexCoords[iIndex].s;
nuclear@0 482 float t = (float)pcTexCoords[iIndex].t;
nuclear@0 483
nuclear@0 484 // translate texture coordinates
nuclear@0 485 if (0 == pcTriangles->facesfront && 0 != pcTexCoords[iIndex].onseam) {
nuclear@0 486 s += pcHeader->skinwidth * 0.5f;
nuclear@0 487 }
nuclear@0 488
nuclear@0 489 // Scale s and t to range from 0.0 to 1.0
nuclear@0 490 pcMesh->mTextureCoords[0][iCurrent].x = (s + 0.5f) / pcHeader->skinwidth;
nuclear@0 491 pcMesh->mTextureCoords[0][iCurrent].y = 1.0f-(t + 0.5f) / pcHeader->skinheight;
nuclear@0 492
nuclear@0 493 }
nuclear@0 494 pcMesh->mFaces[i].mIndices[0] = iTemp+2;
nuclear@0 495 pcMesh->mFaces[i].mIndices[1] = iTemp+1;
nuclear@0 496 pcMesh->mFaces[i].mIndices[2] = iTemp+0;
nuclear@0 497 pcTriangles++;
nuclear@0 498 }
nuclear@0 499 return;
nuclear@0 500 }
nuclear@0 501
nuclear@0 502 // ------------------------------------------------------------------------------------------------
nuclear@0 503 // Setup material properties for Quake and older GameStudio files
nuclear@0 504 void MDLImporter::SetupMaterialProperties_3DGS_MDL5_Quake1( )
nuclear@0 505 {
nuclear@0 506 const MDL::Header* const pcHeader = (const MDL::Header*)this->mBuffer;
nuclear@0 507
nuclear@0 508 // allocate ONE material
nuclear@0 509 pScene->mMaterials = new aiMaterial*[1];
nuclear@0 510 pScene->mMaterials[0] = new aiMaterial();
nuclear@0 511 pScene->mNumMaterials = 1;
nuclear@0 512
nuclear@0 513 // setup the material's properties
nuclear@0 514 const int iMode = (int)aiShadingMode_Gouraud;
nuclear@0 515 aiMaterial* const pcHelper = (aiMaterial*)pScene->mMaterials[0];
nuclear@0 516 pcHelper->AddProperty<int>(&iMode, 1, AI_MATKEY_SHADING_MODEL);
nuclear@0 517
nuclear@0 518 aiColor4D clr;
nuclear@0 519 if (0 != pcHeader->num_skins && pScene->mNumTextures) {
nuclear@0 520 // can we replace the texture with a single color?
nuclear@0 521 clr = this->ReplaceTextureWithColor(pScene->mTextures[0]);
nuclear@0 522 if (is_not_qnan(clr.r)) {
nuclear@0 523 delete pScene->mTextures[0];
nuclear@0 524 delete[] pScene->mTextures;
nuclear@0 525
nuclear@0 526 pScene->mTextures = NULL;
nuclear@0 527 pScene->mNumTextures = 0;
nuclear@0 528 }
nuclear@0 529 else {
nuclear@0 530 clr.b = clr.a = clr.g = clr.r = 1.0f;
nuclear@0 531 aiString szString;
nuclear@0 532 ::memcpy(szString.data,AI_MAKE_EMBEDDED_TEXNAME(0),3);
nuclear@0 533 szString.length = 2;
nuclear@0 534 pcHelper->AddProperty(&szString,AI_MATKEY_TEXTURE_DIFFUSE(0));
nuclear@0 535 }
nuclear@0 536 }
nuclear@0 537
nuclear@0 538 pcHelper->AddProperty<aiColor4D>(&clr, 1,AI_MATKEY_COLOR_DIFFUSE);
nuclear@0 539 pcHelper->AddProperty<aiColor4D>(&clr, 1,AI_MATKEY_COLOR_SPECULAR);
nuclear@0 540
nuclear@0 541 clr.r *= 0.05f;clr.g *= 0.05f;
nuclear@0 542 clr.b *= 0.05f;clr.a = 1.0f;
nuclear@0 543 pcHelper->AddProperty<aiColor4D>(&clr, 1,AI_MATKEY_COLOR_AMBIENT);
nuclear@0 544 }
nuclear@0 545
nuclear@0 546 // ------------------------------------------------------------------------------------------------
nuclear@0 547 // Read a MDL 3,4,5 file
nuclear@0 548 void MDLImporter::InternReadFile_3DGS_MDL345( )
nuclear@0 549 {
nuclear@0 550 ai_assert(NULL != pScene);
nuclear@0 551
nuclear@0 552 // the header of MDL 3/4/5 is nearly identical to the original Quake1 header
nuclear@0 553 BE_NCONST MDL::Header *pcHeader = (BE_NCONST MDL::Header*)this->mBuffer;
nuclear@0 554 #ifdef AI_BUILD_BIG_ENDIAN
nuclear@0 555 FlipQuakeHeader(pcHeader);
nuclear@0 556 #endif
nuclear@0 557 ValidateHeader_Quake1(pcHeader);
nuclear@0 558
nuclear@0 559 // current cursor position in the file
nuclear@0 560 const unsigned char* szCurrent = (const unsigned char*)(pcHeader+1);
nuclear@0 561
nuclear@0 562 // need to read all textures
nuclear@0 563 for (unsigned int i = 0; i < (unsigned int)pcHeader->num_skins;++i) {
nuclear@0 564 BE_NCONST MDL::Skin* pcSkin;
nuclear@0 565 pcSkin = (BE_NCONST MDL::Skin*)szCurrent;
nuclear@0 566 AI_SWAP4( pcSkin->group);
nuclear@0 567 // create one output image
nuclear@0 568 unsigned int iSkip = i ? UINT_MAX : 0;
nuclear@0 569 if (5 <= iGSFileVersion)
nuclear@0 570 {
nuclear@0 571 // MDL5 format could contain MIPmaps
nuclear@0 572 CreateTexture_3DGS_MDL5((unsigned char*)pcSkin + sizeof(uint32_t),
nuclear@0 573 pcSkin->group,&iSkip);
nuclear@0 574 }
nuclear@0 575 else {
nuclear@0 576 CreateTexture_3DGS_MDL4((unsigned char*)pcSkin + sizeof(uint32_t),
nuclear@0 577 pcSkin->group,&iSkip);
nuclear@0 578 }
nuclear@0 579 // need to skip one image
nuclear@0 580 szCurrent += iSkip + sizeof(uint32_t);
nuclear@0 581
nuclear@0 582 }
nuclear@0 583 // get a pointer to the texture coordinates
nuclear@0 584 BE_NCONST MDL::TexCoord_MDL3* pcTexCoords = (BE_NCONST MDL::TexCoord_MDL3*)szCurrent;
nuclear@0 585 szCurrent += sizeof(MDL::TexCoord_MDL3) * pcHeader->synctype;
nuclear@0 586
nuclear@0 587 // NOTE: for MDLn formats "synctype" corresponds to the number of UV coords
nuclear@0 588
nuclear@0 589 // get a pointer to the triangles
nuclear@0 590 BE_NCONST MDL::Triangle_MDL3* pcTriangles = (BE_NCONST MDL::Triangle_MDL3*)szCurrent;
nuclear@0 591 szCurrent += sizeof(MDL::Triangle_MDL3) * pcHeader->num_tris;
nuclear@0 592
nuclear@0 593 #ifdef AI_BUILD_BIG_ENDIAN
nuclear@0 594
nuclear@0 595 for (int i = 0; i<pcHeader->synctype;++i) {
nuclear@0 596 AI_SWAP2( pcTexCoords[i].u );
nuclear@0 597 AI_SWAP2( pcTexCoords[i].v );
nuclear@0 598 }
nuclear@0 599
nuclear@0 600 for (int i = 0; i<pcHeader->num_tris;++i) {
nuclear@0 601 AI_SWAP2( pcTriangles[i].index_xyz[0]);
nuclear@0 602 AI_SWAP2( pcTriangles[i].index_xyz[1]);
nuclear@0 603 AI_SWAP2( pcTriangles[i].index_xyz[2]);
nuclear@0 604 AI_SWAP2( pcTriangles[i].index_uv[0]);
nuclear@0 605 AI_SWAP2( pcTriangles[i].index_uv[1]);
nuclear@0 606 AI_SWAP2( pcTriangles[i].index_uv[2]);
nuclear@0 607 }
nuclear@0 608
nuclear@0 609 #endif
nuclear@0 610
nuclear@0 611 VALIDATE_FILE_SIZE(szCurrent);
nuclear@0 612
nuclear@0 613 // setup materials
nuclear@0 614 SetupMaterialProperties_3DGS_MDL5_Quake1();
nuclear@0 615
nuclear@0 616 // allocate enough storage to hold all vertices and triangles
nuclear@0 617 aiMesh* pcMesh = new aiMesh();
nuclear@0 618 pcMesh->mPrimitiveTypes = aiPrimitiveType_TRIANGLE;
nuclear@0 619
nuclear@0 620 pcMesh->mNumVertices = pcHeader->num_tris * 3;
nuclear@0 621 pcMesh->mNumFaces = pcHeader->num_tris;
nuclear@0 622 pcMesh->mFaces = new aiFace[pcMesh->mNumFaces];
nuclear@0 623
nuclear@0 624 // there won't be more than one mesh inside the file
nuclear@0 625 pScene->mRootNode = new aiNode();
nuclear@0 626 pScene->mRootNode->mNumMeshes = 1;
nuclear@0 627 pScene->mRootNode->mMeshes = new unsigned int[1];
nuclear@0 628 pScene->mRootNode->mMeshes[0] = 0;
nuclear@0 629 pScene->mNumMeshes = 1;
nuclear@0 630 pScene->mMeshes = new aiMesh*[1];
nuclear@0 631 pScene->mMeshes[0] = pcMesh;
nuclear@0 632
nuclear@0 633 // allocate output storage
nuclear@0 634 pcMesh->mNumVertices = (unsigned int)pcHeader->num_tris*3;
nuclear@0 635 pcMesh->mVertices = new aiVector3D[pcMesh->mNumVertices];
nuclear@0 636 pcMesh->mNormals = new aiVector3D[pcMesh->mNumVertices];
nuclear@0 637
nuclear@0 638 if (pcHeader->synctype) {
nuclear@0 639 pcMesh->mTextureCoords[0] = new aiVector3D[pcMesh->mNumVertices];
nuclear@0 640 pcMesh->mNumUVComponents[0] = 2;
nuclear@0 641 }
nuclear@0 642
nuclear@0 643 // now get a pointer to the first frame in the file
nuclear@0 644 BE_NCONST MDL::Frame* pcFrames = (BE_NCONST MDL::Frame*)szCurrent;
nuclear@0 645 AI_SWAP4(pcFrames->type);
nuclear@0 646
nuclear@0 647 // byte packed vertices
nuclear@0 648 // FIXME: these two snippets below are almost identical ... join them?
nuclear@0 649 /////////////////////////////////////////////////////////////////////////////////////
nuclear@0 650 if (0 == pcFrames->type || 3 >= this->iGSFileVersion) {
nuclear@0 651
nuclear@0 652 const MDL::SimpleFrame* pcFirstFrame = (const MDL::SimpleFrame*)(szCurrent + sizeof(uint32_t));
nuclear@0 653 const MDL::Vertex* pcVertices = (const MDL::Vertex*) ((pcFirstFrame->name) + sizeof(pcFirstFrame->name));
nuclear@0 654
nuclear@0 655 VALIDATE_FILE_SIZE(pcVertices + pcHeader->num_verts);
nuclear@0 656
nuclear@0 657 // now iterate through all triangles
nuclear@0 658 unsigned int iCurrent = 0;
nuclear@0 659 for (unsigned int i = 0; i < (unsigned int) pcHeader->num_tris;++i) {
nuclear@0 660 pcMesh->mFaces[i].mIndices = new unsigned int[3];
nuclear@0 661 pcMesh->mFaces[i].mNumIndices = 3;
nuclear@0 662
nuclear@0 663 unsigned int iTemp = iCurrent;
nuclear@0 664 for (unsigned int c = 0; c < 3;++c,++iCurrent) {
nuclear@0 665 // read vertices
nuclear@0 666 unsigned int iIndex = pcTriangles->index_xyz[c];
nuclear@0 667 if (iIndex >= (unsigned int)pcHeader->num_verts) {
nuclear@0 668 iIndex = pcHeader->num_verts-1;
nuclear@0 669 DefaultLogger::get()->warn("Index overflow in MDLn vertex list");
nuclear@0 670 }
nuclear@0 671
nuclear@0 672 aiVector3D& vec = pcMesh->mVertices[iCurrent];
nuclear@0 673 vec.x = (float)pcVertices[iIndex].v[0] * pcHeader->scale[0];
nuclear@0 674 vec.x += pcHeader->translate[0];
nuclear@0 675
nuclear@0 676 vec.y = (float)pcVertices[iIndex].v[1] * pcHeader->scale[1];
nuclear@0 677 vec.y += pcHeader->translate[1];
nuclear@0 678 // vec.y *= -1.0f;
nuclear@0 679
nuclear@0 680 vec.z = (float)pcVertices[iIndex].v[2] * pcHeader->scale[2];
nuclear@0 681 vec.z += pcHeader->translate[2];
nuclear@0 682
nuclear@0 683 // read the normal vector from the precalculated normal table
nuclear@0 684 MD2::LookupNormalIndex(pcVertices[iIndex].normalIndex,pcMesh->mNormals[iCurrent]);
nuclear@0 685 // pcMesh->mNormals[iCurrent].y *= -1.0f;
nuclear@0 686
nuclear@0 687 // read texture coordinates
nuclear@0 688 if (pcHeader->synctype) {
nuclear@0 689 ImportUVCoordinate_3DGS_MDL345(pcMesh->mTextureCoords[0][iCurrent],
nuclear@0 690 pcTexCoords,pcTriangles->index_uv[c]);
nuclear@0 691 }
nuclear@0 692 }
nuclear@0 693 pcMesh->mFaces[i].mIndices[0] = iTemp+2;
nuclear@0 694 pcMesh->mFaces[i].mIndices[1] = iTemp+1;
nuclear@0 695 pcMesh->mFaces[i].mIndices[2] = iTemp+0;
nuclear@0 696 pcTriangles++;
nuclear@0 697 }
nuclear@0 698
nuclear@0 699 }
nuclear@0 700 // short packed vertices
nuclear@0 701 /////////////////////////////////////////////////////////////////////////////////////
nuclear@0 702 else {
nuclear@0 703 // now get a pointer to the first frame in the file
nuclear@0 704 const MDL::SimpleFrame_MDLn_SP* pcFirstFrame = (const MDL::SimpleFrame_MDLn_SP*) (szCurrent + sizeof(uint32_t));
nuclear@0 705
nuclear@0 706 // get a pointer to the vertices
nuclear@0 707 const MDL::Vertex_MDL4* pcVertices = (const MDL::Vertex_MDL4*) ((pcFirstFrame->name) +
nuclear@0 708 sizeof(pcFirstFrame->name));
nuclear@0 709
nuclear@0 710 VALIDATE_FILE_SIZE(pcVertices + pcHeader->num_verts);
nuclear@0 711
nuclear@0 712 // now iterate through all triangles
nuclear@0 713 unsigned int iCurrent = 0;
nuclear@0 714 for (unsigned int i = 0; i < (unsigned int) pcHeader->num_tris;++i) {
nuclear@0 715 pcMesh->mFaces[i].mIndices = new unsigned int[3];
nuclear@0 716 pcMesh->mFaces[i].mNumIndices = 3;
nuclear@0 717
nuclear@0 718 unsigned int iTemp = iCurrent;
nuclear@0 719 for (unsigned int c = 0; c < 3;++c,++iCurrent) {
nuclear@0 720 // read vertices
nuclear@0 721 unsigned int iIndex = pcTriangles->index_xyz[c];
nuclear@0 722 if (iIndex >= (unsigned int)pcHeader->num_verts) {
nuclear@0 723 iIndex = pcHeader->num_verts-1;
nuclear@0 724 DefaultLogger::get()->warn("Index overflow in MDLn vertex list");
nuclear@0 725 }
nuclear@0 726
nuclear@0 727 aiVector3D& vec = pcMesh->mVertices[iCurrent];
nuclear@0 728 vec.x = (float)pcVertices[iIndex].v[0] * pcHeader->scale[0];
nuclear@0 729 vec.x += pcHeader->translate[0];
nuclear@0 730
nuclear@0 731 vec.y = (float)pcVertices[iIndex].v[1] * pcHeader->scale[1];
nuclear@0 732 vec.y += pcHeader->translate[1];
nuclear@0 733 // vec.y *= -1.0f;
nuclear@0 734
nuclear@0 735 vec.z = (float)pcVertices[iIndex].v[2] * pcHeader->scale[2];
nuclear@0 736 vec.z += pcHeader->translate[2];
nuclear@0 737
nuclear@0 738 // read the normal vector from the precalculated normal table
nuclear@0 739 MD2::LookupNormalIndex(pcVertices[iIndex].normalIndex,pcMesh->mNormals[iCurrent]);
nuclear@0 740 // pcMesh->mNormals[iCurrent].y *= -1.0f;
nuclear@0 741
nuclear@0 742 // read texture coordinates
nuclear@0 743 if (pcHeader->synctype) {
nuclear@0 744 ImportUVCoordinate_3DGS_MDL345(pcMesh->mTextureCoords[0][iCurrent],
nuclear@0 745 pcTexCoords,pcTriangles->index_uv[c]);
nuclear@0 746 }
nuclear@0 747 }
nuclear@0 748 pcMesh->mFaces[i].mIndices[0] = iTemp+2;
nuclear@0 749 pcMesh->mFaces[i].mIndices[1] = iTemp+1;
nuclear@0 750 pcMesh->mFaces[i].mIndices[2] = iTemp+0;
nuclear@0 751 pcTriangles++;
nuclear@0 752 }
nuclear@0 753 }
nuclear@0 754
nuclear@0 755 // For MDL5 we will need to build valid texture coordinates
nuclear@0 756 // basing upon the file loaded (only support one file as skin)
nuclear@0 757 if (0x5 == iGSFileVersion)
nuclear@0 758 CalculateUVCoordinates_MDL5();
nuclear@0 759 return;
nuclear@0 760 }
nuclear@0 761
nuclear@0 762 // ------------------------------------------------------------------------------------------------
nuclear@0 763 // Get a single UV coordinate for Quake and older GameStudio files
nuclear@0 764 void MDLImporter::ImportUVCoordinate_3DGS_MDL345(
nuclear@0 765 aiVector3D& vOut,
nuclear@0 766 const MDL::TexCoord_MDL3* pcSrc,
nuclear@0 767 unsigned int iIndex)
nuclear@0 768 {
nuclear@0 769 ai_assert(NULL != pcSrc);
nuclear@0 770 const MDL::Header* const pcHeader = (const MDL::Header*)this->mBuffer;
nuclear@0 771
nuclear@0 772 // validate UV indices
nuclear@0 773 if (iIndex >= (unsigned int) pcHeader->synctype) {
nuclear@0 774 iIndex = pcHeader->synctype-1;
nuclear@0 775 DefaultLogger::get()->warn("Index overflow in MDLn UV coord list");
nuclear@0 776 }
nuclear@0 777
nuclear@0 778 float s = (float)pcSrc[iIndex].u;
nuclear@0 779 float t = (float)pcSrc[iIndex].v;
nuclear@0 780
nuclear@0 781 // Scale s and t to range from 0.0 to 1.0
nuclear@0 782 if (0x5 != iGSFileVersion) {
nuclear@0 783 s = (s + 0.5f) / pcHeader->skinwidth;
nuclear@0 784 t = 1.0f-(t + 0.5f) / pcHeader->skinheight;
nuclear@0 785 }
nuclear@0 786
nuclear@0 787 vOut.x = s;
nuclear@0 788 vOut.y = t;
nuclear@0 789 vOut.z = 0.0f;
nuclear@0 790 }
nuclear@0 791
nuclear@0 792 // ------------------------------------------------------------------------------------------------
nuclear@0 793 // Compute UV coordinates for a MDL5 file
nuclear@0 794 void MDLImporter::CalculateUVCoordinates_MDL5()
nuclear@0 795 {
nuclear@0 796 const MDL::Header* const pcHeader = (const MDL::Header*)this->mBuffer;
nuclear@0 797 if (pcHeader->num_skins && this->pScene->mNumTextures) {
nuclear@0 798 const aiTexture* pcTex = this->pScene->mTextures[0];
nuclear@0 799
nuclear@0 800 // if the file is loaded in DDS format: get the size of the
nuclear@0 801 // texture from the header of the DDS file
nuclear@0 802 // skip three DWORDs and read first height, then the width
nuclear@0 803 unsigned int iWidth, iHeight;
nuclear@0 804 if (!pcTex->mHeight) {
nuclear@0 805 const uint32_t* piPtr = (uint32_t*)pcTex->pcData;
nuclear@0 806
nuclear@0 807 piPtr += 3;
nuclear@0 808 iHeight = (unsigned int)*piPtr++;
nuclear@0 809 iWidth = (unsigned int)*piPtr;
nuclear@0 810 if (!iHeight || !iWidth)
nuclear@0 811 {
nuclear@0 812 DefaultLogger::get()->warn("Either the width or the height of the "
nuclear@0 813 "embedded DDS texture is zero. Unable to compute final texture "
nuclear@0 814 "coordinates. The texture coordinates remain in their original "
nuclear@0 815 "0-x/0-y (x,y = texture size) range.");
nuclear@0 816 iWidth = 1;
nuclear@0 817 iHeight = 1;
nuclear@0 818 }
nuclear@0 819 }
nuclear@0 820 else {
nuclear@0 821 iWidth = pcTex->mWidth;
nuclear@0 822 iHeight = pcTex->mHeight;
nuclear@0 823 }
nuclear@0 824
nuclear@0 825 if (1 != iWidth || 1 != iHeight) {
nuclear@0 826 const float fWidth = (float)iWidth;
nuclear@0 827 const float fHeight = (float)iHeight;
nuclear@0 828 aiMesh* pcMesh = this->pScene->mMeshes[0];
nuclear@0 829 for (unsigned int i = 0; i < pcMesh->mNumVertices;++i)
nuclear@0 830 {
nuclear@0 831 pcMesh->mTextureCoords[0][i].x /= fWidth;
nuclear@0 832 pcMesh->mTextureCoords[0][i].y /= fHeight;
nuclear@0 833 pcMesh->mTextureCoords[0][i].y = 1.0f - pcMesh->mTextureCoords[0][i].y; // DX to OGL
nuclear@0 834 }
nuclear@0 835 }
nuclear@0 836 }
nuclear@0 837 }
nuclear@0 838
nuclear@0 839 // ------------------------------------------------------------------------------------------------
nuclear@0 840 // Validate the header of a MDL7 file
nuclear@0 841 void MDLImporter::ValidateHeader_3DGS_MDL7(const MDL::Header_MDL7* pcHeader)
nuclear@0 842 {
nuclear@0 843 ai_assert(NULL != pcHeader);
nuclear@0 844
nuclear@0 845 // There are some fixed sizes ...
nuclear@0 846 if (sizeof(MDL::ColorValue_MDL7) != pcHeader->colorvalue_stc_size) {
nuclear@0 847 throw DeadlyImportError(
nuclear@0 848 "[3DGS MDL7] sizeof(MDL::ColorValue_MDL7) != pcHeader->colorvalue_stc_size");
nuclear@0 849 }
nuclear@0 850 if (sizeof(MDL::TexCoord_MDL7) != pcHeader->skinpoint_stc_size) {
nuclear@0 851 throw DeadlyImportError(
nuclear@0 852 "[3DGS MDL7] sizeof(MDL::TexCoord_MDL7) != pcHeader->skinpoint_stc_size");
nuclear@0 853 }
nuclear@0 854 if (sizeof(MDL::Skin_MDL7) != pcHeader->skin_stc_size) {
nuclear@0 855 throw DeadlyImportError(
nuclear@0 856 "sizeof(MDL::Skin_MDL7) != pcHeader->skin_stc_size");
nuclear@0 857 }
nuclear@0 858
nuclear@0 859 // if there are no groups ... how should we load such a file?
nuclear@0 860 if(!pcHeader->groups_num) {
nuclear@0 861 throw DeadlyImportError( "[3DGS MDL7] No frames found");
nuclear@0 862 }
nuclear@0 863 }
nuclear@0 864
nuclear@0 865 // ------------------------------------------------------------------------------------------------
nuclear@0 866 // resolve bone animation matrices
nuclear@0 867 void MDLImporter::CalcAbsBoneMatrices_3DGS_MDL7(MDL::IntBone_MDL7** apcOutBones)
nuclear@0 868 {
nuclear@0 869 const MDL::Header_MDL7 *pcHeader = (const MDL::Header_MDL7*)this->mBuffer;
nuclear@0 870 const MDL::Bone_MDL7* pcBones = (const MDL::Bone_MDL7*)(pcHeader+1);
nuclear@0 871 ai_assert(NULL != apcOutBones);
nuclear@0 872
nuclear@0 873 // first find the bone that has NO parent, calculate the
nuclear@0 874 // animation matrix for it, then go on and search for the next parent
nuclear@0 875 // index (0) and so on until we can't find a new node.
nuclear@0 876 uint16_t iParent = 0xffff;
nuclear@0 877 uint32_t iIterations = 0;
nuclear@0 878 while (iIterations++ < pcHeader->bones_num) {
nuclear@0 879 for (uint32_t iBone = 0; iBone < pcHeader->bones_num;++iBone) {
nuclear@0 880 BE_NCONST MDL::Bone_MDL7* pcBone = _AI_MDL7_ACCESS_PTR(pcBones,iBone,
nuclear@0 881 pcHeader->bone_stc_size,MDL::Bone_MDL7);
nuclear@0 882
nuclear@0 883 AI_SWAP2(pcBone->parent_index);
nuclear@0 884 AI_SWAP4(pcBone->x);
nuclear@0 885 AI_SWAP4(pcBone->y);
nuclear@0 886 AI_SWAP4(pcBone->z);
nuclear@0 887
nuclear@0 888 if (iParent == pcBone->parent_index) {
nuclear@0 889 // MDL7 readme
nuclear@0 890 ////////////////////////////////////////////////////////////////
nuclear@0 891 /*
nuclear@0 892 The animation matrix is then calculated the following way:
nuclear@0 893
nuclear@0 894 vector3 bPos = <absolute bone position>
nuclear@0 895 matrix44 laM; // local animation matrix
nuclear@0 896 sphrvector key_rotate = <bone rotation>
nuclear@0 897
nuclear@0 898 matrix44 m1,m2;
nuclear@0 899 create_trans_matrix(m1, -bPos.x, -bPos.y, -bPos.z);
nuclear@0 900 create_trans_matrix(m2, -bPos.x, -bPos.y, -bPos.z);
nuclear@0 901
nuclear@0 902 create_rotation_matrix(laM,key_rotate);
nuclear@0 903
nuclear@0 904 laM = sm1 * laM;
nuclear@0 905 laM = laM * sm2;
nuclear@0 906 */
nuclear@0 907 /////////////////////////////////////////////////////////////////
nuclear@0 908
nuclear@0 909 MDL::IntBone_MDL7* const pcOutBone = apcOutBones[iBone];
nuclear@0 910
nuclear@0 911 // store the parent index of the bone
nuclear@0 912 pcOutBone->iParent = pcBone->parent_index;
nuclear@0 913 if (0xffff != iParent) {
nuclear@0 914 const MDL::IntBone_MDL7* pcParentBone = apcOutBones[iParent];
nuclear@0 915 pcOutBone->mOffsetMatrix.a4 = -pcParentBone->vPosition.x;
nuclear@0 916 pcOutBone->mOffsetMatrix.b4 = -pcParentBone->vPosition.y;
nuclear@0 917 pcOutBone->mOffsetMatrix.c4 = -pcParentBone->vPosition.z;
nuclear@0 918 }
nuclear@0 919 pcOutBone->vPosition.x = pcBone->x;
nuclear@0 920 pcOutBone->vPosition.y = pcBone->y;
nuclear@0 921 pcOutBone->vPosition.z = pcBone->z;
nuclear@0 922 pcOutBone->mOffsetMatrix.a4 -= pcBone->x;
nuclear@0 923 pcOutBone->mOffsetMatrix.b4 -= pcBone->y;
nuclear@0 924 pcOutBone->mOffsetMatrix.c4 -= pcBone->z;
nuclear@0 925
nuclear@0 926 if (AI_MDL7_BONE_STRUCT_SIZE__NAME_IS_NOT_THERE == pcHeader->bone_stc_size) {
nuclear@0 927 // no real name for our poor bone is specified :-(
nuclear@0 928 pcOutBone->mName.length = ::sprintf(pcOutBone->mName.data,
nuclear@0 929 "UnnamedBone_%i",iBone);
nuclear@0 930 }
nuclear@0 931 else {
nuclear@0 932 // Make sure we won't run over the buffer's end if there is no
nuclear@0 933 // terminal 0 character (however the documentation says there
nuclear@0 934 // should be one)
nuclear@0 935 uint32_t iMaxLen = pcHeader->bone_stc_size-16;
nuclear@0 936 for (uint32_t qq = 0; qq < iMaxLen;++qq) {
nuclear@0 937 if (!pcBone->name[qq]) {
nuclear@0 938 iMaxLen = qq;
nuclear@0 939 break;
nuclear@0 940 }
nuclear@0 941 }
nuclear@0 942
nuclear@0 943 // store the name of the bone
nuclear@0 944 pcOutBone->mName.length = (size_t)iMaxLen;
nuclear@0 945 ::memcpy(pcOutBone->mName.data,pcBone->name,pcOutBone->mName.length);
nuclear@0 946 pcOutBone->mName.data[pcOutBone->mName.length] = '\0';
nuclear@0 947 }
nuclear@0 948 }
nuclear@0 949 }
nuclear@0 950 ++iParent;
nuclear@0 951 }
nuclear@0 952 }
nuclear@0 953
nuclear@0 954 // ------------------------------------------------------------------------------------------------
nuclear@0 955 // read bones from a MDL7 file
nuclear@0 956 MDL::IntBone_MDL7** MDLImporter::LoadBones_3DGS_MDL7()
nuclear@0 957 {
nuclear@0 958 const MDL::Header_MDL7 *pcHeader = (const MDL::Header_MDL7*)this->mBuffer;
nuclear@0 959 if (pcHeader->bones_num) {
nuclear@0 960 // validate the size of the bone data structure in the file
nuclear@0 961 if (AI_MDL7_BONE_STRUCT_SIZE__NAME_IS_20_CHARS != pcHeader->bone_stc_size &&
nuclear@0 962 AI_MDL7_BONE_STRUCT_SIZE__NAME_IS_32_CHARS != pcHeader->bone_stc_size &&
nuclear@0 963 AI_MDL7_BONE_STRUCT_SIZE__NAME_IS_NOT_THERE != pcHeader->bone_stc_size)
nuclear@0 964 {
nuclear@0 965 DefaultLogger::get()->warn("Unknown size of bone data structure");
nuclear@0 966 return NULL;
nuclear@0 967 }
nuclear@0 968
nuclear@0 969 MDL::IntBone_MDL7** apcBonesOut = new MDL::IntBone_MDL7*[pcHeader->bones_num];
nuclear@0 970 for (uint32_t crank = 0; crank < pcHeader->bones_num;++crank)
nuclear@0 971 apcBonesOut[crank] = new MDL::IntBone_MDL7();
nuclear@0 972
nuclear@0 973 // and calculate absolute bone offset matrices ...
nuclear@0 974 CalcAbsBoneMatrices_3DGS_MDL7(apcBonesOut);
nuclear@0 975 return apcBonesOut;
nuclear@0 976 }
nuclear@0 977 return NULL;
nuclear@0 978 }
nuclear@0 979
nuclear@0 980 // ------------------------------------------------------------------------------------------------
nuclear@0 981 // read faces from a MDL7 file
nuclear@0 982 void MDLImporter::ReadFaces_3DGS_MDL7(const MDL::IntGroupInfo_MDL7& groupInfo,
nuclear@0 983 MDL::IntGroupData_MDL7& groupData)
nuclear@0 984 {
nuclear@0 985 const MDL::Header_MDL7 *pcHeader = (const MDL::Header_MDL7*)this->mBuffer;
nuclear@0 986 MDL::Triangle_MDL7* pcGroupTris = groupInfo.pcGroupTris;
nuclear@0 987
nuclear@0 988 // iterate through all triangles and build valid display lists
nuclear@0 989 unsigned int iOutIndex = 0;
nuclear@0 990 for (unsigned int iTriangle = 0; iTriangle < (unsigned int)groupInfo.pcGroup->numtris; ++iTriangle) {
nuclear@0 991 AI_SWAP2(pcGroupTris->v_index[0]);
nuclear@0 992 AI_SWAP2(pcGroupTris->v_index[1]);
nuclear@0 993 AI_SWAP2(pcGroupTris->v_index[2]);
nuclear@0 994
nuclear@0 995 // iterate through all indices of the current triangle
nuclear@0 996 for (unsigned int c = 0; c < 3;++c,++iOutIndex) {
nuclear@0 997
nuclear@0 998 // validate the vertex index
nuclear@0 999 unsigned int iIndex = pcGroupTris->v_index[c];
nuclear@0 1000 if(iIndex > (unsigned int)groupInfo.pcGroup->numverts) {
nuclear@0 1001 // (we might need to read this section a second time - to process frame vertices correctly)
nuclear@0 1002 pcGroupTris->v_index[c] = iIndex = groupInfo.pcGroup->numverts-1;
nuclear@0 1003 DefaultLogger::get()->warn("Index overflow in MDL7 vertex list");
nuclear@0 1004 }
nuclear@0 1005
nuclear@0 1006 // write the output face index
nuclear@0 1007 groupData.pcFaces[iTriangle].mIndices[2-c] = iOutIndex;
nuclear@0 1008
nuclear@0 1009 aiVector3D& vPosition = groupData.vPositions[ iOutIndex ];
nuclear@0 1010 vPosition.x = _AI_MDL7_ACCESS_VERT(groupInfo.pcGroupVerts,iIndex, pcHeader->mainvertex_stc_size) .x;
nuclear@0 1011 vPosition.y = _AI_MDL7_ACCESS_VERT(groupInfo.pcGroupVerts,iIndex,pcHeader->mainvertex_stc_size) .y;
nuclear@0 1012 vPosition.z = _AI_MDL7_ACCESS_VERT(groupInfo.pcGroupVerts,iIndex,pcHeader->mainvertex_stc_size) .z;
nuclear@0 1013
nuclear@0 1014 // if we have bones, save the index
nuclear@0 1015 if (!groupData.aiBones.empty()) {
nuclear@0 1016 groupData.aiBones[iOutIndex] = _AI_MDL7_ACCESS_VERT(groupInfo.pcGroupVerts,
nuclear@0 1017 iIndex,pcHeader->mainvertex_stc_size).vertindex;
nuclear@0 1018 }
nuclear@0 1019
nuclear@0 1020 // now read the normal vector
nuclear@0 1021 if (AI_MDL7_FRAMEVERTEX030305_STCSIZE <= pcHeader->mainvertex_stc_size) {
nuclear@0 1022 // read the full normal vector
nuclear@0 1023 aiVector3D& vNormal = groupData.vNormals[ iOutIndex ];
nuclear@0 1024 vNormal.x = _AI_MDL7_ACCESS_VERT(groupInfo.pcGroupVerts,iIndex,pcHeader->mainvertex_stc_size) .norm[0];
nuclear@0 1025 AI_SWAP4(vNormal.x);
nuclear@0 1026 vNormal.y = _AI_MDL7_ACCESS_VERT(groupInfo.pcGroupVerts,iIndex,pcHeader->mainvertex_stc_size) .norm[1];
nuclear@0 1027 AI_SWAP4(vNormal.y);
nuclear@0 1028 vNormal.z = _AI_MDL7_ACCESS_VERT(groupInfo.pcGroupVerts,iIndex,pcHeader->mainvertex_stc_size) .norm[2];
nuclear@0 1029 AI_SWAP4(vNormal.z);
nuclear@0 1030 }
nuclear@0 1031 else if (AI_MDL7_FRAMEVERTEX120503_STCSIZE <= pcHeader->mainvertex_stc_size) {
nuclear@0 1032 // read the normal vector from Quake2's smart table
nuclear@0 1033 aiVector3D& vNormal = groupData.vNormals[ iOutIndex ];
nuclear@0 1034 MD2::LookupNormalIndex(_AI_MDL7_ACCESS_VERT(groupInfo.pcGroupVerts,iIndex,
nuclear@0 1035 pcHeader->mainvertex_stc_size) .norm162index,vNormal);
nuclear@0 1036 }
nuclear@0 1037 // validate and process the first uv coordinate set
nuclear@0 1038 if (pcHeader->triangle_stc_size >= AI_MDL7_TRIANGLE_STD_SIZE_ONE_UV) {
nuclear@0 1039
nuclear@0 1040 if (groupInfo.pcGroup->num_stpts) {
nuclear@0 1041 AI_SWAP2(pcGroupTris->skinsets[0].st_index[0]);
nuclear@0 1042 AI_SWAP2(pcGroupTris->skinsets[0].st_index[1]);
nuclear@0 1043 AI_SWAP2(pcGroupTris->skinsets[0].st_index[2]);
nuclear@0 1044
nuclear@0 1045 iIndex = pcGroupTris->skinsets[0].st_index[c];
nuclear@0 1046 if(iIndex > (unsigned int)groupInfo.pcGroup->num_stpts) {
nuclear@0 1047 iIndex = groupInfo.pcGroup->num_stpts-1;
nuclear@0 1048 DefaultLogger::get()->warn("Index overflow in MDL7 UV coordinate list (#1)");
nuclear@0 1049 }
nuclear@0 1050
nuclear@0 1051 float u = groupInfo.pcGroupUVs[iIndex].u;
nuclear@0 1052 float v = 1.0f-groupInfo.pcGroupUVs[iIndex].v; // DX to OGL
nuclear@0 1053
nuclear@0 1054 groupData.vTextureCoords1[iOutIndex].x = u;
nuclear@0 1055 groupData.vTextureCoords1[iOutIndex].y = v;
nuclear@0 1056 }
nuclear@0 1057 // assign the material index, but only if it is existing
nuclear@0 1058 if (pcHeader->triangle_stc_size >= AI_MDL7_TRIANGLE_STD_SIZE_ONE_UV_WITH_MATINDEX){
nuclear@0 1059 AI_SWAP4(pcGroupTris->skinsets[0].material);
nuclear@0 1060 groupData.pcFaces[iTriangle].iMatIndex[0] = pcGroupTris->skinsets[0].material;
nuclear@0 1061 }
nuclear@0 1062 }
nuclear@0 1063 // validate and process the second uv coordinate set
nuclear@0 1064 if (pcHeader->triangle_stc_size >= AI_MDL7_TRIANGLE_STD_SIZE_TWO_UV) {
nuclear@0 1065
nuclear@0 1066 if (groupInfo.pcGroup->num_stpts) {
nuclear@0 1067 AI_SWAP2(pcGroupTris->skinsets[1].st_index[0]);
nuclear@0 1068 AI_SWAP2(pcGroupTris->skinsets[1].st_index[1]);
nuclear@0 1069 AI_SWAP2(pcGroupTris->skinsets[1].st_index[2]);
nuclear@0 1070 AI_SWAP4(pcGroupTris->skinsets[1].material);
nuclear@0 1071
nuclear@0 1072 iIndex = pcGroupTris->skinsets[1].st_index[c];
nuclear@0 1073 if(iIndex > (unsigned int)groupInfo.pcGroup->num_stpts) {
nuclear@0 1074 iIndex = groupInfo.pcGroup->num_stpts-1;
nuclear@0 1075 DefaultLogger::get()->warn("Index overflow in MDL7 UV coordinate list (#2)");
nuclear@0 1076 }
nuclear@0 1077
nuclear@0 1078 float u = groupInfo.pcGroupUVs[ iIndex ].u;
nuclear@0 1079 float v = 1.0f-groupInfo.pcGroupUVs[ iIndex ].v;
nuclear@0 1080
nuclear@0 1081 groupData.vTextureCoords2[ iOutIndex ].x = u;
nuclear@0 1082 groupData.vTextureCoords2[ iOutIndex ].y = v; // DX to OGL
nuclear@0 1083
nuclear@0 1084 // check whether we do really need the second texture
nuclear@0 1085 // coordinate set ... wastes memory and loading time
nuclear@0 1086 if (0 != iIndex && (u != groupData.vTextureCoords1[ iOutIndex ].x ||
nuclear@0 1087 v != groupData.vTextureCoords1[ iOutIndex ].y ) )
nuclear@0 1088 groupData.bNeed2UV = true;
nuclear@0 1089
nuclear@0 1090 // if the material differs, we need a second skin, too
nuclear@0 1091 if (pcGroupTris->skinsets[ 1 ].material != pcGroupTris->skinsets[ 0 ].material)
nuclear@0 1092 groupData.bNeed2UV = true;
nuclear@0 1093 }
nuclear@0 1094 // assign the material index
nuclear@0 1095 groupData.pcFaces[ iTriangle ].iMatIndex[ 1 ] = pcGroupTris->skinsets[ 1 ].material;
nuclear@0 1096 }
nuclear@0 1097 }
nuclear@0 1098 // get the next triangle in the list
nuclear@0 1099 pcGroupTris = (MDL::Triangle_MDL7*)((const char*)pcGroupTris + pcHeader->triangle_stc_size);
nuclear@0 1100 }
nuclear@0 1101 }
nuclear@0 1102
nuclear@0 1103 // ------------------------------------------------------------------------------------------------
nuclear@0 1104 // handle frames in a MDL7 file
nuclear@0 1105 bool MDLImporter::ProcessFrames_3DGS_MDL7(const MDL::IntGroupInfo_MDL7& groupInfo,
nuclear@0 1106 MDL::IntGroupData_MDL7& groupData,
nuclear@0 1107 MDL::IntSharedData_MDL7& shared,
nuclear@0 1108 const unsigned char* szCurrent,
nuclear@0 1109 const unsigned char** szCurrentOut)
nuclear@0 1110 {
nuclear@0 1111 ai_assert(NULL != szCurrent && NULL != szCurrentOut);
nuclear@0 1112 const MDL::Header_MDL7 *pcHeader = (const MDL::Header_MDL7*)mBuffer;
nuclear@0 1113
nuclear@0 1114 // if we have no bones we can simply skip all frames,
nuclear@0 1115 // otherwise we'll need to process them.
nuclear@0 1116 // FIX: If we need another frame than the first we must apply frame vertex replacements ...
nuclear@0 1117 for(unsigned int iFrame = 0; iFrame < (unsigned int)groupInfo.pcGroup->numframes;++iFrame) {
nuclear@0 1118 MDL::IntFrameInfo_MDL7 frame ((BE_NCONST MDL::Frame_MDL7*)szCurrent,iFrame);
nuclear@0 1119
nuclear@0 1120 AI_SWAP4(frame.pcFrame->vertices_count);
nuclear@0 1121 AI_SWAP4(frame.pcFrame->transmatrix_count);
nuclear@0 1122
nuclear@0 1123 const unsigned int iAdd = pcHeader->frame_stc_size +
nuclear@0 1124 frame.pcFrame->vertices_count * pcHeader->framevertex_stc_size +
nuclear@0 1125 frame.pcFrame->transmatrix_count * pcHeader->bonetrans_stc_size;
nuclear@0 1126
nuclear@0 1127 if (((const char*)szCurrent - (const char*)pcHeader) + iAdd > (unsigned int)pcHeader->data_size) {
nuclear@0 1128 DefaultLogger::get()->warn("Index overflow in frame area. "
nuclear@0 1129 "Ignoring all frames and all further mesh groups, too.");
nuclear@0 1130
nuclear@0 1131 // don't parse more groups if we can't even read one
nuclear@0 1132 // FIXME: sometimes this seems to occur even for valid files ...
nuclear@0 1133 *szCurrentOut = szCurrent;
nuclear@0 1134 return false;
nuclear@0 1135 }
nuclear@0 1136 // our output frame?
nuclear@0 1137 if (configFrameID == iFrame) {
nuclear@0 1138 BE_NCONST MDL::Vertex_MDL7* pcFrameVertices = (BE_NCONST MDL::Vertex_MDL7*)(szCurrent+pcHeader->frame_stc_size);
nuclear@0 1139
nuclear@0 1140 for (unsigned int qq = 0; qq < frame.pcFrame->vertices_count;++qq) {
nuclear@0 1141 // I assume this are simple replacements for normal vertices, the bone index serving
nuclear@0 1142 // as the index of the vertex to be replaced.
nuclear@0 1143 uint16_t iIndex = _AI_MDL7_ACCESS(pcFrameVertices,qq,pcHeader->framevertex_stc_size,MDL::Vertex_MDL7).vertindex;
nuclear@0 1144 AI_SWAP2(iIndex);
nuclear@0 1145 if (iIndex >= groupInfo.pcGroup->numverts) {
nuclear@0 1146 DefaultLogger::get()->warn("Invalid vertex index in frame vertex section");
nuclear@0 1147 continue;
nuclear@0 1148 }
nuclear@0 1149
nuclear@0 1150 aiVector3D vPosition,vNormal;
nuclear@0 1151
nuclear@0 1152 vPosition.x = _AI_MDL7_ACCESS_VERT(pcFrameVertices,qq,pcHeader->framevertex_stc_size) .x;
nuclear@0 1153 AI_SWAP4(vPosition.x);
nuclear@0 1154 vPosition.y = _AI_MDL7_ACCESS_VERT(pcFrameVertices,qq,pcHeader->framevertex_stc_size) .y;
nuclear@0 1155 AI_SWAP4(vPosition.y);
nuclear@0 1156 vPosition.z = _AI_MDL7_ACCESS_VERT(pcFrameVertices,qq,pcHeader->framevertex_stc_size) .z;
nuclear@0 1157 AI_SWAP4(vPosition.z);
nuclear@0 1158
nuclear@0 1159 // now read the normal vector
nuclear@0 1160 if (AI_MDL7_FRAMEVERTEX030305_STCSIZE <= pcHeader->mainvertex_stc_size) {
nuclear@0 1161 // read the full normal vector
nuclear@0 1162 vNormal.x = _AI_MDL7_ACCESS_VERT(pcFrameVertices,qq,pcHeader->framevertex_stc_size) .norm[0];
nuclear@0 1163 AI_SWAP4(vNormal.x);
nuclear@0 1164 vNormal.y = _AI_MDL7_ACCESS_VERT(pcFrameVertices,qq,pcHeader->framevertex_stc_size) .norm[1];
nuclear@0 1165 AI_SWAP4(vNormal.y);
nuclear@0 1166 vNormal.z = _AI_MDL7_ACCESS_VERT(pcFrameVertices,qq,pcHeader->framevertex_stc_size) .norm[2];
nuclear@0 1167 AI_SWAP4(vNormal.z);
nuclear@0 1168 }
nuclear@0 1169 else if (AI_MDL7_FRAMEVERTEX120503_STCSIZE <= pcHeader->mainvertex_stc_size) {
nuclear@0 1170 // read the normal vector from Quake2's smart table
nuclear@0 1171 MD2::LookupNormalIndex(_AI_MDL7_ACCESS_VERT(pcFrameVertices,qq,
nuclear@0 1172 pcHeader->framevertex_stc_size) .norm162index,vNormal);
nuclear@0 1173 }
nuclear@0 1174
nuclear@0 1175 // FIXME: O(n^2) at the moment ...
nuclear@0 1176 BE_NCONST MDL::Triangle_MDL7* pcGroupTris = groupInfo.pcGroupTris;
nuclear@0 1177 unsigned int iOutIndex = 0;
nuclear@0 1178 for (unsigned int iTriangle = 0; iTriangle < (unsigned int)groupInfo.pcGroup->numtris; ++iTriangle) {
nuclear@0 1179 // iterate through all indices of the current triangle
nuclear@0 1180 for (unsigned int c = 0; c < 3;++c,++iOutIndex) {
nuclear@0 1181 // replace the vertex with the new data
nuclear@0 1182 const unsigned int iCurIndex = pcGroupTris->v_index[c];
nuclear@0 1183 if (iCurIndex == iIndex) {
nuclear@0 1184 groupData.vPositions[iOutIndex] = vPosition;
nuclear@0 1185 groupData.vNormals[iOutIndex] = vNormal;
nuclear@0 1186 }
nuclear@0 1187 }
nuclear@0 1188 // get the next triangle in the list
nuclear@0 1189 pcGroupTris = (BE_NCONST MDL::Triangle_MDL7*)((const char*)
nuclear@0 1190 pcGroupTris + pcHeader->triangle_stc_size);
nuclear@0 1191 }
nuclear@0 1192 }
nuclear@0 1193 }
nuclear@0 1194 // parse bone trafo matrix keys (only if there are bones ...)
nuclear@0 1195 if (shared.apcOutBones) {
nuclear@0 1196 ParseBoneTrafoKeys_3DGS_MDL7(groupInfo,frame,shared);
nuclear@0 1197 }
nuclear@0 1198 szCurrent += iAdd;
nuclear@0 1199 }
nuclear@0 1200 *szCurrentOut = szCurrent;
nuclear@0 1201 return true;
nuclear@0 1202 }
nuclear@0 1203
nuclear@0 1204 // ------------------------------------------------------------------------------------------------
nuclear@0 1205 // Sort faces by material, handle multiple UVs correctly
nuclear@0 1206 void MDLImporter::SortByMaterials_3DGS_MDL7(
nuclear@0 1207 const MDL::IntGroupInfo_MDL7& groupInfo,
nuclear@0 1208 MDL::IntGroupData_MDL7& groupData,
nuclear@0 1209 MDL::IntSplitGroupData_MDL7& splitGroupData)
nuclear@0 1210 {
nuclear@0 1211 const unsigned int iNumMaterials = (unsigned int)splitGroupData.shared.pcMats.size();
nuclear@0 1212 if (!groupData.bNeed2UV) {
nuclear@0 1213 // if we don't need a second set of texture coordinates there is no reason to keep it in memory ...
nuclear@0 1214 groupData.vTextureCoords2.clear();
nuclear@0 1215
nuclear@0 1216 // allocate the array
nuclear@0 1217 splitGroupData.aiSplit = new std::vector<unsigned int>*[iNumMaterials];
nuclear@0 1218
nuclear@0 1219 for (unsigned int m = 0; m < iNumMaterials;++m)
nuclear@0 1220 splitGroupData.aiSplit[m] = new std::vector<unsigned int>();
nuclear@0 1221
nuclear@0 1222 // iterate through all faces and sort by material
nuclear@0 1223 for (unsigned int iFace = 0; iFace < (unsigned int)groupInfo.pcGroup->numtris;++iFace) {
nuclear@0 1224 // check range
nuclear@0 1225 if (groupData.pcFaces[iFace].iMatIndex[0] >= iNumMaterials) {
nuclear@0 1226 // use the last material instead
nuclear@0 1227 splitGroupData.aiSplit[iNumMaterials-1]->push_back(iFace);
nuclear@0 1228
nuclear@0 1229 // sometimes MED writes -1, but normally only if there is only
nuclear@0 1230 // one skin assigned. No warning in this case
nuclear@0 1231 if(0xFFFFFFFF != groupData.pcFaces[iFace].iMatIndex[0])
nuclear@0 1232 DefaultLogger::get()->warn("Index overflow in MDL7 material list [#0]");
nuclear@0 1233 }
nuclear@0 1234 else splitGroupData.aiSplit[groupData.pcFaces[iFace].
nuclear@0 1235 iMatIndex[0]]->push_back(iFace);
nuclear@0 1236 }
nuclear@0 1237 }
nuclear@0 1238 else
nuclear@0 1239 {
nuclear@0 1240 // we need to build combined materials for each combination of
nuclear@0 1241 std::vector<MDL::IntMaterial_MDL7> avMats;
nuclear@0 1242 avMats.reserve(iNumMaterials*2);
nuclear@0 1243
nuclear@0 1244 // fixme: why on the heap?
nuclear@0 1245 std::vector<std::vector<unsigned int>* > aiTempSplit(iNumMaterials*2);
nuclear@0 1246 for (unsigned int m = 0; m < iNumMaterials;++m)
nuclear@0 1247 aiTempSplit[m] = new std::vector<unsigned int>();
nuclear@0 1248
nuclear@0 1249 // iterate through all faces and sort by material
nuclear@0 1250 for (unsigned int iFace = 0; iFace < (unsigned int)groupInfo.pcGroup->numtris;++iFace) {
nuclear@0 1251 // check range
nuclear@0 1252 unsigned int iMatIndex = groupData.pcFaces[iFace].iMatIndex[0];
nuclear@0 1253 if (iMatIndex >= iNumMaterials) {
nuclear@0 1254 // sometimes MED writes -1, but normally only if there is only
nuclear@0 1255 // one skin assigned. No warning in this case
nuclear@0 1256 if(UINT_MAX != iMatIndex)
nuclear@0 1257 DefaultLogger::get()->warn("Index overflow in MDL7 material list [#1]");
nuclear@0 1258 iMatIndex = iNumMaterials-1;
nuclear@0 1259 }
nuclear@0 1260 unsigned int iMatIndex2 = groupData.pcFaces[iFace].iMatIndex[1];
nuclear@0 1261
nuclear@0 1262 unsigned int iNum = iMatIndex;
nuclear@0 1263 if (UINT_MAX != iMatIndex2 && iMatIndex != iMatIndex2) {
nuclear@0 1264 if (iMatIndex2 >= iNumMaterials) {
nuclear@0 1265 // sometimes MED writes -1, but normally only if there is only
nuclear@0 1266 // one skin assigned. No warning in this case
nuclear@0 1267 DefaultLogger::get()->warn("Index overflow in MDL7 material list [#2]");
nuclear@0 1268 iMatIndex2 = iNumMaterials-1;
nuclear@0 1269 }
nuclear@0 1270
nuclear@0 1271 // do a slow seach in the list ...
nuclear@0 1272 iNum = 0;
nuclear@0 1273 bool bFound = false;
nuclear@0 1274 for (std::vector<MDL::IntMaterial_MDL7>::iterator i = avMats.begin();i != avMats.end();++i,++iNum){
nuclear@0 1275 if ((*i).iOldMatIndices[0] == iMatIndex && (*i).iOldMatIndices[1] == iMatIndex2) {
nuclear@0 1276 // reuse this material
nuclear@0 1277 bFound = true;
nuclear@0 1278 break;
nuclear@0 1279 }
nuclear@0 1280 }
nuclear@0 1281 if (!bFound) {
nuclear@0 1282 // build a new material ...
nuclear@0 1283 MDL::IntMaterial_MDL7 sHelper;
nuclear@0 1284 sHelper.pcMat = new aiMaterial();
nuclear@0 1285 sHelper.iOldMatIndices[0] = iMatIndex;
nuclear@0 1286 sHelper.iOldMatIndices[1] = iMatIndex2;
nuclear@0 1287 JoinSkins_3DGS_MDL7(splitGroupData.shared.pcMats[iMatIndex],
nuclear@0 1288 splitGroupData.shared.pcMats[iMatIndex2],sHelper.pcMat);
nuclear@0 1289
nuclear@0 1290 // and add it to the list
nuclear@0 1291 avMats.push_back(sHelper);
nuclear@0 1292 iNum = (unsigned int)avMats.size()-1;
nuclear@0 1293 }
nuclear@0 1294 // adjust the size of the file array
nuclear@0 1295 if (iNum == aiTempSplit.size()) {
nuclear@0 1296 aiTempSplit.push_back(new std::vector<unsigned int>());
nuclear@0 1297 }
nuclear@0 1298 }
nuclear@0 1299 aiTempSplit[iNum]->push_back(iFace);
nuclear@0 1300 }
nuclear@0 1301
nuclear@0 1302 // now add the newly created materials to the old list
nuclear@0 1303 if (0 == groupInfo.iIndex) {
nuclear@0 1304 splitGroupData.shared.pcMats.resize(avMats.size());
nuclear@0 1305 for (unsigned int o = 0; o < avMats.size();++o)
nuclear@0 1306 splitGroupData.shared.pcMats[o] = avMats[o].pcMat;
nuclear@0 1307 }
nuclear@0 1308 else {
nuclear@0 1309 // This might result in redundant materials ...
nuclear@0 1310 splitGroupData.shared.pcMats.resize(iNumMaterials + avMats.size());
nuclear@0 1311 for (unsigned int o = iNumMaterials; o < avMats.size();++o)
nuclear@0 1312 splitGroupData.shared.pcMats[o] = avMats[o].pcMat;
nuclear@0 1313 }
nuclear@0 1314
nuclear@0 1315 // and build the final face-to-material array
nuclear@0 1316 splitGroupData.aiSplit = new std::vector<unsigned int>*[aiTempSplit.size()];
nuclear@0 1317 for (unsigned int m = 0; m < iNumMaterials;++m)
nuclear@0 1318 splitGroupData.aiSplit[m] = aiTempSplit[m];
nuclear@0 1319 }
nuclear@0 1320 }
nuclear@0 1321
nuclear@0 1322 // ------------------------------------------------------------------------------------------------
nuclear@0 1323 // Read a MDL7 file
nuclear@0 1324 void MDLImporter::InternReadFile_3DGS_MDL7( )
nuclear@0 1325 {
nuclear@0 1326 ai_assert(NULL != pScene);
nuclear@0 1327
nuclear@0 1328 MDL::IntSharedData_MDL7 sharedData;
nuclear@0 1329
nuclear@0 1330 // current cursor position in the file
nuclear@0 1331 BE_NCONST MDL::Header_MDL7 *pcHeader = (BE_NCONST MDL::Header_MDL7*)this->mBuffer;
nuclear@0 1332 const unsigned char* szCurrent = (const unsigned char*)(pcHeader+1);
nuclear@0 1333
nuclear@0 1334 AI_SWAP4(pcHeader->version);
nuclear@0 1335 AI_SWAP4(pcHeader->bones_num);
nuclear@0 1336 AI_SWAP4(pcHeader->groups_num);
nuclear@0 1337 AI_SWAP4(pcHeader->data_size);
nuclear@0 1338 AI_SWAP4(pcHeader->entlump_size);
nuclear@0 1339 AI_SWAP4(pcHeader->medlump_size);
nuclear@0 1340 AI_SWAP2(pcHeader->bone_stc_size);
nuclear@0 1341 AI_SWAP2(pcHeader->skin_stc_size);
nuclear@0 1342 AI_SWAP2(pcHeader->colorvalue_stc_size);
nuclear@0 1343 AI_SWAP2(pcHeader->material_stc_size);
nuclear@0 1344 AI_SWAP2(pcHeader->skinpoint_stc_size);
nuclear@0 1345 AI_SWAP2(pcHeader->triangle_stc_size);
nuclear@0 1346 AI_SWAP2(pcHeader->mainvertex_stc_size);
nuclear@0 1347 AI_SWAP2(pcHeader->framevertex_stc_size);
nuclear@0 1348 AI_SWAP2(pcHeader->bonetrans_stc_size);
nuclear@0 1349 AI_SWAP2(pcHeader->frame_stc_size);
nuclear@0 1350
nuclear@0 1351 // validate the header of the file. There are some structure
nuclear@0 1352 // sizes that are expected by the loader to be constant
nuclear@0 1353 this->ValidateHeader_3DGS_MDL7(pcHeader);
nuclear@0 1354
nuclear@0 1355 // load all bones (they are shared by all groups, so
nuclear@0 1356 // we'll need to add them to all groups/meshes later)
nuclear@0 1357 // apcBonesOut is a list of all bones or NULL if they could not been loaded
nuclear@0 1358 szCurrent += pcHeader->bones_num * pcHeader->bone_stc_size;
nuclear@0 1359 sharedData.apcOutBones = this->LoadBones_3DGS_MDL7();
nuclear@0 1360
nuclear@0 1361 // vector to held all created meshes
nuclear@0 1362 std::vector<aiMesh*>* avOutList;
nuclear@0 1363
nuclear@0 1364 // 3 meshes per group - that should be OK for most models
nuclear@0 1365 avOutList = new std::vector<aiMesh*>[pcHeader->groups_num];
nuclear@0 1366 for (uint32_t i = 0; i < pcHeader->groups_num;++i)
nuclear@0 1367 avOutList[i].reserve(3);
nuclear@0 1368
nuclear@0 1369 // buffer to held the names of all groups in the file
nuclear@0 1370 char* aszGroupNameBuffer = new char[AI_MDL7_MAX_GROUPNAMESIZE*pcHeader->groups_num];
nuclear@0 1371
nuclear@0 1372 // read all groups
nuclear@0 1373 for (unsigned int iGroup = 0; iGroup < (unsigned int)pcHeader->groups_num;++iGroup) {
nuclear@0 1374 MDL::IntGroupInfo_MDL7 groupInfo((BE_NCONST MDL::Group_MDL7*)szCurrent,iGroup);
nuclear@0 1375 szCurrent = (const unsigned char*)(groupInfo.pcGroup+1);
nuclear@0 1376
nuclear@0 1377 VALIDATE_FILE_SIZE(szCurrent);
nuclear@0 1378
nuclear@0 1379 AI_SWAP4(groupInfo.pcGroup->groupdata_size);
nuclear@0 1380 AI_SWAP4(groupInfo.pcGroup->numskins);
nuclear@0 1381 AI_SWAP4(groupInfo.pcGroup->num_stpts);
nuclear@0 1382 AI_SWAP4(groupInfo.pcGroup->numtris);
nuclear@0 1383 AI_SWAP4(groupInfo.pcGroup->numverts);
nuclear@0 1384 AI_SWAP4(groupInfo.pcGroup->numframes);
nuclear@0 1385
nuclear@0 1386 if (1 != groupInfo.pcGroup->typ) {
nuclear@0 1387 // Not a triangle-based mesh
nuclear@0 1388 DefaultLogger::get()->warn("[3DGS MDL7] Not a triangle mesh group. Continuing happily");
nuclear@0 1389 }
nuclear@0 1390
nuclear@0 1391 // store the name of the group
nuclear@0 1392 const unsigned int ofs = iGroup*AI_MDL7_MAX_GROUPNAMESIZE;
nuclear@0 1393 ::memcpy(&aszGroupNameBuffer[ofs],
nuclear@0 1394 groupInfo.pcGroup->name,AI_MDL7_MAX_GROUPNAMESIZE);
nuclear@0 1395
nuclear@0 1396 // make sure '\0' is at the end
nuclear@0 1397 aszGroupNameBuffer[ofs+AI_MDL7_MAX_GROUPNAMESIZE-1] = '\0';
nuclear@0 1398
nuclear@0 1399 // read all skins
nuclear@0 1400 sharedData.pcMats.reserve(sharedData.pcMats.size() + groupInfo.pcGroup->numskins);
nuclear@0 1401 sharedData.abNeedMaterials.resize(sharedData.abNeedMaterials.size() +
nuclear@0 1402 groupInfo.pcGroup->numskins,false);
nuclear@0 1403
nuclear@0 1404 for (unsigned int iSkin = 0; iSkin < (unsigned int)groupInfo.pcGroup->numskins;++iSkin) {
nuclear@0 1405 ParseSkinLump_3DGS_MDL7(szCurrent,&szCurrent,sharedData.pcMats);
nuclear@0 1406 }
nuclear@0 1407 // if we have absolutely no skin loaded we need to generate a default material
nuclear@0 1408 if (sharedData.pcMats.empty()) {
nuclear@0 1409 const int iMode = (int)aiShadingMode_Gouraud;
nuclear@0 1410 sharedData.pcMats.push_back(new aiMaterial());
nuclear@0 1411 aiMaterial* pcHelper = (aiMaterial*)sharedData.pcMats[0];
nuclear@0 1412 pcHelper->AddProperty<int>(&iMode, 1, AI_MATKEY_SHADING_MODEL);
nuclear@0 1413
nuclear@0 1414 aiColor3D clr;
nuclear@0 1415 clr.b = clr.g = clr.r = 0.6f;
nuclear@0 1416 pcHelper->AddProperty<aiColor3D>(&clr, 1,AI_MATKEY_COLOR_DIFFUSE);
nuclear@0 1417 pcHelper->AddProperty<aiColor3D>(&clr, 1,AI_MATKEY_COLOR_SPECULAR);
nuclear@0 1418
nuclear@0 1419 clr.b = clr.g = clr.r = 0.05f;
nuclear@0 1420 pcHelper->AddProperty<aiColor3D>(&clr, 1,AI_MATKEY_COLOR_AMBIENT);
nuclear@0 1421
nuclear@0 1422 aiString szName;
nuclear@0 1423 szName.Set(AI_DEFAULT_MATERIAL_NAME);
nuclear@0 1424 pcHelper->AddProperty(&szName,AI_MATKEY_NAME);
nuclear@0 1425
nuclear@0 1426 sharedData.abNeedMaterials.resize(1,false);
nuclear@0 1427 }
nuclear@0 1428
nuclear@0 1429 // now get a pointer to all texture coords in the group
nuclear@0 1430 groupInfo.pcGroupUVs = (BE_NCONST MDL::TexCoord_MDL7*)szCurrent;
nuclear@0 1431 for(int i = 0; i < groupInfo.pcGroup->num_stpts; ++i){
nuclear@0 1432 AI_SWAP4(groupInfo.pcGroupUVs[i].u);
nuclear@0 1433 AI_SWAP4(groupInfo.pcGroupUVs[i].v);
nuclear@0 1434 }
nuclear@0 1435 szCurrent += pcHeader->skinpoint_stc_size * groupInfo.pcGroup->num_stpts;
nuclear@0 1436
nuclear@0 1437 // now get a pointer to all triangle in the group
nuclear@0 1438 groupInfo.pcGroupTris = (Triangle_MDL7*)szCurrent;
nuclear@0 1439 szCurrent += pcHeader->triangle_stc_size * groupInfo.pcGroup->numtris;
nuclear@0 1440
nuclear@0 1441 // now get a pointer to all vertices in the group
nuclear@0 1442 groupInfo.pcGroupVerts = (BE_NCONST MDL::Vertex_MDL7*)szCurrent;
nuclear@0 1443 for(int i = 0; i < groupInfo.pcGroup->numverts; ++i){
nuclear@0 1444 AI_SWAP4(groupInfo.pcGroupVerts[i].x);
nuclear@0 1445 AI_SWAP4(groupInfo.pcGroupVerts[i].y);
nuclear@0 1446 AI_SWAP4(groupInfo.pcGroupVerts[i].z);
nuclear@0 1447
nuclear@0 1448 AI_SWAP2(groupInfo.pcGroupVerts[i].vertindex);
nuclear@0 1449 //We can not swap the normal information now as we don't know which of the two kinds it is
nuclear@0 1450 }
nuclear@0 1451 szCurrent += pcHeader->mainvertex_stc_size * groupInfo.pcGroup->numverts;
nuclear@0 1452 VALIDATE_FILE_SIZE(szCurrent);
nuclear@0 1453
nuclear@0 1454 MDL::IntSplitGroupData_MDL7 splitGroupData(sharedData,avOutList[iGroup]);
nuclear@0 1455 MDL::IntGroupData_MDL7 groupData;
nuclear@0 1456 if (groupInfo.pcGroup->numtris && groupInfo.pcGroup->numverts)
nuclear@0 1457 {
nuclear@0 1458 // build output vectors
nuclear@0 1459 const unsigned int iNumVertices = groupInfo.pcGroup->numtris*3;
nuclear@0 1460 groupData.vPositions.resize(iNumVertices);
nuclear@0 1461 groupData.vNormals.resize(iNumVertices);
nuclear@0 1462
nuclear@0 1463 if (sharedData.apcOutBones)groupData.aiBones.resize(iNumVertices,UINT_MAX);
nuclear@0 1464
nuclear@0 1465 // it is also possible that there are 0 UV coordinate sets
nuclear@0 1466 if (groupInfo.pcGroup->num_stpts){
nuclear@0 1467 groupData.vTextureCoords1.resize(iNumVertices,aiVector3D());
nuclear@0 1468
nuclear@0 1469 // check whether the triangle data structure is large enough
nuclear@0 1470 // to contain a second UV coodinate set
nuclear@0 1471 if (pcHeader->triangle_stc_size >= AI_MDL7_TRIANGLE_STD_SIZE_TWO_UV) {
nuclear@0 1472 groupData.vTextureCoords2.resize(iNumVertices,aiVector3D());
nuclear@0 1473 groupData.bNeed2UV = true;
nuclear@0 1474 }
nuclear@0 1475 }
nuclear@0 1476 groupData.pcFaces = new MDL::IntFace_MDL7[groupInfo.pcGroup->numtris];
nuclear@0 1477
nuclear@0 1478 // read all faces into the preallocated arrays
nuclear@0 1479 ReadFaces_3DGS_MDL7(groupInfo, groupData);
nuclear@0 1480
nuclear@0 1481 // sort by materials
nuclear@0 1482 SortByMaterials_3DGS_MDL7(groupInfo, groupData,
nuclear@0 1483 splitGroupData);
nuclear@0 1484
nuclear@0 1485 for (unsigned int qq = 0; qq < sharedData.pcMats.size();++qq) {
nuclear@0 1486 if (!splitGroupData.aiSplit[qq]->empty())
nuclear@0 1487 sharedData.abNeedMaterials[qq] = true;
nuclear@0 1488 }
nuclear@0 1489 }
nuclear@0 1490 else DefaultLogger::get()->warn("[3DGS MDL7] Mesh group consists of 0 "
nuclear@0 1491 "vertices or faces. It will be skipped.");
nuclear@0 1492
nuclear@0 1493 // process all frames and generate output meshes
nuclear@0 1494 ProcessFrames_3DGS_MDL7(groupInfo,groupData, sharedData,szCurrent,&szCurrent);
nuclear@0 1495 GenerateOutputMeshes_3DGS_MDL7(groupData,splitGroupData);
nuclear@0 1496 }
nuclear@0 1497
nuclear@0 1498 // generate a nodegraph and subnodes for each group
nuclear@0 1499 pScene->mRootNode = new aiNode();
nuclear@0 1500
nuclear@0 1501 // now we need to build a final mesh list
nuclear@0 1502 for (uint32_t i = 0; i < pcHeader->groups_num;++i)
nuclear@0 1503 pScene->mNumMeshes += (unsigned int)avOutList[i].size();
nuclear@0 1504
nuclear@0 1505 pScene->mMeshes = new aiMesh*[pScene->mNumMeshes]; {
nuclear@0 1506 unsigned int p = 0,q = 0;
nuclear@0 1507 for (uint32_t i = 0; i < pcHeader->groups_num;++i) {
nuclear@0 1508 for (unsigned int a = 0; a < avOutList[i].size();++a) {
nuclear@0 1509 pScene->mMeshes[p++] = avOutList[i][a];
nuclear@0 1510 }
nuclear@0 1511 if (!avOutList[i].empty())++pScene->mRootNode->mNumChildren;
nuclear@0 1512 }
nuclear@0 1513 // we will later need an extra node to serve as parent for all bones
nuclear@0 1514 if (sharedData.apcOutBones)++pScene->mRootNode->mNumChildren;
nuclear@0 1515 this->pScene->mRootNode->mChildren = new aiNode*[pScene->mRootNode->mNumChildren];
nuclear@0 1516 p = 0;
nuclear@0 1517 for (uint32_t i = 0; i < pcHeader->groups_num;++i) {
nuclear@0 1518 if (avOutList[i].empty())continue;
nuclear@0 1519
nuclear@0 1520 aiNode* const pcNode = pScene->mRootNode->mChildren[p] = new aiNode();
nuclear@0 1521 pcNode->mNumMeshes = (unsigned int)avOutList[i].size();
nuclear@0 1522 pcNode->mMeshes = new unsigned int[pcNode->mNumMeshes];
nuclear@0 1523 pcNode->mParent = this->pScene->mRootNode;
nuclear@0 1524 for (unsigned int a = 0; a < pcNode->mNumMeshes;++a)
nuclear@0 1525 pcNode->mMeshes[a] = q + a;
nuclear@0 1526 q += (unsigned int)avOutList[i].size();
nuclear@0 1527
nuclear@0 1528 // setup the name of the node
nuclear@0 1529 char* const szBuffer = &aszGroupNameBuffer[i*AI_MDL7_MAX_GROUPNAMESIZE];
nuclear@0 1530 if ('\0' == *szBuffer)
nuclear@0 1531 pcNode->mName.length = ::sprintf(szBuffer,"Group_%i",p);
nuclear@0 1532 else pcNode->mName.length = ::strlen(szBuffer);
nuclear@0 1533 ::strcpy(pcNode->mName.data,szBuffer);
nuclear@0 1534 ++p;
nuclear@0 1535 }
nuclear@0 1536 }
nuclear@0 1537
nuclear@0 1538 // if there is only one root node with a single child we can optimize it a bit ...
nuclear@0 1539 if (1 == pScene->mRootNode->mNumChildren && !sharedData.apcOutBones) {
nuclear@0 1540 aiNode* pcOldRoot = this->pScene->mRootNode;
nuclear@0 1541 pScene->mRootNode = pcOldRoot->mChildren[0];
nuclear@0 1542 pcOldRoot->mChildren[0] = NULL;
nuclear@0 1543 delete pcOldRoot;
nuclear@0 1544 pScene->mRootNode->mParent = NULL;
nuclear@0 1545 }
nuclear@0 1546 else pScene->mRootNode->mName.Set("<mesh_root>");
nuclear@0 1547
nuclear@0 1548 delete[] avOutList;
nuclear@0 1549 delete[] aszGroupNameBuffer;
nuclear@0 1550 AI_DEBUG_INVALIDATE_PTR(avOutList);
nuclear@0 1551 AI_DEBUG_INVALIDATE_PTR(aszGroupNameBuffer);
nuclear@0 1552
nuclear@0 1553 // build a final material list.
nuclear@0 1554 CopyMaterials_3DGS_MDL7(sharedData);
nuclear@0 1555 HandleMaterialReferences_3DGS_MDL7();
nuclear@0 1556
nuclear@0 1557 // generate output bone animations and add all bones to the scenegraph
nuclear@0 1558 if (sharedData.apcOutBones) {
nuclear@0 1559 // this step adds empty dummy bones to the nodegraph
nuclear@0 1560 // insert another dummy node to avoid name conflicts
nuclear@0 1561 aiNode* const pc = pScene->mRootNode->mChildren[pScene->mRootNode->mNumChildren-1] = new aiNode();
nuclear@0 1562
nuclear@0 1563 pc->mName.Set("<skeleton_root>");
nuclear@0 1564
nuclear@0 1565 // add bones to the nodegraph
nuclear@0 1566 AddBonesToNodeGraph_3DGS_MDL7((const Assimp::MDL::IntBone_MDL7 **)
nuclear@0 1567 sharedData.apcOutBones,pc,0xffff);
nuclear@0 1568
nuclear@0 1569 // this steps build a valid output animation
nuclear@0 1570 BuildOutputAnims_3DGS_MDL7((const Assimp::MDL::IntBone_MDL7 **)
nuclear@0 1571 sharedData.apcOutBones);
nuclear@0 1572 }
nuclear@0 1573 }
nuclear@0 1574
nuclear@0 1575 // ------------------------------------------------------------------------------------------------
nuclear@0 1576 // Copy materials
nuclear@0 1577 void MDLImporter::CopyMaterials_3DGS_MDL7(MDL::IntSharedData_MDL7 &shared)
nuclear@0 1578 {
nuclear@0 1579 pScene->mNumMaterials = (unsigned int)shared.pcMats.size();
nuclear@0 1580 pScene->mMaterials = new aiMaterial*[pScene->mNumMaterials];
nuclear@0 1581 for (unsigned int i = 0; i < pScene->mNumMaterials;++i)
nuclear@0 1582 pScene->mMaterials[i] = shared.pcMats[i];
nuclear@0 1583 }
nuclear@0 1584
nuclear@0 1585
nuclear@0 1586 // ------------------------------------------------------------------------------------------------
nuclear@0 1587 // Process material references
nuclear@0 1588 void MDLImporter::HandleMaterialReferences_3DGS_MDL7()
nuclear@0 1589 {
nuclear@0 1590 // search for referrer materials
nuclear@0 1591 for (unsigned int i = 0; i < pScene->mNumMaterials;++i) {
nuclear@0 1592 int iIndex = 0;
nuclear@0 1593 if (AI_SUCCESS == aiGetMaterialInteger(pScene->mMaterials[i],AI_MDL7_REFERRER_MATERIAL, &iIndex) ) {
nuclear@0 1594 for (unsigned int a = 0; a < pScene->mNumMeshes;++a) {
nuclear@0 1595 aiMesh* const pcMesh = pScene->mMeshes[a];
nuclear@0 1596 if (i == pcMesh->mMaterialIndex) {
nuclear@0 1597 pcMesh->mMaterialIndex = iIndex;
nuclear@0 1598 }
nuclear@0 1599 }
nuclear@0 1600 // collapse the rest of the array
nuclear@0 1601 delete pScene->mMaterials[i];
nuclear@0 1602 for (unsigned int pp = i; pp < pScene->mNumMaterials-1;++pp) {
nuclear@0 1603
nuclear@0 1604 pScene->mMaterials[pp] = pScene->mMaterials[pp+1];
nuclear@0 1605 for (unsigned int a = 0; a < pScene->mNumMeshes;++a) {
nuclear@0 1606 aiMesh* const pcMesh = pScene->mMeshes[a];
nuclear@0 1607 if (pcMesh->mMaterialIndex > i)--pcMesh->mMaterialIndex;
nuclear@0 1608 }
nuclear@0 1609 }
nuclear@0 1610 --pScene->mNumMaterials;
nuclear@0 1611 }
nuclear@0 1612 }
nuclear@0 1613 }
nuclear@0 1614
nuclear@0 1615 // ------------------------------------------------------------------------------------------------
nuclear@0 1616 // Read bone transformation keys
nuclear@0 1617 void MDLImporter::ParseBoneTrafoKeys_3DGS_MDL7(
nuclear@0 1618 const MDL::IntGroupInfo_MDL7& groupInfo,
nuclear@0 1619 IntFrameInfo_MDL7& frame,
nuclear@0 1620 MDL::IntSharedData_MDL7& shared)
nuclear@0 1621 {
nuclear@0 1622 const MDL::Header_MDL7* const pcHeader = (const MDL::Header_MDL7*)this->mBuffer;
nuclear@0 1623
nuclear@0 1624 // only the first group contains bone animation keys
nuclear@0 1625 if (frame.pcFrame->transmatrix_count) {
nuclear@0 1626 if (!groupInfo.iIndex) {
nuclear@0 1627 // skip all frames vertices. We can't support them
nuclear@0 1628 const MDL::BoneTransform_MDL7* pcBoneTransforms = (const MDL::BoneTransform_MDL7*)
nuclear@0 1629 (((const char*)frame.pcFrame) + pcHeader->frame_stc_size +
nuclear@0 1630 frame.pcFrame->vertices_count * pcHeader->framevertex_stc_size);
nuclear@0 1631
nuclear@0 1632 // read all transformation matrices
nuclear@0 1633 for (unsigned int iTrafo = 0; iTrafo < frame.pcFrame->transmatrix_count;++iTrafo) {
nuclear@0 1634 if(pcBoneTransforms->bone_index >= pcHeader->bones_num) {
nuclear@0 1635 DefaultLogger::get()->warn("Index overflow in frame area. "
nuclear@0 1636 "Unable to parse this bone transformation");
nuclear@0 1637 }
nuclear@0 1638 else {
nuclear@0 1639 AddAnimationBoneTrafoKey_3DGS_MDL7(frame.iIndex,
nuclear@0 1640 pcBoneTransforms,shared.apcOutBones);
nuclear@0 1641 }
nuclear@0 1642 pcBoneTransforms = (const MDL::BoneTransform_MDL7*)(
nuclear@0 1643 (const char*)pcBoneTransforms + pcHeader->bonetrans_stc_size);
nuclear@0 1644 }
nuclear@0 1645 }
nuclear@0 1646 else {
nuclear@0 1647 DefaultLogger::get()->warn("Ignoring animation keyframes in groups != 0");
nuclear@0 1648 }
nuclear@0 1649 }
nuclear@0 1650 }
nuclear@0 1651
nuclear@0 1652 // ------------------------------------------------------------------------------------------------
nuclear@0 1653 // Attach bones to the output nodegraph
nuclear@0 1654 void MDLImporter::AddBonesToNodeGraph_3DGS_MDL7(const MDL::IntBone_MDL7** apcBones,
nuclear@0 1655 aiNode* pcParent,uint16_t iParentIndex)
nuclear@0 1656 {
nuclear@0 1657 ai_assert(NULL != apcBones && NULL != pcParent);
nuclear@0 1658
nuclear@0 1659 // get a pointer to the header ...
nuclear@0 1660 const MDL::Header_MDL7* const pcHeader = (const MDL::Header_MDL7*)this->mBuffer;
nuclear@0 1661
nuclear@0 1662 const MDL::IntBone_MDL7** apcBones2 = apcBones;
nuclear@0 1663 for (uint32_t i = 0; i < pcHeader->bones_num;++i) {
nuclear@0 1664
nuclear@0 1665 const MDL::IntBone_MDL7* const pcBone = *apcBones2++;
nuclear@0 1666 if (pcBone->iParent == iParentIndex) {
nuclear@0 1667 ++pcParent->mNumChildren;
nuclear@0 1668 }
nuclear@0 1669 }
nuclear@0 1670 pcParent->mChildren = new aiNode*[pcParent->mNumChildren];
nuclear@0 1671 unsigned int qq = 0;
nuclear@0 1672 for (uint32_t i = 0; i < pcHeader->bones_num;++i) {
nuclear@0 1673
nuclear@0 1674 const MDL::IntBone_MDL7* const pcBone = *apcBones++;
nuclear@0 1675 if (pcBone->iParent != iParentIndex)continue;
nuclear@0 1676
nuclear@0 1677 aiNode* pcNode = pcParent->mChildren[qq++] = new aiNode();
nuclear@0 1678 pcNode->mName = aiString( pcBone->mName );
nuclear@0 1679
nuclear@0 1680 AddBonesToNodeGraph_3DGS_MDL7(apcBones,pcNode,(uint16_t)i);
nuclear@0 1681 }
nuclear@0 1682 }
nuclear@0 1683
nuclear@0 1684 // ------------------------------------------------------------------------------------------------
nuclear@0 1685 // Build output animations
nuclear@0 1686 void MDLImporter::BuildOutputAnims_3DGS_MDL7(
nuclear@0 1687 const MDL::IntBone_MDL7** apcBonesOut)
nuclear@0 1688 {
nuclear@0 1689 ai_assert(NULL != apcBonesOut);
nuclear@0 1690 const MDL::Header_MDL7* const pcHeader = (const MDL::Header_MDL7*)mBuffer;
nuclear@0 1691
nuclear@0 1692 // one animation ...
nuclear@0 1693 aiAnimation* pcAnim = new aiAnimation();
nuclear@0 1694 for (uint32_t i = 0; i < pcHeader->bones_num;++i) {
nuclear@0 1695 if (!apcBonesOut[i]->pkeyPositions.empty()) {
nuclear@0 1696
nuclear@0 1697 // get the last frame ... (needn't be equal to pcHeader->frames_num)
nuclear@0 1698 for (size_t qq = 0; qq < apcBonesOut[i]->pkeyPositions.size();++qq) {
nuclear@0 1699 pcAnim->mDuration = std::max(pcAnim->mDuration, (double)
nuclear@0 1700 apcBonesOut[i]->pkeyPositions[qq].mTime);
nuclear@0 1701 }
nuclear@0 1702 ++pcAnim->mNumChannels;
nuclear@0 1703 }
nuclear@0 1704 }
nuclear@0 1705 if (pcAnim->mDuration) {
nuclear@0 1706 pcAnim->mChannels = new aiNodeAnim*[pcAnim->mNumChannels];
nuclear@0 1707
nuclear@0 1708 unsigned int iCnt = 0;
nuclear@0 1709 for (uint32_t i = 0; i < pcHeader->bones_num;++i) {
nuclear@0 1710 if (!apcBonesOut[i]->pkeyPositions.empty()) {
nuclear@0 1711 const MDL::IntBone_MDL7* const intBone = apcBonesOut[i];
nuclear@0 1712
nuclear@0 1713 aiNodeAnim* const pcNodeAnim = pcAnim->mChannels[iCnt++] = new aiNodeAnim();
nuclear@0 1714 pcNodeAnim->mNodeName = aiString( intBone->mName );
nuclear@0 1715
nuclear@0 1716 // allocate enough storage for all keys
nuclear@0 1717 pcNodeAnim->mNumPositionKeys = (unsigned int)intBone->pkeyPositions.size();
nuclear@0 1718 pcNodeAnim->mNumScalingKeys = (unsigned int)intBone->pkeyPositions.size();
nuclear@0 1719 pcNodeAnim->mNumRotationKeys = (unsigned int)intBone->pkeyPositions.size();
nuclear@0 1720
nuclear@0 1721 pcNodeAnim->mPositionKeys = new aiVectorKey[pcNodeAnim->mNumPositionKeys];
nuclear@0 1722 pcNodeAnim->mScalingKeys = new aiVectorKey[pcNodeAnim->mNumPositionKeys];
nuclear@0 1723 pcNodeAnim->mRotationKeys = new aiQuatKey[pcNodeAnim->mNumPositionKeys];
nuclear@0 1724
nuclear@0 1725 // copy all keys
nuclear@0 1726 for (unsigned int qq = 0; qq < pcNodeAnim->mNumPositionKeys;++qq) {
nuclear@0 1727 pcNodeAnim->mPositionKeys[qq] = intBone->pkeyPositions[qq];
nuclear@0 1728 pcNodeAnim->mScalingKeys[qq] = intBone->pkeyScalings[qq];
nuclear@0 1729 pcNodeAnim->mRotationKeys[qq] = intBone->pkeyRotations[qq];
nuclear@0 1730 }
nuclear@0 1731 }
nuclear@0 1732 }
nuclear@0 1733
nuclear@0 1734 // store the output animation
nuclear@0 1735 pScene->mNumAnimations = 1;
nuclear@0 1736 pScene->mAnimations = new aiAnimation*[1];
nuclear@0 1737 pScene->mAnimations[0] = pcAnim;
nuclear@0 1738 }
nuclear@0 1739 else delete pcAnim;
nuclear@0 1740 }
nuclear@0 1741
nuclear@0 1742 // ------------------------------------------------------------------------------------------------
nuclear@0 1743 void MDLImporter::AddAnimationBoneTrafoKey_3DGS_MDL7(unsigned int iTrafo,
nuclear@0 1744 const MDL::BoneTransform_MDL7* pcBoneTransforms,
nuclear@0 1745 MDL::IntBone_MDL7** apcBonesOut)
nuclear@0 1746 {
nuclear@0 1747 ai_assert(NULL != pcBoneTransforms);
nuclear@0 1748 ai_assert(NULL != apcBonesOut);
nuclear@0 1749
nuclear@0 1750 // first .. get the transformation matrix
nuclear@0 1751 aiMatrix4x4 mTransform;
nuclear@0 1752 mTransform.a1 = pcBoneTransforms->m[0];
nuclear@0 1753 mTransform.b1 = pcBoneTransforms->m[1];
nuclear@0 1754 mTransform.c1 = pcBoneTransforms->m[2];
nuclear@0 1755 mTransform.d1 = pcBoneTransforms->m[3];
nuclear@0 1756
nuclear@0 1757 mTransform.a2 = pcBoneTransforms->m[4];
nuclear@0 1758 mTransform.b2 = pcBoneTransforms->m[5];
nuclear@0 1759 mTransform.c2 = pcBoneTransforms->m[6];
nuclear@0 1760 mTransform.d2 = pcBoneTransforms->m[7];
nuclear@0 1761
nuclear@0 1762 mTransform.a3 = pcBoneTransforms->m[8];
nuclear@0 1763 mTransform.b3 = pcBoneTransforms->m[9];
nuclear@0 1764 mTransform.c3 = pcBoneTransforms->m[10];
nuclear@0 1765 mTransform.d3 = pcBoneTransforms->m[11];
nuclear@0 1766
nuclear@0 1767 // now decompose the transformation matrix into separate
nuclear@0 1768 // scaling, rotation and translation
nuclear@0 1769 aiVectorKey vScaling,vPosition;
nuclear@0 1770 aiQuatKey qRotation;
nuclear@0 1771
nuclear@0 1772 // FIXME: Decompose will assert in debug builds if the matrix is invalid ...
nuclear@0 1773 mTransform.Decompose(vScaling.mValue,qRotation.mValue,vPosition.mValue);
nuclear@0 1774
nuclear@0 1775 // now generate keys
nuclear@0 1776 vScaling.mTime = qRotation.mTime = vPosition.mTime = (double)iTrafo;
nuclear@0 1777
nuclear@0 1778 // add the keys to the bone
nuclear@0 1779 MDL::IntBone_MDL7* const pcBoneOut = apcBonesOut[pcBoneTransforms->bone_index];
nuclear@0 1780 pcBoneOut->pkeyPositions.push_back ( vPosition );
nuclear@0 1781 pcBoneOut->pkeyScalings.push_back ( vScaling );
nuclear@0 1782 pcBoneOut->pkeyRotations.push_back ( qRotation );
nuclear@0 1783 }
nuclear@0 1784
nuclear@0 1785 // ------------------------------------------------------------------------------------------------
nuclear@0 1786 // Construct output meshes
nuclear@0 1787 void MDLImporter::GenerateOutputMeshes_3DGS_MDL7(
nuclear@0 1788 MDL::IntGroupData_MDL7& groupData,
nuclear@0 1789 MDL::IntSplitGroupData_MDL7& splitGroupData)
nuclear@0 1790 {
nuclear@0 1791 const MDL::IntSharedData_MDL7& shared = splitGroupData.shared;
nuclear@0 1792
nuclear@0 1793 // get a pointer to the header ...
nuclear@0 1794 const MDL::Header_MDL7* const pcHeader = (const MDL::Header_MDL7*)this->mBuffer;
nuclear@0 1795 const unsigned int iNumOutBones = pcHeader->bones_num;
nuclear@0 1796
nuclear@0 1797 for (std::vector<aiMaterial*>::size_type i = 0; i < shared.pcMats.size();++i) {
nuclear@0 1798 if (!splitGroupData.aiSplit[i]->empty()) {
nuclear@0 1799
nuclear@0 1800 // allocate the output mesh
nuclear@0 1801 aiMesh* pcMesh = new aiMesh();
nuclear@0 1802
nuclear@0 1803 pcMesh->mPrimitiveTypes = aiPrimitiveType_TRIANGLE;
nuclear@0 1804 pcMesh->mMaterialIndex = (unsigned int)i;
nuclear@0 1805
nuclear@0 1806 // allocate output storage
nuclear@0 1807 pcMesh->mNumFaces = (unsigned int)splitGroupData.aiSplit[i]->size();
nuclear@0 1808 pcMesh->mFaces = new aiFace[pcMesh->mNumFaces];
nuclear@0 1809
nuclear@0 1810 pcMesh->mNumVertices = pcMesh->mNumFaces*3;
nuclear@0 1811 pcMesh->mVertices = new aiVector3D[pcMesh->mNumVertices];
nuclear@0 1812 pcMesh->mNormals = new aiVector3D[pcMesh->mNumVertices];
nuclear@0 1813
nuclear@0 1814 if (!groupData.vTextureCoords1.empty()) {
nuclear@0 1815 pcMesh->mNumUVComponents[0] = 2;
nuclear@0 1816 pcMesh->mTextureCoords[0] = new aiVector3D[pcMesh->mNumVertices];
nuclear@0 1817 if (!groupData.vTextureCoords2.empty()) {
nuclear@0 1818 pcMesh->mNumUVComponents[1] = 2;
nuclear@0 1819 pcMesh->mTextureCoords[1] = new aiVector3D[pcMesh->mNumVertices];
nuclear@0 1820 }
nuclear@0 1821 }
nuclear@0 1822
nuclear@0 1823 // iterate through all faces and build an unique set of vertices
nuclear@0 1824 unsigned int iCurrent = 0;
nuclear@0 1825 for (unsigned int iFace = 0; iFace < pcMesh->mNumFaces;++iFace) {
nuclear@0 1826 pcMesh->mFaces[iFace].mNumIndices = 3;
nuclear@0 1827 pcMesh->mFaces[iFace].mIndices = new unsigned int[3];
nuclear@0 1828
nuclear@0 1829 unsigned int iSrcFace = splitGroupData.aiSplit[i]->operator[](iFace);
nuclear@0 1830 const MDL::IntFace_MDL7& oldFace = groupData.pcFaces[iSrcFace];
nuclear@0 1831
nuclear@0 1832 // iterate through all face indices
nuclear@0 1833 for (unsigned int c = 0; c < 3;++c) {
nuclear@0 1834 const uint32_t iIndex = oldFace.mIndices[c];
nuclear@0 1835 pcMesh->mVertices[iCurrent] = groupData.vPositions[iIndex];
nuclear@0 1836 pcMesh->mNormals[iCurrent] = groupData.vNormals[iIndex];
nuclear@0 1837
nuclear@0 1838 if (!groupData.vTextureCoords1.empty()) {
nuclear@0 1839
nuclear@0 1840 pcMesh->mTextureCoords[0][iCurrent] = groupData.vTextureCoords1[iIndex];
nuclear@0 1841 if (!groupData.vTextureCoords2.empty()) {
nuclear@0 1842 pcMesh->mTextureCoords[1][iCurrent] = groupData.vTextureCoords2[iIndex];
nuclear@0 1843 }
nuclear@0 1844 }
nuclear@0 1845 pcMesh->mFaces[iFace].mIndices[c] = iCurrent++;
nuclear@0 1846 }
nuclear@0 1847 }
nuclear@0 1848
nuclear@0 1849 // if we have bones in the mesh we'll need to generate
nuclear@0 1850 // proper vertex weights for them
nuclear@0 1851 if (!groupData.aiBones.empty()) {
nuclear@0 1852 std::vector<std::vector<unsigned int> > aaiVWeightList;
nuclear@0 1853 aaiVWeightList.resize(iNumOutBones);
nuclear@0 1854
nuclear@0 1855 int iCurrent = 0;
nuclear@0 1856 for (unsigned int iFace = 0; iFace < pcMesh->mNumFaces;++iFace) {
nuclear@0 1857 unsigned int iSrcFace = splitGroupData.aiSplit[i]->operator[](iFace);
nuclear@0 1858 const MDL::IntFace_MDL7& oldFace = groupData.pcFaces[iSrcFace];
nuclear@0 1859
nuclear@0 1860 // iterate through all face indices
nuclear@0 1861 for (unsigned int c = 0; c < 3;++c) {
nuclear@0 1862 unsigned int iBone = groupData.aiBones[ oldFace.mIndices[c] ];
nuclear@0 1863 if (UINT_MAX != iBone) {
nuclear@0 1864 if (iBone >= iNumOutBones) {
nuclear@0 1865 DefaultLogger::get()->error("Bone index overflow. "
nuclear@0 1866 "The bone index of a vertex exceeds the allowed range. ");
nuclear@0 1867 iBone = iNumOutBones-1;
nuclear@0 1868 }
nuclear@0 1869 aaiVWeightList[ iBone ].push_back ( iCurrent );
nuclear@0 1870 }
nuclear@0 1871 ++iCurrent;
nuclear@0 1872 }
nuclear@0 1873 }
nuclear@0 1874 // now check which bones are required ...
nuclear@0 1875 for (std::vector<std::vector<unsigned int> >::const_iterator k = aaiVWeightList.begin();k != aaiVWeightList.end();++k) {
nuclear@0 1876 if (!(*k).empty()) {
nuclear@0 1877 ++pcMesh->mNumBones;
nuclear@0 1878 }
nuclear@0 1879 }
nuclear@0 1880 pcMesh->mBones = new aiBone*[pcMesh->mNumBones];
nuclear@0 1881 iCurrent = 0;
nuclear@0 1882 for (std::vector<std::vector<unsigned int> >::const_iterator k = aaiVWeightList.begin();k!= aaiVWeightList.end();++k,++iCurrent)
nuclear@0 1883 {
nuclear@0 1884 if ((*k).empty())
nuclear@0 1885 continue;
nuclear@0 1886
nuclear@0 1887 // seems we'll need this node
nuclear@0 1888 aiBone* pcBone = pcMesh->mBones[ iCurrent ] = new aiBone();
nuclear@0 1889 pcBone->mName = aiString(shared.apcOutBones[ iCurrent ]->mName);
nuclear@0 1890 pcBone->mOffsetMatrix = shared.apcOutBones[ iCurrent ]->mOffsetMatrix;
nuclear@0 1891
nuclear@0 1892 // setup vertex weights
nuclear@0 1893 pcBone->mNumWeights = (unsigned int)(*k).size();
nuclear@0 1894 pcBone->mWeights = new aiVertexWeight[pcBone->mNumWeights];
nuclear@0 1895
nuclear@0 1896 for (unsigned int weight = 0; weight < pcBone->mNumWeights;++weight) {
nuclear@0 1897 pcBone->mWeights[weight].mVertexId = (*k)[weight];
nuclear@0 1898 pcBone->mWeights[weight].mWeight = 1.0f;
nuclear@0 1899 }
nuclear@0 1900 }
nuclear@0 1901 }
nuclear@0 1902 // add the mesh to the list of output meshes
nuclear@0 1903 splitGroupData.avOutList.push_back(pcMesh);
nuclear@0 1904 }
nuclear@0 1905 }
nuclear@0 1906 }
nuclear@0 1907
nuclear@0 1908 // ------------------------------------------------------------------------------------------------
nuclear@0 1909 // Join to materials
nuclear@0 1910 void MDLImporter::JoinSkins_3DGS_MDL7(
nuclear@0 1911 aiMaterial* pcMat1,
nuclear@0 1912 aiMaterial* pcMat2,
nuclear@0 1913 aiMaterial* pcMatOut)
nuclear@0 1914 {
nuclear@0 1915 ai_assert(NULL != pcMat1 && NULL != pcMat2 && NULL != pcMatOut);
nuclear@0 1916
nuclear@0 1917 // first create a full copy of the first skin property set
nuclear@0 1918 // and assign it to the output material
nuclear@0 1919 aiMaterial::CopyPropertyList(pcMatOut,pcMat1);
nuclear@0 1920
nuclear@0 1921 int iVal = 0;
nuclear@0 1922 pcMatOut->AddProperty<int>(&iVal,1,AI_MATKEY_UVWSRC_DIFFUSE(0));
nuclear@0 1923
nuclear@0 1924 // then extract the diffuse texture from the second skin,
nuclear@0 1925 // setup 1 as UV source and we have it
nuclear@0 1926 aiString sString;
nuclear@0 1927 if(AI_SUCCESS == aiGetMaterialString ( pcMat2, AI_MATKEY_TEXTURE_DIFFUSE(0),&sString )) {
nuclear@0 1928 iVal = 1;
nuclear@0 1929 pcMatOut->AddProperty<int>(&iVal,1,AI_MATKEY_UVWSRC_DIFFUSE(1));
nuclear@0 1930 pcMatOut->AddProperty(&sString,AI_MATKEY_TEXTURE_DIFFUSE(1));
nuclear@0 1931 }
nuclear@0 1932 }
nuclear@0 1933
nuclear@0 1934 // ------------------------------------------------------------------------------------------------
nuclear@0 1935 // Read a half-life 2 MDL
nuclear@0 1936 void MDLImporter::InternReadFile_HL2( )
nuclear@0 1937 {
nuclear@0 1938 //const MDL::Header_HL2* pcHeader = (const MDL::Header_HL2*)this->mBuffer;
nuclear@0 1939 throw DeadlyImportError("HL2 MDLs are not implemented");
nuclear@0 1940 }
nuclear@0 1941
nuclear@0 1942 #endif // !! ASSIMP_BUILD_NO_MDL_IMPORTER