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