vrshoot
diff 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 |
line diff
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/libs/assimp/MDLLoader.cpp Sat Feb 01 19:58:19 2014 +0200 1.3 @@ -0,0 +1,1942 @@ 1.4 +/* 1.5 +--------------------------------------------------------------------------- 1.6 +Open Asset Import Library (assimp) 1.7 +--------------------------------------------------------------------------- 1.8 + 1.9 +Copyright (c) 2006-2012, assimp team 1.10 + 1.11 +All rights reserved. 1.12 + 1.13 +Redistribution and use of this software in source and binary forms, 1.14 +with or without modification, are permitted provided that the following 1.15 +conditions are met: 1.16 + 1.17 +* Redistributions of source code must retain the above 1.18 + copyright notice, this list of conditions and the 1.19 + following disclaimer. 1.20 + 1.21 +* Redistributions in binary form must reproduce the above 1.22 + copyright notice, this list of conditions and the 1.23 + following disclaimer in the documentation and/or other 1.24 + materials provided with the distribution. 1.25 + 1.26 +* Neither the name of the assimp team, nor the names of its 1.27 + contributors may be used to endorse or promote products 1.28 + derived from this software without specific prior 1.29 + written permission of the assimp team. 1.30 + 1.31 +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 1.32 +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 1.33 +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 1.34 +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 1.35 +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 1.36 +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 1.37 +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 1.38 +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 1.39 +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 1.40 +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 1.41 +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 1.42 +--------------------------------------------------------------------------- 1.43 +*/ 1.44 + 1.45 +/** @file MDLLoader.cpp 1.46 + * @brief Implementation of the main parts of the MDL importer class 1.47 + * *TODO* Cleanup and further testing of some parts necessary 1.48 + */ 1.49 + 1.50 +// internal headers 1.51 +#include "AssimpPCH.h" 1.52 +#ifndef ASSIMP_BUILD_NO_MDL_IMPORTER 1.53 + 1.54 +#include "MDLLoader.h" 1.55 +#include "MDLDefaultColorMap.h" 1.56 +#include "MD2FileData.h" 1.57 + 1.58 +using namespace Assimp; 1.59 + 1.60 +static const aiImporterDesc desc = { 1.61 + "Quake Mesh / 3D GameStudio Mesh Importer", 1.62 + "", 1.63 + "", 1.64 + "", 1.65 + aiImporterFlags_SupportBinaryFlavour, 1.66 + 0, 1.67 + 0, 1.68 + 7, 1.69 + 0, 1.70 + "mdl" 1.71 +}; 1.72 + 1.73 +// ------------------------------------------------------------------------------------------------ 1.74 +// Ugly stuff ... nevermind 1.75 +#define _AI_MDL7_ACCESS(_data, _index, _limit, _type) \ 1.76 + (*((const _type*)(((const char*)_data) + _index * _limit))) 1.77 + 1.78 +#define _AI_MDL7_ACCESS_PTR(_data, _index, _limit, _type) \ 1.79 + ((BE_NCONST _type*)(((const char*)_data) + _index * _limit)) 1.80 + 1.81 +#define _AI_MDL7_ACCESS_VERT(_data, _index, _limit) \ 1.82 + _AI_MDL7_ACCESS(_data,_index,_limit,MDL::Vertex_MDL7) 1.83 + 1.84 +// ------------------------------------------------------------------------------------------------ 1.85 +// Constructor to be privately used by Importer 1.86 +MDLImporter::MDLImporter() 1.87 +{} 1.88 + 1.89 +// ------------------------------------------------------------------------------------------------ 1.90 +// Destructor, private as well 1.91 +MDLImporter::~MDLImporter() 1.92 +{} 1.93 + 1.94 +// ------------------------------------------------------------------------------------------------ 1.95 +// Returns whether the class can handle the format of the given file. 1.96 +bool MDLImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const 1.97 +{ 1.98 + const std::string extension = GetExtension(pFile); 1.99 + 1.100 + // if check for extension is not enough, check for the magic tokens 1.101 + if (extension == "mdl" || !extension.length() || checkSig) { 1.102 + uint32_t tokens[8]; 1.103 + tokens[0] = AI_MDL_MAGIC_NUMBER_LE_HL2a; 1.104 + tokens[1] = AI_MDL_MAGIC_NUMBER_LE_HL2b; 1.105 + tokens[2] = AI_MDL_MAGIC_NUMBER_LE_GS7; 1.106 + tokens[3] = AI_MDL_MAGIC_NUMBER_LE_GS5b; 1.107 + tokens[4] = AI_MDL_MAGIC_NUMBER_LE_GS5a; 1.108 + tokens[5] = AI_MDL_MAGIC_NUMBER_LE_GS4; 1.109 + tokens[6] = AI_MDL_MAGIC_NUMBER_LE_GS3; 1.110 + tokens[7] = AI_MDL_MAGIC_NUMBER_LE; 1.111 + return CheckMagicToken(pIOHandler,pFile,tokens,8,0); 1.112 + } 1.113 + return false; 1.114 +} 1.115 + 1.116 +// ------------------------------------------------------------------------------------------------ 1.117 +// Setup configuration properties 1.118 +void MDLImporter::SetupProperties(const Importer* pImp) 1.119 +{ 1.120 + configFrameID = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_MDL_KEYFRAME,-1); 1.121 + 1.122 + // The 1.123 + // AI_CONFIG_IMPORT_MDL_KEYFRAME option overrides the 1.124 + // AI_CONFIG_IMPORT_GLOBAL_KEYFRAME option. 1.125 + if(static_cast<unsigned int>(-1) == configFrameID) { 1.126 + configFrameID = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_GLOBAL_KEYFRAME,0); 1.127 + } 1.128 + 1.129 + // AI_CONFIG_IMPORT_MDL_COLORMAP - pallette file 1.130 + configPalette = pImp->GetPropertyString(AI_CONFIG_IMPORT_MDL_COLORMAP,"colormap.lmp"); 1.131 +} 1.132 + 1.133 +// ------------------------------------------------------------------------------------------------ 1.134 +// Get a list of all supported extensions 1.135 +const aiImporterDesc* MDLImporter::GetInfo () const 1.136 +{ 1.137 + return &desc; 1.138 +} 1.139 + 1.140 +// ------------------------------------------------------------------------------------------------ 1.141 +// Imports the given file into the given scene structure. 1.142 +void MDLImporter::InternReadFile( const std::string& pFile, 1.143 + aiScene* _pScene, IOSystem* _pIOHandler) 1.144 +{ 1.145 + pScene = _pScene; 1.146 + pIOHandler = _pIOHandler; 1.147 + boost::scoped_ptr<IOStream> file( pIOHandler->Open( pFile)); 1.148 + 1.149 + // Check whether we can read from the file 1.150 + if( file.get() == NULL) { 1.151 + throw DeadlyImportError( "Failed to open MDL file " + pFile + "."); 1.152 + } 1.153 + 1.154 + // This should work for all other types of MDL files, too ... 1.155 + // the quake header is one of the smallest, afaik 1.156 + iFileSize = (unsigned int)file->FileSize(); 1.157 + if( iFileSize < sizeof(MDL::Header)) { 1.158 + throw DeadlyImportError( "MDL File is too small."); 1.159 + } 1.160 + 1.161 + // Allocate storage and copy the contents of the file to a memory buffer 1.162 + std::vector<unsigned char> buffer(iFileSize+1); 1.163 + mBuffer = &buffer[0]; 1.164 + file->Read( (void*)mBuffer, 1, iFileSize); 1.165 + 1.166 + // Append a binary zero to the end of the buffer. 1.167 + // this is just for safety that string parsing routines 1.168 + // find the end of the buffer ... 1.169 + mBuffer[iFileSize] = '\0'; 1.170 + const uint32_t iMagicWord = *((uint32_t*)mBuffer); 1.171 + 1.172 + // Determine the file subtype and call the appropriate member function 1.173 + 1.174 + // Original Quake1 format 1.175 + if (AI_MDL_MAGIC_NUMBER_BE == iMagicWord || AI_MDL_MAGIC_NUMBER_LE == iMagicWord) { 1.176 + DefaultLogger::get()->debug("MDL subtype: Quake 1, magic word is IDPO"); 1.177 + iGSFileVersion = 0; 1.178 + InternReadFile_Quake1(); 1.179 + } 1.180 + // GameStudio A<old> MDL2 format - used by some test models that come with 3DGS 1.181 + else if (AI_MDL_MAGIC_NUMBER_BE_GS3 == iMagicWord || AI_MDL_MAGIC_NUMBER_LE_GS3 == iMagicWord) { 1.182 + DefaultLogger::get()->debug("MDL subtype: 3D GameStudio A2, magic word is MDL2"); 1.183 + iGSFileVersion = 2; 1.184 + InternReadFile_Quake1(); 1.185 + } 1.186 + // GameStudio A4 MDL3 format 1.187 + else if (AI_MDL_MAGIC_NUMBER_BE_GS4 == iMagicWord || AI_MDL_MAGIC_NUMBER_LE_GS4 == iMagicWord) { 1.188 + DefaultLogger::get()->debug("MDL subtype: 3D GameStudio A4, magic word is MDL3"); 1.189 + iGSFileVersion = 3; 1.190 + InternReadFile_3DGS_MDL345(); 1.191 + } 1.192 + // GameStudio A5+ MDL4 format 1.193 + else if (AI_MDL_MAGIC_NUMBER_BE_GS5a == iMagicWord || AI_MDL_MAGIC_NUMBER_LE_GS5a == iMagicWord) { 1.194 + DefaultLogger::get()->debug("MDL subtype: 3D GameStudio A4, magic word is MDL4"); 1.195 + iGSFileVersion = 4; 1.196 + InternReadFile_3DGS_MDL345(); 1.197 + } 1.198 + // GameStudio A5+ MDL5 format 1.199 + else if (AI_MDL_MAGIC_NUMBER_BE_GS5b == iMagicWord || AI_MDL_MAGIC_NUMBER_LE_GS5b == iMagicWord) { 1.200 + DefaultLogger::get()->debug("MDL subtype: 3D GameStudio A5, magic word is MDL5"); 1.201 + iGSFileVersion = 5; 1.202 + InternReadFile_3DGS_MDL345(); 1.203 + } 1.204 + // GameStudio A7 MDL7 format 1.205 + else if (AI_MDL_MAGIC_NUMBER_BE_GS7 == iMagicWord || AI_MDL_MAGIC_NUMBER_LE_GS7 == iMagicWord) { 1.206 + DefaultLogger::get()->debug("MDL subtype: 3D GameStudio A7, magic word is MDL7"); 1.207 + iGSFileVersion = 7; 1.208 + InternReadFile_3DGS_MDL7(); 1.209 + } 1.210 + // IDST/IDSQ Format (CS:S/HL^2, etc ...) 1.211 + else if (AI_MDL_MAGIC_NUMBER_BE_HL2a == iMagicWord || AI_MDL_MAGIC_NUMBER_LE_HL2a == iMagicWord || 1.212 + AI_MDL_MAGIC_NUMBER_BE_HL2b == iMagicWord || AI_MDL_MAGIC_NUMBER_LE_HL2b == iMagicWord) 1.213 + { 1.214 + DefaultLogger::get()->debug("MDL subtype: Source(tm) Engine, magic word is IDST/IDSQ"); 1.215 + iGSFileVersion = 0; 1.216 + InternReadFile_HL2(); 1.217 + } 1.218 + else { 1.219 + // print the magic word to the log file 1.220 + throw DeadlyImportError( "Unknown MDL subformat " + pFile + 1.221 + ". Magic word (" + std::string((char*)&iMagicWord,4) + ") is not known"); 1.222 + } 1.223 + 1.224 + // Now rotate the whole scene 90 degrees around the x axis to convert to internal coordinate system 1.225 + pScene->mRootNode->mTransformation = aiMatrix4x4(1.f,0.f,0.f,0.f, 1.226 + 0.f,0.f,1.f,0.f,0.f,-1.f,0.f,0.f,0.f,0.f,0.f,1.f); 1.227 + 1.228 + // delete the file buffer and cleanup 1.229 + AI_DEBUG_INVALIDATE_PTR(mBuffer); 1.230 + AI_DEBUG_INVALIDATE_PTR(pIOHandler); 1.231 + AI_DEBUG_INVALIDATE_PTR(pScene); 1.232 +} 1.233 + 1.234 +// ------------------------------------------------------------------------------------------------ 1.235 +// Check whether we're still inside the valid file range 1.236 +void MDLImporter::SizeCheck(const void* szPos) 1.237 +{ 1.238 + if (!szPos || (const unsigned char*)szPos > this->mBuffer + this->iFileSize) 1.239 + { 1.240 + throw DeadlyImportError("Invalid MDL file. The file is too small " 1.241 + "or contains invalid data."); 1.242 + } 1.243 +} 1.244 + 1.245 +// ------------------------------------------------------------------------------------------------ 1.246 +// Just for debgging purposes 1.247 +void MDLImporter::SizeCheck(const void* szPos, const char* szFile, unsigned int iLine) 1.248 +{ 1.249 + ai_assert(NULL != szFile); 1.250 + if (!szPos || (const unsigned char*)szPos > mBuffer + iFileSize) 1.251 + { 1.252 + // remove a directory if there is one 1.253 + const char* szFilePtr = ::strrchr(szFile,'\\'); 1.254 + if (!szFilePtr) { 1.255 + if(!(szFilePtr = ::strrchr(szFile,'/'))) 1.256 + szFilePtr = szFile; 1.257 + } 1.258 + if (szFilePtr)++szFilePtr; 1.259 + 1.260 + char szBuffer[1024]; 1.261 + ::sprintf(szBuffer,"Invalid MDL file. The file is too small " 1.262 + "or contains invalid data (File: %s Line: %i)",szFilePtr,iLine); 1.263 + 1.264 + throw DeadlyImportError(szBuffer); 1.265 + } 1.266 +} 1.267 + 1.268 +// ------------------------------------------------------------------------------------------------ 1.269 +// Validate a quake file header 1.270 +void MDLImporter::ValidateHeader_Quake1(const MDL::Header* pcHeader) 1.271 +{ 1.272 + // some values may not be NULL 1.273 + if (!pcHeader->num_frames) 1.274 + throw DeadlyImportError( "[Quake 1 MDL] There are no frames in the file"); 1.275 + 1.276 + if (!pcHeader->num_verts) 1.277 + throw DeadlyImportError( "[Quake 1 MDL] There are no vertices in the file"); 1.278 + 1.279 + if (!pcHeader->num_tris) 1.280 + throw DeadlyImportError( "[Quake 1 MDL] There are no triangles in the file"); 1.281 + 1.282 + // check whether the maxima are exceeded ...however, this applies for Quake 1 MDLs only 1.283 + if (!this->iGSFileVersion) 1.284 + { 1.285 + if (pcHeader->num_verts > AI_MDL_MAX_VERTS) 1.286 + DefaultLogger::get()->warn("Quake 1 MDL model has more than AI_MDL_MAX_VERTS vertices"); 1.287 + 1.288 + if (pcHeader->num_tris > AI_MDL_MAX_TRIANGLES) 1.289 + DefaultLogger::get()->warn("Quake 1 MDL model has more than AI_MDL_MAX_TRIANGLES triangles"); 1.290 + 1.291 + if (pcHeader->num_frames > AI_MDL_MAX_FRAMES) 1.292 + DefaultLogger::get()->warn("Quake 1 MDL model has more than AI_MDL_MAX_FRAMES frames"); 1.293 + 1.294 + // (this does not apply for 3DGS MDLs) 1.295 + if (!this->iGSFileVersion && pcHeader->version != AI_MDL_VERSION) 1.296 + DefaultLogger::get()->warn("Quake 1 MDL model has an unknown version: AI_MDL_VERSION (=6) is " 1.297 + "the expected file format version"); 1.298 + if(pcHeader->num_skins && (!pcHeader->skinwidth || !pcHeader->skinheight)) 1.299 + DefaultLogger::get()->warn("Skin width or height are 0"); 1.300 + } 1.301 +} 1.302 + 1.303 +#ifdef AI_BUILD_BIG_ENDIAN 1.304 +// ------------------------------------------------------------------------------------------------ 1.305 +void FlipQuakeHeader(BE_NCONST MDL::Header* pcHeader) 1.306 +{ 1.307 + AI_SWAP4( pcHeader->ident); 1.308 + AI_SWAP4( pcHeader->version); 1.309 + AI_SWAP4( pcHeader->boundingradius); 1.310 + AI_SWAP4( pcHeader->flags); 1.311 + AI_SWAP4( pcHeader->num_frames); 1.312 + AI_SWAP4( pcHeader->num_skins); 1.313 + AI_SWAP4( pcHeader->num_tris); 1.314 + AI_SWAP4( pcHeader->num_verts); 1.315 + for (unsigned int i = 0; i < 3;++i) 1.316 + { 1.317 + AI_SWAP4( pcHeader->scale[i]); 1.318 + AI_SWAP4( pcHeader->translate[i]); 1.319 + } 1.320 + AI_SWAP4( pcHeader->size); 1.321 + AI_SWAP4( pcHeader->skinheight); 1.322 + AI_SWAP4( pcHeader->skinwidth); 1.323 + AI_SWAP4( pcHeader->synctype); 1.324 +} 1.325 +#endif 1.326 + 1.327 +// ------------------------------------------------------------------------------------------------ 1.328 +// Read a Quake 1 file 1.329 +void MDLImporter::InternReadFile_Quake1( ) 1.330 +{ 1.331 + ai_assert(NULL != pScene); 1.332 + BE_NCONST MDL::Header *pcHeader = (BE_NCONST MDL::Header*)this->mBuffer; 1.333 + 1.334 +#ifdef AI_BUILD_BIG_ENDIAN 1.335 + FlipQuakeHeader(pcHeader); 1.336 +#endif 1.337 + 1.338 + ValidateHeader_Quake1(pcHeader); 1.339 + 1.340 + // current cursor position in the file 1.341 + const unsigned char* szCurrent = (const unsigned char*)(pcHeader+1); 1.342 + 1.343 + // need to read all textures 1.344 + for (unsigned int i = 0; i < (unsigned int)pcHeader->num_skins;++i) 1.345 + { 1.346 + union{BE_NCONST MDL::Skin* pcSkin;BE_NCONST MDL::GroupSkin* pcGroupSkin;}; 1.347 + pcSkin = (BE_NCONST MDL::Skin*)szCurrent; 1.348 + 1.349 + AI_SWAP4( pcSkin->group ); 1.350 + 1.351 + // Quake 1 groupskins 1.352 + if (1 == pcSkin->group) 1.353 + { 1.354 + AI_SWAP4( pcGroupSkin->nb ); 1.355 + 1.356 + // need to skip multiple images 1.357 + const unsigned int iNumImages = (unsigned int)pcGroupSkin->nb; 1.358 + szCurrent += sizeof(uint32_t) * 2; 1.359 + 1.360 + if (0 != iNumImages) 1.361 + { 1.362 + if (!i) { 1.363 + // however, create only one output image (the first) 1.364 + this->CreateTextureARGB8_3DGS_MDL3(szCurrent + iNumImages * sizeof(float)); 1.365 + } 1.366 + // go to the end of the skin section / the beginning of the next skin 1.367 + szCurrent += pcHeader->skinheight * pcHeader->skinwidth + 1.368 + sizeof(float) * iNumImages; 1.369 + } 1.370 + } 1.371 + // 3DGS has a few files that are using other 3DGS like texture formats here 1.372 + else 1.373 + { 1.374 + szCurrent += sizeof(uint32_t); 1.375 + unsigned int iSkip = i ? UINT_MAX : 0; 1.376 + CreateTexture_3DGS_MDL4(szCurrent,pcSkin->group,&iSkip); 1.377 + szCurrent += iSkip; 1.378 + } 1.379 + } 1.380 + // get a pointer to the texture coordinates 1.381 + BE_NCONST MDL::TexCoord* pcTexCoords = (BE_NCONST MDL::TexCoord*)szCurrent; 1.382 + szCurrent += sizeof(MDL::TexCoord) * pcHeader->num_verts; 1.383 + 1.384 + // get a pointer to the triangles 1.385 + BE_NCONST MDL::Triangle* pcTriangles = (BE_NCONST MDL::Triangle*)szCurrent; 1.386 + szCurrent += sizeof(MDL::Triangle) * pcHeader->num_tris; 1.387 + VALIDATE_FILE_SIZE(szCurrent); 1.388 + 1.389 + // now get a pointer to the first frame in the file 1.390 + BE_NCONST MDL::Frame* pcFrames = (BE_NCONST MDL::Frame*)szCurrent; 1.391 + BE_NCONST MDL::SimpleFrame* pcFirstFrame; 1.392 + 1.393 + if (0 == pcFrames->type) 1.394 + { 1.395 + // get address of single frame 1.396 + pcFirstFrame = &pcFrames->frame; 1.397 + } 1.398 + else 1.399 + { 1.400 + // get the first frame in the group 1.401 + BE_NCONST MDL::GroupFrame* pcFrames2 = (BE_NCONST MDL::GroupFrame*)pcFrames; 1.402 + pcFirstFrame = (BE_NCONST MDL::SimpleFrame*)(&pcFrames2->time + pcFrames->type); 1.403 + } 1.404 + BE_NCONST MDL::Vertex* pcVertices = (BE_NCONST MDL::Vertex*) ((pcFirstFrame->name) + sizeof(pcFirstFrame->name)); 1.405 + VALIDATE_FILE_SIZE((const unsigned char*)(pcVertices + pcHeader->num_verts)); 1.406 + 1.407 +#ifdef AI_BUILD_BIG_ENDIAN 1.408 + for (int i = 0; i<pcHeader->num_verts;++i) 1.409 + { 1.410 + AI_SWAP4( pcTexCoords[i].onseam ); 1.411 + AI_SWAP4( pcTexCoords[i].s ); 1.412 + AI_SWAP4( pcTexCoords[i].t ); 1.413 + } 1.414 + 1.415 + for (int i = 0; i<pcHeader->num_tris;++i) 1.416 + { 1.417 + AI_SWAP4( pcTriangles[i].facesfront); 1.418 + AI_SWAP4( pcTriangles[i].vertex[0]); 1.419 + AI_SWAP4( pcTriangles[i].vertex[1]); 1.420 + AI_SWAP4( pcTriangles[i].vertex[2]); 1.421 + } 1.422 +#endif 1.423 + 1.424 + // setup materials 1.425 + SetupMaterialProperties_3DGS_MDL5_Quake1(); 1.426 + 1.427 + // allocate enough storage to hold all vertices and triangles 1.428 + aiMesh* pcMesh = new aiMesh(); 1.429 + 1.430 + pcMesh->mPrimitiveTypes = aiPrimitiveType_TRIANGLE; 1.431 + pcMesh->mNumVertices = pcHeader->num_tris * 3; 1.432 + pcMesh->mNumFaces = pcHeader->num_tris; 1.433 + pcMesh->mVertices = new aiVector3D[pcMesh->mNumVertices]; 1.434 + pcMesh->mTextureCoords[0] = new aiVector3D[pcMesh->mNumVertices]; 1.435 + pcMesh->mFaces = new aiFace[pcMesh->mNumFaces]; 1.436 + pcMesh->mNormals = new aiVector3D[pcMesh->mNumVertices]; 1.437 + pcMesh->mNumUVComponents[0] = 2; 1.438 + 1.439 + // there won't be more than one mesh inside the file 1.440 + pScene->mRootNode = new aiNode(); 1.441 + pScene->mRootNode->mNumMeshes = 1; 1.442 + pScene->mRootNode->mMeshes = new unsigned int[1]; 1.443 + pScene->mRootNode->mMeshes[0] = 0; 1.444 + pScene->mNumMeshes = 1; 1.445 + pScene->mMeshes = new aiMesh*[1]; 1.446 + pScene->mMeshes[0] = pcMesh; 1.447 + 1.448 + // now iterate through all triangles 1.449 + unsigned int iCurrent = 0; 1.450 + for (unsigned int i = 0; i < (unsigned int) pcHeader->num_tris;++i) 1.451 + { 1.452 + pcMesh->mFaces[i].mIndices = new unsigned int[3]; 1.453 + pcMesh->mFaces[i].mNumIndices = 3; 1.454 + 1.455 + unsigned int iTemp = iCurrent; 1.456 + for (unsigned int c = 0; c < 3;++c,++iCurrent) 1.457 + { 1.458 + pcMesh->mFaces[i].mIndices[c] = iCurrent; 1.459 + 1.460 + // read vertices 1.461 + unsigned int iIndex = pcTriangles->vertex[c]; 1.462 + if (iIndex >= (unsigned int)pcHeader->num_verts) 1.463 + { 1.464 + iIndex = pcHeader->num_verts-1; 1.465 + DefaultLogger::get()->warn("Index overflow in Q1-MDL vertex list."); 1.466 + } 1.467 + 1.468 + aiVector3D& vec = pcMesh->mVertices[iCurrent]; 1.469 + vec.x = (float)pcVertices[iIndex].v[0] * pcHeader->scale[0]; 1.470 + vec.x += pcHeader->translate[0]; 1.471 + 1.472 + vec.y = (float)pcVertices[iIndex].v[1] * pcHeader->scale[1]; 1.473 + vec.y += pcHeader->translate[1]; 1.474 + //vec.y *= -1.0f; 1.475 + 1.476 + vec.z = (float)pcVertices[iIndex].v[2] * pcHeader->scale[2]; 1.477 + vec.z += pcHeader->translate[2]; 1.478 + 1.479 + // read the normal vector from the precalculated normal table 1.480 + MD2::LookupNormalIndex(pcVertices[iIndex].normalIndex,pcMesh->mNormals[iCurrent]); 1.481 + //pcMesh->mNormals[iCurrent].y *= -1.0f; 1.482 + 1.483 + // read texture coordinates 1.484 + float s = (float)pcTexCoords[iIndex].s; 1.485 + float t = (float)pcTexCoords[iIndex].t; 1.486 + 1.487 + // translate texture coordinates 1.488 + if (0 == pcTriangles->facesfront && 0 != pcTexCoords[iIndex].onseam) { 1.489 + s += pcHeader->skinwidth * 0.5f; 1.490 + } 1.491 + 1.492 + // Scale s and t to range from 0.0 to 1.0 1.493 + pcMesh->mTextureCoords[0][iCurrent].x = (s + 0.5f) / pcHeader->skinwidth; 1.494 + pcMesh->mTextureCoords[0][iCurrent].y = 1.0f-(t + 0.5f) / pcHeader->skinheight; 1.495 + 1.496 + } 1.497 + pcMesh->mFaces[i].mIndices[0] = iTemp+2; 1.498 + pcMesh->mFaces[i].mIndices[1] = iTemp+1; 1.499 + pcMesh->mFaces[i].mIndices[2] = iTemp+0; 1.500 + pcTriangles++; 1.501 + } 1.502 + return; 1.503 +} 1.504 + 1.505 +// ------------------------------------------------------------------------------------------------ 1.506 +// Setup material properties for Quake and older GameStudio files 1.507 +void MDLImporter::SetupMaterialProperties_3DGS_MDL5_Quake1( ) 1.508 +{ 1.509 + const MDL::Header* const pcHeader = (const MDL::Header*)this->mBuffer; 1.510 + 1.511 + // allocate ONE material 1.512 + pScene->mMaterials = new aiMaterial*[1]; 1.513 + pScene->mMaterials[0] = new aiMaterial(); 1.514 + pScene->mNumMaterials = 1; 1.515 + 1.516 + // setup the material's properties 1.517 + const int iMode = (int)aiShadingMode_Gouraud; 1.518 + aiMaterial* const pcHelper = (aiMaterial*)pScene->mMaterials[0]; 1.519 + pcHelper->AddProperty<int>(&iMode, 1, AI_MATKEY_SHADING_MODEL); 1.520 + 1.521 + aiColor4D clr; 1.522 + if (0 != pcHeader->num_skins && pScene->mNumTextures) { 1.523 + // can we replace the texture with a single color? 1.524 + clr = this->ReplaceTextureWithColor(pScene->mTextures[0]); 1.525 + if (is_not_qnan(clr.r)) { 1.526 + delete pScene->mTextures[0]; 1.527 + delete[] pScene->mTextures; 1.528 + 1.529 + pScene->mTextures = NULL; 1.530 + pScene->mNumTextures = 0; 1.531 + } 1.532 + else { 1.533 + clr.b = clr.a = clr.g = clr.r = 1.0f; 1.534 + aiString szString; 1.535 + ::memcpy(szString.data,AI_MAKE_EMBEDDED_TEXNAME(0),3); 1.536 + szString.length = 2; 1.537 + pcHelper->AddProperty(&szString,AI_MATKEY_TEXTURE_DIFFUSE(0)); 1.538 + } 1.539 + } 1.540 + 1.541 + pcHelper->AddProperty<aiColor4D>(&clr, 1,AI_MATKEY_COLOR_DIFFUSE); 1.542 + pcHelper->AddProperty<aiColor4D>(&clr, 1,AI_MATKEY_COLOR_SPECULAR); 1.543 + 1.544 + clr.r *= 0.05f;clr.g *= 0.05f; 1.545 + clr.b *= 0.05f;clr.a = 1.0f; 1.546 + pcHelper->AddProperty<aiColor4D>(&clr, 1,AI_MATKEY_COLOR_AMBIENT); 1.547 +} 1.548 + 1.549 +// ------------------------------------------------------------------------------------------------ 1.550 +// Read a MDL 3,4,5 file 1.551 +void MDLImporter::InternReadFile_3DGS_MDL345( ) 1.552 +{ 1.553 + ai_assert(NULL != pScene); 1.554 + 1.555 + // the header of MDL 3/4/5 is nearly identical to the original Quake1 header 1.556 + BE_NCONST MDL::Header *pcHeader = (BE_NCONST MDL::Header*)this->mBuffer; 1.557 +#ifdef AI_BUILD_BIG_ENDIAN 1.558 + FlipQuakeHeader(pcHeader); 1.559 +#endif 1.560 + ValidateHeader_Quake1(pcHeader); 1.561 + 1.562 + // current cursor position in the file 1.563 + const unsigned char* szCurrent = (const unsigned char*)(pcHeader+1); 1.564 + 1.565 + // need to read all textures 1.566 + for (unsigned int i = 0; i < (unsigned int)pcHeader->num_skins;++i) { 1.567 + BE_NCONST MDL::Skin* pcSkin; 1.568 + pcSkin = (BE_NCONST MDL::Skin*)szCurrent; 1.569 + AI_SWAP4( pcSkin->group); 1.570 + // create one output image 1.571 + unsigned int iSkip = i ? UINT_MAX : 0; 1.572 + if (5 <= iGSFileVersion) 1.573 + { 1.574 + // MDL5 format could contain MIPmaps 1.575 + CreateTexture_3DGS_MDL5((unsigned char*)pcSkin + sizeof(uint32_t), 1.576 + pcSkin->group,&iSkip); 1.577 + } 1.578 + else { 1.579 + CreateTexture_3DGS_MDL4((unsigned char*)pcSkin + sizeof(uint32_t), 1.580 + pcSkin->group,&iSkip); 1.581 + } 1.582 + // need to skip one image 1.583 + szCurrent += iSkip + sizeof(uint32_t); 1.584 + 1.585 + } 1.586 + // get a pointer to the texture coordinates 1.587 + BE_NCONST MDL::TexCoord_MDL3* pcTexCoords = (BE_NCONST MDL::TexCoord_MDL3*)szCurrent; 1.588 + szCurrent += sizeof(MDL::TexCoord_MDL3) * pcHeader->synctype; 1.589 + 1.590 + // NOTE: for MDLn formats "synctype" corresponds to the number of UV coords 1.591 + 1.592 + // get a pointer to the triangles 1.593 + BE_NCONST MDL::Triangle_MDL3* pcTriangles = (BE_NCONST MDL::Triangle_MDL3*)szCurrent; 1.594 + szCurrent += sizeof(MDL::Triangle_MDL3) * pcHeader->num_tris; 1.595 + 1.596 +#ifdef AI_BUILD_BIG_ENDIAN 1.597 + 1.598 + for (int i = 0; i<pcHeader->synctype;++i) { 1.599 + AI_SWAP2( pcTexCoords[i].u ); 1.600 + AI_SWAP2( pcTexCoords[i].v ); 1.601 + } 1.602 + 1.603 + for (int i = 0; i<pcHeader->num_tris;++i) { 1.604 + AI_SWAP2( pcTriangles[i].index_xyz[0]); 1.605 + AI_SWAP2( pcTriangles[i].index_xyz[1]); 1.606 + AI_SWAP2( pcTriangles[i].index_xyz[2]); 1.607 + AI_SWAP2( pcTriangles[i].index_uv[0]); 1.608 + AI_SWAP2( pcTriangles[i].index_uv[1]); 1.609 + AI_SWAP2( pcTriangles[i].index_uv[2]); 1.610 + } 1.611 + 1.612 +#endif 1.613 + 1.614 + VALIDATE_FILE_SIZE(szCurrent); 1.615 + 1.616 + // setup materials 1.617 + SetupMaterialProperties_3DGS_MDL5_Quake1(); 1.618 + 1.619 + // allocate enough storage to hold all vertices and triangles 1.620 + aiMesh* pcMesh = new aiMesh(); 1.621 + pcMesh->mPrimitiveTypes = aiPrimitiveType_TRIANGLE; 1.622 + 1.623 + pcMesh->mNumVertices = pcHeader->num_tris * 3; 1.624 + pcMesh->mNumFaces = pcHeader->num_tris; 1.625 + pcMesh->mFaces = new aiFace[pcMesh->mNumFaces]; 1.626 + 1.627 + // there won't be more than one mesh inside the file 1.628 + pScene->mRootNode = new aiNode(); 1.629 + pScene->mRootNode->mNumMeshes = 1; 1.630 + pScene->mRootNode->mMeshes = new unsigned int[1]; 1.631 + pScene->mRootNode->mMeshes[0] = 0; 1.632 + pScene->mNumMeshes = 1; 1.633 + pScene->mMeshes = new aiMesh*[1]; 1.634 + pScene->mMeshes[0] = pcMesh; 1.635 + 1.636 + // allocate output storage 1.637 + pcMesh->mNumVertices = (unsigned int)pcHeader->num_tris*3; 1.638 + pcMesh->mVertices = new aiVector3D[pcMesh->mNumVertices]; 1.639 + pcMesh->mNormals = new aiVector3D[pcMesh->mNumVertices]; 1.640 + 1.641 + if (pcHeader->synctype) { 1.642 + pcMesh->mTextureCoords[0] = new aiVector3D[pcMesh->mNumVertices]; 1.643 + pcMesh->mNumUVComponents[0] = 2; 1.644 + } 1.645 + 1.646 + // now get a pointer to the first frame in the file 1.647 + BE_NCONST MDL::Frame* pcFrames = (BE_NCONST MDL::Frame*)szCurrent; 1.648 + AI_SWAP4(pcFrames->type); 1.649 + 1.650 + // byte packed vertices 1.651 + // FIXME: these two snippets below are almost identical ... join them? 1.652 + ///////////////////////////////////////////////////////////////////////////////////// 1.653 + if (0 == pcFrames->type || 3 >= this->iGSFileVersion) { 1.654 + 1.655 + const MDL::SimpleFrame* pcFirstFrame = (const MDL::SimpleFrame*)(szCurrent + sizeof(uint32_t)); 1.656 + const MDL::Vertex* pcVertices = (const MDL::Vertex*) ((pcFirstFrame->name) + sizeof(pcFirstFrame->name)); 1.657 + 1.658 + VALIDATE_FILE_SIZE(pcVertices + pcHeader->num_verts); 1.659 + 1.660 + // now iterate through all triangles 1.661 + unsigned int iCurrent = 0; 1.662 + for (unsigned int i = 0; i < (unsigned int) pcHeader->num_tris;++i) { 1.663 + pcMesh->mFaces[i].mIndices = new unsigned int[3]; 1.664 + pcMesh->mFaces[i].mNumIndices = 3; 1.665 + 1.666 + unsigned int iTemp = iCurrent; 1.667 + for (unsigned int c = 0; c < 3;++c,++iCurrent) { 1.668 + // read vertices 1.669 + unsigned int iIndex = pcTriangles->index_xyz[c]; 1.670 + if (iIndex >= (unsigned int)pcHeader->num_verts) { 1.671 + iIndex = pcHeader->num_verts-1; 1.672 + DefaultLogger::get()->warn("Index overflow in MDLn vertex list"); 1.673 + } 1.674 + 1.675 + aiVector3D& vec = pcMesh->mVertices[iCurrent]; 1.676 + vec.x = (float)pcVertices[iIndex].v[0] * pcHeader->scale[0]; 1.677 + vec.x += pcHeader->translate[0]; 1.678 + 1.679 + vec.y = (float)pcVertices[iIndex].v[1] * pcHeader->scale[1]; 1.680 + vec.y += pcHeader->translate[1]; 1.681 + // vec.y *= -1.0f; 1.682 + 1.683 + vec.z = (float)pcVertices[iIndex].v[2] * pcHeader->scale[2]; 1.684 + vec.z += pcHeader->translate[2]; 1.685 + 1.686 + // read the normal vector from the precalculated normal table 1.687 + MD2::LookupNormalIndex(pcVertices[iIndex].normalIndex,pcMesh->mNormals[iCurrent]); 1.688 + // pcMesh->mNormals[iCurrent].y *= -1.0f; 1.689 + 1.690 + // read texture coordinates 1.691 + if (pcHeader->synctype) { 1.692 + ImportUVCoordinate_3DGS_MDL345(pcMesh->mTextureCoords[0][iCurrent], 1.693 + pcTexCoords,pcTriangles->index_uv[c]); 1.694 + } 1.695 + } 1.696 + pcMesh->mFaces[i].mIndices[0] = iTemp+2; 1.697 + pcMesh->mFaces[i].mIndices[1] = iTemp+1; 1.698 + pcMesh->mFaces[i].mIndices[2] = iTemp+0; 1.699 + pcTriangles++; 1.700 + } 1.701 + 1.702 + } 1.703 + // short packed vertices 1.704 + ///////////////////////////////////////////////////////////////////////////////////// 1.705 + else { 1.706 + // now get a pointer to the first frame in the file 1.707 + const MDL::SimpleFrame_MDLn_SP* pcFirstFrame = (const MDL::SimpleFrame_MDLn_SP*) (szCurrent + sizeof(uint32_t)); 1.708 + 1.709 + // get a pointer to the vertices 1.710 + const MDL::Vertex_MDL4* pcVertices = (const MDL::Vertex_MDL4*) ((pcFirstFrame->name) + 1.711 + sizeof(pcFirstFrame->name)); 1.712 + 1.713 + VALIDATE_FILE_SIZE(pcVertices + pcHeader->num_verts); 1.714 + 1.715 + // now iterate through all triangles 1.716 + unsigned int iCurrent = 0; 1.717 + for (unsigned int i = 0; i < (unsigned int) pcHeader->num_tris;++i) { 1.718 + pcMesh->mFaces[i].mIndices = new unsigned int[3]; 1.719 + pcMesh->mFaces[i].mNumIndices = 3; 1.720 + 1.721 + unsigned int iTemp = iCurrent; 1.722 + for (unsigned int c = 0; c < 3;++c,++iCurrent) { 1.723 + // read vertices 1.724 + unsigned int iIndex = pcTriangles->index_xyz[c]; 1.725 + if (iIndex >= (unsigned int)pcHeader->num_verts) { 1.726 + iIndex = pcHeader->num_verts-1; 1.727 + DefaultLogger::get()->warn("Index overflow in MDLn vertex list"); 1.728 + } 1.729 + 1.730 + aiVector3D& vec = pcMesh->mVertices[iCurrent]; 1.731 + vec.x = (float)pcVertices[iIndex].v[0] * pcHeader->scale[0]; 1.732 + vec.x += pcHeader->translate[0]; 1.733 + 1.734 + vec.y = (float)pcVertices[iIndex].v[1] * pcHeader->scale[1]; 1.735 + vec.y += pcHeader->translate[1]; 1.736 + // vec.y *= -1.0f; 1.737 + 1.738 + vec.z = (float)pcVertices[iIndex].v[2] * pcHeader->scale[2]; 1.739 + vec.z += pcHeader->translate[2]; 1.740 + 1.741 + // read the normal vector from the precalculated normal table 1.742 + MD2::LookupNormalIndex(pcVertices[iIndex].normalIndex,pcMesh->mNormals[iCurrent]); 1.743 + // pcMesh->mNormals[iCurrent].y *= -1.0f; 1.744 + 1.745 + // read texture coordinates 1.746 + if (pcHeader->synctype) { 1.747 + ImportUVCoordinate_3DGS_MDL345(pcMesh->mTextureCoords[0][iCurrent], 1.748 + pcTexCoords,pcTriangles->index_uv[c]); 1.749 + } 1.750 + } 1.751 + pcMesh->mFaces[i].mIndices[0] = iTemp+2; 1.752 + pcMesh->mFaces[i].mIndices[1] = iTemp+1; 1.753 + pcMesh->mFaces[i].mIndices[2] = iTemp+0; 1.754 + pcTriangles++; 1.755 + } 1.756 + } 1.757 + 1.758 + // For MDL5 we will need to build valid texture coordinates 1.759 + // basing upon the file loaded (only support one file as skin) 1.760 + if (0x5 == iGSFileVersion) 1.761 + CalculateUVCoordinates_MDL5(); 1.762 + return; 1.763 +} 1.764 + 1.765 +// ------------------------------------------------------------------------------------------------ 1.766 +// Get a single UV coordinate for Quake and older GameStudio files 1.767 +void MDLImporter::ImportUVCoordinate_3DGS_MDL345( 1.768 + aiVector3D& vOut, 1.769 + const MDL::TexCoord_MDL3* pcSrc, 1.770 + unsigned int iIndex) 1.771 +{ 1.772 + ai_assert(NULL != pcSrc); 1.773 + const MDL::Header* const pcHeader = (const MDL::Header*)this->mBuffer; 1.774 + 1.775 + // validate UV indices 1.776 + if (iIndex >= (unsigned int) pcHeader->synctype) { 1.777 + iIndex = pcHeader->synctype-1; 1.778 + DefaultLogger::get()->warn("Index overflow in MDLn UV coord list"); 1.779 + } 1.780 + 1.781 + float s = (float)pcSrc[iIndex].u; 1.782 + float t = (float)pcSrc[iIndex].v; 1.783 + 1.784 + // Scale s and t to range from 0.0 to 1.0 1.785 + if (0x5 != iGSFileVersion) { 1.786 + s = (s + 0.5f) / pcHeader->skinwidth; 1.787 + t = 1.0f-(t + 0.5f) / pcHeader->skinheight; 1.788 + } 1.789 + 1.790 + vOut.x = s; 1.791 + vOut.y = t; 1.792 + vOut.z = 0.0f; 1.793 +} 1.794 + 1.795 +// ------------------------------------------------------------------------------------------------ 1.796 +// Compute UV coordinates for a MDL5 file 1.797 +void MDLImporter::CalculateUVCoordinates_MDL5() 1.798 +{ 1.799 + const MDL::Header* const pcHeader = (const MDL::Header*)this->mBuffer; 1.800 + if (pcHeader->num_skins && this->pScene->mNumTextures) { 1.801 + const aiTexture* pcTex = this->pScene->mTextures[0]; 1.802 + 1.803 + // if the file is loaded in DDS format: get the size of the 1.804 + // texture from the header of the DDS file 1.805 + // skip three DWORDs and read first height, then the width 1.806 + unsigned int iWidth, iHeight; 1.807 + if (!pcTex->mHeight) { 1.808 + const uint32_t* piPtr = (uint32_t*)pcTex->pcData; 1.809 + 1.810 + piPtr += 3; 1.811 + iHeight = (unsigned int)*piPtr++; 1.812 + iWidth = (unsigned int)*piPtr; 1.813 + if (!iHeight || !iWidth) 1.814 + { 1.815 + DefaultLogger::get()->warn("Either the width or the height of the " 1.816 + "embedded DDS texture is zero. Unable to compute final texture " 1.817 + "coordinates. The texture coordinates remain in their original " 1.818 + "0-x/0-y (x,y = texture size) range."); 1.819 + iWidth = 1; 1.820 + iHeight = 1; 1.821 + } 1.822 + } 1.823 + else { 1.824 + iWidth = pcTex->mWidth; 1.825 + iHeight = pcTex->mHeight; 1.826 + } 1.827 + 1.828 + if (1 != iWidth || 1 != iHeight) { 1.829 + const float fWidth = (float)iWidth; 1.830 + const float fHeight = (float)iHeight; 1.831 + aiMesh* pcMesh = this->pScene->mMeshes[0]; 1.832 + for (unsigned int i = 0; i < pcMesh->mNumVertices;++i) 1.833 + { 1.834 + pcMesh->mTextureCoords[0][i].x /= fWidth; 1.835 + pcMesh->mTextureCoords[0][i].y /= fHeight; 1.836 + pcMesh->mTextureCoords[0][i].y = 1.0f - pcMesh->mTextureCoords[0][i].y; // DX to OGL 1.837 + } 1.838 + } 1.839 + } 1.840 +} 1.841 + 1.842 +// ------------------------------------------------------------------------------------------------ 1.843 +// Validate the header of a MDL7 file 1.844 +void MDLImporter::ValidateHeader_3DGS_MDL7(const MDL::Header_MDL7* pcHeader) 1.845 +{ 1.846 + ai_assert(NULL != pcHeader); 1.847 + 1.848 + // There are some fixed sizes ... 1.849 + if (sizeof(MDL::ColorValue_MDL7) != pcHeader->colorvalue_stc_size) { 1.850 + throw DeadlyImportError( 1.851 + "[3DGS MDL7] sizeof(MDL::ColorValue_MDL7) != pcHeader->colorvalue_stc_size"); 1.852 + } 1.853 + if (sizeof(MDL::TexCoord_MDL7) != pcHeader->skinpoint_stc_size) { 1.854 + throw DeadlyImportError( 1.855 + "[3DGS MDL7] sizeof(MDL::TexCoord_MDL7) != pcHeader->skinpoint_stc_size"); 1.856 + } 1.857 + if (sizeof(MDL::Skin_MDL7) != pcHeader->skin_stc_size) { 1.858 + throw DeadlyImportError( 1.859 + "sizeof(MDL::Skin_MDL7) != pcHeader->skin_stc_size"); 1.860 + } 1.861 + 1.862 + // if there are no groups ... how should we load such a file? 1.863 + if(!pcHeader->groups_num) { 1.864 + throw DeadlyImportError( "[3DGS MDL7] No frames found"); 1.865 + } 1.866 +} 1.867 + 1.868 +// ------------------------------------------------------------------------------------------------ 1.869 +// resolve bone animation matrices 1.870 +void MDLImporter::CalcAbsBoneMatrices_3DGS_MDL7(MDL::IntBone_MDL7** apcOutBones) 1.871 +{ 1.872 + const MDL::Header_MDL7 *pcHeader = (const MDL::Header_MDL7*)this->mBuffer; 1.873 + const MDL::Bone_MDL7* pcBones = (const MDL::Bone_MDL7*)(pcHeader+1); 1.874 + ai_assert(NULL != apcOutBones); 1.875 + 1.876 + // first find the bone that has NO parent, calculate the 1.877 + // animation matrix for it, then go on and search for the next parent 1.878 + // index (0) and so on until we can't find a new node. 1.879 + uint16_t iParent = 0xffff; 1.880 + uint32_t iIterations = 0; 1.881 + while (iIterations++ < pcHeader->bones_num) { 1.882 + for (uint32_t iBone = 0; iBone < pcHeader->bones_num;++iBone) { 1.883 + BE_NCONST MDL::Bone_MDL7* pcBone = _AI_MDL7_ACCESS_PTR(pcBones,iBone, 1.884 + pcHeader->bone_stc_size,MDL::Bone_MDL7); 1.885 + 1.886 + AI_SWAP2(pcBone->parent_index); 1.887 + AI_SWAP4(pcBone->x); 1.888 + AI_SWAP4(pcBone->y); 1.889 + AI_SWAP4(pcBone->z); 1.890 + 1.891 + if (iParent == pcBone->parent_index) { 1.892 + // MDL7 readme 1.893 + //////////////////////////////////////////////////////////////// 1.894 + /* 1.895 + The animation matrix is then calculated the following way: 1.896 + 1.897 + vector3 bPos = <absolute bone position> 1.898 + matrix44 laM; // local animation matrix 1.899 + sphrvector key_rotate = <bone rotation> 1.900 + 1.901 + matrix44 m1,m2; 1.902 + create_trans_matrix(m1, -bPos.x, -bPos.y, -bPos.z); 1.903 + create_trans_matrix(m2, -bPos.x, -bPos.y, -bPos.z); 1.904 + 1.905 + create_rotation_matrix(laM,key_rotate); 1.906 + 1.907 + laM = sm1 * laM; 1.908 + laM = laM * sm2; 1.909 + */ 1.910 + ///////////////////////////////////////////////////////////////// 1.911 + 1.912 + MDL::IntBone_MDL7* const pcOutBone = apcOutBones[iBone]; 1.913 + 1.914 + // store the parent index of the bone 1.915 + pcOutBone->iParent = pcBone->parent_index; 1.916 + if (0xffff != iParent) { 1.917 + const MDL::IntBone_MDL7* pcParentBone = apcOutBones[iParent]; 1.918 + pcOutBone->mOffsetMatrix.a4 = -pcParentBone->vPosition.x; 1.919 + pcOutBone->mOffsetMatrix.b4 = -pcParentBone->vPosition.y; 1.920 + pcOutBone->mOffsetMatrix.c4 = -pcParentBone->vPosition.z; 1.921 + } 1.922 + pcOutBone->vPosition.x = pcBone->x; 1.923 + pcOutBone->vPosition.y = pcBone->y; 1.924 + pcOutBone->vPosition.z = pcBone->z; 1.925 + pcOutBone->mOffsetMatrix.a4 -= pcBone->x; 1.926 + pcOutBone->mOffsetMatrix.b4 -= pcBone->y; 1.927 + pcOutBone->mOffsetMatrix.c4 -= pcBone->z; 1.928 + 1.929 + if (AI_MDL7_BONE_STRUCT_SIZE__NAME_IS_NOT_THERE == pcHeader->bone_stc_size) { 1.930 + // no real name for our poor bone is specified :-( 1.931 + pcOutBone->mName.length = ::sprintf(pcOutBone->mName.data, 1.932 + "UnnamedBone_%i",iBone); 1.933 + } 1.934 + else { 1.935 + // Make sure we won't run over the buffer's end if there is no 1.936 + // terminal 0 character (however the documentation says there 1.937 + // should be one) 1.938 + uint32_t iMaxLen = pcHeader->bone_stc_size-16; 1.939 + for (uint32_t qq = 0; qq < iMaxLen;++qq) { 1.940 + if (!pcBone->name[qq]) { 1.941 + iMaxLen = qq; 1.942 + break; 1.943 + } 1.944 + } 1.945 + 1.946 + // store the name of the bone 1.947 + pcOutBone->mName.length = (size_t)iMaxLen; 1.948 + ::memcpy(pcOutBone->mName.data,pcBone->name,pcOutBone->mName.length); 1.949 + pcOutBone->mName.data[pcOutBone->mName.length] = '\0'; 1.950 + } 1.951 + } 1.952 + } 1.953 + ++iParent; 1.954 + } 1.955 +} 1.956 + 1.957 +// ------------------------------------------------------------------------------------------------ 1.958 +// read bones from a MDL7 file 1.959 +MDL::IntBone_MDL7** MDLImporter::LoadBones_3DGS_MDL7() 1.960 +{ 1.961 + const MDL::Header_MDL7 *pcHeader = (const MDL::Header_MDL7*)this->mBuffer; 1.962 + if (pcHeader->bones_num) { 1.963 + // validate the size of the bone data structure in the file 1.964 + if (AI_MDL7_BONE_STRUCT_SIZE__NAME_IS_20_CHARS != pcHeader->bone_stc_size && 1.965 + AI_MDL7_BONE_STRUCT_SIZE__NAME_IS_32_CHARS != pcHeader->bone_stc_size && 1.966 + AI_MDL7_BONE_STRUCT_SIZE__NAME_IS_NOT_THERE != pcHeader->bone_stc_size) 1.967 + { 1.968 + DefaultLogger::get()->warn("Unknown size of bone data structure"); 1.969 + return NULL; 1.970 + } 1.971 + 1.972 + MDL::IntBone_MDL7** apcBonesOut = new MDL::IntBone_MDL7*[pcHeader->bones_num]; 1.973 + for (uint32_t crank = 0; crank < pcHeader->bones_num;++crank) 1.974 + apcBonesOut[crank] = new MDL::IntBone_MDL7(); 1.975 + 1.976 + // and calculate absolute bone offset matrices ... 1.977 + CalcAbsBoneMatrices_3DGS_MDL7(apcBonesOut); 1.978 + return apcBonesOut; 1.979 + } 1.980 + return NULL; 1.981 +} 1.982 + 1.983 +// ------------------------------------------------------------------------------------------------ 1.984 +// read faces from a MDL7 file 1.985 +void MDLImporter::ReadFaces_3DGS_MDL7(const MDL::IntGroupInfo_MDL7& groupInfo, 1.986 + MDL::IntGroupData_MDL7& groupData) 1.987 +{ 1.988 + const MDL::Header_MDL7 *pcHeader = (const MDL::Header_MDL7*)this->mBuffer; 1.989 + MDL::Triangle_MDL7* pcGroupTris = groupInfo.pcGroupTris; 1.990 + 1.991 + // iterate through all triangles and build valid display lists 1.992 + unsigned int iOutIndex = 0; 1.993 + for (unsigned int iTriangle = 0; iTriangle < (unsigned int)groupInfo.pcGroup->numtris; ++iTriangle) { 1.994 + AI_SWAP2(pcGroupTris->v_index[0]); 1.995 + AI_SWAP2(pcGroupTris->v_index[1]); 1.996 + AI_SWAP2(pcGroupTris->v_index[2]); 1.997 + 1.998 + // iterate through all indices of the current triangle 1.999 + for (unsigned int c = 0; c < 3;++c,++iOutIndex) { 1.1000 + 1.1001 + // validate the vertex index 1.1002 + unsigned int iIndex = pcGroupTris->v_index[c]; 1.1003 + if(iIndex > (unsigned int)groupInfo.pcGroup->numverts) { 1.1004 + // (we might need to read this section a second time - to process frame vertices correctly) 1.1005 + pcGroupTris->v_index[c] = iIndex = groupInfo.pcGroup->numverts-1; 1.1006 + DefaultLogger::get()->warn("Index overflow in MDL7 vertex list"); 1.1007 + } 1.1008 + 1.1009 + // write the output face index 1.1010 + groupData.pcFaces[iTriangle].mIndices[2-c] = iOutIndex; 1.1011 + 1.1012 + aiVector3D& vPosition = groupData.vPositions[ iOutIndex ]; 1.1013 + vPosition.x = _AI_MDL7_ACCESS_VERT(groupInfo.pcGroupVerts,iIndex, pcHeader->mainvertex_stc_size) .x; 1.1014 + vPosition.y = _AI_MDL7_ACCESS_VERT(groupInfo.pcGroupVerts,iIndex,pcHeader->mainvertex_stc_size) .y; 1.1015 + vPosition.z = _AI_MDL7_ACCESS_VERT(groupInfo.pcGroupVerts,iIndex,pcHeader->mainvertex_stc_size) .z; 1.1016 + 1.1017 + // if we have bones, save the index 1.1018 + if (!groupData.aiBones.empty()) { 1.1019 + groupData.aiBones[iOutIndex] = _AI_MDL7_ACCESS_VERT(groupInfo.pcGroupVerts, 1.1020 + iIndex,pcHeader->mainvertex_stc_size).vertindex; 1.1021 + } 1.1022 + 1.1023 + // now read the normal vector 1.1024 + if (AI_MDL7_FRAMEVERTEX030305_STCSIZE <= pcHeader->mainvertex_stc_size) { 1.1025 + // read the full normal vector 1.1026 + aiVector3D& vNormal = groupData.vNormals[ iOutIndex ]; 1.1027 + vNormal.x = _AI_MDL7_ACCESS_VERT(groupInfo.pcGroupVerts,iIndex,pcHeader->mainvertex_stc_size) .norm[0]; 1.1028 + AI_SWAP4(vNormal.x); 1.1029 + vNormal.y = _AI_MDL7_ACCESS_VERT(groupInfo.pcGroupVerts,iIndex,pcHeader->mainvertex_stc_size) .norm[1]; 1.1030 + AI_SWAP4(vNormal.y); 1.1031 + vNormal.z = _AI_MDL7_ACCESS_VERT(groupInfo.pcGroupVerts,iIndex,pcHeader->mainvertex_stc_size) .norm[2]; 1.1032 + AI_SWAP4(vNormal.z); 1.1033 + } 1.1034 + else if (AI_MDL7_FRAMEVERTEX120503_STCSIZE <= pcHeader->mainvertex_stc_size) { 1.1035 + // read the normal vector from Quake2's smart table 1.1036 + aiVector3D& vNormal = groupData.vNormals[ iOutIndex ]; 1.1037 + MD2::LookupNormalIndex(_AI_MDL7_ACCESS_VERT(groupInfo.pcGroupVerts,iIndex, 1.1038 + pcHeader->mainvertex_stc_size) .norm162index,vNormal); 1.1039 + } 1.1040 + // validate and process the first uv coordinate set 1.1041 + if (pcHeader->triangle_stc_size >= AI_MDL7_TRIANGLE_STD_SIZE_ONE_UV) { 1.1042 + 1.1043 + if (groupInfo.pcGroup->num_stpts) { 1.1044 + AI_SWAP2(pcGroupTris->skinsets[0].st_index[0]); 1.1045 + AI_SWAP2(pcGroupTris->skinsets[0].st_index[1]); 1.1046 + AI_SWAP2(pcGroupTris->skinsets[0].st_index[2]); 1.1047 + 1.1048 + iIndex = pcGroupTris->skinsets[0].st_index[c]; 1.1049 + if(iIndex > (unsigned int)groupInfo.pcGroup->num_stpts) { 1.1050 + iIndex = groupInfo.pcGroup->num_stpts-1; 1.1051 + DefaultLogger::get()->warn("Index overflow in MDL7 UV coordinate list (#1)"); 1.1052 + } 1.1053 + 1.1054 + float u = groupInfo.pcGroupUVs[iIndex].u; 1.1055 + float v = 1.0f-groupInfo.pcGroupUVs[iIndex].v; // DX to OGL 1.1056 + 1.1057 + groupData.vTextureCoords1[iOutIndex].x = u; 1.1058 + groupData.vTextureCoords1[iOutIndex].y = v; 1.1059 + } 1.1060 + // assign the material index, but only if it is existing 1.1061 + if (pcHeader->triangle_stc_size >= AI_MDL7_TRIANGLE_STD_SIZE_ONE_UV_WITH_MATINDEX){ 1.1062 + AI_SWAP4(pcGroupTris->skinsets[0].material); 1.1063 + groupData.pcFaces[iTriangle].iMatIndex[0] = pcGroupTris->skinsets[0].material; 1.1064 + } 1.1065 + } 1.1066 + // validate and process the second uv coordinate set 1.1067 + if (pcHeader->triangle_stc_size >= AI_MDL7_TRIANGLE_STD_SIZE_TWO_UV) { 1.1068 + 1.1069 + if (groupInfo.pcGroup->num_stpts) { 1.1070 + AI_SWAP2(pcGroupTris->skinsets[1].st_index[0]); 1.1071 + AI_SWAP2(pcGroupTris->skinsets[1].st_index[1]); 1.1072 + AI_SWAP2(pcGroupTris->skinsets[1].st_index[2]); 1.1073 + AI_SWAP4(pcGroupTris->skinsets[1].material); 1.1074 + 1.1075 + iIndex = pcGroupTris->skinsets[1].st_index[c]; 1.1076 + if(iIndex > (unsigned int)groupInfo.pcGroup->num_stpts) { 1.1077 + iIndex = groupInfo.pcGroup->num_stpts-1; 1.1078 + DefaultLogger::get()->warn("Index overflow in MDL7 UV coordinate list (#2)"); 1.1079 + } 1.1080 + 1.1081 + float u = groupInfo.pcGroupUVs[ iIndex ].u; 1.1082 + float v = 1.0f-groupInfo.pcGroupUVs[ iIndex ].v; 1.1083 + 1.1084 + groupData.vTextureCoords2[ iOutIndex ].x = u; 1.1085 + groupData.vTextureCoords2[ iOutIndex ].y = v; // DX to OGL 1.1086 + 1.1087 + // check whether we do really need the second texture 1.1088 + // coordinate set ... wastes memory and loading time 1.1089 + if (0 != iIndex && (u != groupData.vTextureCoords1[ iOutIndex ].x || 1.1090 + v != groupData.vTextureCoords1[ iOutIndex ].y ) ) 1.1091 + groupData.bNeed2UV = true; 1.1092 + 1.1093 + // if the material differs, we need a second skin, too 1.1094 + if (pcGroupTris->skinsets[ 1 ].material != pcGroupTris->skinsets[ 0 ].material) 1.1095 + groupData.bNeed2UV = true; 1.1096 + } 1.1097 + // assign the material index 1.1098 + groupData.pcFaces[ iTriangle ].iMatIndex[ 1 ] = pcGroupTris->skinsets[ 1 ].material; 1.1099 + } 1.1100 + } 1.1101 + // get the next triangle in the list 1.1102 + pcGroupTris = (MDL::Triangle_MDL7*)((const char*)pcGroupTris + pcHeader->triangle_stc_size); 1.1103 + } 1.1104 +} 1.1105 + 1.1106 +// ------------------------------------------------------------------------------------------------ 1.1107 +// handle frames in a MDL7 file 1.1108 +bool MDLImporter::ProcessFrames_3DGS_MDL7(const MDL::IntGroupInfo_MDL7& groupInfo, 1.1109 + MDL::IntGroupData_MDL7& groupData, 1.1110 + MDL::IntSharedData_MDL7& shared, 1.1111 + const unsigned char* szCurrent, 1.1112 + const unsigned char** szCurrentOut) 1.1113 +{ 1.1114 + ai_assert(NULL != szCurrent && NULL != szCurrentOut); 1.1115 + const MDL::Header_MDL7 *pcHeader = (const MDL::Header_MDL7*)mBuffer; 1.1116 + 1.1117 + // if we have no bones we can simply skip all frames, 1.1118 + // otherwise we'll need to process them. 1.1119 + // FIX: If we need another frame than the first we must apply frame vertex replacements ... 1.1120 + for(unsigned int iFrame = 0; iFrame < (unsigned int)groupInfo.pcGroup->numframes;++iFrame) { 1.1121 + MDL::IntFrameInfo_MDL7 frame ((BE_NCONST MDL::Frame_MDL7*)szCurrent,iFrame); 1.1122 + 1.1123 + AI_SWAP4(frame.pcFrame->vertices_count); 1.1124 + AI_SWAP4(frame.pcFrame->transmatrix_count); 1.1125 + 1.1126 + const unsigned int iAdd = pcHeader->frame_stc_size + 1.1127 + frame.pcFrame->vertices_count * pcHeader->framevertex_stc_size + 1.1128 + frame.pcFrame->transmatrix_count * pcHeader->bonetrans_stc_size; 1.1129 + 1.1130 + if (((const char*)szCurrent - (const char*)pcHeader) + iAdd > (unsigned int)pcHeader->data_size) { 1.1131 + DefaultLogger::get()->warn("Index overflow in frame area. " 1.1132 + "Ignoring all frames and all further mesh groups, too."); 1.1133 + 1.1134 + // don't parse more groups if we can't even read one 1.1135 + // FIXME: sometimes this seems to occur even for valid files ... 1.1136 + *szCurrentOut = szCurrent; 1.1137 + return false; 1.1138 + } 1.1139 + // our output frame? 1.1140 + if (configFrameID == iFrame) { 1.1141 + BE_NCONST MDL::Vertex_MDL7* pcFrameVertices = (BE_NCONST MDL::Vertex_MDL7*)(szCurrent+pcHeader->frame_stc_size); 1.1142 + 1.1143 + for (unsigned int qq = 0; qq < frame.pcFrame->vertices_count;++qq) { 1.1144 + // I assume this are simple replacements for normal vertices, the bone index serving 1.1145 + // as the index of the vertex to be replaced. 1.1146 + uint16_t iIndex = _AI_MDL7_ACCESS(pcFrameVertices,qq,pcHeader->framevertex_stc_size,MDL::Vertex_MDL7).vertindex; 1.1147 + AI_SWAP2(iIndex); 1.1148 + if (iIndex >= groupInfo.pcGroup->numverts) { 1.1149 + DefaultLogger::get()->warn("Invalid vertex index in frame vertex section"); 1.1150 + continue; 1.1151 + } 1.1152 + 1.1153 + aiVector3D vPosition,vNormal; 1.1154 + 1.1155 + vPosition.x = _AI_MDL7_ACCESS_VERT(pcFrameVertices,qq,pcHeader->framevertex_stc_size) .x; 1.1156 + AI_SWAP4(vPosition.x); 1.1157 + vPosition.y = _AI_MDL7_ACCESS_VERT(pcFrameVertices,qq,pcHeader->framevertex_stc_size) .y; 1.1158 + AI_SWAP4(vPosition.y); 1.1159 + vPosition.z = _AI_MDL7_ACCESS_VERT(pcFrameVertices,qq,pcHeader->framevertex_stc_size) .z; 1.1160 + AI_SWAP4(vPosition.z); 1.1161 + 1.1162 + // now read the normal vector 1.1163 + if (AI_MDL7_FRAMEVERTEX030305_STCSIZE <= pcHeader->mainvertex_stc_size) { 1.1164 + // read the full normal vector 1.1165 + vNormal.x = _AI_MDL7_ACCESS_VERT(pcFrameVertices,qq,pcHeader->framevertex_stc_size) .norm[0]; 1.1166 + AI_SWAP4(vNormal.x); 1.1167 + vNormal.y = _AI_MDL7_ACCESS_VERT(pcFrameVertices,qq,pcHeader->framevertex_stc_size) .norm[1]; 1.1168 + AI_SWAP4(vNormal.y); 1.1169 + vNormal.z = _AI_MDL7_ACCESS_VERT(pcFrameVertices,qq,pcHeader->framevertex_stc_size) .norm[2]; 1.1170 + AI_SWAP4(vNormal.z); 1.1171 + } 1.1172 + else if (AI_MDL7_FRAMEVERTEX120503_STCSIZE <= pcHeader->mainvertex_stc_size) { 1.1173 + // read the normal vector from Quake2's smart table 1.1174 + MD2::LookupNormalIndex(_AI_MDL7_ACCESS_VERT(pcFrameVertices,qq, 1.1175 + pcHeader->framevertex_stc_size) .norm162index,vNormal); 1.1176 + } 1.1177 + 1.1178 + // FIXME: O(n^2) at the moment ... 1.1179 + BE_NCONST MDL::Triangle_MDL7* pcGroupTris = groupInfo.pcGroupTris; 1.1180 + unsigned int iOutIndex = 0; 1.1181 + for (unsigned int iTriangle = 0; iTriangle < (unsigned int)groupInfo.pcGroup->numtris; ++iTriangle) { 1.1182 + // iterate through all indices of the current triangle 1.1183 + for (unsigned int c = 0; c < 3;++c,++iOutIndex) { 1.1184 + // replace the vertex with the new data 1.1185 + const unsigned int iCurIndex = pcGroupTris->v_index[c]; 1.1186 + if (iCurIndex == iIndex) { 1.1187 + groupData.vPositions[iOutIndex] = vPosition; 1.1188 + groupData.vNormals[iOutIndex] = vNormal; 1.1189 + } 1.1190 + } 1.1191 + // get the next triangle in the list 1.1192 + pcGroupTris = (BE_NCONST MDL::Triangle_MDL7*)((const char*) 1.1193 + pcGroupTris + pcHeader->triangle_stc_size); 1.1194 + } 1.1195 + } 1.1196 + } 1.1197 + // parse bone trafo matrix keys (only if there are bones ...) 1.1198 + if (shared.apcOutBones) { 1.1199 + ParseBoneTrafoKeys_3DGS_MDL7(groupInfo,frame,shared); 1.1200 + } 1.1201 + szCurrent += iAdd; 1.1202 + } 1.1203 + *szCurrentOut = szCurrent; 1.1204 + return true; 1.1205 +} 1.1206 + 1.1207 +// ------------------------------------------------------------------------------------------------ 1.1208 +// Sort faces by material, handle multiple UVs correctly 1.1209 +void MDLImporter::SortByMaterials_3DGS_MDL7( 1.1210 + const MDL::IntGroupInfo_MDL7& groupInfo, 1.1211 + MDL::IntGroupData_MDL7& groupData, 1.1212 + MDL::IntSplitGroupData_MDL7& splitGroupData) 1.1213 +{ 1.1214 + const unsigned int iNumMaterials = (unsigned int)splitGroupData.shared.pcMats.size(); 1.1215 + if (!groupData.bNeed2UV) { 1.1216 + // if we don't need a second set of texture coordinates there is no reason to keep it in memory ... 1.1217 + groupData.vTextureCoords2.clear(); 1.1218 + 1.1219 + // allocate the array 1.1220 + splitGroupData.aiSplit = new std::vector<unsigned int>*[iNumMaterials]; 1.1221 + 1.1222 + for (unsigned int m = 0; m < iNumMaterials;++m) 1.1223 + splitGroupData.aiSplit[m] = new std::vector<unsigned int>(); 1.1224 + 1.1225 + // iterate through all faces and sort by material 1.1226 + for (unsigned int iFace = 0; iFace < (unsigned int)groupInfo.pcGroup->numtris;++iFace) { 1.1227 + // check range 1.1228 + if (groupData.pcFaces[iFace].iMatIndex[0] >= iNumMaterials) { 1.1229 + // use the last material instead 1.1230 + splitGroupData.aiSplit[iNumMaterials-1]->push_back(iFace); 1.1231 + 1.1232 + // sometimes MED writes -1, but normally only if there is only 1.1233 + // one skin assigned. No warning in this case 1.1234 + if(0xFFFFFFFF != groupData.pcFaces[iFace].iMatIndex[0]) 1.1235 + DefaultLogger::get()->warn("Index overflow in MDL7 material list [#0]"); 1.1236 + } 1.1237 + else splitGroupData.aiSplit[groupData.pcFaces[iFace]. 1.1238 + iMatIndex[0]]->push_back(iFace); 1.1239 + } 1.1240 + } 1.1241 + else 1.1242 + { 1.1243 + // we need to build combined materials for each combination of 1.1244 + std::vector<MDL::IntMaterial_MDL7> avMats; 1.1245 + avMats.reserve(iNumMaterials*2); 1.1246 + 1.1247 + // fixme: why on the heap? 1.1248 + std::vector<std::vector<unsigned int>* > aiTempSplit(iNumMaterials*2); 1.1249 + for (unsigned int m = 0; m < iNumMaterials;++m) 1.1250 + aiTempSplit[m] = new std::vector<unsigned int>(); 1.1251 + 1.1252 + // iterate through all faces and sort by material 1.1253 + for (unsigned int iFace = 0; iFace < (unsigned int)groupInfo.pcGroup->numtris;++iFace) { 1.1254 + // check range 1.1255 + unsigned int iMatIndex = groupData.pcFaces[iFace].iMatIndex[0]; 1.1256 + if (iMatIndex >= iNumMaterials) { 1.1257 + // sometimes MED writes -1, but normally only if there is only 1.1258 + // one skin assigned. No warning in this case 1.1259 + if(UINT_MAX != iMatIndex) 1.1260 + DefaultLogger::get()->warn("Index overflow in MDL7 material list [#1]"); 1.1261 + iMatIndex = iNumMaterials-1; 1.1262 + } 1.1263 + unsigned int iMatIndex2 = groupData.pcFaces[iFace].iMatIndex[1]; 1.1264 + 1.1265 + unsigned int iNum = iMatIndex; 1.1266 + if (UINT_MAX != iMatIndex2 && iMatIndex != iMatIndex2) { 1.1267 + if (iMatIndex2 >= iNumMaterials) { 1.1268 + // sometimes MED writes -1, but normally only if there is only 1.1269 + // one skin assigned. No warning in this case 1.1270 + DefaultLogger::get()->warn("Index overflow in MDL7 material list [#2]"); 1.1271 + iMatIndex2 = iNumMaterials-1; 1.1272 + } 1.1273 + 1.1274 + // do a slow seach in the list ... 1.1275 + iNum = 0; 1.1276 + bool bFound = false; 1.1277 + for (std::vector<MDL::IntMaterial_MDL7>::iterator i = avMats.begin();i != avMats.end();++i,++iNum){ 1.1278 + if ((*i).iOldMatIndices[0] == iMatIndex && (*i).iOldMatIndices[1] == iMatIndex2) { 1.1279 + // reuse this material 1.1280 + bFound = true; 1.1281 + break; 1.1282 + } 1.1283 + } 1.1284 + if (!bFound) { 1.1285 + // build a new material ... 1.1286 + MDL::IntMaterial_MDL7 sHelper; 1.1287 + sHelper.pcMat = new aiMaterial(); 1.1288 + sHelper.iOldMatIndices[0] = iMatIndex; 1.1289 + sHelper.iOldMatIndices[1] = iMatIndex2; 1.1290 + JoinSkins_3DGS_MDL7(splitGroupData.shared.pcMats[iMatIndex], 1.1291 + splitGroupData.shared.pcMats[iMatIndex2],sHelper.pcMat); 1.1292 + 1.1293 + // and add it to the list 1.1294 + avMats.push_back(sHelper); 1.1295 + iNum = (unsigned int)avMats.size()-1; 1.1296 + } 1.1297 + // adjust the size of the file array 1.1298 + if (iNum == aiTempSplit.size()) { 1.1299 + aiTempSplit.push_back(new std::vector<unsigned int>()); 1.1300 + } 1.1301 + } 1.1302 + aiTempSplit[iNum]->push_back(iFace); 1.1303 + } 1.1304 + 1.1305 + // now add the newly created materials to the old list 1.1306 + if (0 == groupInfo.iIndex) { 1.1307 + splitGroupData.shared.pcMats.resize(avMats.size()); 1.1308 + for (unsigned int o = 0; o < avMats.size();++o) 1.1309 + splitGroupData.shared.pcMats[o] = avMats[o].pcMat; 1.1310 + } 1.1311 + else { 1.1312 + // This might result in redundant materials ... 1.1313 + splitGroupData.shared.pcMats.resize(iNumMaterials + avMats.size()); 1.1314 + for (unsigned int o = iNumMaterials; o < avMats.size();++o) 1.1315 + splitGroupData.shared.pcMats[o] = avMats[o].pcMat; 1.1316 + } 1.1317 + 1.1318 + // and build the final face-to-material array 1.1319 + splitGroupData.aiSplit = new std::vector<unsigned int>*[aiTempSplit.size()]; 1.1320 + for (unsigned int m = 0; m < iNumMaterials;++m) 1.1321 + splitGroupData.aiSplit[m] = aiTempSplit[m]; 1.1322 + } 1.1323 +} 1.1324 + 1.1325 +// ------------------------------------------------------------------------------------------------ 1.1326 +// Read a MDL7 file 1.1327 +void MDLImporter::InternReadFile_3DGS_MDL7( ) 1.1328 +{ 1.1329 + ai_assert(NULL != pScene); 1.1330 + 1.1331 + MDL::IntSharedData_MDL7 sharedData; 1.1332 + 1.1333 + // current cursor position in the file 1.1334 + BE_NCONST MDL::Header_MDL7 *pcHeader = (BE_NCONST MDL::Header_MDL7*)this->mBuffer; 1.1335 + const unsigned char* szCurrent = (const unsigned char*)(pcHeader+1); 1.1336 + 1.1337 + AI_SWAP4(pcHeader->version); 1.1338 + AI_SWAP4(pcHeader->bones_num); 1.1339 + AI_SWAP4(pcHeader->groups_num); 1.1340 + AI_SWAP4(pcHeader->data_size); 1.1341 + AI_SWAP4(pcHeader->entlump_size); 1.1342 + AI_SWAP4(pcHeader->medlump_size); 1.1343 + AI_SWAP2(pcHeader->bone_stc_size); 1.1344 + AI_SWAP2(pcHeader->skin_stc_size); 1.1345 + AI_SWAP2(pcHeader->colorvalue_stc_size); 1.1346 + AI_SWAP2(pcHeader->material_stc_size); 1.1347 + AI_SWAP2(pcHeader->skinpoint_stc_size); 1.1348 + AI_SWAP2(pcHeader->triangle_stc_size); 1.1349 + AI_SWAP2(pcHeader->mainvertex_stc_size); 1.1350 + AI_SWAP2(pcHeader->framevertex_stc_size); 1.1351 + AI_SWAP2(pcHeader->bonetrans_stc_size); 1.1352 + AI_SWAP2(pcHeader->frame_stc_size); 1.1353 + 1.1354 + // validate the header of the file. There are some structure 1.1355 + // sizes that are expected by the loader to be constant 1.1356 + this->ValidateHeader_3DGS_MDL7(pcHeader); 1.1357 + 1.1358 + // load all bones (they are shared by all groups, so 1.1359 + // we'll need to add them to all groups/meshes later) 1.1360 + // apcBonesOut is a list of all bones or NULL if they could not been loaded 1.1361 + szCurrent += pcHeader->bones_num * pcHeader->bone_stc_size; 1.1362 + sharedData.apcOutBones = this->LoadBones_3DGS_MDL7(); 1.1363 + 1.1364 + // vector to held all created meshes 1.1365 + std::vector<aiMesh*>* avOutList; 1.1366 + 1.1367 + // 3 meshes per group - that should be OK for most models 1.1368 + avOutList = new std::vector<aiMesh*>[pcHeader->groups_num]; 1.1369 + for (uint32_t i = 0; i < pcHeader->groups_num;++i) 1.1370 + avOutList[i].reserve(3); 1.1371 + 1.1372 + // buffer to held the names of all groups in the file 1.1373 + char* aszGroupNameBuffer = new char[AI_MDL7_MAX_GROUPNAMESIZE*pcHeader->groups_num]; 1.1374 + 1.1375 + // read all groups 1.1376 + for (unsigned int iGroup = 0; iGroup < (unsigned int)pcHeader->groups_num;++iGroup) { 1.1377 + MDL::IntGroupInfo_MDL7 groupInfo((BE_NCONST MDL::Group_MDL7*)szCurrent,iGroup); 1.1378 + szCurrent = (const unsigned char*)(groupInfo.pcGroup+1); 1.1379 + 1.1380 + VALIDATE_FILE_SIZE(szCurrent); 1.1381 + 1.1382 + AI_SWAP4(groupInfo.pcGroup->groupdata_size); 1.1383 + AI_SWAP4(groupInfo.pcGroup->numskins); 1.1384 + AI_SWAP4(groupInfo.pcGroup->num_stpts); 1.1385 + AI_SWAP4(groupInfo.pcGroup->numtris); 1.1386 + AI_SWAP4(groupInfo.pcGroup->numverts); 1.1387 + AI_SWAP4(groupInfo.pcGroup->numframes); 1.1388 + 1.1389 + if (1 != groupInfo.pcGroup->typ) { 1.1390 + // Not a triangle-based mesh 1.1391 + DefaultLogger::get()->warn("[3DGS MDL7] Not a triangle mesh group. Continuing happily"); 1.1392 + } 1.1393 + 1.1394 + // store the name of the group 1.1395 + const unsigned int ofs = iGroup*AI_MDL7_MAX_GROUPNAMESIZE; 1.1396 + ::memcpy(&aszGroupNameBuffer[ofs], 1.1397 + groupInfo.pcGroup->name,AI_MDL7_MAX_GROUPNAMESIZE); 1.1398 + 1.1399 + // make sure '\0' is at the end 1.1400 + aszGroupNameBuffer[ofs+AI_MDL7_MAX_GROUPNAMESIZE-1] = '\0'; 1.1401 + 1.1402 + // read all skins 1.1403 + sharedData.pcMats.reserve(sharedData.pcMats.size() + groupInfo.pcGroup->numskins); 1.1404 + sharedData.abNeedMaterials.resize(sharedData.abNeedMaterials.size() + 1.1405 + groupInfo.pcGroup->numskins,false); 1.1406 + 1.1407 + for (unsigned int iSkin = 0; iSkin < (unsigned int)groupInfo.pcGroup->numskins;++iSkin) { 1.1408 + ParseSkinLump_3DGS_MDL7(szCurrent,&szCurrent,sharedData.pcMats); 1.1409 + } 1.1410 + // if we have absolutely no skin loaded we need to generate a default material 1.1411 + if (sharedData.pcMats.empty()) { 1.1412 + const int iMode = (int)aiShadingMode_Gouraud; 1.1413 + sharedData.pcMats.push_back(new aiMaterial()); 1.1414 + aiMaterial* pcHelper = (aiMaterial*)sharedData.pcMats[0]; 1.1415 + pcHelper->AddProperty<int>(&iMode, 1, AI_MATKEY_SHADING_MODEL); 1.1416 + 1.1417 + aiColor3D clr; 1.1418 + clr.b = clr.g = clr.r = 0.6f; 1.1419 + pcHelper->AddProperty<aiColor3D>(&clr, 1,AI_MATKEY_COLOR_DIFFUSE); 1.1420 + pcHelper->AddProperty<aiColor3D>(&clr, 1,AI_MATKEY_COLOR_SPECULAR); 1.1421 + 1.1422 + clr.b = clr.g = clr.r = 0.05f; 1.1423 + pcHelper->AddProperty<aiColor3D>(&clr, 1,AI_MATKEY_COLOR_AMBIENT); 1.1424 + 1.1425 + aiString szName; 1.1426 + szName.Set(AI_DEFAULT_MATERIAL_NAME); 1.1427 + pcHelper->AddProperty(&szName,AI_MATKEY_NAME); 1.1428 + 1.1429 + sharedData.abNeedMaterials.resize(1,false); 1.1430 + } 1.1431 + 1.1432 + // now get a pointer to all texture coords in the group 1.1433 + groupInfo.pcGroupUVs = (BE_NCONST MDL::TexCoord_MDL7*)szCurrent; 1.1434 + for(int i = 0; i < groupInfo.pcGroup->num_stpts; ++i){ 1.1435 + AI_SWAP4(groupInfo.pcGroupUVs[i].u); 1.1436 + AI_SWAP4(groupInfo.pcGroupUVs[i].v); 1.1437 + } 1.1438 + szCurrent += pcHeader->skinpoint_stc_size * groupInfo.pcGroup->num_stpts; 1.1439 + 1.1440 + // now get a pointer to all triangle in the group 1.1441 + groupInfo.pcGroupTris = (Triangle_MDL7*)szCurrent; 1.1442 + szCurrent += pcHeader->triangle_stc_size * groupInfo.pcGroup->numtris; 1.1443 + 1.1444 + // now get a pointer to all vertices in the group 1.1445 + groupInfo.pcGroupVerts = (BE_NCONST MDL::Vertex_MDL7*)szCurrent; 1.1446 + for(int i = 0; i < groupInfo.pcGroup->numverts; ++i){ 1.1447 + AI_SWAP4(groupInfo.pcGroupVerts[i].x); 1.1448 + AI_SWAP4(groupInfo.pcGroupVerts[i].y); 1.1449 + AI_SWAP4(groupInfo.pcGroupVerts[i].z); 1.1450 + 1.1451 + AI_SWAP2(groupInfo.pcGroupVerts[i].vertindex); 1.1452 + //We can not swap the normal information now as we don't know which of the two kinds it is 1.1453 + } 1.1454 + szCurrent += pcHeader->mainvertex_stc_size * groupInfo.pcGroup->numverts; 1.1455 + VALIDATE_FILE_SIZE(szCurrent); 1.1456 + 1.1457 + MDL::IntSplitGroupData_MDL7 splitGroupData(sharedData,avOutList[iGroup]); 1.1458 + MDL::IntGroupData_MDL7 groupData; 1.1459 + if (groupInfo.pcGroup->numtris && groupInfo.pcGroup->numverts) 1.1460 + { 1.1461 + // build output vectors 1.1462 + const unsigned int iNumVertices = groupInfo.pcGroup->numtris*3; 1.1463 + groupData.vPositions.resize(iNumVertices); 1.1464 + groupData.vNormals.resize(iNumVertices); 1.1465 + 1.1466 + if (sharedData.apcOutBones)groupData.aiBones.resize(iNumVertices,UINT_MAX); 1.1467 + 1.1468 + // it is also possible that there are 0 UV coordinate sets 1.1469 + if (groupInfo.pcGroup->num_stpts){ 1.1470 + groupData.vTextureCoords1.resize(iNumVertices,aiVector3D()); 1.1471 + 1.1472 + // check whether the triangle data structure is large enough 1.1473 + // to contain a second UV coodinate set 1.1474 + if (pcHeader->triangle_stc_size >= AI_MDL7_TRIANGLE_STD_SIZE_TWO_UV) { 1.1475 + groupData.vTextureCoords2.resize(iNumVertices,aiVector3D()); 1.1476 + groupData.bNeed2UV = true; 1.1477 + } 1.1478 + } 1.1479 + groupData.pcFaces = new MDL::IntFace_MDL7[groupInfo.pcGroup->numtris]; 1.1480 + 1.1481 + // read all faces into the preallocated arrays 1.1482 + ReadFaces_3DGS_MDL7(groupInfo, groupData); 1.1483 + 1.1484 + // sort by materials 1.1485 + SortByMaterials_3DGS_MDL7(groupInfo, groupData, 1.1486 + splitGroupData); 1.1487 + 1.1488 + for (unsigned int qq = 0; qq < sharedData.pcMats.size();++qq) { 1.1489 + if (!splitGroupData.aiSplit[qq]->empty()) 1.1490 + sharedData.abNeedMaterials[qq] = true; 1.1491 + } 1.1492 + } 1.1493 + else DefaultLogger::get()->warn("[3DGS MDL7] Mesh group consists of 0 " 1.1494 + "vertices or faces. It will be skipped."); 1.1495 + 1.1496 + // process all frames and generate output meshes 1.1497 + ProcessFrames_3DGS_MDL7(groupInfo,groupData, sharedData,szCurrent,&szCurrent); 1.1498 + GenerateOutputMeshes_3DGS_MDL7(groupData,splitGroupData); 1.1499 + } 1.1500 + 1.1501 + // generate a nodegraph and subnodes for each group 1.1502 + pScene->mRootNode = new aiNode(); 1.1503 + 1.1504 + // now we need to build a final mesh list 1.1505 + for (uint32_t i = 0; i < pcHeader->groups_num;++i) 1.1506 + pScene->mNumMeshes += (unsigned int)avOutList[i].size(); 1.1507 + 1.1508 + pScene->mMeshes = new aiMesh*[pScene->mNumMeshes]; { 1.1509 + unsigned int p = 0,q = 0; 1.1510 + for (uint32_t i = 0; i < pcHeader->groups_num;++i) { 1.1511 + for (unsigned int a = 0; a < avOutList[i].size();++a) { 1.1512 + pScene->mMeshes[p++] = avOutList[i][a]; 1.1513 + } 1.1514 + if (!avOutList[i].empty())++pScene->mRootNode->mNumChildren; 1.1515 + } 1.1516 + // we will later need an extra node to serve as parent for all bones 1.1517 + if (sharedData.apcOutBones)++pScene->mRootNode->mNumChildren; 1.1518 + this->pScene->mRootNode->mChildren = new aiNode*[pScene->mRootNode->mNumChildren]; 1.1519 + p = 0; 1.1520 + for (uint32_t i = 0; i < pcHeader->groups_num;++i) { 1.1521 + if (avOutList[i].empty())continue; 1.1522 + 1.1523 + aiNode* const pcNode = pScene->mRootNode->mChildren[p] = new aiNode(); 1.1524 + pcNode->mNumMeshes = (unsigned int)avOutList[i].size(); 1.1525 + pcNode->mMeshes = new unsigned int[pcNode->mNumMeshes]; 1.1526 + pcNode->mParent = this->pScene->mRootNode; 1.1527 + for (unsigned int a = 0; a < pcNode->mNumMeshes;++a) 1.1528 + pcNode->mMeshes[a] = q + a; 1.1529 + q += (unsigned int)avOutList[i].size(); 1.1530 + 1.1531 + // setup the name of the node 1.1532 + char* const szBuffer = &aszGroupNameBuffer[i*AI_MDL7_MAX_GROUPNAMESIZE]; 1.1533 + if ('\0' == *szBuffer) 1.1534 + pcNode->mName.length = ::sprintf(szBuffer,"Group_%i",p); 1.1535 + else pcNode->mName.length = ::strlen(szBuffer); 1.1536 + ::strcpy(pcNode->mName.data,szBuffer); 1.1537 + ++p; 1.1538 + } 1.1539 + } 1.1540 + 1.1541 + // if there is only one root node with a single child we can optimize it a bit ... 1.1542 + if (1 == pScene->mRootNode->mNumChildren && !sharedData.apcOutBones) { 1.1543 + aiNode* pcOldRoot = this->pScene->mRootNode; 1.1544 + pScene->mRootNode = pcOldRoot->mChildren[0]; 1.1545 + pcOldRoot->mChildren[0] = NULL; 1.1546 + delete pcOldRoot; 1.1547 + pScene->mRootNode->mParent = NULL; 1.1548 + } 1.1549 + else pScene->mRootNode->mName.Set("<mesh_root>"); 1.1550 + 1.1551 + delete[] avOutList; 1.1552 + delete[] aszGroupNameBuffer; 1.1553 + AI_DEBUG_INVALIDATE_PTR(avOutList); 1.1554 + AI_DEBUG_INVALIDATE_PTR(aszGroupNameBuffer); 1.1555 + 1.1556 + // build a final material list. 1.1557 + CopyMaterials_3DGS_MDL7(sharedData); 1.1558 + HandleMaterialReferences_3DGS_MDL7(); 1.1559 + 1.1560 + // generate output bone animations and add all bones to the scenegraph 1.1561 + if (sharedData.apcOutBones) { 1.1562 + // this step adds empty dummy bones to the nodegraph 1.1563 + // insert another dummy node to avoid name conflicts 1.1564 + aiNode* const pc = pScene->mRootNode->mChildren[pScene->mRootNode->mNumChildren-1] = new aiNode(); 1.1565 + 1.1566 + pc->mName.Set("<skeleton_root>"); 1.1567 + 1.1568 + // add bones to the nodegraph 1.1569 + AddBonesToNodeGraph_3DGS_MDL7((const Assimp::MDL::IntBone_MDL7 **) 1.1570 + sharedData.apcOutBones,pc,0xffff); 1.1571 + 1.1572 + // this steps build a valid output animation 1.1573 + BuildOutputAnims_3DGS_MDL7((const Assimp::MDL::IntBone_MDL7 **) 1.1574 + sharedData.apcOutBones); 1.1575 + } 1.1576 +} 1.1577 + 1.1578 +// ------------------------------------------------------------------------------------------------ 1.1579 +// Copy materials 1.1580 +void MDLImporter::CopyMaterials_3DGS_MDL7(MDL::IntSharedData_MDL7 &shared) 1.1581 +{ 1.1582 + pScene->mNumMaterials = (unsigned int)shared.pcMats.size(); 1.1583 + pScene->mMaterials = new aiMaterial*[pScene->mNumMaterials]; 1.1584 + for (unsigned int i = 0; i < pScene->mNumMaterials;++i) 1.1585 + pScene->mMaterials[i] = shared.pcMats[i]; 1.1586 +} 1.1587 + 1.1588 + 1.1589 +// ------------------------------------------------------------------------------------------------ 1.1590 +// Process material references 1.1591 +void MDLImporter::HandleMaterialReferences_3DGS_MDL7() 1.1592 +{ 1.1593 + // search for referrer materials 1.1594 + for (unsigned int i = 0; i < pScene->mNumMaterials;++i) { 1.1595 + int iIndex = 0; 1.1596 + if (AI_SUCCESS == aiGetMaterialInteger(pScene->mMaterials[i],AI_MDL7_REFERRER_MATERIAL, &iIndex) ) { 1.1597 + for (unsigned int a = 0; a < pScene->mNumMeshes;++a) { 1.1598 + aiMesh* const pcMesh = pScene->mMeshes[a]; 1.1599 + if (i == pcMesh->mMaterialIndex) { 1.1600 + pcMesh->mMaterialIndex = iIndex; 1.1601 + } 1.1602 + } 1.1603 + // collapse the rest of the array 1.1604 + delete pScene->mMaterials[i]; 1.1605 + for (unsigned int pp = i; pp < pScene->mNumMaterials-1;++pp) { 1.1606 + 1.1607 + pScene->mMaterials[pp] = pScene->mMaterials[pp+1]; 1.1608 + for (unsigned int a = 0; a < pScene->mNumMeshes;++a) { 1.1609 + aiMesh* const pcMesh = pScene->mMeshes[a]; 1.1610 + if (pcMesh->mMaterialIndex > i)--pcMesh->mMaterialIndex; 1.1611 + } 1.1612 + } 1.1613 + --pScene->mNumMaterials; 1.1614 + } 1.1615 + } 1.1616 +} 1.1617 + 1.1618 +// ------------------------------------------------------------------------------------------------ 1.1619 +// Read bone transformation keys 1.1620 +void MDLImporter::ParseBoneTrafoKeys_3DGS_MDL7( 1.1621 + const MDL::IntGroupInfo_MDL7& groupInfo, 1.1622 + IntFrameInfo_MDL7& frame, 1.1623 + MDL::IntSharedData_MDL7& shared) 1.1624 +{ 1.1625 + const MDL::Header_MDL7* const pcHeader = (const MDL::Header_MDL7*)this->mBuffer; 1.1626 + 1.1627 + // only the first group contains bone animation keys 1.1628 + if (frame.pcFrame->transmatrix_count) { 1.1629 + if (!groupInfo.iIndex) { 1.1630 + // skip all frames vertices. We can't support them 1.1631 + const MDL::BoneTransform_MDL7* pcBoneTransforms = (const MDL::BoneTransform_MDL7*) 1.1632 + (((const char*)frame.pcFrame) + pcHeader->frame_stc_size + 1.1633 + frame.pcFrame->vertices_count * pcHeader->framevertex_stc_size); 1.1634 + 1.1635 + // read all transformation matrices 1.1636 + for (unsigned int iTrafo = 0; iTrafo < frame.pcFrame->transmatrix_count;++iTrafo) { 1.1637 + if(pcBoneTransforms->bone_index >= pcHeader->bones_num) { 1.1638 + DefaultLogger::get()->warn("Index overflow in frame area. " 1.1639 + "Unable to parse this bone transformation"); 1.1640 + } 1.1641 + else { 1.1642 + AddAnimationBoneTrafoKey_3DGS_MDL7(frame.iIndex, 1.1643 + pcBoneTransforms,shared.apcOutBones); 1.1644 + } 1.1645 + pcBoneTransforms = (const MDL::BoneTransform_MDL7*)( 1.1646 + (const char*)pcBoneTransforms + pcHeader->bonetrans_stc_size); 1.1647 + } 1.1648 + } 1.1649 + else { 1.1650 + DefaultLogger::get()->warn("Ignoring animation keyframes in groups != 0"); 1.1651 + } 1.1652 + } 1.1653 +} 1.1654 + 1.1655 +// ------------------------------------------------------------------------------------------------ 1.1656 +// Attach bones to the output nodegraph 1.1657 +void MDLImporter::AddBonesToNodeGraph_3DGS_MDL7(const MDL::IntBone_MDL7** apcBones, 1.1658 + aiNode* pcParent,uint16_t iParentIndex) 1.1659 +{ 1.1660 + ai_assert(NULL != apcBones && NULL != pcParent); 1.1661 + 1.1662 + // get a pointer to the header ... 1.1663 + const MDL::Header_MDL7* const pcHeader = (const MDL::Header_MDL7*)this->mBuffer; 1.1664 + 1.1665 + const MDL::IntBone_MDL7** apcBones2 = apcBones; 1.1666 + for (uint32_t i = 0; i < pcHeader->bones_num;++i) { 1.1667 + 1.1668 + const MDL::IntBone_MDL7* const pcBone = *apcBones2++; 1.1669 + if (pcBone->iParent == iParentIndex) { 1.1670 + ++pcParent->mNumChildren; 1.1671 + } 1.1672 + } 1.1673 + pcParent->mChildren = new aiNode*[pcParent->mNumChildren]; 1.1674 + unsigned int qq = 0; 1.1675 + for (uint32_t i = 0; i < pcHeader->bones_num;++i) { 1.1676 + 1.1677 + const MDL::IntBone_MDL7* const pcBone = *apcBones++; 1.1678 + if (pcBone->iParent != iParentIndex)continue; 1.1679 + 1.1680 + aiNode* pcNode = pcParent->mChildren[qq++] = new aiNode(); 1.1681 + pcNode->mName = aiString( pcBone->mName ); 1.1682 + 1.1683 + AddBonesToNodeGraph_3DGS_MDL7(apcBones,pcNode,(uint16_t)i); 1.1684 + } 1.1685 +} 1.1686 + 1.1687 +// ------------------------------------------------------------------------------------------------ 1.1688 +// Build output animations 1.1689 +void MDLImporter::BuildOutputAnims_3DGS_MDL7( 1.1690 + const MDL::IntBone_MDL7** apcBonesOut) 1.1691 +{ 1.1692 + ai_assert(NULL != apcBonesOut); 1.1693 + const MDL::Header_MDL7* const pcHeader = (const MDL::Header_MDL7*)mBuffer; 1.1694 + 1.1695 + // one animation ... 1.1696 + aiAnimation* pcAnim = new aiAnimation(); 1.1697 + for (uint32_t i = 0; i < pcHeader->bones_num;++i) { 1.1698 + if (!apcBonesOut[i]->pkeyPositions.empty()) { 1.1699 + 1.1700 + // get the last frame ... (needn't be equal to pcHeader->frames_num) 1.1701 + for (size_t qq = 0; qq < apcBonesOut[i]->pkeyPositions.size();++qq) { 1.1702 + pcAnim->mDuration = std::max(pcAnim->mDuration, (double) 1.1703 + apcBonesOut[i]->pkeyPositions[qq].mTime); 1.1704 + } 1.1705 + ++pcAnim->mNumChannels; 1.1706 + } 1.1707 + } 1.1708 + if (pcAnim->mDuration) { 1.1709 + pcAnim->mChannels = new aiNodeAnim*[pcAnim->mNumChannels]; 1.1710 + 1.1711 + unsigned int iCnt = 0; 1.1712 + for (uint32_t i = 0; i < pcHeader->bones_num;++i) { 1.1713 + if (!apcBonesOut[i]->pkeyPositions.empty()) { 1.1714 + const MDL::IntBone_MDL7* const intBone = apcBonesOut[i]; 1.1715 + 1.1716 + aiNodeAnim* const pcNodeAnim = pcAnim->mChannels[iCnt++] = new aiNodeAnim(); 1.1717 + pcNodeAnim->mNodeName = aiString( intBone->mName ); 1.1718 + 1.1719 + // allocate enough storage for all keys 1.1720 + pcNodeAnim->mNumPositionKeys = (unsigned int)intBone->pkeyPositions.size(); 1.1721 + pcNodeAnim->mNumScalingKeys = (unsigned int)intBone->pkeyPositions.size(); 1.1722 + pcNodeAnim->mNumRotationKeys = (unsigned int)intBone->pkeyPositions.size(); 1.1723 + 1.1724 + pcNodeAnim->mPositionKeys = new aiVectorKey[pcNodeAnim->mNumPositionKeys]; 1.1725 + pcNodeAnim->mScalingKeys = new aiVectorKey[pcNodeAnim->mNumPositionKeys]; 1.1726 + pcNodeAnim->mRotationKeys = new aiQuatKey[pcNodeAnim->mNumPositionKeys]; 1.1727 + 1.1728 + // copy all keys 1.1729 + for (unsigned int qq = 0; qq < pcNodeAnim->mNumPositionKeys;++qq) { 1.1730 + pcNodeAnim->mPositionKeys[qq] = intBone->pkeyPositions[qq]; 1.1731 + pcNodeAnim->mScalingKeys[qq] = intBone->pkeyScalings[qq]; 1.1732 + pcNodeAnim->mRotationKeys[qq] = intBone->pkeyRotations[qq]; 1.1733 + } 1.1734 + } 1.1735 + } 1.1736 + 1.1737 + // store the output animation 1.1738 + pScene->mNumAnimations = 1; 1.1739 + pScene->mAnimations = new aiAnimation*[1]; 1.1740 + pScene->mAnimations[0] = pcAnim; 1.1741 + } 1.1742 + else delete pcAnim; 1.1743 +} 1.1744 + 1.1745 +// ------------------------------------------------------------------------------------------------ 1.1746 +void MDLImporter::AddAnimationBoneTrafoKey_3DGS_MDL7(unsigned int iTrafo, 1.1747 + const MDL::BoneTransform_MDL7* pcBoneTransforms, 1.1748 + MDL::IntBone_MDL7** apcBonesOut) 1.1749 +{ 1.1750 + ai_assert(NULL != pcBoneTransforms); 1.1751 + ai_assert(NULL != apcBonesOut); 1.1752 + 1.1753 + // first .. get the transformation matrix 1.1754 + aiMatrix4x4 mTransform; 1.1755 + mTransform.a1 = pcBoneTransforms->m[0]; 1.1756 + mTransform.b1 = pcBoneTransforms->m[1]; 1.1757 + mTransform.c1 = pcBoneTransforms->m[2]; 1.1758 + mTransform.d1 = pcBoneTransforms->m[3]; 1.1759 + 1.1760 + mTransform.a2 = pcBoneTransforms->m[4]; 1.1761 + mTransform.b2 = pcBoneTransforms->m[5]; 1.1762 + mTransform.c2 = pcBoneTransforms->m[6]; 1.1763 + mTransform.d2 = pcBoneTransforms->m[7]; 1.1764 + 1.1765 + mTransform.a3 = pcBoneTransforms->m[8]; 1.1766 + mTransform.b3 = pcBoneTransforms->m[9]; 1.1767 + mTransform.c3 = pcBoneTransforms->m[10]; 1.1768 + mTransform.d3 = pcBoneTransforms->m[11]; 1.1769 + 1.1770 + // now decompose the transformation matrix into separate 1.1771 + // scaling, rotation and translation 1.1772 + aiVectorKey vScaling,vPosition; 1.1773 + aiQuatKey qRotation; 1.1774 + 1.1775 + // FIXME: Decompose will assert in debug builds if the matrix is invalid ... 1.1776 + mTransform.Decompose(vScaling.mValue,qRotation.mValue,vPosition.mValue); 1.1777 + 1.1778 + // now generate keys 1.1779 + vScaling.mTime = qRotation.mTime = vPosition.mTime = (double)iTrafo; 1.1780 + 1.1781 + // add the keys to the bone 1.1782 + MDL::IntBone_MDL7* const pcBoneOut = apcBonesOut[pcBoneTransforms->bone_index]; 1.1783 + pcBoneOut->pkeyPositions.push_back ( vPosition ); 1.1784 + pcBoneOut->pkeyScalings.push_back ( vScaling ); 1.1785 + pcBoneOut->pkeyRotations.push_back ( qRotation ); 1.1786 +} 1.1787 + 1.1788 +// ------------------------------------------------------------------------------------------------ 1.1789 +// Construct output meshes 1.1790 +void MDLImporter::GenerateOutputMeshes_3DGS_MDL7( 1.1791 + MDL::IntGroupData_MDL7& groupData, 1.1792 + MDL::IntSplitGroupData_MDL7& splitGroupData) 1.1793 +{ 1.1794 + const MDL::IntSharedData_MDL7& shared = splitGroupData.shared; 1.1795 + 1.1796 + // get a pointer to the header ... 1.1797 + const MDL::Header_MDL7* const pcHeader = (const MDL::Header_MDL7*)this->mBuffer; 1.1798 + const unsigned int iNumOutBones = pcHeader->bones_num; 1.1799 + 1.1800 + for (std::vector<aiMaterial*>::size_type i = 0; i < shared.pcMats.size();++i) { 1.1801 + if (!splitGroupData.aiSplit[i]->empty()) { 1.1802 + 1.1803 + // allocate the output mesh 1.1804 + aiMesh* pcMesh = new aiMesh(); 1.1805 + 1.1806 + pcMesh->mPrimitiveTypes = aiPrimitiveType_TRIANGLE; 1.1807 + pcMesh->mMaterialIndex = (unsigned int)i; 1.1808 + 1.1809 + // allocate output storage 1.1810 + pcMesh->mNumFaces = (unsigned int)splitGroupData.aiSplit[i]->size(); 1.1811 + pcMesh->mFaces = new aiFace[pcMesh->mNumFaces]; 1.1812 + 1.1813 + pcMesh->mNumVertices = pcMesh->mNumFaces*3; 1.1814 + pcMesh->mVertices = new aiVector3D[pcMesh->mNumVertices]; 1.1815 + pcMesh->mNormals = new aiVector3D[pcMesh->mNumVertices]; 1.1816 + 1.1817 + if (!groupData.vTextureCoords1.empty()) { 1.1818 + pcMesh->mNumUVComponents[0] = 2; 1.1819 + pcMesh->mTextureCoords[0] = new aiVector3D[pcMesh->mNumVertices]; 1.1820 + if (!groupData.vTextureCoords2.empty()) { 1.1821 + pcMesh->mNumUVComponents[1] = 2; 1.1822 + pcMesh->mTextureCoords[1] = new aiVector3D[pcMesh->mNumVertices]; 1.1823 + } 1.1824 + } 1.1825 + 1.1826 + // iterate through all faces and build an unique set of vertices 1.1827 + unsigned int iCurrent = 0; 1.1828 + for (unsigned int iFace = 0; iFace < pcMesh->mNumFaces;++iFace) { 1.1829 + pcMesh->mFaces[iFace].mNumIndices = 3; 1.1830 + pcMesh->mFaces[iFace].mIndices = new unsigned int[3]; 1.1831 + 1.1832 + unsigned int iSrcFace = splitGroupData.aiSplit[i]->operator[](iFace); 1.1833 + const MDL::IntFace_MDL7& oldFace = groupData.pcFaces[iSrcFace]; 1.1834 + 1.1835 + // iterate through all face indices 1.1836 + for (unsigned int c = 0; c < 3;++c) { 1.1837 + const uint32_t iIndex = oldFace.mIndices[c]; 1.1838 + pcMesh->mVertices[iCurrent] = groupData.vPositions[iIndex]; 1.1839 + pcMesh->mNormals[iCurrent] = groupData.vNormals[iIndex]; 1.1840 + 1.1841 + if (!groupData.vTextureCoords1.empty()) { 1.1842 + 1.1843 + pcMesh->mTextureCoords[0][iCurrent] = groupData.vTextureCoords1[iIndex]; 1.1844 + if (!groupData.vTextureCoords2.empty()) { 1.1845 + pcMesh->mTextureCoords[1][iCurrent] = groupData.vTextureCoords2[iIndex]; 1.1846 + } 1.1847 + } 1.1848 + pcMesh->mFaces[iFace].mIndices[c] = iCurrent++; 1.1849 + } 1.1850 + } 1.1851 + 1.1852 + // if we have bones in the mesh we'll need to generate 1.1853 + // proper vertex weights for them 1.1854 + if (!groupData.aiBones.empty()) { 1.1855 + std::vector<std::vector<unsigned int> > aaiVWeightList; 1.1856 + aaiVWeightList.resize(iNumOutBones); 1.1857 + 1.1858 + int iCurrent = 0; 1.1859 + for (unsigned int iFace = 0; iFace < pcMesh->mNumFaces;++iFace) { 1.1860 + unsigned int iSrcFace = splitGroupData.aiSplit[i]->operator[](iFace); 1.1861 + const MDL::IntFace_MDL7& oldFace = groupData.pcFaces[iSrcFace]; 1.1862 + 1.1863 + // iterate through all face indices 1.1864 + for (unsigned int c = 0; c < 3;++c) { 1.1865 + unsigned int iBone = groupData.aiBones[ oldFace.mIndices[c] ]; 1.1866 + if (UINT_MAX != iBone) { 1.1867 + if (iBone >= iNumOutBones) { 1.1868 + DefaultLogger::get()->error("Bone index overflow. " 1.1869 + "The bone index of a vertex exceeds the allowed range. "); 1.1870 + iBone = iNumOutBones-1; 1.1871 + } 1.1872 + aaiVWeightList[ iBone ].push_back ( iCurrent ); 1.1873 + } 1.1874 + ++iCurrent; 1.1875 + } 1.1876 + } 1.1877 + // now check which bones are required ... 1.1878 + for (std::vector<std::vector<unsigned int> >::const_iterator k = aaiVWeightList.begin();k != aaiVWeightList.end();++k) { 1.1879 + if (!(*k).empty()) { 1.1880 + ++pcMesh->mNumBones; 1.1881 + } 1.1882 + } 1.1883 + pcMesh->mBones = new aiBone*[pcMesh->mNumBones]; 1.1884 + iCurrent = 0; 1.1885 + for (std::vector<std::vector<unsigned int> >::const_iterator k = aaiVWeightList.begin();k!= aaiVWeightList.end();++k,++iCurrent) 1.1886 + { 1.1887 + if ((*k).empty()) 1.1888 + continue; 1.1889 + 1.1890 + // seems we'll need this node 1.1891 + aiBone* pcBone = pcMesh->mBones[ iCurrent ] = new aiBone(); 1.1892 + pcBone->mName = aiString(shared.apcOutBones[ iCurrent ]->mName); 1.1893 + pcBone->mOffsetMatrix = shared.apcOutBones[ iCurrent ]->mOffsetMatrix; 1.1894 + 1.1895 + // setup vertex weights 1.1896 + pcBone->mNumWeights = (unsigned int)(*k).size(); 1.1897 + pcBone->mWeights = new aiVertexWeight[pcBone->mNumWeights]; 1.1898 + 1.1899 + for (unsigned int weight = 0; weight < pcBone->mNumWeights;++weight) { 1.1900 + pcBone->mWeights[weight].mVertexId = (*k)[weight]; 1.1901 + pcBone->mWeights[weight].mWeight = 1.0f; 1.1902 + } 1.1903 + } 1.1904 + } 1.1905 + // add the mesh to the list of output meshes 1.1906 + splitGroupData.avOutList.push_back(pcMesh); 1.1907 + } 1.1908 + } 1.1909 +} 1.1910 + 1.1911 +// ------------------------------------------------------------------------------------------------ 1.1912 +// Join to materials 1.1913 +void MDLImporter::JoinSkins_3DGS_MDL7( 1.1914 + aiMaterial* pcMat1, 1.1915 + aiMaterial* pcMat2, 1.1916 + aiMaterial* pcMatOut) 1.1917 +{ 1.1918 + ai_assert(NULL != pcMat1 && NULL != pcMat2 && NULL != pcMatOut); 1.1919 + 1.1920 + // first create a full copy of the first skin property set 1.1921 + // and assign it to the output material 1.1922 + aiMaterial::CopyPropertyList(pcMatOut,pcMat1); 1.1923 + 1.1924 + int iVal = 0; 1.1925 + pcMatOut->AddProperty<int>(&iVal,1,AI_MATKEY_UVWSRC_DIFFUSE(0)); 1.1926 + 1.1927 + // then extract the diffuse texture from the second skin, 1.1928 + // setup 1 as UV source and we have it 1.1929 + aiString sString; 1.1930 + if(AI_SUCCESS == aiGetMaterialString ( pcMat2, AI_MATKEY_TEXTURE_DIFFUSE(0),&sString )) { 1.1931 + iVal = 1; 1.1932 + pcMatOut->AddProperty<int>(&iVal,1,AI_MATKEY_UVWSRC_DIFFUSE(1)); 1.1933 + pcMatOut->AddProperty(&sString,AI_MATKEY_TEXTURE_DIFFUSE(1)); 1.1934 + } 1.1935 +} 1.1936 + 1.1937 +// ------------------------------------------------------------------------------------------------ 1.1938 +// Read a half-life 2 MDL 1.1939 +void MDLImporter::InternReadFile_HL2( ) 1.1940 +{ 1.1941 + //const MDL::Header_HL2* pcHeader = (const MDL::Header_HL2*)this->mBuffer; 1.1942 + throw DeadlyImportError("HL2 MDLs are not implemented"); 1.1943 +} 1.1944 + 1.1945 +#endif // !! ASSIMP_BUILD_NO_MDL_IMPORTER