diff options
Diffstat (limited to 'src/3rdparty/assimp/code/XFileParser.cpp')
-rw-r--r-- | src/3rdparty/assimp/code/XFileParser.cpp | 1480 |
1 files changed, 0 insertions, 1480 deletions
diff --git a/src/3rdparty/assimp/code/XFileParser.cpp b/src/3rdparty/assimp/code/XFileParser.cpp deleted file mode 100644 index 1f8b8cbd3..000000000 --- a/src/3rdparty/assimp/code/XFileParser.cpp +++ /dev/null @@ -1,1480 +0,0 @@ -/* ---------------------------------------------------------------------------- -Open Asset Import Library (assimp) ---------------------------------------------------------------------------- - -Copyright (c) 2006-2017, assimp team - - -All rights reserved. - -Redistribution and use of this software in source and binary forms, -with or without modification, are permitted provided that the following -conditions are met: - -* Redistributions of source code must retain the above - copyright notice, this list of conditions and the - following disclaimer. - -* Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the - following disclaimer in the documentation and/or other - materials provided with the distribution. - -* Neither the name of the assimp team, nor the names of its - contributors may be used to endorse or promote products - derived from this software without specific prior - written permission of the assimp team. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ---------------------------------------------------------------------------- -*/ - -/** @file Implementation of the XFile parser helper class */ - - -#ifndef ASSIMP_BUILD_NO_X_IMPORTER - -#include "XFileParser.h" -#include "XFileHelper.h" -#include "fast_atof.h" -#include "Exceptional.h" -#include "TinyFormatter.h" -#include "ByteSwapper.h" -#include "StringUtils.h" -#include <assimp/DefaultLogger.hpp> - - -using namespace Assimp; -using namespace Assimp::XFile; -using namespace Assimp::Formatter; - -#ifndef ASSIMP_BUILD_NO_COMPRESSED_X - -# ifdef ASSIMP_BUILD_NO_OWN_ZLIB -# include <zlib.h> -# else -# include "../contrib/zlib/zlib.h" -# endif - -// Magic identifier for MSZIP compressed data -#define MSZIP_MAGIC 0x4B43 -#define MSZIP_BLOCK 32786 - -// ------------------------------------------------------------------------------------------------ -// Dummy memory wrappers for use with zlib -static void* dummy_alloc (void* /*opaque*/, unsigned int items, unsigned int size) { - return ::operator new(items*size); -} - -static void dummy_free (void* /*opaque*/, void* address) { - return ::operator delete(address); -} - -#endif // !! ASSIMP_BUILD_NO_COMPRESSED_X - -// ------------------------------------------------------------------------------------------------ -// Constructor. Creates a data structure out of the XFile given in the memory block. -XFileParser::XFileParser( const std::vector<char>& pBuffer) -{ - mMajorVersion = mMinorVersion = 0; - mIsBinaryFormat = false; - mBinaryNumCount = 0; - P = End = NULL; - mLineNumber = 0; - mScene = NULL; - - // vector to store uncompressed file for INFLATE'd X files - std::vector<char> uncompressed; - - // set up memory pointers - P = &pBuffer.front(); - End = P + pBuffer.size() - 1; - - // check header - if( strncmp( P, "xof ", 4) != 0) - throw DeadlyImportError( "Header mismatch, file is not an XFile."); - - // read version. It comes in a four byte format such as "0302" - mMajorVersion = (unsigned int)(P[4] - 48) * 10 + (unsigned int)(P[5] - 48); - mMinorVersion = (unsigned int)(P[6] - 48) * 10 + (unsigned int)(P[7] - 48); - - bool compressed = false; - - // txt - pure ASCII text format - if( strncmp( P + 8, "txt ", 4) == 0) - mIsBinaryFormat = false; - - // bin - Binary format - else if( strncmp( P + 8, "bin ", 4) == 0) - mIsBinaryFormat = true; - - // tzip - Inflate compressed text format - else if( strncmp( P + 8, "tzip", 4) == 0) - { - mIsBinaryFormat = false; - compressed = true; - } - // bzip - Inflate compressed binary format - else if( strncmp( P + 8, "bzip", 4) == 0) - { - mIsBinaryFormat = true; - compressed = true; - } - else ThrowException( format() << "Unsupported xfile format '" << - P[8] << P[9] << P[10] << P[11] << "'"); - - // float size - mBinaryFloatSize = (unsigned int)(P[12] - 48) * 1000 - + (unsigned int)(P[13] - 48) * 100 - + (unsigned int)(P[14] - 48) * 10 - + (unsigned int)(P[15] - 48); - - if( mBinaryFloatSize != 32 && mBinaryFloatSize != 64) - ThrowException( format() << "Unknown float size " << mBinaryFloatSize << " specified in xfile header." ); - - // The x format specifies size in bits, but we work in bytes - mBinaryFloatSize /= 8; - - P += 16; - - // If this is a compressed X file, apply the inflate algorithm to it - if (compressed) - { -#ifdef ASSIMP_BUILD_NO_COMPRESSED_X - throw DeadlyImportError("Assimp was built without compressed X support"); -#else - /* /////////////////////////////////////////////////////////////////////// - * COMPRESSED X FILE FORMAT - * /////////////////////////////////////////////////////////////////////// - * [xhead] - * 2 major - * 2 minor - * 4 type // bzip,tzip - * [mszip_master_head] - * 4 unkn // checksum? - * 2 unkn // flags? (seems to be constant) - * [mszip_head] - * 2 ofs // offset to next section - * 2 magic // 'CK' - * ... ofs bytes of data - * ... next mszip_head - * - * http://www.kdedevelopers.org/node/3181 has been very helpful. - * /////////////////////////////////////////////////////////////////////// - */ - - // build a zlib stream - z_stream stream; - stream.opaque = NULL; - stream.zalloc = &dummy_alloc; - stream.zfree = &dummy_free; - stream.data_type = (mIsBinaryFormat ? Z_BINARY : Z_ASCII); - - // initialize the inflation algorithm - ::inflateInit2(&stream, -MAX_WBITS); - - // skip unknown data (checksum, flags?) - P += 6; - - // First find out how much storage we'll need. Count sections. - const char* P1 = P; - unsigned int est_out = 0; - - while (P1 + 3 < End) - { - // read next offset - uint16_t ofs = *((uint16_t*)P1); - AI_SWAP2(ofs); P1 += 2; - - if (ofs >= MSZIP_BLOCK) - throw DeadlyImportError("X: Invalid offset to next MSZIP compressed block"); - - // check magic word - uint16_t magic = *((uint16_t*)P1); - AI_SWAP2(magic); P1 += 2; - - if (magic != MSZIP_MAGIC) - throw DeadlyImportError("X: Unsupported compressed format, expected MSZIP header"); - - // and advance to the next offset - P1 += ofs; - est_out += MSZIP_BLOCK; // one decompressed block is 32786 in size - } - - // Allocate storage and terminating zero and do the actual uncompressing - uncompressed.resize(est_out + 1); - char* out = &uncompressed.front(); - while (P + 3 < End) - { - uint16_t ofs = *((uint16_t*)P); - AI_SWAP2(ofs); - P += 4; - - if (P + ofs > End + 2) { - throw DeadlyImportError("X: Unexpected EOF in compressed chunk"); - } - - // push data to the stream - stream.next_in = (Bytef*)P; - stream.avail_in = ofs; - stream.next_out = (Bytef*)out; - stream.avail_out = MSZIP_BLOCK; - - // and decompress the data .... - int ret = ::inflate( &stream, Z_SYNC_FLUSH ); - if (ret != Z_OK && ret != Z_STREAM_END) - throw DeadlyImportError("X: Failed to decompress MSZIP-compressed data"); - - ::inflateReset( &stream ); - ::inflateSetDictionary( &stream, (const Bytef*)out , MSZIP_BLOCK - stream.avail_out ); - - // and advance to the next offset - out += MSZIP_BLOCK - stream.avail_out; - P += ofs; - } - - // terminate zlib - ::inflateEnd(&stream); - - // ok, update pointers to point to the uncompressed file data - P = &uncompressed[0]; - End = out; - - // FIXME: we don't need the compressed data anymore, could release - // it already for better memory usage. Consider breaking const-co. - DefaultLogger::get()->info("Successfully decompressed MSZIP-compressed file"); -#endif // !! ASSIMP_BUILD_NO_COMPRESSED_X - } - else - { - // start reading here - ReadUntilEndOfLine(); - } - - mScene = new Scene; - ParseFile(); - - // filter the imported hierarchy for some degenerated cases - if( mScene->mRootNode) { - FilterHierarchy( mScene->mRootNode); - } -} - -// ------------------------------------------------------------------------------------------------ -// Destructor. Destroys all imported data along with it -XFileParser::~XFileParser() -{ - // kill everything we created - delete mScene; -} - -// ------------------------------------------------------------------------------------------------ -void XFileParser::ParseFile() -{ - bool running = true; - while( running ) - { - // read name of next object - std::string objectName = GetNextToken(); - if (objectName.length() == 0) - break; - - // parse specific object - if( objectName == "template") - ParseDataObjectTemplate(); - else - if( objectName == "Frame") - ParseDataObjectFrame( NULL); - else - if( objectName == "Mesh") - { - // some meshes have no frames at all - Mesh* mesh = new Mesh; - ParseDataObjectMesh( mesh); - mScene->mGlobalMeshes.push_back( mesh); - } else - if( objectName == "AnimTicksPerSecond") - ParseDataObjectAnimTicksPerSecond(); - else - if( objectName == "AnimationSet") - ParseDataObjectAnimationSet(); - else - if( objectName == "Material") - { - // Material outside of a mesh or node - Material material; - ParseDataObjectMaterial( &material); - mScene->mGlobalMaterials.push_back( material); - } else - if( objectName == "}") - { - // whatever? - DefaultLogger::get()->warn("} found in dataObject"); - } else - { - // unknown format - DefaultLogger::get()->warn("Unknown data object in animation of .x file"); - ParseUnknownDataObject(); - } - } -} - -// ------------------------------------------------------------------------------------------------ -void XFileParser::ParseDataObjectTemplate() -{ - // parse a template data object. Currently not stored. - std::string name; - readHeadOfDataObject( &name); - - // read GUID - std::string guid = GetNextToken(); - - // read and ignore data members - bool running = true; - while ( running ) - { - std::string s = GetNextToken(); - - if( s == "}") - break; - - if( s.length() == 0) - ThrowException( "Unexpected end of file reached while parsing template definition"); - } -} - -// ------------------------------------------------------------------------------------------------ -void XFileParser::ParseDataObjectFrame( Node* pParent) -{ - // A coordinate frame, or "frame of reference." The Frame template - // is open and can contain any object. The Direct3D extensions (D3DX) - // mesh-loading functions recognize Mesh, FrameTransformMatrix, and - // Frame template instances as child objects when loading a Frame - // instance. - std::string name; - readHeadOfDataObject(&name); - - // create a named node and place it at its parent, if given - Node* node = new Node( pParent); - node->mName = name; - if( pParent) - { - pParent->mChildren.push_back( node); - } else - { - // there might be multiple root nodes - if( mScene->mRootNode != NULL) - { - // place a dummy root if not there - if( mScene->mRootNode->mName != "$dummy_root") - { - Node* exroot = mScene->mRootNode; - mScene->mRootNode = new Node( NULL); - mScene->mRootNode->mName = "$dummy_root"; - mScene->mRootNode->mChildren.push_back( exroot); - exroot->mParent = mScene->mRootNode; - } - // put the new node as its child instead - mScene->mRootNode->mChildren.push_back( node); - node->mParent = mScene->mRootNode; - } else - { - // it's the first node imported. place it as root - mScene->mRootNode = node; - } - } - - // Now inside a frame. - // read tokens until closing brace is reached. - bool running = true; - while ( running ) - { - std::string objectName = GetNextToken(); - if (objectName.size() == 0) - ThrowException( "Unexpected end of file reached while parsing frame"); - - if( objectName == "}") - break; // frame finished - else - if( objectName == "Frame") - ParseDataObjectFrame( node); // child frame - else - if( objectName == "FrameTransformMatrix") - ParseDataObjectTransformationMatrix( node->mTrafoMatrix); - else - if( objectName == "Mesh") - { - Mesh* mesh = new Mesh(name); - node->mMeshes.push_back( mesh); - ParseDataObjectMesh( mesh); - } else - { - DefaultLogger::get()->warn("Unknown data object in frame in x file"); - ParseUnknownDataObject(); - } - } -} - -// ------------------------------------------------------------------------------------------------ -void XFileParser::ParseDataObjectTransformationMatrix( aiMatrix4x4& pMatrix) -{ - // read header, we're not interested if it has a name - readHeadOfDataObject(); - - // read its components - pMatrix.a1 = ReadFloat(); pMatrix.b1 = ReadFloat(); - pMatrix.c1 = ReadFloat(); pMatrix.d1 = ReadFloat(); - pMatrix.a2 = ReadFloat(); pMatrix.b2 = ReadFloat(); - pMatrix.c2 = ReadFloat(); pMatrix.d2 = ReadFloat(); - pMatrix.a3 = ReadFloat(); pMatrix.b3 = ReadFloat(); - pMatrix.c3 = ReadFloat(); pMatrix.d3 = ReadFloat(); - pMatrix.a4 = ReadFloat(); pMatrix.b4 = ReadFloat(); - pMatrix.c4 = ReadFloat(); pMatrix.d4 = ReadFloat(); - - // trailing symbols - CheckForSemicolon(); - CheckForClosingBrace(); -} - -// ------------------------------------------------------------------------------------------------ -void XFileParser::ParseDataObjectMesh( Mesh* pMesh) -{ - std::string name; - readHeadOfDataObject( &name); - - // read vertex count - unsigned int numVertices = ReadInt(); - pMesh->mPositions.resize( numVertices); - - // read vertices - for( unsigned int a = 0; a < numVertices; a++) - pMesh->mPositions[a] = ReadVector3(); - - // read position faces - unsigned int numPosFaces = ReadInt(); - pMesh->mPosFaces.resize( numPosFaces); - for( unsigned int a = 0; a < numPosFaces; a++) - { - // read indices - unsigned int numIndices = ReadInt(); - Face& face = pMesh->mPosFaces[a]; - for (unsigned int b = 0; b < numIndices; b++) { - face.mIndices.push_back( ReadInt() ); - } - TestForSeparator(); - } - - // here, other data objects may follow - bool running = true; - while ( running ) - { - std::string objectName = GetNextToken(); - - if( objectName.size() == 0) - ThrowException( "Unexpected end of file while parsing mesh structure"); - else - if( objectName == "}") - break; // mesh finished - else - if( objectName == "MeshNormals") - ParseDataObjectMeshNormals( pMesh); - else - if( objectName == "MeshTextureCoords") - ParseDataObjectMeshTextureCoords( pMesh); - else - if( objectName == "MeshVertexColors") - ParseDataObjectMeshVertexColors( pMesh); - else - if( objectName == "MeshMaterialList") - ParseDataObjectMeshMaterialList( pMesh); - else - if( objectName == "VertexDuplicationIndices") - ParseUnknownDataObject(); // we'll ignore vertex duplication indices - else - if( objectName == "XSkinMeshHeader") - ParseDataObjectSkinMeshHeader( pMesh); - else - if( objectName == "SkinWeights") - ParseDataObjectSkinWeights( pMesh); - else - { - DefaultLogger::get()->warn("Unknown data object in mesh in x file"); - ParseUnknownDataObject(); - } - } -} - -// ------------------------------------------------------------------------------------------------ -void XFileParser::ParseDataObjectSkinWeights( Mesh *pMesh) -{ - readHeadOfDataObject(); - - std::string transformNodeName; - GetNextTokenAsString( transformNodeName); - - pMesh->mBones.push_back( Bone()); - Bone& bone = pMesh->mBones.back(); - bone.mName = transformNodeName; - - // read vertex weights - unsigned int numWeights = ReadInt(); - bone.mWeights.reserve( numWeights); - - for( unsigned int a = 0; a < numWeights; a++) - { - BoneWeight weight; - weight.mVertex = ReadInt(); - bone.mWeights.push_back( weight); - } - - // read vertex weights - for( unsigned int a = 0; a < numWeights; a++) - bone.mWeights[a].mWeight = ReadFloat(); - - // read matrix offset - bone.mOffsetMatrix.a1 = ReadFloat(); bone.mOffsetMatrix.b1 = ReadFloat(); - bone.mOffsetMatrix.c1 = ReadFloat(); bone.mOffsetMatrix.d1 = ReadFloat(); - bone.mOffsetMatrix.a2 = ReadFloat(); bone.mOffsetMatrix.b2 = ReadFloat(); - bone.mOffsetMatrix.c2 = ReadFloat(); bone.mOffsetMatrix.d2 = ReadFloat(); - bone.mOffsetMatrix.a3 = ReadFloat(); bone.mOffsetMatrix.b3 = ReadFloat(); - bone.mOffsetMatrix.c3 = ReadFloat(); bone.mOffsetMatrix.d3 = ReadFloat(); - bone.mOffsetMatrix.a4 = ReadFloat(); bone.mOffsetMatrix.b4 = ReadFloat(); - bone.mOffsetMatrix.c4 = ReadFloat(); bone.mOffsetMatrix.d4 = ReadFloat(); - - CheckForSemicolon(); - CheckForClosingBrace(); -} - -// ------------------------------------------------------------------------------------------------ -void XFileParser::ParseDataObjectSkinMeshHeader( Mesh* /*pMesh*/ ) -{ - readHeadOfDataObject(); - - /*unsigned int maxSkinWeightsPerVertex =*/ ReadInt(); - /*unsigned int maxSkinWeightsPerFace =*/ ReadInt(); - /*unsigned int numBonesInMesh = */ReadInt(); - - CheckForClosingBrace(); -} - -// ------------------------------------------------------------------------------------------------ -void XFileParser::ParseDataObjectMeshNormals( Mesh* pMesh) -{ - readHeadOfDataObject(); - - // read count - unsigned int numNormals = ReadInt(); - pMesh->mNormals.resize( numNormals); - - // read normal vectors - for( unsigned int a = 0; a < numNormals; a++) - pMesh->mNormals[a] = ReadVector3(); - - // read normal indices - unsigned int numFaces = ReadInt(); - if( numFaces != pMesh->mPosFaces.size()) - ThrowException( "Normal face count does not match vertex face count."); - - for( unsigned int a = 0; a < numFaces; a++) - { - unsigned int numIndices = ReadInt(); - pMesh->mNormFaces.push_back( Face()); - Face& face = pMesh->mNormFaces.back(); - - for( unsigned int b = 0; b < numIndices; b++) - face.mIndices.push_back( ReadInt()); - - TestForSeparator(); - } - - CheckForClosingBrace(); -} - -// ------------------------------------------------------------------------------------------------ -void XFileParser::ParseDataObjectMeshTextureCoords( Mesh* pMesh) -{ - readHeadOfDataObject(); - if( pMesh->mNumTextures + 1 > AI_MAX_NUMBER_OF_TEXTURECOORDS) - ThrowException( "Too many sets of texture coordinates"); - - std::vector<aiVector2D>& coords = pMesh->mTexCoords[pMesh->mNumTextures++]; - - unsigned int numCoords = ReadInt(); - if( numCoords != pMesh->mPositions.size()) - ThrowException( "Texture coord count does not match vertex count"); - - coords.resize( numCoords); - for( unsigned int a = 0; a < numCoords; a++) - coords[a] = ReadVector2(); - - CheckForClosingBrace(); -} - -// ------------------------------------------------------------------------------------------------ -void XFileParser::ParseDataObjectMeshVertexColors( Mesh* pMesh) -{ - readHeadOfDataObject(); - if( pMesh->mNumColorSets + 1 > AI_MAX_NUMBER_OF_COLOR_SETS) - ThrowException( "Too many colorsets"); - std::vector<aiColor4D>& colors = pMesh->mColors[pMesh->mNumColorSets++]; - - unsigned int numColors = ReadInt(); - if( numColors != pMesh->mPositions.size()) - ThrowException( "Vertex color count does not match vertex count"); - - colors.resize( numColors, aiColor4D( 0, 0, 0, 1)); - for( unsigned int a = 0; a < numColors; a++) - { - unsigned int index = ReadInt(); - if( index >= pMesh->mPositions.size()) - ThrowException( "Vertex color index out of bounds"); - - colors[index] = ReadRGBA(); - // HACK: (thom) Maxon Cinema XPort plugin puts a third separator here, kwxPort puts a comma. - // Ignore gracefully. - if( !mIsBinaryFormat) - { - FindNextNoneWhiteSpace(); - if( *P == ';' || *P == ',') - P++; - } - } - - CheckForClosingBrace(); -} - -// ------------------------------------------------------------------------------------------------ -void XFileParser::ParseDataObjectMeshMaterialList( Mesh* pMesh) -{ - readHeadOfDataObject(); - - // read material count - /*unsigned int numMaterials =*/ ReadInt(); - // read non triangulated face material index count - unsigned int numMatIndices = ReadInt(); - - // some models have a material index count of 1... to be able to read them we - // replicate this single material index on every face - if( numMatIndices != pMesh->mPosFaces.size() && numMatIndices != 1) - ThrowException( "Per-Face material index count does not match face count."); - - // read per-face material indices - for( unsigned int a = 0; a < numMatIndices; a++) - pMesh->mFaceMaterials.push_back( ReadInt()); - - // in version 03.02, the face indices end with two semicolons. - // commented out version check, as version 03.03 exported from blender also has 2 semicolons - if( !mIsBinaryFormat) // && MajorVersion == 3 && MinorVersion <= 2) - { - if(P < End && *P == ';') - ++P; - } - - // if there was only a single material index, replicate it on all faces - while( pMesh->mFaceMaterials.size() < pMesh->mPosFaces.size()) - pMesh->mFaceMaterials.push_back( pMesh->mFaceMaterials.front()); - - // read following data objects - bool running = true; - while ( running ) - { - std::string objectName = GetNextToken(); - if( objectName.size() == 0) - ThrowException( "Unexpected end of file while parsing mesh material list."); - else - if( objectName == "}") - break; // material list finished - else - if( objectName == "{") - { - // template materials - std::string matName = GetNextToken(); - Material material; - material.mIsReference = true; - material.mName = matName; - pMesh->mMaterials.push_back( material); - - CheckForClosingBrace(); // skip } - } else - if( objectName == "Material") - { - pMesh->mMaterials.push_back( Material()); - ParseDataObjectMaterial( &pMesh->mMaterials.back()); - } else - if( objectName == ";") - { - // ignore - } else - { - DefaultLogger::get()->warn("Unknown data object in material list in x file"); - ParseUnknownDataObject(); - } - } -} - -// ------------------------------------------------------------------------------------------------ -void XFileParser::ParseDataObjectMaterial( Material* pMaterial) -{ - std::string matName; - readHeadOfDataObject( &matName); - if( matName.empty()) - matName = std::string( "material") + to_string( mLineNumber ); - pMaterial->mName = matName; - pMaterial->mIsReference = false; - - // read material values - pMaterial->mDiffuse = ReadRGBA(); - pMaterial->mSpecularExponent = ReadFloat(); - pMaterial->mSpecular = ReadRGB(); - pMaterial->mEmissive = ReadRGB(); - - // read other data objects - bool running = true; - while ( running ) - { - std::string objectName = GetNextToken(); - if( objectName.size() == 0) - ThrowException( "Unexpected end of file while parsing mesh material"); - else - if( objectName == "}") - break; // material finished - else - if( objectName == "TextureFilename" || objectName == "TextureFileName") - { - // some exporters write "TextureFileName" instead. - std::string texname; - ParseDataObjectTextureFilename( texname); - pMaterial->mTextures.push_back( TexEntry( texname)); - } else - if( objectName == "NormalmapFilename" || objectName == "NormalmapFileName") - { - // one exporter writes out the normal map in a separate filename tag - std::string texname; - ParseDataObjectTextureFilename( texname); - pMaterial->mTextures.push_back( TexEntry( texname, true)); - } else - { - DefaultLogger::get()->warn("Unknown data object in material in x file"); - ParseUnknownDataObject(); - } - } -} - -// ------------------------------------------------------------------------------------------------ -void XFileParser::ParseDataObjectAnimTicksPerSecond() -{ - readHeadOfDataObject(); - mScene->mAnimTicksPerSecond = ReadInt(); - CheckForClosingBrace(); -} - -// ------------------------------------------------------------------------------------------------ -void XFileParser::ParseDataObjectAnimationSet() -{ - std::string animName; - readHeadOfDataObject( &animName); - - Animation* anim = new Animation; - mScene->mAnims.push_back( anim); - anim->mName = animName; - - bool running = true; - while ( running ) - { - std::string objectName = GetNextToken(); - if( objectName.length() == 0) - ThrowException( "Unexpected end of file while parsing animation set."); - else - if( objectName == "}") - break; // animation set finished - else - if( objectName == "Animation") - ParseDataObjectAnimation( anim); - else - { - DefaultLogger::get()->warn("Unknown data object in animation set in x file"); - ParseUnknownDataObject(); - } - } -} - -// ------------------------------------------------------------------------------------------------ -void XFileParser::ParseDataObjectAnimation( Animation* pAnim) -{ - readHeadOfDataObject(); - AnimBone* banim = new AnimBone; - pAnim->mAnims.push_back( banim); - - bool running = true; - while( running ) - { - std::string objectName = GetNextToken(); - - if( objectName.length() == 0) - ThrowException( "Unexpected end of file while parsing animation."); - else - if( objectName == "}") - break; // animation finished - else - if( objectName == "AnimationKey") - ParseDataObjectAnimationKey( banim); - else - if( objectName == "AnimationOptions") - ParseUnknownDataObject(); // not interested - else - if( objectName == "{") - { - // read frame name - banim->mBoneName = GetNextToken(); - CheckForClosingBrace(); - } else - { - DefaultLogger::get()->warn("Unknown data object in animation in x file"); - ParseUnknownDataObject(); - } - } -} - -// ------------------------------------------------------------------------------------------------ -void XFileParser::ParseDataObjectAnimationKey( AnimBone* pAnimBone) -{ - readHeadOfDataObject(); - - // read key type - unsigned int keyType = ReadInt(); - - // read number of keys - unsigned int numKeys = ReadInt(); - - for( unsigned int a = 0; a < numKeys; a++) - { - // read time - unsigned int time = ReadInt(); - - // read keys - switch( keyType) - { - case 0: // rotation quaternion - { - // read count - if( ReadInt() != 4) - ThrowException( "Invalid number of arguments for quaternion key in animation"); - - aiQuatKey key; - key.mTime = double( time); - key.mValue.w = ReadFloat(); - key.mValue.x = ReadFloat(); - key.mValue.y = ReadFloat(); - key.mValue.z = ReadFloat(); - pAnimBone->mRotKeys.push_back( key); - - CheckForSemicolon(); - break; - } - - case 1: // scale vector - case 2: // position vector - { - // read count - if( ReadInt() != 3) - ThrowException( "Invalid number of arguments for vector key in animation"); - - aiVectorKey key; - key.mTime = double( time); - key.mValue = ReadVector3(); - - if( keyType == 2) - pAnimBone->mPosKeys.push_back( key); - else - pAnimBone->mScaleKeys.push_back( key); - - break; - } - - case 3: // combined transformation matrix - case 4: // denoted both as 3 or as 4 - { - // read count - if( ReadInt() != 16) - ThrowException( "Invalid number of arguments for matrix key in animation"); - - // read matrix - MatrixKey key; - key.mTime = double( time); - key.mMatrix.a1 = ReadFloat(); key.mMatrix.b1 = ReadFloat(); - key.mMatrix.c1 = ReadFloat(); key.mMatrix.d1 = ReadFloat(); - key.mMatrix.a2 = ReadFloat(); key.mMatrix.b2 = ReadFloat(); - key.mMatrix.c2 = ReadFloat(); key.mMatrix.d2 = ReadFloat(); - key.mMatrix.a3 = ReadFloat(); key.mMatrix.b3 = ReadFloat(); - key.mMatrix.c3 = ReadFloat(); key.mMatrix.d3 = ReadFloat(); - key.mMatrix.a4 = ReadFloat(); key.mMatrix.b4 = ReadFloat(); - key.mMatrix.c4 = ReadFloat(); key.mMatrix.d4 = ReadFloat(); - pAnimBone->mTrafoKeys.push_back( key); - - CheckForSemicolon(); - break; - } - - default: - ThrowException( format() << "Unknown key type " << keyType << " in animation." ); - break; - } // end switch - - // key separator - CheckForSeparator(); - } - - CheckForClosingBrace(); -} - -// ------------------------------------------------------------------------------------------------ -void XFileParser::ParseDataObjectTextureFilename( std::string& pName) -{ - readHeadOfDataObject(); - GetNextTokenAsString( pName); - CheckForClosingBrace(); - - // FIX: some files (e.g. AnimationTest.x) have "" as texture file name - if (!pName.length()) - { - DefaultLogger::get()->warn("Length of texture file name is zero. Skipping this texture."); - } - - // some exporters write double backslash paths out. We simply replace them if we find them - while( pName.find( "\\\\") != std::string::npos) - pName.replace( pName.find( "\\\\"), 2, "\\"); -} - -// ------------------------------------------------------------------------------------------------ -void XFileParser::ParseUnknownDataObject() -{ - // find opening delimiter - bool running = true; - while( running ) - { - std::string t = GetNextToken(); - if( t.length() == 0) - ThrowException( "Unexpected end of file while parsing unknown segment."); - - if( t == "{") - break; - } - - unsigned int counter = 1; - - // parse until closing delimiter - while( counter > 0) - { - std::string t = GetNextToken(); - - if( t.length() == 0) - ThrowException( "Unexpected end of file while parsing unknown segment."); - - if( t == "{") - ++counter; - else - if( t == "}") - --counter; - } -} - -// ------------------------------------------------------------------------------------------------ -//! checks for closing curly brace -void XFileParser::CheckForClosingBrace() -{ - if( GetNextToken() != "}") - ThrowException( "Closing brace expected."); -} - -// ------------------------------------------------------------------------------------------------ -//! checks for one following semicolon -void XFileParser::CheckForSemicolon() -{ - if( mIsBinaryFormat) - return; - - if( GetNextToken() != ";") - ThrowException( "Semicolon expected."); -} - -// ------------------------------------------------------------------------------------------------ -//! checks for a separator char, either a ',' or a ';' -void XFileParser::CheckForSeparator() -{ - if( mIsBinaryFormat) - return; - - std::string token = GetNextToken(); - if( token != "," && token != ";") - ThrowException( "Separator character (';' or ',') expected."); -} - -// ------------------------------------------------------------------------------------------------ -// tests and possibly consumes a separator char, but does nothing if there was no separator -void XFileParser::TestForSeparator() -{ - if( mIsBinaryFormat) - return; - - FindNextNoneWhiteSpace(); - if( P >= End) - return; - - // test and skip - if( *P == ';' || *P == ',') - P++; -} - -// ------------------------------------------------------------------------------------------------ -void XFileParser::readHeadOfDataObject( std::string* poName) -{ - std::string nameOrBrace = GetNextToken(); - if( nameOrBrace != "{") - { - if( poName) - *poName = nameOrBrace; - - if( GetNextToken() != "{") - ThrowException( "Opening brace expected."); - } -} - -// ------------------------------------------------------------------------------------------------ -std::string XFileParser::GetNextToken() -{ - std::string s; - - // process binary-formatted file - if( mIsBinaryFormat) - { - // in binary mode it will only return NAME and STRING token - // and (correctly) skip over other tokens. - - if( End - P < 2) return s; - unsigned int tok = ReadBinWord(); - unsigned int len; - - // standalone tokens - switch( tok) - { - case 1: - // name token - if( End - P < 4) return s; - len = ReadBinDWord(); - if( End - P < int(len)) return s; - s = std::string(P, len); - P += len; - return s; - case 2: - // string token - if( End - P < 4) return s; - len = ReadBinDWord(); - if( End - P < int(len)) return s; - s = std::string(P, len); - P += (len + 2); - return s; - case 3: - // integer token - P += 4; - return "<integer>"; - case 5: - // GUID token - P += 16; - return "<guid>"; - case 6: - if( End - P < 4) return s; - len = ReadBinDWord(); - P += (len * 4); - return "<int_list>"; - case 7: - if( End - P < 4) return s; - len = ReadBinDWord(); - P += (len * mBinaryFloatSize); - return "<flt_list>"; - case 0x0a: - return "{"; - case 0x0b: - return "}"; - case 0x0c: - return "("; - case 0x0d: - return ")"; - case 0x0e: - return "["; - case 0x0f: - return "]"; - case 0x10: - return "<"; - case 0x11: - return ">"; - case 0x12: - return "."; - case 0x13: - return ","; - case 0x14: - return ";"; - case 0x1f: - return "template"; - case 0x28: - return "WORD"; - case 0x29: - return "DWORD"; - case 0x2a: - return "FLOAT"; - case 0x2b: - return "DOUBLE"; - case 0x2c: - return "CHAR"; - case 0x2d: - return "UCHAR"; - case 0x2e: - return "SWORD"; - case 0x2f: - return "SDWORD"; - case 0x30: - return "void"; - case 0x31: - return "string"; - case 0x32: - return "unicode"; - case 0x33: - return "cstring"; - case 0x34: - return "array"; - } - } - // process text-formatted file - else - { - FindNextNoneWhiteSpace(); - if( P >= End) - return s; - - while( (P < End) && !isspace( (unsigned char) *P)) - { - // either keep token delimiters when already holding a token, or return if first valid char - if( *P == ';' || *P == '}' || *P == '{' || *P == ',') - { - if( !s.size()) - s.append( P++, 1); - break; // stop for delimiter - } - s.append( P++, 1); - } - } - return s; -} - -// ------------------------------------------------------------------------------------------------ -void XFileParser::FindNextNoneWhiteSpace() -{ - if( mIsBinaryFormat) - return; - - bool running = true; - while( running ) - { - while( P < End && isspace( (unsigned char) *P)) - { - if( *P == '\n') - mLineNumber++; - ++P; - } - - if( P >= End) - return; - - // check if this is a comment - if( (P[0] == '/' && P[1] == '/') || P[0] == '#') - ReadUntilEndOfLine(); - else - break; - } -} - -// ------------------------------------------------------------------------------------------------ -void XFileParser::GetNextTokenAsString( std::string& poString) -{ - if( mIsBinaryFormat) - { - poString = GetNextToken(); - return; - } - - FindNextNoneWhiteSpace(); - if( P >= End) - ThrowException( "Unexpected end of file while parsing string"); - - if( *P != '"') - ThrowException( "Expected quotation mark."); - ++P; - - while( P < End && *P != '"') - poString.append( P++, 1); - - if( P >= End-1) - ThrowException( "Unexpected end of file while parsing string"); - - if( P[1] != ';' || P[0] != '"') - ThrowException( "Expected quotation mark and semicolon at the end of a string."); - P+=2; -} - -// ------------------------------------------------------------------------------------------------ -void XFileParser::ReadUntilEndOfLine() -{ - if( mIsBinaryFormat) - return; - - while( P < End) - { - if( *P == '\n' || *P == '\r') - { - ++P; mLineNumber++; - return; - } - - ++P; - } -} - -// ------------------------------------------------------------------------------------------------ -unsigned short XFileParser::ReadBinWord() -{ - ai_assert(End - P >= 2); - const unsigned char* q = (const unsigned char*) P; - unsigned short tmp = q[0] | (q[1] << 8); - P += 2; - return tmp; -} - -// ------------------------------------------------------------------------------------------------ -unsigned int XFileParser::ReadBinDWord() -{ - ai_assert(End - P >= 4); - const unsigned char* q = (const unsigned char*) P; - unsigned int tmp = q[0] | (q[1] << 8) | (q[2] << 16) | (q[3] << 24); - P += 4; - return tmp; -} - -// ------------------------------------------------------------------------------------------------ -unsigned int XFileParser::ReadInt() -{ - if( mIsBinaryFormat) - { - if( mBinaryNumCount == 0 && End - P >= 2) - { - unsigned short tmp = ReadBinWord(); // 0x06 or 0x03 - if( tmp == 0x06 && End - P >= 4) // array of ints follows - mBinaryNumCount = ReadBinDWord(); - else // single int follows - mBinaryNumCount = 1; - } - - --mBinaryNumCount; - if ( End - P >= 4) { - return ReadBinDWord(); - } else { - P = End; - return 0; - } - } else - { - FindNextNoneWhiteSpace(); - - // TODO: consider using strtol10 instead??? - - // check preceding minus sign - bool isNegative = false; - if( *P == '-') - { - isNegative = true; - P++; - } - - // at least one digit expected - if( !isdigit( *P)) - ThrowException( "Number expected."); - - // read digits - unsigned int number = 0; - while( P < End) - { - if( !isdigit( *P)) - break; - number = number * 10 + (*P - 48); - P++; - } - - CheckForSeparator(); - return isNegative ? ((unsigned int) -int( number)) : number; - } -} - -// ------------------------------------------------------------------------------------------------ -ai_real XFileParser::ReadFloat() -{ - if( mIsBinaryFormat) - { - if( mBinaryNumCount == 0 && End - P >= 2) - { - unsigned short tmp = ReadBinWord(); // 0x07 or 0x42 - if( tmp == 0x07 && End - P >= 4) // array of floats following - mBinaryNumCount = ReadBinDWord(); - else // single float following - mBinaryNumCount = 1; - } - - --mBinaryNumCount; - if( mBinaryFloatSize == 8) - { - if( End - P >= 8) { - ai_real result = (ai_real) (*(double*) P); - P += 8; - return result; - } else { - P = End; - return 0; - } - } else - { - if( End - P >= 4) { - ai_real result = *(ai_real*) P; - P += 4; - return result; - } else { - P = End; - return 0; - } - } - } - - // text version - FindNextNoneWhiteSpace(); - // check for various special strings to allow reading files from faulty exporters - // I mean you, Blender! - // Reading is safe because of the terminating zero - if( strncmp( P, "-1.#IND00", 9) == 0 || strncmp( P, "1.#IND00", 8) == 0) - { - P += 9; - CheckForSeparator(); - return 0.0; - } else - if( strncmp( P, "1.#QNAN0", 8) == 0) - { - P += 8; - CheckForSeparator(); - return 0.0; - } - - ai_real result = 0.0; - P = fast_atoreal_move<ai_real>( P, result); - - CheckForSeparator(); - - return result; -} - -// ------------------------------------------------------------------------------------------------ -aiVector2D XFileParser::ReadVector2() -{ - aiVector2D vector; - vector.x = ReadFloat(); - vector.y = ReadFloat(); - TestForSeparator(); - - return vector; -} - -// ------------------------------------------------------------------------------------------------ -aiVector3D XFileParser::ReadVector3() -{ - aiVector3D vector; - vector.x = ReadFloat(); - vector.y = ReadFloat(); - vector.z = ReadFloat(); - TestForSeparator(); - - return vector; -} - -// ------------------------------------------------------------------------------------------------ -aiColor4D XFileParser::ReadRGBA() -{ - aiColor4D color; - color.r = ReadFloat(); - color.g = ReadFloat(); - color.b = ReadFloat(); - color.a = ReadFloat(); - TestForSeparator(); - - return color; -} - -// ------------------------------------------------------------------------------------------------ -aiColor3D XFileParser::ReadRGB() -{ - aiColor3D color; - color.r = ReadFloat(); - color.g = ReadFloat(); - color.b = ReadFloat(); - TestForSeparator(); - - return color; -} - -// ------------------------------------------------------------------------------------------------ -// Throws an exception with a line number and the given text. -AI_WONT_RETURN void XFileParser::ThrowException( const std::string& pText) -{ - if( mIsBinaryFormat) - throw DeadlyImportError( pText); - else - throw DeadlyImportError( format() << "Line " << mLineNumber << ": " << pText ); -} - - -// ------------------------------------------------------------------------------------------------ -// Filters the imported hierarchy for some degenerated cases that some exporters produce. -void XFileParser::FilterHierarchy( XFile::Node* pNode) -{ - // if the node has just a single unnamed child containing a mesh, remove - // the anonymous node between. The 3DSMax kwXport plugin seems to produce this - // mess in some cases - if( pNode->mChildren.size() == 1 && pNode->mMeshes.empty() ) - { - XFile::Node* child = pNode->mChildren.front(); - if( child->mName.length() == 0 && child->mMeshes.size() > 0) - { - // transfer its meshes to us - for( unsigned int a = 0; a < child->mMeshes.size(); a++) - pNode->mMeshes.push_back( child->mMeshes[a]); - child->mMeshes.clear(); - - // transfer the transform as well - pNode->mTrafoMatrix = pNode->mTrafoMatrix * child->mTrafoMatrix; - - // then kill it - delete child; - pNode->mChildren.clear(); - } - } - - // recurse - for( unsigned int a = 0; a < pNode->mChildren.size(); a++) - FilterHierarchy( pNode->mChildren[a]); -} - -#endif // !! ASSIMP_BUILD_NO_X_IMPORTER |