vrshoot
diff libs/assimp/CSMLoader.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/CSMLoader.cpp Sat Feb 01 19:58:19 2014 +0200 1.3 @@ -0,0 +1,299 @@ 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 CSMLoader.cpp 1.46 + * Implementation of the CSM importer class. 1.47 + */ 1.48 + 1.49 +#include "AssimpPCH.h" 1.50 + 1.51 +#ifndef ASSIMP_BUILD_NO_CSM_IMPORTER 1.52 + 1.53 +#include "CSMLoader.h" 1.54 +#include "SkeletonMeshBuilder.h" 1.55 +#include "ParsingUtils.h" 1.56 +#include "fast_atof.h" 1.57 + 1.58 +using namespace Assimp; 1.59 + 1.60 +static const aiImporterDesc desc = { 1.61 + "CharacterStudio Motion Importer (MoCap)", 1.62 + "", 1.63 + "", 1.64 + "", 1.65 + aiImporterFlags_SupportTextFlavour, 1.66 + 0, 1.67 + 0, 1.68 + 0, 1.69 + 0, 1.70 + "csm" 1.71 +}; 1.72 + 1.73 + 1.74 +// ------------------------------------------------------------------------------------------------ 1.75 +// Constructor to be privately used by Importer 1.76 +CSMImporter::CSMImporter() 1.77 +: noSkeletonMesh() 1.78 +{} 1.79 + 1.80 +// ------------------------------------------------------------------------------------------------ 1.81 +// Destructor, private as well 1.82 +CSMImporter::~CSMImporter() 1.83 +{} 1.84 + 1.85 +// ------------------------------------------------------------------------------------------------ 1.86 +// Returns whether the class can handle the format of the given file. 1.87 +bool CSMImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const 1.88 +{ 1.89 + // check file extension 1.90 + const std::string extension = GetExtension(pFile); 1.91 + 1.92 + if( extension == "csm") 1.93 + return true; 1.94 + 1.95 + if ((checkSig || !extension.length()) && pIOHandler) { 1.96 + const char* tokens[] = {"$Filename"}; 1.97 + return SearchFileHeaderForToken(pIOHandler,pFile,tokens,1); 1.98 + } 1.99 + return false; 1.100 +} 1.101 + 1.102 +// ------------------------------------------------------------------------------------------------ 1.103 +// Build a string of all file extensions supported 1.104 +const aiImporterDesc* CSMImporter::GetInfo () const 1.105 +{ 1.106 + return &desc; 1.107 +} 1.108 + 1.109 +// ------------------------------------------------------------------------------------------------ 1.110 +// Setup configuration properties for the loader 1.111 +void CSMImporter::SetupProperties(const Importer* pImp) 1.112 +{ 1.113 + noSkeletonMesh = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_NO_SKELETON_MESHES,0) != 0; 1.114 +} 1.115 + 1.116 +// ------------------------------------------------------------------------------------------------ 1.117 +// Imports the given file into the given scene structure. 1.118 +void CSMImporter::InternReadFile( const std::string& pFile, 1.119 + aiScene* pScene, IOSystem* pIOHandler) 1.120 +{ 1.121 + boost::scoped_ptr<IOStream> file( pIOHandler->Open( pFile, "rb")); 1.122 + 1.123 + // Check whether we can read from the file 1.124 + if( file.get() == NULL) { 1.125 + throw DeadlyImportError( "Failed to open CSM file " + pFile + "."); 1.126 + } 1.127 + 1.128 + // allocate storage and copy the contents of the file to a memory buffer 1.129 + std::vector<char> mBuffer2; 1.130 + TextFileToBuffer(file.get(),mBuffer2); 1.131 + const char* buffer = &mBuffer2[0]; 1.132 + 1.133 + aiAnimation* anim = new aiAnimation(); 1.134 + int first = 0, last = 0x00ffffff; 1.135 + 1.136 + // now process the file and look out for '$' sections 1.137 + while (1) { 1.138 + SkipSpaces(&buffer); 1.139 + if ('\0' == *buffer) 1.140 + break; 1.141 + 1.142 + if ('$' == *buffer) { 1.143 + ++buffer; 1.144 + if (TokenMatchI(buffer,"firstframe",10)) { 1.145 + SkipSpaces(&buffer); 1.146 + first = strtol10(buffer,&buffer); 1.147 + } 1.148 + else if (TokenMatchI(buffer,"lastframe",9)) { 1.149 + SkipSpaces(&buffer); 1.150 + last = strtol10(buffer,&buffer); 1.151 + } 1.152 + else if (TokenMatchI(buffer,"rate",4)) { 1.153 + SkipSpaces(&buffer); 1.154 + float d; 1.155 + buffer = fast_atoreal_move<float>(buffer,d); 1.156 + anim->mTicksPerSecond = d; 1.157 + } 1.158 + else if (TokenMatchI(buffer,"order",5)) { 1.159 + std::vector< aiNodeAnim* > anims_temp; 1.160 + anims_temp.reserve(30); 1.161 + while (1) { 1.162 + SkipSpaces(&buffer); 1.163 + if (IsLineEnd(*buffer) && SkipSpacesAndLineEnd(&buffer) && *buffer == '$') 1.164 + break; // next section 1.165 + 1.166 + // Construct a new node animation channel and setup its name 1.167 + anims_temp.push_back(new aiNodeAnim()); 1.168 + aiNodeAnim* nda = anims_temp.back(); 1.169 + 1.170 + char* ot = nda->mNodeName.data; 1.171 + while (!IsSpaceOrNewLine(*buffer)) 1.172 + *ot++ = *buffer++; 1.173 + 1.174 + *ot = '\0'; 1.175 + nda->mNodeName.length = (size_t)(ot-nda->mNodeName.data); 1.176 + } 1.177 + 1.178 + anim->mNumChannels = anims_temp.size(); 1.179 + if (!anim->mNumChannels) 1.180 + throw DeadlyImportError("CSM: Empty $order section"); 1.181 + 1.182 + // copy over to the output animation 1.183 + anim->mChannels = new aiNodeAnim*[anim->mNumChannels]; 1.184 + ::memcpy(anim->mChannels,&anims_temp[0],sizeof(aiNodeAnim*)*anim->mNumChannels); 1.185 + } 1.186 + else if (TokenMatchI(buffer,"points",6)) { 1.187 + if (!anim->mNumChannels) 1.188 + throw DeadlyImportError("CSM: \'$order\' section is required to appear prior to \'$points\'"); 1.189 + 1.190 + // If we know how many frames we'll read, we can preallocate some storage 1.191 + unsigned int alloc = 100; 1.192 + if (last != 0x00ffffff) 1.193 + { 1.194 + alloc = last-first; 1.195 + alloc += alloc>>2u; // + 25% 1.196 + for (unsigned int i = 0; i < anim->mNumChannels;++i) 1.197 + anim->mChannels[i]->mPositionKeys = new aiVectorKey[alloc]; 1.198 + } 1.199 + 1.200 + unsigned int filled = 0; 1.201 + 1.202 + // Now read all point data. 1.203 + while (1) { 1.204 + SkipSpaces(&buffer); 1.205 + if (IsLineEnd(*buffer) && (!SkipSpacesAndLineEnd(&buffer) || *buffer == '$')) { 1.206 + break; // next section 1.207 + } 1.208 + 1.209 + // read frame 1.210 + const int frame = ::strtoul10(buffer,&buffer); 1.211 + last = std::max(frame,last); 1.212 + first = std::min(frame,last); 1.213 + for (unsigned int i = 0; i < anim->mNumChannels;++i) { 1.214 + 1.215 + aiNodeAnim* s = anim->mChannels[i]; 1.216 + if (s->mNumPositionKeys == alloc) { /* need to reallocate? */ 1.217 + 1.218 + aiVectorKey* old = s->mPositionKeys; 1.219 + s->mPositionKeys = new aiVectorKey[s->mNumPositionKeys = alloc*2]; 1.220 + ::memcpy(s->mPositionKeys,old,sizeof(aiVectorKey)*alloc); 1.221 + delete[] old; 1.222 + } 1.223 + 1.224 + // read x,y,z 1.225 + if(!SkipSpacesAndLineEnd(&buffer)) 1.226 + throw DeadlyImportError("CSM: Unexpected EOF occured reading sample x coord"); 1.227 + 1.228 + if (TokenMatchI(buffer, "DROPOUT", 7)) { 1.229 + // seems this is invalid marker data; at least the doc says it's possible 1.230 + DefaultLogger::get()->warn("CSM: Encountered invalid marker data (DROPOUT)"); 1.231 + } 1.232 + else { 1.233 + aiVectorKey* sub = s->mPositionKeys + s->mNumPositionKeys; 1.234 + sub->mTime = (double)frame; 1.235 + buffer = fast_atoreal_move<float>(buffer, (float&)sub->mValue.x); 1.236 + 1.237 + if(!SkipSpacesAndLineEnd(&buffer)) 1.238 + throw DeadlyImportError("CSM: Unexpected EOF occured reading sample y coord"); 1.239 + buffer = fast_atoreal_move<float>(buffer, (float&)sub->mValue.y); 1.240 + 1.241 + if(!SkipSpacesAndLineEnd(&buffer)) 1.242 + throw DeadlyImportError("CSM: Unexpected EOF occured reading sample z coord"); 1.243 + buffer = fast_atoreal_move<float>(buffer, (float&)sub->mValue.z); 1.244 + 1.245 + ++s->mNumPositionKeys; 1.246 + } 1.247 + } 1.248 + 1.249 + // update allocation granularity 1.250 + if (filled == alloc) 1.251 + alloc *= 2; 1.252 + 1.253 + ++filled; 1.254 + } 1.255 + // all channels must be complete in order to continue safely. 1.256 + for (unsigned int i = 0; i < anim->mNumChannels;++i) { 1.257 + 1.258 + if (!anim->mChannels[i]->mNumPositionKeys) 1.259 + throw DeadlyImportError("CSM: Invalid marker track"); 1.260 + } 1.261 + } 1.262 + } 1.263 + else { 1.264 + // advance to the next line 1.265 + SkipLine(&buffer); 1.266 + } 1.267 + } 1.268 + 1.269 + // Setup a proper animation duration 1.270 + anim->mDuration = last - std::min( first, 0 ); 1.271 + 1.272 + // build a dummy root node with the tiny markers as children 1.273 + pScene->mRootNode = new aiNode(); 1.274 + pScene->mRootNode->mName.Set("$CSM_DummyRoot"); 1.275 + 1.276 + pScene->mRootNode->mNumChildren = anim->mNumChannels; 1.277 + pScene->mRootNode->mChildren = new aiNode* [anim->mNumChannels]; 1.278 + 1.279 + for (unsigned int i = 0; i < anim->mNumChannels;++i) { 1.280 + aiNodeAnim* na = anim->mChannels[i]; 1.281 + 1.282 + aiNode* nd = pScene->mRootNode->mChildren[i] = new aiNode(); 1.283 + nd->mName = anim->mChannels[i]->mNodeName; 1.284 + nd->mParent = pScene->mRootNode; 1.285 + 1.286 + aiMatrix4x4::Translation(na->mPositionKeys[0].mValue, nd->mTransformation); 1.287 + } 1.288 + 1.289 + // Store the one and only animation in the scene 1.290 + pScene->mAnimations = new aiAnimation*[pScene->mNumAnimations=1]; 1.291 + pScene->mAnimations[0] = anim; 1.292 + anim->mName.Set("$CSM_MasterAnim"); 1.293 + 1.294 + // mark the scene as incomplete and run SkeletonMeshBuilder on it 1.295 + pScene->mFlags |= AI_SCENE_FLAGS_INCOMPLETE; 1.296 + 1.297 + if (!noSkeletonMesh) { 1.298 + SkeletonMeshBuilder maker(pScene,pScene->mRootNode,true); 1.299 + } 1.300 +} 1.301 + 1.302 +#endif // !! ASSIMP_BUILD_NO_CSM_IMPORTER