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