diff options
Diffstat (limited to 'src/3rdparty/assimp/code/CSMLoader.cpp')
-rw-r--r-- | src/3rdparty/assimp/code/CSMLoader.cpp | 443 |
1 files changed, 225 insertions, 218 deletions
diff --git a/src/3rdparty/assimp/code/CSMLoader.cpp b/src/3rdparty/assimp/code/CSMLoader.cpp index c92a3ac79..925abf4bd 100644 --- a/src/3rdparty/assimp/code/CSMLoader.cpp +++ b/src/3rdparty/assimp/code/CSMLoader.cpp @@ -3,12 +3,12 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2012, assimp team +Copyright (c) 2006-2016, 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 +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 @@ -25,16 +25,16 @@ conditions are met: 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 +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 +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 +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 +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. --------------------------------------------------------------------------- */ @@ -43,7 +43,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * Implementation of the CSM importer class. */ -#include "AssimpPCH.h" + #ifndef ASSIMP_BUILD_NO_CSM_IMPORTER @@ -51,20 +51,27 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "SkeletonMeshBuilder.h" #include "ParsingUtils.h" #include "fast_atof.h" +#include <assimp/Importer.hpp> +#include <memory> +#include <assimp/IOSystem.hpp> +#include <assimp/anim.h> +#include <assimp/DefaultLogger.hpp> +#include <assimp/scene.h> + using namespace Assimp; static const aiImporterDesc desc = { - "CharacterStudio Motion Importer (MoCap)", - "", - "", - "", - aiImporterFlags_SupportTextFlavour, - 0, - 0, - 0, - 0, - "csm" + "CharacterStudio Motion Importer (MoCap)", + "", + "", + "", + aiImporterFlags_SupportTextFlavour, + 0, + 0, + 0, + 0, + "csm" }; @@ -75,225 +82,225 @@ CSMImporter::CSMImporter() {} // ------------------------------------------------------------------------------------------------ -// Destructor, private as well +// Destructor, private as well CSMImporter::~CSMImporter() {} // ------------------------------------------------------------------------------------------------ -// Returns whether the class can handle the format of the given file. +// Returns whether the class can handle the format of the given file. bool CSMImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const { - // check file extension - const std::string extension = GetExtension(pFile); - - if( extension == "csm") - return true; - - if ((checkSig || !extension.length()) && pIOHandler) { - const char* tokens[] = {"$Filename"}; - return SearchFileHeaderForToken(pIOHandler,pFile,tokens,1); - } - return false; + // check file extension + const std::string extension = GetExtension(pFile); + + if( extension == "csm") + return true; + + if ((checkSig || !extension.length()) && pIOHandler) { + const char* tokens[] = {"$Filename"}; + return SearchFileHeaderForToken(pIOHandler,pFile,tokens,1); + } + return false; } // ------------------------------------------------------------------------------------------------ // Build a string of all file extensions supported const aiImporterDesc* CSMImporter::GetInfo () const { - return &desc; + return &desc; } // ------------------------------------------------------------------------------------------------ // Setup configuration properties for the loader void CSMImporter::SetupProperties(const Importer* pImp) { - noSkeletonMesh = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_NO_SKELETON_MESHES,0) != 0; + noSkeletonMesh = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_NO_SKELETON_MESHES,0) != 0; } // ------------------------------------------------------------------------------------------------ -// Imports the given file into the given scene structure. -void CSMImporter::InternReadFile( const std::string& pFile, - aiScene* pScene, IOSystem* pIOHandler) +// Imports the given file into the given scene structure. +void CSMImporter::InternReadFile( const std::string& pFile, + aiScene* pScene, IOSystem* pIOHandler) { - boost::scoped_ptr<IOStream> file( pIOHandler->Open( pFile, "rb")); - - // Check whether we can read from the file - if( file.get() == NULL) { - throw DeadlyImportError( "Failed to open CSM file " + pFile + "."); - } - - // allocate storage and copy the contents of the file to a memory buffer - std::vector<char> mBuffer2; - TextFileToBuffer(file.get(),mBuffer2); - const char* buffer = &mBuffer2[0]; - - aiAnimation* anim = new aiAnimation(); - int first = 0, last = 0x00ffffff; - - // now process the file and look out for '$' sections - while (1) { - SkipSpaces(&buffer); - if ('\0' == *buffer) - break; - - if ('$' == *buffer) { - ++buffer; - if (TokenMatchI(buffer,"firstframe",10)) { - SkipSpaces(&buffer); - first = strtol10(buffer,&buffer); - } - else if (TokenMatchI(buffer,"lastframe",9)) { - SkipSpaces(&buffer); - last = strtol10(buffer,&buffer); - } - else if (TokenMatchI(buffer,"rate",4)) { - SkipSpaces(&buffer); - float d; - buffer = fast_atoreal_move<float>(buffer,d); - anim->mTicksPerSecond = d; - } - else if (TokenMatchI(buffer,"order",5)) { - std::vector< aiNodeAnim* > anims_temp; - anims_temp.reserve(30); - while (1) { - SkipSpaces(&buffer); - if (IsLineEnd(*buffer) && SkipSpacesAndLineEnd(&buffer) && *buffer == '$') - break; // next section - - // Construct a new node animation channel and setup its name - anims_temp.push_back(new aiNodeAnim()); - aiNodeAnim* nda = anims_temp.back(); - - char* ot = nda->mNodeName.data; - while (!IsSpaceOrNewLine(*buffer)) - *ot++ = *buffer++; - - *ot = '\0'; - nda->mNodeName.length = (size_t)(ot-nda->mNodeName.data); - } - - anim->mNumChannels = anims_temp.size(); - if (!anim->mNumChannels) - throw DeadlyImportError("CSM: Empty $order section"); - - // copy over to the output animation - anim->mChannels = new aiNodeAnim*[anim->mNumChannels]; - ::memcpy(anim->mChannels,&anims_temp[0],sizeof(aiNodeAnim*)*anim->mNumChannels); - } - else if (TokenMatchI(buffer,"points",6)) { - if (!anim->mNumChannels) - throw DeadlyImportError("CSM: \'$order\' section is required to appear prior to \'$points\'"); - - // If we know how many frames we'll read, we can preallocate some storage - unsigned int alloc = 100; - if (last != 0x00ffffff) - { - alloc = last-first; - alloc += alloc>>2u; // + 25% - for (unsigned int i = 0; i < anim->mNumChannels;++i) - anim->mChannels[i]->mPositionKeys = new aiVectorKey[alloc]; - } - - unsigned int filled = 0; - - // Now read all point data. - while (1) { - SkipSpaces(&buffer); - if (IsLineEnd(*buffer) && (!SkipSpacesAndLineEnd(&buffer) || *buffer == '$')) { - break; // next section - } - - // read frame - const int frame = ::strtoul10(buffer,&buffer); - last = std::max(frame,last); - first = std::min(frame,last); - for (unsigned int i = 0; i < anim->mNumChannels;++i) { - - aiNodeAnim* s = anim->mChannels[i]; - if (s->mNumPositionKeys == alloc) { /* need to reallocate? */ - - aiVectorKey* old = s->mPositionKeys; - s->mPositionKeys = new aiVectorKey[s->mNumPositionKeys = alloc*2]; - ::memcpy(s->mPositionKeys,old,sizeof(aiVectorKey)*alloc); - delete[] old; - } - - // read x,y,z - if(!SkipSpacesAndLineEnd(&buffer)) - throw DeadlyImportError("CSM: Unexpected EOF occured reading sample x coord"); - - if (TokenMatchI(buffer, "DROPOUT", 7)) { - // seems this is invalid marker data; at least the doc says it's possible - DefaultLogger::get()->warn("CSM: Encountered invalid marker data (DROPOUT)"); - } - else { - aiVectorKey* sub = s->mPositionKeys + s->mNumPositionKeys; - sub->mTime = (double)frame; - buffer = fast_atoreal_move<float>(buffer, (float&)sub->mValue.x); - - if(!SkipSpacesAndLineEnd(&buffer)) - throw DeadlyImportError("CSM: Unexpected EOF occured reading sample y coord"); - buffer = fast_atoreal_move<float>(buffer, (float&)sub->mValue.y); - - if(!SkipSpacesAndLineEnd(&buffer)) - throw DeadlyImportError("CSM: Unexpected EOF occured reading sample z coord"); - buffer = fast_atoreal_move<float>(buffer, (float&)sub->mValue.z); - - ++s->mNumPositionKeys; - } - } - - // update allocation granularity - if (filled == alloc) - alloc *= 2; - - ++filled; - } - // all channels must be complete in order to continue safely. - for (unsigned int i = 0; i < anim->mNumChannels;++i) { - - if (!anim->mChannels[i]->mNumPositionKeys) - throw DeadlyImportError("CSM: Invalid marker track"); - } - } - } - else { - // advance to the next line - SkipLine(&buffer); - } - } - - // Setup a proper animation duration - anim->mDuration = last - std::min( first, 0 ); - - // build a dummy root node with the tiny markers as children - pScene->mRootNode = new aiNode(); - pScene->mRootNode->mName.Set("$CSM_DummyRoot"); - - pScene->mRootNode->mNumChildren = anim->mNumChannels; - pScene->mRootNode->mChildren = new aiNode* [anim->mNumChannels]; - - for (unsigned int i = 0; i < anim->mNumChannels;++i) { - aiNodeAnim* na = anim->mChannels[i]; - - aiNode* nd = pScene->mRootNode->mChildren[i] = new aiNode(); - nd->mName = anim->mChannels[i]->mNodeName; - nd->mParent = pScene->mRootNode; - - aiMatrix4x4::Translation(na->mPositionKeys[0].mValue, nd->mTransformation); - } - - // Store the one and only animation in the scene - pScene->mAnimations = new aiAnimation*[pScene->mNumAnimations=1]; - pScene->mAnimations[0] = anim; - anim->mName.Set("$CSM_MasterAnim"); - - // mark the scene as incomplete and run SkeletonMeshBuilder on it - pScene->mFlags |= AI_SCENE_FLAGS_INCOMPLETE; - - if (!noSkeletonMesh) { - SkeletonMeshBuilder maker(pScene,pScene->mRootNode,true); - } + std::unique_ptr<IOStream> file( pIOHandler->Open( pFile, "rb")); + + // Check whether we can read from the file + if( file.get() == NULL) { + throw DeadlyImportError( "Failed to open CSM file " + pFile + "."); + } + + // allocate storage and copy the contents of the file to a memory buffer + std::vector<char> mBuffer2; + TextFileToBuffer(file.get(),mBuffer2); + const char* buffer = &mBuffer2[0]; + + aiAnimation* anim = new aiAnimation(); + int first = 0, last = 0x00ffffff; + + // now process the file and look out for '$' sections + while (1) { + SkipSpaces(&buffer); + if ('\0' == *buffer) + break; + + if ('$' == *buffer) { + ++buffer; + if (TokenMatchI(buffer,"firstframe",10)) { + SkipSpaces(&buffer); + first = strtol10(buffer,&buffer); + } + else if (TokenMatchI(buffer,"lastframe",9)) { + SkipSpaces(&buffer); + last = strtol10(buffer,&buffer); + } + else if (TokenMatchI(buffer,"rate",4)) { + SkipSpaces(&buffer); + float d; + buffer = fast_atoreal_move<float>(buffer,d); + anim->mTicksPerSecond = d; + } + else if (TokenMatchI(buffer,"order",5)) { + std::vector< aiNodeAnim* > anims_temp; + anims_temp.reserve(30); + while (1) { + SkipSpaces(&buffer); + if (IsLineEnd(*buffer) && SkipSpacesAndLineEnd(&buffer) && *buffer == '$') + break; // next section + + // Construct a new node animation channel and setup its name + anims_temp.push_back(new aiNodeAnim()); + aiNodeAnim* nda = anims_temp.back(); + + char* ot = nda->mNodeName.data; + while (!IsSpaceOrNewLine(*buffer)) + *ot++ = *buffer++; + + *ot = '\0'; + nda->mNodeName.length = (size_t)(ot-nda->mNodeName.data); + } + + anim->mNumChannels = anims_temp.size(); + if (!anim->mNumChannels) + throw DeadlyImportError("CSM: Empty $order section"); + + // copy over to the output animation + anim->mChannels = new aiNodeAnim*[anim->mNumChannels]; + ::memcpy(anim->mChannels,&anims_temp[0],sizeof(aiNodeAnim*)*anim->mNumChannels); + } + else if (TokenMatchI(buffer,"points",6)) { + if (!anim->mNumChannels) + throw DeadlyImportError("CSM: \'$order\' section is required to appear prior to \'$points\'"); + + // If we know how many frames we'll read, we can preallocate some storage + unsigned int alloc = 100; + if (last != 0x00ffffff) + { + alloc = last-first; + alloc += alloc>>2u; // + 25% + for (unsigned int i = 0; i < anim->mNumChannels;++i) + anim->mChannels[i]->mPositionKeys = new aiVectorKey[alloc]; + } + + unsigned int filled = 0; + + // Now read all point data. + while (1) { + SkipSpaces(&buffer); + if (IsLineEnd(*buffer) && (!SkipSpacesAndLineEnd(&buffer) || *buffer == '$')) { + break; // next section + } + + // read frame + const int frame = ::strtoul10(buffer,&buffer); + last = std::max(frame,last); + first = std::min(frame,last); + for (unsigned int i = 0; i < anim->mNumChannels;++i) { + + aiNodeAnim* s = anim->mChannels[i]; + if (s->mNumPositionKeys == alloc) { /* need to reallocate? */ + + aiVectorKey* old = s->mPositionKeys; + s->mPositionKeys = new aiVectorKey[s->mNumPositionKeys = alloc*2]; + ::memcpy(s->mPositionKeys,old,sizeof(aiVectorKey)*alloc); + delete[] old; + } + + // read x,y,z + if(!SkipSpacesAndLineEnd(&buffer)) + throw DeadlyImportError("CSM: Unexpected EOF occurred reading sample x coord"); + + if (TokenMatchI(buffer, "DROPOUT", 7)) { + // seems this is invalid marker data; at least the doc says it's possible + DefaultLogger::get()->warn("CSM: Encountered invalid marker data (DROPOUT)"); + } + else { + aiVectorKey* sub = s->mPositionKeys + s->mNumPositionKeys; + sub->mTime = (double)frame; + buffer = fast_atoreal_move<float>(buffer, (float&)sub->mValue.x); + + if(!SkipSpacesAndLineEnd(&buffer)) + throw DeadlyImportError("CSM: Unexpected EOF occurred reading sample y coord"); + buffer = fast_atoreal_move<float>(buffer, (float&)sub->mValue.y); + + if(!SkipSpacesAndLineEnd(&buffer)) + throw DeadlyImportError("CSM: Unexpected EOF occurred reading sample z coord"); + buffer = fast_atoreal_move<float>(buffer, (float&)sub->mValue.z); + + ++s->mNumPositionKeys; + } + } + + // update allocation granularity + if (filled == alloc) + alloc *= 2; + + ++filled; + } + // all channels must be complete in order to continue safely. + for (unsigned int i = 0; i < anim->mNumChannels;++i) { + + if (!anim->mChannels[i]->mNumPositionKeys) + throw DeadlyImportError("CSM: Invalid marker track"); + } + } + } + else { + // advance to the next line + SkipLine(&buffer); + } + } + + // Setup a proper animation duration + anim->mDuration = last - std::min( first, 0 ); + + // build a dummy root node with the tiny markers as children + pScene->mRootNode = new aiNode(); + pScene->mRootNode->mName.Set("$CSM_DummyRoot"); + + pScene->mRootNode->mNumChildren = anim->mNumChannels; + pScene->mRootNode->mChildren = new aiNode* [anim->mNumChannels]; + + for (unsigned int i = 0; i < anim->mNumChannels;++i) { + aiNodeAnim* na = anim->mChannels[i]; + + aiNode* nd = pScene->mRootNode->mChildren[i] = new aiNode(); + nd->mName = anim->mChannels[i]->mNodeName; + nd->mParent = pScene->mRootNode; + + aiMatrix4x4::Translation(na->mPositionKeys[0].mValue, nd->mTransformation); + } + + // Store the one and only animation in the scene + pScene->mAnimations = new aiAnimation*[pScene->mNumAnimations=1]; + pScene->mAnimations[0] = anim; + anim->mName.Set("$CSM_MasterAnim"); + + // mark the scene as incomplete and run SkeletonMeshBuilder on it + pScene->mFlags |= AI_SCENE_FLAGS_INCOMPLETE; + + if (!noSkeletonMesh) { + SkeletonMeshBuilder maker(pScene,pScene->mRootNode,true); + } } #endif // !! ASSIMP_BUILD_NO_CSM_IMPORTER |