vrshoot

diff libs/assimp/XFileParser.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/XFileParser.cpp	Sat Feb 01 19:58:19 2014 +0200
     1.3 @@ -0,0 +1,1468 @@
     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 Implementation of the XFile parser helper class */
    1.46 +
    1.47 +#include "AssimpPCH.h"
    1.48 +#ifndef ASSIMP_BUILD_NO_X_IMPORTER
    1.49 +
    1.50 +#include "XFileParser.h"
    1.51 +#include "XFileHelper.h"
    1.52 +#include "fast_atof.h"
    1.53 +
    1.54 +using namespace Assimp;
    1.55 +using namespace Assimp::XFile;
    1.56 +
    1.57 +#ifndef ASSIMP_BUILD_NO_COMPRESSED_X
    1.58 +
    1.59 +#	ifdef ASSIMP_BUILD_NO_OWN_ZLIB
    1.60 +#		include <zlib.h>
    1.61 +#	else
    1.62 +#		include "../contrib/zlib/zlib.h"
    1.63 +#	endif
    1.64 +
    1.65 +// Magic identifier for MSZIP compressed data
    1.66 +#define MSZIP_MAGIC 0x4B43
    1.67 +#define MSZIP_BLOCK 32786
    1.68 +
    1.69 +// ------------------------------------------------------------------------------------------------
    1.70 +// Dummy memory wrappers for use with zlib
    1.71 +static void* dummy_alloc (void* /*opaque*/, unsigned int items, unsigned int size)	{
    1.72 +	return ::operator new(items*size);
    1.73 +}
    1.74 +
    1.75 +static void  dummy_free  (void* /*opaque*/, void* address)	{
    1.76 +	return ::operator delete(address);
    1.77 +}
    1.78 +
    1.79 +#endif // !! ASSIMP_BUILD_NO_COMPRESSED_X
    1.80 +
    1.81 +// ------------------------------------------------------------------------------------------------
    1.82 +// Constructor. Creates a data structure out of the XFile given in the memory block. 
    1.83 +XFileParser::XFileParser( const std::vector<char>& pBuffer)
    1.84 +{
    1.85 +	mMajorVersion = mMinorVersion = 0;
    1.86 +	mIsBinaryFormat = false;
    1.87 +	mBinaryNumCount = 0;
    1.88 +	P = End = NULL;
    1.89 +	mLineNumber = 0;
    1.90 +	mScene = NULL;
    1.91 +
    1.92 +	// vector to store uncompressed file for INFLATE'd X files
    1.93 +	std::vector<char> uncompressed;
    1.94 +
    1.95 +	// set up memory pointers
    1.96 +	P = &pBuffer.front();
    1.97 +	End = P + pBuffer.size() - 1;
    1.98 +
    1.99 +	// check header
   1.100 +	if( strncmp( P, "xof ", 4) != 0)
   1.101 +		throw DeadlyImportError( "Header mismatch, file is not an XFile.");
   1.102 +
   1.103 +	// read version. It comes in a four byte format such as "0302"
   1.104 +	mMajorVersion = (unsigned int)(P[4] - 48) * 10 + (unsigned int)(P[5] - 48);
   1.105 +	mMinorVersion = (unsigned int)(P[6] - 48) * 10 + (unsigned int)(P[7] - 48);
   1.106 +
   1.107 +	bool compressed = false;
   1.108 +
   1.109 +	// txt - pure ASCII text format
   1.110 +	if( strncmp( P + 8, "txt ", 4) == 0)
   1.111 +		mIsBinaryFormat = false;
   1.112 +
   1.113 +	// bin - Binary format
   1.114 +	else if( strncmp( P + 8, "bin ", 4) == 0)
   1.115 +		mIsBinaryFormat = true;
   1.116 +
   1.117 +	// tzip - Inflate compressed text format
   1.118 +	else if( strncmp( P + 8, "tzip", 4) == 0)
   1.119 +	{
   1.120 +		mIsBinaryFormat = false;
   1.121 +		compressed = true;
   1.122 +	}
   1.123 +	// bzip - Inflate compressed binary format
   1.124 +	else if( strncmp( P + 8, "bzip", 4) == 0)
   1.125 +	{
   1.126 +		mIsBinaryFormat = true;
   1.127 +		compressed = true;
   1.128 +	}
   1.129 +	else ThrowException( boost::str(boost::format("Unsupported xfile format '%c%c%c%c'") 
   1.130 +		% P[8] % P[9] % P[10] % P[11]));
   1.131 +
   1.132 +	// float size
   1.133 +	mBinaryFloatSize = (unsigned int)(P[12] - 48) * 1000
   1.134 +		+ (unsigned int)(P[13] - 48) * 100
   1.135 +		+ (unsigned int)(P[14] - 48) * 10
   1.136 +		+ (unsigned int)(P[15] - 48);
   1.137 +
   1.138 +	if( mBinaryFloatSize != 32 && mBinaryFloatSize != 64)
   1.139 +		ThrowException( boost::str( boost::format( "Unknown float size %1% specified in xfile header.")
   1.140 +			% mBinaryFloatSize));
   1.141 +
   1.142 +	P += 16;
   1.143 +
   1.144 +	// If this is a compressed X file, apply the inflate algorithm to it
   1.145 +	if (compressed)
   1.146 +	{
   1.147 +#ifdef ASSIMP_BUILD_NO_COMPRESSED_X
   1.148 +		throw DeadlyImportError("Assimp was built without compressed X support");
   1.149 +#else
   1.150 +		/* ///////////////////////////////////////////////////////////////////////  
   1.151 +		 * COMPRESSED X FILE FORMAT
   1.152 +		 * ///////////////////////////////////////////////////////////////////////
   1.153 +		 *    [xhead]
   1.154 +		 *    2 major
   1.155 +		 *    2 minor
   1.156 +		 *    4 type    // bzip,tzip
   1.157 +		 *    [mszip_master_head]
   1.158 +		 *    4 unkn    // checksum?
   1.159 +		 *    2 unkn    // flags? (seems to be constant)
   1.160 +		 *    [mszip_head]
   1.161 +		 *    2 ofs     // offset to next section
   1.162 +		 *    2 magic   // 'CK'
   1.163 +		 *    ... ofs bytes of data
   1.164 +		 *    ... next mszip_head
   1.165 +		 *
   1.166 +		 *  http://www.kdedevelopers.org/node/3181 has been very helpful.
   1.167 +		 * ///////////////////////////////////////////////////////////////////////
   1.168 +		 */
   1.169 +
   1.170 +		// build a zlib stream
   1.171 +		z_stream stream;
   1.172 +		stream.opaque = NULL;
   1.173 +		stream.zalloc = &dummy_alloc;
   1.174 +		stream.zfree  = &dummy_free;
   1.175 +		stream.data_type = (mIsBinaryFormat ? Z_BINARY : Z_ASCII);
   1.176 +
   1.177 +		// initialize the inflation algorithm
   1.178 +		::inflateInit2(&stream, -MAX_WBITS);
   1.179 +
   1.180 +		// skip unknown data (checksum, flags?)
   1.181 +		P += 6;
   1.182 +
   1.183 +		// First find out how much storage we'll need. Count sections.
   1.184 +		const char* P1       = P;
   1.185 +		unsigned int est_out = 0;
   1.186 +
   1.187 +		while (P1 + 3 < End)
   1.188 +		{
   1.189 +			// read next offset
   1.190 +			uint16_t ofs = *((uint16_t*)P1);
   1.191 +			AI_SWAP2(ofs); P1 += 2;
   1.192 +
   1.193 +			if (ofs >= MSZIP_BLOCK)
   1.194 +				throw DeadlyImportError("X: Invalid offset to next MSZIP compressed block");
   1.195 +
   1.196 +			// check magic word
   1.197 +			uint16_t magic = *((uint16_t*)P1);
   1.198 +			AI_SWAP2(magic); P1 += 2;
   1.199 +
   1.200 +			if (magic != MSZIP_MAGIC)
   1.201 +				throw DeadlyImportError("X: Unsupported compressed format, expected MSZIP header");
   1.202 +
   1.203 +			// and advance to the next offset
   1.204 +			P1 += ofs;
   1.205 +			est_out += MSZIP_BLOCK; // one decompressed block is 32786 in size
   1.206 +		}
   1.207 +		
   1.208 +		// Allocate storage and terminating zero and do the actual uncompressing
   1.209 +		uncompressed.resize(est_out + 1);
   1.210 +		char* out = &uncompressed.front();
   1.211 +		while (P + 3 < End)
   1.212 +		{
   1.213 +			uint16_t ofs = *((uint16_t*)P);
   1.214 +			AI_SWAP2(ofs); 
   1.215 +			P += 4;
   1.216 +
   1.217 +			// push data to the stream
   1.218 +			stream.next_in   = (Bytef*)P;
   1.219 +			stream.avail_in  = ofs;
   1.220 +			stream.next_out  = (Bytef*)out;
   1.221 +			stream.avail_out = MSZIP_BLOCK;
   1.222 +
   1.223 +			// and decompress the data ....
   1.224 +			int ret = ::inflate( &stream, Z_SYNC_FLUSH );
   1.225 +			if (ret != Z_OK && ret != Z_STREAM_END)
   1.226 +				throw DeadlyImportError("X: Failed to decompress MSZIP-compressed data");
   1.227 +
   1.228 +			::inflateReset( &stream );
   1.229 +			::inflateSetDictionary( &stream, (const Bytef*)out , MSZIP_BLOCK - stream.avail_out );
   1.230 +
   1.231 +			// and advance to the next offset
   1.232 +			out +=  MSZIP_BLOCK - stream.avail_out;
   1.233 +			P   += ofs;
   1.234 +		}
   1.235 +
   1.236 +		// terminate zlib
   1.237 +		::inflateEnd(&stream);
   1.238 +		
   1.239 +		// ok, update pointers to point to the uncompressed file data
   1.240 +		P = &uncompressed[0];
   1.241 +		End = out;
   1.242 +
   1.243 +		// FIXME: we don't need the compressed data anymore, could release
   1.244 +		// it already for better memory usage. Consider breaking const-co.
   1.245 +		DefaultLogger::get()->info("Successfully decompressed MSZIP-compressed file");
   1.246 +#endif // !! ASSIMP_BUILD_NO_COMPRESSED_X
   1.247 +	}
   1.248 +	else
   1.249 +	{
   1.250 +		// start reading here
   1.251 +		ReadUntilEndOfLine();
   1.252 +	}
   1.253 +
   1.254 +	mScene = new Scene;
   1.255 +	ParseFile();
   1.256 +
   1.257 +	// filter the imported hierarchy for some degenerated cases
   1.258 +	if( mScene->mRootNode) {
   1.259 +		FilterHierarchy( mScene->mRootNode);
   1.260 +	}
   1.261 +}
   1.262 +
   1.263 +// ------------------------------------------------------------------------------------------------
   1.264 +// Destructor. Destroys all imported data along with it 
   1.265 +XFileParser::~XFileParser()
   1.266 +{
   1.267 +	// kill everything we created
   1.268 +	delete mScene;
   1.269 +}
   1.270 +
   1.271 +// ------------------------------------------------------------------------------------------------
   1.272 +void XFileParser::ParseFile()
   1.273 +{
   1.274 +	bool running = true;
   1.275 +	while( running )
   1.276 +	{
   1.277 +		// read name of next object
   1.278 +		std::string objectName = GetNextToken();
   1.279 +		if (objectName.length() == 0)
   1.280 +			break;
   1.281 +
   1.282 +		// parse specific object
   1.283 +		if( objectName == "template")
   1.284 +			ParseDataObjectTemplate();
   1.285 +		else
   1.286 +		if( objectName == "Frame")
   1.287 +			ParseDataObjectFrame( NULL);
   1.288 +		else
   1.289 +		if( objectName == "Mesh")
   1.290 +		{
   1.291 +			// some meshes have no frames at all
   1.292 +			Mesh* mesh = new Mesh;
   1.293 +			ParseDataObjectMesh( mesh);
   1.294 +			mScene->mGlobalMeshes.push_back( mesh);
   1.295 +		} else
   1.296 +		if( objectName == "AnimTicksPerSecond")
   1.297 +			ParseDataObjectAnimTicksPerSecond();
   1.298 +		else
   1.299 +		if( objectName == "AnimationSet")
   1.300 +			ParseDataObjectAnimationSet();
   1.301 +		else
   1.302 +		if( objectName == "Material")
   1.303 +		{
   1.304 +			// Material outside of a mesh or node
   1.305 +			Material material; 
   1.306 +			ParseDataObjectMaterial( &material);
   1.307 +			mScene->mGlobalMaterials.push_back( material);
   1.308 +		} else
   1.309 +		if( objectName == "}")
   1.310 +		{
   1.311 +			// whatever?
   1.312 +			DefaultLogger::get()->warn("} found in dataObject");
   1.313 +		} else
   1.314 +		{
   1.315 +			// unknown format
   1.316 +			DefaultLogger::get()->warn("Unknown data object in animation of .x file");
   1.317 +			ParseUnknownDataObject();
   1.318 +		}
   1.319 +	}
   1.320 +}
   1.321 +
   1.322 +// ------------------------------------------------------------------------------------------------
   1.323 +void XFileParser::ParseDataObjectTemplate()
   1.324 +{
   1.325 +	// parse a template data object. Currently not stored.
   1.326 +	std::string name;
   1.327 +	readHeadOfDataObject( &name);
   1.328 +
   1.329 +	// read GUID
   1.330 +	std::string guid = GetNextToken();
   1.331 +
   1.332 +	// read and ignore data members
   1.333 +	bool running = true;
   1.334 +	while ( running )
   1.335 +	{
   1.336 +		std::string s = GetNextToken();
   1.337 +
   1.338 +		if( s == "}")
   1.339 +			break;
   1.340 +
   1.341 +		if( s.length() == 0)
   1.342 +			ThrowException( "Unexpected end of file reached while parsing template definition");
   1.343 +	}
   1.344 +}
   1.345 +
   1.346 +// ------------------------------------------------------------------------------------------------
   1.347 +void XFileParser::ParseDataObjectFrame( Node* pParent)
   1.348 +{
   1.349 +	// A coordinate frame, or "frame of reference." The Frame template
   1.350 +	// is open and can contain any object. The Direct3D extensions (D3DX)
   1.351 +	// mesh-loading functions recognize Mesh, FrameTransformMatrix, and
   1.352 +	// Frame template instances as child objects when loading a Frame
   1.353 +	// instance.
   1.354 +	std::string name;
   1.355 +	readHeadOfDataObject(&name);
   1.356 +
   1.357 +	// create a named node and place it at its parent, if given
   1.358 +	Node* node = new Node( pParent);
   1.359 +	node->mName = name;
   1.360 +	if( pParent)
   1.361 +	{
   1.362 +		pParent->mChildren.push_back( node);
   1.363 +	} else
   1.364 +	{
   1.365 +		// there might be multiple root nodes
   1.366 +		if( mScene->mRootNode != NULL)
   1.367 +		{
   1.368 +			// place a dummy root if not there
   1.369 +			if( mScene->mRootNode->mName != "$dummy_root")
   1.370 +			{
   1.371 +				Node* exroot = mScene->mRootNode;
   1.372 +				mScene->mRootNode = new Node( NULL);
   1.373 +				mScene->mRootNode->mName = "$dummy_root";
   1.374 +				mScene->mRootNode->mChildren.push_back( exroot);
   1.375 +				exroot->mParent = mScene->mRootNode;
   1.376 +			}
   1.377 +			// put the new node as its child instead
   1.378 +			mScene->mRootNode->mChildren.push_back( node);
   1.379 +			node->mParent = mScene->mRootNode;
   1.380 +		} else
   1.381 +		{
   1.382 +			// it's the first node imported. place it as root
   1.383 +			mScene->mRootNode = node;
   1.384 +		}
   1.385 +	}
   1.386 +
   1.387 +	// Now inside a frame.
   1.388 +	// read tokens until closing brace is reached.
   1.389 +	bool running = true;
   1.390 +	while ( running )
   1.391 +	{
   1.392 +		std::string objectName = GetNextToken();
   1.393 +		if (objectName.size() == 0)
   1.394 +			ThrowException( "Unexpected end of file reached while parsing frame");
   1.395 +
   1.396 +		if( objectName == "}")
   1.397 +			break; // frame finished
   1.398 +		else
   1.399 +		if( objectName == "Frame")
   1.400 +			ParseDataObjectFrame( node); // child frame
   1.401 +		else
   1.402 +		if( objectName == "FrameTransformMatrix")
   1.403 +			ParseDataObjectTransformationMatrix( node->mTrafoMatrix);
   1.404 +		else
   1.405 +		if( objectName == "Mesh")
   1.406 +		{
   1.407 +			Mesh* mesh = new Mesh;
   1.408 +			node->mMeshes.push_back( mesh);
   1.409 +			ParseDataObjectMesh( mesh);
   1.410 +		} else
   1.411 +		{
   1.412 +			DefaultLogger::get()->warn("Unknown data object in frame in x file");
   1.413 +			ParseUnknownDataObject();
   1.414 +		}
   1.415 +	}
   1.416 +}
   1.417 +
   1.418 +// ------------------------------------------------------------------------------------------------
   1.419 +void XFileParser::ParseDataObjectTransformationMatrix( aiMatrix4x4& pMatrix)
   1.420 +{
   1.421 +	// read header, we're not interested if it has a name
   1.422 +	readHeadOfDataObject();
   1.423 +
   1.424 +	// read its components
   1.425 +	pMatrix.a1 = ReadFloat(); pMatrix.b1 = ReadFloat();
   1.426 +	pMatrix.c1 = ReadFloat(); pMatrix.d1 = ReadFloat();
   1.427 +	pMatrix.a2 = ReadFloat(); pMatrix.b2 = ReadFloat();
   1.428 +	pMatrix.c2 = ReadFloat(); pMatrix.d2 = ReadFloat();
   1.429 +	pMatrix.a3 = ReadFloat(); pMatrix.b3 = ReadFloat();
   1.430 +	pMatrix.c3 = ReadFloat(); pMatrix.d3 = ReadFloat();
   1.431 +	pMatrix.a4 = ReadFloat(); pMatrix.b4 = ReadFloat();
   1.432 +	pMatrix.c4 = ReadFloat(); pMatrix.d4 = ReadFloat();
   1.433 +
   1.434 +	// trailing symbols
   1.435 +	CheckForSemicolon();
   1.436 +	CheckForClosingBrace();
   1.437 +}
   1.438 +
   1.439 +// ------------------------------------------------------------------------------------------------
   1.440 +void XFileParser::ParseDataObjectMesh( Mesh* pMesh)
   1.441 +{
   1.442 +	std::string name;
   1.443 +	readHeadOfDataObject( &name);
   1.444 +
   1.445 +	// read vertex count
   1.446 +	unsigned int numVertices = ReadInt();
   1.447 +	pMesh->mPositions.resize( numVertices);
   1.448 +
   1.449 +	// read vertices
   1.450 +	for( unsigned int a = 0; a < numVertices; a++)
   1.451 +		pMesh->mPositions[a] = ReadVector3();
   1.452 +
   1.453 +	// read position faces
   1.454 +	unsigned int numPosFaces = ReadInt();
   1.455 +	pMesh->mPosFaces.resize( numPosFaces);
   1.456 +	for( unsigned int a = 0; a < numPosFaces; a++)
   1.457 +	{
   1.458 +		unsigned int numIndices = ReadInt();
   1.459 +		if( numIndices < 3)
   1.460 +			ThrowException( boost::str( boost::format( "Invalid index count %1% for face %2%.") % numIndices % a));
   1.461 +
   1.462 +		// read indices
   1.463 +		Face& face = pMesh->mPosFaces[a];
   1.464 +		for( unsigned int b = 0; b < numIndices; b++)
   1.465 +			face.mIndices.push_back( ReadInt());
   1.466 +		TestForSeparator();
   1.467 +	}
   1.468 +
   1.469 +	// here, other data objects may follow
   1.470 +	bool running = true;
   1.471 +	while ( running )
   1.472 +	{
   1.473 +		std::string objectName = GetNextToken();
   1.474 +
   1.475 +		if( objectName.size() == 0)
   1.476 +			ThrowException( "Unexpected end of file while parsing mesh structure");
   1.477 +		else
   1.478 +		if( objectName == "}")
   1.479 +			break; // mesh finished
   1.480 +		else
   1.481 +		if( objectName == "MeshNormals")
   1.482 +			ParseDataObjectMeshNormals( pMesh);
   1.483 +		else
   1.484 +		if( objectName == "MeshTextureCoords")
   1.485 +			ParseDataObjectMeshTextureCoords( pMesh);
   1.486 +		else
   1.487 +		if( objectName == "MeshVertexColors")
   1.488 +			ParseDataObjectMeshVertexColors( pMesh);
   1.489 +		else
   1.490 +		if( objectName == "MeshMaterialList")
   1.491 +			ParseDataObjectMeshMaterialList( pMesh);
   1.492 +		else
   1.493 +		if( objectName == "VertexDuplicationIndices")
   1.494 +			ParseUnknownDataObject(); // we'll ignore vertex duplication indices
   1.495 +		else
   1.496 +		if( objectName == "XSkinMeshHeader")
   1.497 +			ParseDataObjectSkinMeshHeader( pMesh);
   1.498 +		else
   1.499 +		if( objectName == "SkinWeights")
   1.500 +			ParseDataObjectSkinWeights( pMesh);
   1.501 +		else
   1.502 +		{
   1.503 +			DefaultLogger::get()->warn("Unknown data object in mesh in x file");
   1.504 +			ParseUnknownDataObject();
   1.505 +		}
   1.506 +	}
   1.507 +}
   1.508 +
   1.509 +// ------------------------------------------------------------------------------------------------
   1.510 +void XFileParser::ParseDataObjectSkinWeights( Mesh *pMesh)
   1.511 +{
   1.512 +	readHeadOfDataObject();
   1.513 +
   1.514 +	std::string transformNodeName;
   1.515 +	GetNextTokenAsString( transformNodeName);
   1.516 +
   1.517 +	pMesh->mBones.push_back( Bone());
   1.518 +	Bone& bone = pMesh->mBones.back();
   1.519 +	bone.mName = transformNodeName;
   1.520 +
   1.521 +	// read vertex weights
   1.522 +	unsigned int numWeights = ReadInt();
   1.523 +	bone.mWeights.reserve( numWeights);
   1.524 +
   1.525 +	for( unsigned int a = 0; a < numWeights; a++)
   1.526 +	{
   1.527 +		BoneWeight weight;
   1.528 +		weight.mVertex = ReadInt();
   1.529 +		bone.mWeights.push_back( weight);
   1.530 +	}
   1.531 +
   1.532 +	// read vertex weights
   1.533 +	for( unsigned int a = 0; a < numWeights; a++)
   1.534 +		bone.mWeights[a].mWeight = ReadFloat();
   1.535 +
   1.536 +	// read matrix offset
   1.537 +	bone.mOffsetMatrix.a1 = ReadFloat(); bone.mOffsetMatrix.b1 = ReadFloat();
   1.538 +	bone.mOffsetMatrix.c1 = ReadFloat(); bone.mOffsetMatrix.d1 = ReadFloat();
   1.539 +	bone.mOffsetMatrix.a2 = ReadFloat(); bone.mOffsetMatrix.b2 = ReadFloat();
   1.540 +	bone.mOffsetMatrix.c2 = ReadFloat(); bone.mOffsetMatrix.d2 = ReadFloat();
   1.541 +	bone.mOffsetMatrix.a3 = ReadFloat(); bone.mOffsetMatrix.b3 = ReadFloat();
   1.542 +	bone.mOffsetMatrix.c3 = ReadFloat(); bone.mOffsetMatrix.d3 = ReadFloat();
   1.543 +	bone.mOffsetMatrix.a4 = ReadFloat(); bone.mOffsetMatrix.b4 = ReadFloat();
   1.544 +	bone.mOffsetMatrix.c4 = ReadFloat(); bone.mOffsetMatrix.d4 = ReadFloat();
   1.545 +
   1.546 +	CheckForSemicolon();
   1.547 +	CheckForClosingBrace();
   1.548 +}
   1.549 +
   1.550 +// ------------------------------------------------------------------------------------------------
   1.551 +void XFileParser::ParseDataObjectSkinMeshHeader( Mesh* /*pMesh*/ )
   1.552 +{
   1.553 +	readHeadOfDataObject();
   1.554 +
   1.555 +	/*unsigned int maxSkinWeightsPerVertex =*/ ReadInt();
   1.556 +	/*unsigned int maxSkinWeightsPerFace =*/ ReadInt();
   1.557 +	/*unsigned int numBonesInMesh = */ReadInt();
   1.558 +
   1.559 +	CheckForClosingBrace();
   1.560 +}
   1.561 +
   1.562 +// ------------------------------------------------------------------------------------------------
   1.563 +void XFileParser::ParseDataObjectMeshNormals( Mesh* pMesh)
   1.564 +{
   1.565 +	readHeadOfDataObject();
   1.566 +
   1.567 +	// read count
   1.568 +	unsigned int numNormals = ReadInt();
   1.569 +	pMesh->mNormals.resize( numNormals);
   1.570 +
   1.571 +	// read normal vectors
   1.572 +	for( unsigned int a = 0; a < numNormals; a++)
   1.573 +		pMesh->mNormals[a] = ReadVector3();
   1.574 +
   1.575 +	// read normal indices
   1.576 +	unsigned int numFaces = ReadInt();
   1.577 +	if( numFaces != pMesh->mPosFaces.size())
   1.578 +		ThrowException( "Normal face count does not match vertex face count.");
   1.579 +
   1.580 +	for( unsigned int a = 0; a < numFaces; a++)
   1.581 +	{
   1.582 +		unsigned int numIndices = ReadInt();
   1.583 +		pMesh->mNormFaces.push_back( Face());
   1.584 +		Face& face = pMesh->mNormFaces.back();
   1.585 +
   1.586 +		for( unsigned int b = 0; b < numIndices; b++)
   1.587 +			face.mIndices.push_back( ReadInt());
   1.588 +
   1.589 +		TestForSeparator();
   1.590 +	}
   1.591 +
   1.592 +	CheckForClosingBrace();
   1.593 +}
   1.594 +
   1.595 +// ------------------------------------------------------------------------------------------------
   1.596 +void XFileParser::ParseDataObjectMeshTextureCoords( Mesh* pMesh)
   1.597 +{
   1.598 +	readHeadOfDataObject();
   1.599 +	if( pMesh->mNumTextures + 1 > AI_MAX_NUMBER_OF_TEXTURECOORDS)
   1.600 +		ThrowException( "Too many sets of texture coordinates");
   1.601 +
   1.602 +	std::vector<aiVector2D>& coords = pMesh->mTexCoords[pMesh->mNumTextures++];
   1.603 +
   1.604 +	unsigned int numCoords = ReadInt();
   1.605 +	if( numCoords != pMesh->mPositions.size())
   1.606 +		ThrowException( "Texture coord count does not match vertex count");
   1.607 +
   1.608 +	coords.resize( numCoords);
   1.609 +	for( unsigned int a = 0; a < numCoords; a++)
   1.610 +		coords[a] = ReadVector2();
   1.611 +
   1.612 +	CheckForClosingBrace();
   1.613 +}
   1.614 +
   1.615 +// ------------------------------------------------------------------------------------------------
   1.616 +void XFileParser::ParseDataObjectMeshVertexColors( Mesh* pMesh)
   1.617 +{
   1.618 +	readHeadOfDataObject();
   1.619 +	if( pMesh->mNumColorSets + 1 > AI_MAX_NUMBER_OF_COLOR_SETS)
   1.620 +		ThrowException( "Too many colorsets");
   1.621 +	std::vector<aiColor4D>& colors = pMesh->mColors[pMesh->mNumColorSets++];
   1.622 +
   1.623 +	unsigned int numColors = ReadInt();
   1.624 +	if( numColors != pMesh->mPositions.size())
   1.625 +		ThrowException( "Vertex color count does not match vertex count");
   1.626 +
   1.627 +	colors.resize( numColors, aiColor4D( 0, 0, 0, 1));
   1.628 +	for( unsigned int a = 0; a < numColors; a++)
   1.629 +	{
   1.630 +		unsigned int index = ReadInt();
   1.631 +		if( index >= pMesh->mPositions.size())
   1.632 +			ThrowException( "Vertex color index out of bounds");
   1.633 +
   1.634 +		colors[index] = ReadRGBA();
   1.635 +		// HACK: (thom) Maxon Cinema XPort plugin puts a third separator here, kwxPort puts a comma.
   1.636 +		// Ignore gracefully.
   1.637 +		if( !mIsBinaryFormat)
   1.638 +		{
   1.639 +			FindNextNoneWhiteSpace();
   1.640 +			if( *P == ';' || *P == ',')
   1.641 +				P++;
   1.642 +		}
   1.643 +	}
   1.644 +
   1.645 +	CheckForClosingBrace();
   1.646 +}
   1.647 +
   1.648 +// ------------------------------------------------------------------------------------------------
   1.649 +void XFileParser::ParseDataObjectMeshMaterialList( Mesh* pMesh)
   1.650 +{
   1.651 +	readHeadOfDataObject();
   1.652 +
   1.653 +	// read material count
   1.654 +	/*unsigned int numMaterials =*/ ReadInt();
   1.655 +	// read non triangulated face material index count
   1.656 +	unsigned int numMatIndices = ReadInt();
   1.657 +
   1.658 +	// some models have a material index count of 1... to be able to read them we
   1.659 +	// replicate this single material index on every face
   1.660 +	if( numMatIndices != pMesh->mPosFaces.size() && numMatIndices != 1)
   1.661 +		ThrowException( "Per-Face material index count does not match face count.");
   1.662 +
   1.663 +	// read per-face material indices
   1.664 +	for( unsigned int a = 0; a < numMatIndices; a++)
   1.665 +		pMesh->mFaceMaterials.push_back( ReadInt());
   1.666 +
   1.667 +	// in version 03.02, the face indices end with two semicolons.
   1.668 +	// commented out version check, as version 03.03 exported from blender also has 2 semicolons
   1.669 +	if( !mIsBinaryFormat) // && MajorVersion == 3 && MinorVersion <= 2)
   1.670 +	{
   1.671 +		if(P < End && *P == ';')
   1.672 +			++P;
   1.673 +	}
   1.674 +
   1.675 +	// if there was only a single material index, replicate it on all faces
   1.676 +	while( pMesh->mFaceMaterials.size() < pMesh->mPosFaces.size())
   1.677 +		pMesh->mFaceMaterials.push_back( pMesh->mFaceMaterials.front());
   1.678 +
   1.679 +	// read following data objects
   1.680 +	bool running = true;
   1.681 +	while ( running )
   1.682 +	{
   1.683 +		std::string objectName = GetNextToken();
   1.684 +		if( objectName.size() == 0)
   1.685 +			ThrowException( "Unexpected end of file while parsing mesh material list.");
   1.686 +		else
   1.687 +		if( objectName == "}")
   1.688 +			break; // material list finished
   1.689 +		else
   1.690 +		if( objectName == "{")
   1.691 +		{
   1.692 +			// template materials 
   1.693 +			std::string matName = GetNextToken();
   1.694 +			Material material;
   1.695 +			material.mIsReference = true;
   1.696 +			material.mName = matName;
   1.697 +			pMesh->mMaterials.push_back( material);
   1.698 +
   1.699 +			CheckForClosingBrace(); // skip }
   1.700 +		} else
   1.701 +		if( objectName == "Material")
   1.702 +		{
   1.703 +			pMesh->mMaterials.push_back( Material());
   1.704 +			ParseDataObjectMaterial( &pMesh->mMaterials.back());
   1.705 +		} else
   1.706 +		if( objectName == ";")
   1.707 +		{
   1.708 +			// ignore
   1.709 +		} else
   1.710 +		{
   1.711 +			DefaultLogger::get()->warn("Unknown data object in material list in x file");
   1.712 +			ParseUnknownDataObject();
   1.713 +		}
   1.714 +	}
   1.715 +}
   1.716 +
   1.717 +// ------------------------------------------------------------------------------------------------
   1.718 +void XFileParser::ParseDataObjectMaterial( Material* pMaterial)
   1.719 +{
   1.720 +	std::string matName;
   1.721 +	readHeadOfDataObject( &matName);
   1.722 +	if( matName.empty())
   1.723 +		matName = std::string( "material") + boost::lexical_cast<std::string>( mLineNumber);
   1.724 +	pMaterial->mName = matName;
   1.725 +	pMaterial->mIsReference = false;
   1.726 +
   1.727 +	// read material values
   1.728 +	pMaterial->mDiffuse = ReadRGBA(); 
   1.729 +	pMaterial->mSpecularExponent = ReadFloat();
   1.730 +	pMaterial->mSpecular = ReadRGB(); 
   1.731 +	pMaterial->mEmissive = ReadRGB(); 
   1.732 +
   1.733 +	// read other data objects
   1.734 +	bool running = true;
   1.735 +	while ( running )
   1.736 +	{
   1.737 +		std::string objectName = GetNextToken();
   1.738 +		if( objectName.size() == 0)
   1.739 +			ThrowException( "Unexpected end of file while parsing mesh material");
   1.740 +		else
   1.741 +		if( objectName == "}")
   1.742 +			break; // material finished
   1.743 +		else
   1.744 +		if( objectName == "TextureFilename" || objectName == "TextureFileName")
   1.745 +		{
   1.746 +			// some exporters write "TextureFileName" instead.
   1.747 +			std::string texname;
   1.748 +			ParseDataObjectTextureFilename( texname);
   1.749 +			pMaterial->mTextures.push_back( TexEntry( texname));
   1.750 +		} else
   1.751 +		if( objectName == "NormalmapFilename" || objectName == "NormalmapFileName")
   1.752 +		{
   1.753 +			// one exporter writes out the normal map in a separate filename tag
   1.754 +			std::string texname;
   1.755 +			ParseDataObjectTextureFilename( texname);
   1.756 +			pMaterial->mTextures.push_back( TexEntry( texname, true));
   1.757 +		} else
   1.758 +		{
   1.759 +			DefaultLogger::get()->warn("Unknown data object in material in x file");
   1.760 +			ParseUnknownDataObject();
   1.761 +		}
   1.762 +	}
   1.763 +}
   1.764 +
   1.765 +// ------------------------------------------------------------------------------------------------
   1.766 +void XFileParser::ParseDataObjectAnimTicksPerSecond()
   1.767 +{
   1.768 +	readHeadOfDataObject();
   1.769 +	mScene->mAnimTicksPerSecond = ReadInt();
   1.770 +	CheckForClosingBrace();
   1.771 +}
   1.772 +
   1.773 +// ------------------------------------------------------------------------------------------------
   1.774 +void XFileParser::ParseDataObjectAnimationSet()
   1.775 +{
   1.776 +	std::string animName;
   1.777 +	readHeadOfDataObject( &animName);
   1.778 +
   1.779 +	Animation* anim = new Animation;
   1.780 +	mScene->mAnims.push_back( anim);
   1.781 +	anim->mName = animName;
   1.782 +
   1.783 +	bool running = true;
   1.784 +	while ( running )
   1.785 +	{
   1.786 +		std::string objectName = GetNextToken();
   1.787 +		if( objectName.length() == 0)
   1.788 +			ThrowException( "Unexpected end of file while parsing animation set.");
   1.789 +		else
   1.790 +		if( objectName == "}")
   1.791 +			break; // animation set finished
   1.792 +		else
   1.793 +		if( objectName == "Animation")
   1.794 +			ParseDataObjectAnimation( anim);
   1.795 +		else
   1.796 +		{
   1.797 +			DefaultLogger::get()->warn("Unknown data object in animation set in x file");
   1.798 +			ParseUnknownDataObject();
   1.799 +		}
   1.800 +	}
   1.801 +}
   1.802 +
   1.803 +// ------------------------------------------------------------------------------------------------
   1.804 +void XFileParser::ParseDataObjectAnimation( Animation* pAnim)
   1.805 +{
   1.806 +	readHeadOfDataObject();
   1.807 +	AnimBone* banim = new AnimBone;
   1.808 +	pAnim->mAnims.push_back( banim);
   1.809 +
   1.810 +	bool running = true;
   1.811 +	while( running )
   1.812 +	{
   1.813 +		std::string objectName = GetNextToken();
   1.814 +
   1.815 +		if( objectName.length() == 0)
   1.816 +			ThrowException( "Unexpected end of file while parsing animation.");
   1.817 +		else
   1.818 +		if( objectName == "}")
   1.819 +			break; // animation finished
   1.820 +		else
   1.821 +		if( objectName == "AnimationKey")
   1.822 +			ParseDataObjectAnimationKey( banim);
   1.823 +		else
   1.824 +		if( objectName == "AnimationOptions")
   1.825 +			ParseUnknownDataObject(); // not interested
   1.826 +		else
   1.827 +		if( objectName == "{")
   1.828 +		{
   1.829 +			// read frame name
   1.830 +			banim->mBoneName = GetNextToken();
   1.831 +			CheckForClosingBrace();
   1.832 +		} else
   1.833 +		{
   1.834 +			DefaultLogger::get()->warn("Unknown data object in animation in x file");
   1.835 +			ParseUnknownDataObject();
   1.836 +		}
   1.837 +	}
   1.838 +}
   1.839 +
   1.840 +// ------------------------------------------------------------------------------------------------
   1.841 +void XFileParser::ParseDataObjectAnimationKey( AnimBone* pAnimBone)
   1.842 +{
   1.843 +	readHeadOfDataObject();
   1.844 +
   1.845 +	// read key type
   1.846 +	unsigned int keyType = ReadInt();
   1.847 +
   1.848 +	// read number of keys
   1.849 +	unsigned int numKeys = ReadInt();
   1.850 +
   1.851 +	for( unsigned int a = 0; a < numKeys; a++)
   1.852 +	{
   1.853 +		// read time
   1.854 +		unsigned int time = ReadInt();
   1.855 +
   1.856 +		// read keys
   1.857 +		switch( keyType)
   1.858 +		{
   1.859 +			case 0: // rotation quaternion
   1.860 +			{
   1.861 +				// read count
   1.862 +				if( ReadInt() != 4)
   1.863 +					ThrowException( "Invalid number of arguments for quaternion key in animation");
   1.864 +
   1.865 +				aiQuatKey key;
   1.866 +				key.mTime = double( time);
   1.867 +				key.mValue.w = ReadFloat();
   1.868 +				key.mValue.x = ReadFloat();
   1.869 +				key.mValue.y = ReadFloat();
   1.870 +				key.mValue.z = ReadFloat();
   1.871 +				pAnimBone->mRotKeys.push_back( key);
   1.872 +
   1.873 +				CheckForSemicolon();
   1.874 +				break;
   1.875 +			}
   1.876 +
   1.877 +			case 1: // scale vector
   1.878 +			case 2: // position vector
   1.879 +			{
   1.880 +				// read count
   1.881 +				if( ReadInt() != 3)
   1.882 +					ThrowException( "Invalid number of arguments for vector key in animation");
   1.883 +
   1.884 +				aiVectorKey key;
   1.885 +				key.mTime = double( time);
   1.886 +				key.mValue = ReadVector3();
   1.887 +
   1.888 +				if( keyType == 2)
   1.889 +					pAnimBone->mPosKeys.push_back( key);
   1.890 +				else
   1.891 +					pAnimBone->mScaleKeys.push_back( key);
   1.892 +
   1.893 +				break;
   1.894 +			}
   1.895 +
   1.896 +			case 3: // combined transformation matrix
   1.897 +			case 4: // denoted both as 3 or as 4
   1.898 +			{
   1.899 +				// read count
   1.900 +				if( ReadInt() != 16)
   1.901 +					ThrowException( "Invalid number of arguments for matrix key in animation");
   1.902 +
   1.903 +				// read matrix
   1.904 +				MatrixKey key;
   1.905 +				key.mTime = double( time);
   1.906 +				key.mMatrix.a1 = ReadFloat(); key.mMatrix.b1 = ReadFloat();
   1.907 +				key.mMatrix.c1 = ReadFloat(); key.mMatrix.d1 = ReadFloat();
   1.908 +				key.mMatrix.a2 = ReadFloat(); key.mMatrix.b2 = ReadFloat();
   1.909 +				key.mMatrix.c2 = ReadFloat(); key.mMatrix.d2 = ReadFloat();
   1.910 +				key.mMatrix.a3 = ReadFloat(); key.mMatrix.b3 = ReadFloat();
   1.911 +				key.mMatrix.c3 = ReadFloat(); key.mMatrix.d3 = ReadFloat();
   1.912 +				key.mMatrix.a4 = ReadFloat(); key.mMatrix.b4 = ReadFloat();
   1.913 +				key.mMatrix.c4 = ReadFloat(); key.mMatrix.d4 = ReadFloat();
   1.914 +				pAnimBone->mTrafoKeys.push_back( key);
   1.915 +
   1.916 +				CheckForSemicolon();
   1.917 +				break;
   1.918 +			}
   1.919 +
   1.920 +			default:
   1.921 +				ThrowException( boost::str( boost::format( "Unknown key type %1% in animation.") % keyType));
   1.922 +				break;
   1.923 +		} // end switch
   1.924 +
   1.925 +		// key separator
   1.926 +		CheckForSeparator();
   1.927 +	}
   1.928 +
   1.929 +	CheckForClosingBrace();
   1.930 +}
   1.931 +
   1.932 +// ------------------------------------------------------------------------------------------------
   1.933 +void XFileParser::ParseDataObjectTextureFilename( std::string& pName)
   1.934 +{
   1.935 +	readHeadOfDataObject();
   1.936 +	GetNextTokenAsString( pName);
   1.937 +	CheckForClosingBrace();
   1.938 +
   1.939 +	// FIX: some files (e.g. AnimationTest.x) have "" as texture file name
   1.940 +	if (!pName.length())
   1.941 +	{
   1.942 +		DefaultLogger::get()->warn("Length of texture file name is zero. Skipping this texture.");
   1.943 +	}
   1.944 +
   1.945 +	// some exporters write double backslash paths out. We simply replace them if we find them
   1.946 +	while( pName.find( "\\\\") != std::string::npos)
   1.947 +		pName.replace( pName.find( "\\\\"), 2, "\\");
   1.948 +}
   1.949 +
   1.950 +// ------------------------------------------------------------------------------------------------
   1.951 +void XFileParser::ParseUnknownDataObject()
   1.952 +{
   1.953 +	// find opening delimiter
   1.954 +	bool running = true;
   1.955 +	while( running )
   1.956 +	{
   1.957 +		std::string t = GetNextToken();
   1.958 +		if( t.length() == 0)
   1.959 +			ThrowException( "Unexpected end of file while parsing unknown segment.");
   1.960 +
   1.961 +		if( t == "{")
   1.962 +			break;
   1.963 +	}
   1.964 +
   1.965 +	unsigned int counter = 1;
   1.966 +
   1.967 +	// parse until closing delimiter
   1.968 +	while( counter > 0)
   1.969 +	{
   1.970 +		std::string t = GetNextToken();
   1.971 +
   1.972 +		if( t.length() == 0)
   1.973 +			ThrowException( "Unexpected end of file while parsing unknown segment.");
   1.974 +
   1.975 +		if( t == "{")
   1.976 +			++counter;
   1.977 +		else
   1.978 +		if( t == "}")
   1.979 +			--counter;
   1.980 +	}
   1.981 +}
   1.982 +
   1.983 +// ------------------------------------------------------------------------------------------------
   1.984 +//! checks for closing curly brace
   1.985 +void XFileParser::CheckForClosingBrace()
   1.986 +{
   1.987 +	if( GetNextToken() != "}")
   1.988 +		ThrowException( "Closing brace expected.");
   1.989 +}
   1.990 +
   1.991 +// ------------------------------------------------------------------------------------------------
   1.992 +//! checks for one following semicolon
   1.993 +void XFileParser::CheckForSemicolon()
   1.994 +{
   1.995 +	if( mIsBinaryFormat)
   1.996 +		return;
   1.997 +
   1.998 +	if( GetNextToken() != ";")
   1.999 +		ThrowException( "Semicolon expected.");
  1.1000 +}
  1.1001 +
  1.1002 +// ------------------------------------------------------------------------------------------------
  1.1003 +//! checks for a separator char, either a ',' or a ';'
  1.1004 +void XFileParser::CheckForSeparator()
  1.1005 +{
  1.1006 +	if( mIsBinaryFormat)
  1.1007 +		return;
  1.1008 +
  1.1009 +	std::string token = GetNextToken();
  1.1010 +	if( token != "," && token != ";")
  1.1011 +		ThrowException( "Separator character (';' or ',') expected.");
  1.1012 +}
  1.1013 +
  1.1014 +// ------------------------------------------------------------------------------------------------
  1.1015 +// tests and possibly consumes a separator char, but does nothing if there was no separator
  1.1016 +void XFileParser::TestForSeparator()
  1.1017 +{
  1.1018 +  if( mIsBinaryFormat)
  1.1019 +    return;
  1.1020 +
  1.1021 +  FindNextNoneWhiteSpace();
  1.1022 +  if( P >= End)
  1.1023 +    return;
  1.1024 +
  1.1025 +  // test and skip
  1.1026 +  if( *P == ';' || *P == ',')
  1.1027 +    P++;
  1.1028 +}
  1.1029 +
  1.1030 +// ------------------------------------------------------------------------------------------------
  1.1031 +void XFileParser::readHeadOfDataObject( std::string* poName)
  1.1032 +{
  1.1033 +	std::string nameOrBrace = GetNextToken();
  1.1034 +	if( nameOrBrace != "{")
  1.1035 +	{
  1.1036 +		if( poName)
  1.1037 +			*poName = nameOrBrace;
  1.1038 +
  1.1039 +		if( GetNextToken() != "{")
  1.1040 +			ThrowException( "Opening brace expected.");
  1.1041 +	}
  1.1042 +}
  1.1043 +
  1.1044 +// ------------------------------------------------------------------------------------------------
  1.1045 +std::string XFileParser::GetNextToken()
  1.1046 +{
  1.1047 +	std::string s;
  1.1048 +
  1.1049 +	// process binary-formatted file
  1.1050 +	if( mIsBinaryFormat)
  1.1051 +	{
  1.1052 +		// in binary mode it will only return NAME and STRING token
  1.1053 +		// and (correctly) skip over other tokens.
  1.1054 +
  1.1055 +		if( End - P < 2) return s;
  1.1056 +		unsigned int tok = ReadBinWord();
  1.1057 +		unsigned int len;
  1.1058 +
  1.1059 +		// standalone tokens
  1.1060 +		switch( tok) 
  1.1061 +		{
  1.1062 +			case 1:
  1.1063 +				// name token
  1.1064 +				if( End - P < 4) return s;
  1.1065 +				len = ReadBinDWord();
  1.1066 +				if( End - P < int(len)) return s;
  1.1067 +				s = std::string(P, len);
  1.1068 +				P += len;
  1.1069 +				return s;
  1.1070 +			case 2:
  1.1071 +				// string token
  1.1072 +				if( End - P < 4) return s;
  1.1073 +				len = ReadBinDWord();
  1.1074 +				if( End - P < int(len)) return s;
  1.1075 +				s = std::string(P, len);
  1.1076 +				P += (len + 2);
  1.1077 +				return s;
  1.1078 +			case 3:
  1.1079 +				// integer token
  1.1080 +				P += 4;
  1.1081 +				return "<integer>";
  1.1082 +			case 5:
  1.1083 +				// GUID token
  1.1084 +				P += 16;
  1.1085 +				return "<guid>";
  1.1086 +			case 6:
  1.1087 +				if( End - P < 4) return s;
  1.1088 +				len = ReadBinDWord();
  1.1089 +				P += (len * 4);
  1.1090 +				return "<int_list>";
  1.1091 +			case 7:
  1.1092 +				if( End - P < 4) return s;
  1.1093 +				len = ReadBinDWord();
  1.1094 +				P += (len * mBinaryFloatSize);
  1.1095 +				return "<flt_list>";
  1.1096 +			case 0x0a:
  1.1097 +				return "{";
  1.1098 +			case 0x0b:
  1.1099 +				return "}";
  1.1100 +			case 0x0c:
  1.1101 +				return "(";
  1.1102 +			case 0x0d:
  1.1103 +				return ")";
  1.1104 +			case 0x0e:
  1.1105 +				return "[";
  1.1106 +			case 0x0f:
  1.1107 +				return "]";
  1.1108 +			case 0x10:
  1.1109 +				return "<";
  1.1110 +			case 0x11:
  1.1111 +				return ">";
  1.1112 +			case 0x12:
  1.1113 +				return ".";
  1.1114 +			case 0x13:
  1.1115 +				return ",";
  1.1116 +			case 0x14:
  1.1117 +				return ";";
  1.1118 +			case 0x1f:
  1.1119 +				return "template";
  1.1120 +			case 0x28:
  1.1121 +				return "WORD";
  1.1122 +			case 0x29:
  1.1123 +				return "DWORD";
  1.1124 +			case 0x2a:
  1.1125 +				return "FLOAT";
  1.1126 +			case 0x2b:
  1.1127 +				return "DOUBLE";
  1.1128 +			case 0x2c:
  1.1129 +				return "CHAR";
  1.1130 +			case 0x2d:
  1.1131 +				return "UCHAR";
  1.1132 +			case 0x2e:
  1.1133 +				return "SWORD";
  1.1134 +			case 0x2f:
  1.1135 +				return "SDWORD";
  1.1136 +			case 0x30:
  1.1137 +				return "void";
  1.1138 +			case 0x31:
  1.1139 +				return "string";
  1.1140 +			case 0x32:
  1.1141 +				return "unicode";
  1.1142 +			case 0x33:
  1.1143 +				return "cstring";
  1.1144 +			case 0x34:
  1.1145 +				return "array";
  1.1146 +		}
  1.1147 +	}
  1.1148 +	// process text-formatted file
  1.1149 +	else
  1.1150 +	{
  1.1151 +		FindNextNoneWhiteSpace();
  1.1152 +		if( P >= End)
  1.1153 +			return s;
  1.1154 +
  1.1155 +		while( (P < End) && !isspace( (unsigned char) *P))
  1.1156 +		{
  1.1157 +			// either keep token delimiters when already holding a token, or return if first valid char
  1.1158 +			if( *P == ';' || *P == '}' || *P == '{' || *P == ',')
  1.1159 +			{
  1.1160 +				if( !s.size())
  1.1161 +					s.append( P++, 1);
  1.1162 +				break; // stop for delimiter
  1.1163 +			}
  1.1164 +			s.append( P++, 1);
  1.1165 +		}
  1.1166 +	}
  1.1167 +	return s;
  1.1168 +}
  1.1169 +
  1.1170 +// ------------------------------------------------------------------------------------------------
  1.1171 +void XFileParser::FindNextNoneWhiteSpace()
  1.1172 +{
  1.1173 +	if( mIsBinaryFormat)
  1.1174 +		return;
  1.1175 +
  1.1176 +	bool running = true;
  1.1177 +	while( running )
  1.1178 +	{
  1.1179 +		while( P < End && isspace( (unsigned char) *P))
  1.1180 +		{
  1.1181 +			if( *P == '\n')
  1.1182 +				mLineNumber++;
  1.1183 +			++P;
  1.1184 +		}
  1.1185 +
  1.1186 +		if( P >= End)
  1.1187 +			return;
  1.1188 +
  1.1189 +		// check if this is a comment
  1.1190 +		if( (P[0] == '/' && P[1] == '/') ||	P[0] == '#')
  1.1191 +			ReadUntilEndOfLine();
  1.1192 +		else
  1.1193 +			break;
  1.1194 +	}
  1.1195 +}
  1.1196 +
  1.1197 +// ------------------------------------------------------------------------------------------------
  1.1198 +void XFileParser::GetNextTokenAsString( std::string& poString)
  1.1199 +{
  1.1200 +	if( mIsBinaryFormat)
  1.1201 +	{
  1.1202 +		poString = GetNextToken();
  1.1203 +		return;
  1.1204 +	}
  1.1205 +
  1.1206 +	FindNextNoneWhiteSpace();
  1.1207 +	if( P >= End)
  1.1208 +		ThrowException( "Unexpected end of file while parsing string");
  1.1209 +
  1.1210 +	if( *P != '"')
  1.1211 +		ThrowException( "Expected quotation mark.");
  1.1212 +	++P;
  1.1213 +
  1.1214 +	while( P < End && *P != '"')
  1.1215 +		poString.append( P++, 1);
  1.1216 +
  1.1217 +	if( P >= End-1)
  1.1218 +		ThrowException( "Unexpected end of file while parsing string");
  1.1219 +
  1.1220 +	if( P[1] != ';' || P[0] != '"')
  1.1221 +		ThrowException( "Expected quotation mark and semicolon at the end of a string.");
  1.1222 +	P+=2;
  1.1223 +}
  1.1224 +
  1.1225 +// ------------------------------------------------------------------------------------------------
  1.1226 +void XFileParser::ReadUntilEndOfLine()
  1.1227 +{
  1.1228 +	if( mIsBinaryFormat)
  1.1229 +		return;
  1.1230 +
  1.1231 +	while( P < End)
  1.1232 +	{
  1.1233 +		if( *P == '\n' || *P == '\r')
  1.1234 +		{
  1.1235 +			++P; mLineNumber++;
  1.1236 +			return;
  1.1237 +		}
  1.1238 +
  1.1239 +		++P;
  1.1240 +	}
  1.1241 +}
  1.1242 +
  1.1243 +// ------------------------------------------------------------------------------------------------
  1.1244 +unsigned short XFileParser::ReadBinWord()
  1.1245 +{
  1.1246 +	ai_assert(End - P >= 2);
  1.1247 +	const unsigned char* q = (const unsigned char*) P;
  1.1248 +	unsigned short tmp = q[0] | (q[1] << 8);
  1.1249 +	P += 2;
  1.1250 +	return tmp;
  1.1251 +}
  1.1252 +
  1.1253 +// ------------------------------------------------------------------------------------------------
  1.1254 +unsigned int XFileParser::ReadBinDWord()
  1.1255 +{
  1.1256 +	ai_assert(End - P >= 4);
  1.1257 +	const unsigned char* q = (const unsigned char*) P;
  1.1258 +	unsigned int tmp = q[0] | (q[1] << 8) | (q[2] << 16) | (q[3] << 24);
  1.1259 +	P += 4;
  1.1260 +	return tmp;
  1.1261 +}
  1.1262 +
  1.1263 +// ------------------------------------------------------------------------------------------------
  1.1264 +unsigned int XFileParser::ReadInt()
  1.1265 +{
  1.1266 +	if( mIsBinaryFormat)
  1.1267 +	{
  1.1268 +		if( mBinaryNumCount == 0 && End - P >= 2)
  1.1269 +		{
  1.1270 +			unsigned short tmp = ReadBinWord(); // 0x06 or 0x03
  1.1271 +			if( tmp == 0x06 && End - P >= 4) // array of ints follows
  1.1272 +				mBinaryNumCount = ReadBinDWord();
  1.1273 +			else // single int follows
  1.1274 +				mBinaryNumCount = 1; 
  1.1275 +		}
  1.1276 +
  1.1277 +		--mBinaryNumCount;
  1.1278 +		if ( End - P >= 4) {
  1.1279 +			return ReadBinDWord();
  1.1280 +		} else {
  1.1281 +			P = End;
  1.1282 +			return 0;
  1.1283 +		}
  1.1284 +	} else
  1.1285 +	{
  1.1286 +		FindNextNoneWhiteSpace();
  1.1287 +
  1.1288 +		// TODO: consider using strtol10 instead???
  1.1289 +
  1.1290 +		// check preceeding minus sign
  1.1291 +		bool isNegative = false;
  1.1292 +		if( *P == '-')
  1.1293 +		{
  1.1294 +			isNegative = true;
  1.1295 +			P++;
  1.1296 +		}
  1.1297 +
  1.1298 +		// at least one digit expected
  1.1299 +		if( !isdigit( *P))
  1.1300 +			ThrowException( "Number expected.");
  1.1301 +
  1.1302 +		// read digits
  1.1303 +		unsigned int number = 0;
  1.1304 +		while( P < End)
  1.1305 +		{
  1.1306 +			if( !isdigit( *P))
  1.1307 +				break;
  1.1308 +			number = number * 10 + (*P - 48);
  1.1309 +			P++;
  1.1310 +		}
  1.1311 +		
  1.1312 +		CheckForSeparator();
  1.1313 +		return isNegative ? ((unsigned int) -int( number)) : number;
  1.1314 +	}
  1.1315 +}
  1.1316 +
  1.1317 +// ------------------------------------------------------------------------------------------------
  1.1318 +float XFileParser::ReadFloat()
  1.1319 +{
  1.1320 +	if( mIsBinaryFormat)
  1.1321 +	{
  1.1322 +		if( mBinaryNumCount == 0 && End - P >= 2)
  1.1323 +		{
  1.1324 +			unsigned short tmp = ReadBinWord(); // 0x07 or 0x42
  1.1325 +			if( tmp == 0x07 && End - P >= 4) // array of floats following
  1.1326 +				mBinaryNumCount = ReadBinDWord();
  1.1327 +			else // single float following
  1.1328 +				mBinaryNumCount = 1; 
  1.1329 +		}
  1.1330 +
  1.1331 +		--mBinaryNumCount;
  1.1332 +		if( mBinaryFloatSize == 8)
  1.1333 +		{
  1.1334 +			if( End - P >= 8) {
  1.1335 +				float result = (float) (*(double*) P);
  1.1336 +				P += 8;
  1.1337 +				return result;
  1.1338 +			} else {
  1.1339 +				P = End;
  1.1340 +				return 0;
  1.1341 +			}
  1.1342 +		} else
  1.1343 +		{
  1.1344 +			if( End - P >= 4) {
  1.1345 +				float result = *(float*) P;
  1.1346 +				P += 4;
  1.1347 +				return result;
  1.1348 +			} else {
  1.1349 +				P = End;
  1.1350 +				return 0;
  1.1351 +			}
  1.1352 +		}
  1.1353 +	}
  1.1354 +
  1.1355 +	// text version
  1.1356 +	FindNextNoneWhiteSpace();
  1.1357 +	// check for various special strings to allow reading files from faulty exporters
  1.1358 +	// I mean you, Blender!
  1.1359 +	// Reading is safe because of the terminating zero
  1.1360 +	if( strncmp( P, "-1.#IND00", 9) == 0 || strncmp( P, "1.#IND00", 8) == 0)
  1.1361 +	{ 
  1.1362 +		P += 9;
  1.1363 +		CheckForSeparator();
  1.1364 +		return 0.0f;
  1.1365 +	} else
  1.1366 +	if( strncmp( P, "1.#QNAN0", 8) == 0)
  1.1367 +	{
  1.1368 +		P += 8;
  1.1369 +		CheckForSeparator();
  1.1370 +		return 0.0f;
  1.1371 +	}
  1.1372 +
  1.1373 +	float result = 0.0f;
  1.1374 +	P = fast_atoreal_move<float>( P, result);
  1.1375 +
  1.1376 +	CheckForSeparator();
  1.1377 +
  1.1378 +	return result;
  1.1379 +}
  1.1380 +
  1.1381 +// ------------------------------------------------------------------------------------------------
  1.1382 +aiVector2D XFileParser::ReadVector2()
  1.1383 +{
  1.1384 +	aiVector2D vector;
  1.1385 +	vector.x = ReadFloat();
  1.1386 +	vector.y = ReadFloat();
  1.1387 +	TestForSeparator();
  1.1388 +
  1.1389 +	return vector;
  1.1390 +}
  1.1391 +
  1.1392 +// ------------------------------------------------------------------------------------------------
  1.1393 +aiVector3D XFileParser::ReadVector3()
  1.1394 +{
  1.1395 +	aiVector3D vector;
  1.1396 +	vector.x = ReadFloat();
  1.1397 +	vector.y = ReadFloat();
  1.1398 +	vector.z = ReadFloat();
  1.1399 +	TestForSeparator();
  1.1400 +
  1.1401 +	return vector;
  1.1402 +}
  1.1403 +
  1.1404 +// ------------------------------------------------------------------------------------------------
  1.1405 +aiColor4D XFileParser::ReadRGBA()
  1.1406 +{
  1.1407 +	aiColor4D color;
  1.1408 +	color.r = ReadFloat();
  1.1409 +	color.g = ReadFloat();
  1.1410 +	color.b = ReadFloat();
  1.1411 +	color.a = ReadFloat();
  1.1412 +	TestForSeparator();
  1.1413 +
  1.1414 +	return color;
  1.1415 +}
  1.1416 +
  1.1417 +// ------------------------------------------------------------------------------------------------
  1.1418 +aiColor3D XFileParser::ReadRGB()
  1.1419 +{
  1.1420 +	aiColor3D color;
  1.1421 +	color.r = ReadFloat();
  1.1422 +	color.g = ReadFloat();
  1.1423 +	color.b = ReadFloat();
  1.1424 +	TestForSeparator();
  1.1425 +
  1.1426 +	return color;
  1.1427 +}
  1.1428 +
  1.1429 +// ------------------------------------------------------------------------------------------------
  1.1430 +// Throws an exception with a line number and the given text.
  1.1431 +void XFileParser::ThrowException( const std::string& pText)
  1.1432 +{
  1.1433 +	if( mIsBinaryFormat)
  1.1434 +		throw DeadlyImportError( pText);
  1.1435 +	else
  1.1436 +		throw DeadlyImportError( boost::str( boost::format( "Line %d: %s") % mLineNumber % pText));
  1.1437 +}
  1.1438 +
  1.1439 +
  1.1440 +// ------------------------------------------------------------------------------------------------
  1.1441 +// Filters the imported hierarchy for some degenerated cases that some exporters produce.
  1.1442 +void XFileParser::FilterHierarchy( XFile::Node* pNode)
  1.1443 +{
  1.1444 +	// if the node has just a single unnamed child containing a mesh, remove
  1.1445 +	// the anonymous node inbetween. The 3DSMax kwXport plugin seems to produce this
  1.1446 +	// mess in some cases
  1.1447 +	if( pNode->mChildren.size() == 1 && pNode->mMeshes.empty() )
  1.1448 +	{
  1.1449 +		XFile::Node* child = pNode->mChildren.front();
  1.1450 +		if( child->mName.length() == 0 && child->mMeshes.size() > 0)
  1.1451 +		{
  1.1452 +			// transfer its meshes to us
  1.1453 +			for( unsigned int a = 0; a < child->mMeshes.size(); a++)
  1.1454 +				pNode->mMeshes.push_back( child->mMeshes[a]);
  1.1455 +			child->mMeshes.clear();
  1.1456 +
  1.1457 +			// transfer the transform as well
  1.1458 +			pNode->mTrafoMatrix = pNode->mTrafoMatrix * child->mTrafoMatrix;
  1.1459 +
  1.1460 +			// then kill it
  1.1461 +			delete child;
  1.1462 +			pNode->mChildren.clear();
  1.1463 +		}
  1.1464 +	}
  1.1465 +
  1.1466 +	// recurse
  1.1467 +	for( unsigned int a = 0; a < pNode->mChildren.size(); a++)
  1.1468 +		FilterHierarchy( pNode->mChildren[a]);
  1.1469 +}
  1.1470 +
  1.1471 +#endif // !! ASSIMP_BUILD_NO_X_IMPORTER