vrshoot

annotate 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
rev   line source
nuclear@0 1 /*
nuclear@0 2 ---------------------------------------------------------------------------
nuclear@0 3 Open Asset Import Library (assimp)
nuclear@0 4 ---------------------------------------------------------------------------
nuclear@0 5
nuclear@0 6 Copyright (c) 2006-2012, assimp team
nuclear@0 7
nuclear@0 8 All rights reserved.
nuclear@0 9
nuclear@0 10 Redistribution and use of this software in source and binary forms,
nuclear@0 11 with or without modification, are permitted provided that the following
nuclear@0 12 conditions are met:
nuclear@0 13
nuclear@0 14 * Redistributions of source code must retain the above
nuclear@0 15 copyright notice, this list of conditions and the
nuclear@0 16 following disclaimer.
nuclear@0 17
nuclear@0 18 * Redistributions in binary form must reproduce the above
nuclear@0 19 copyright notice, this list of conditions and the
nuclear@0 20 following disclaimer in the documentation and/or other
nuclear@0 21 materials provided with the distribution.
nuclear@0 22
nuclear@0 23 * Neither the name of the assimp team, nor the names of its
nuclear@0 24 contributors may be used to endorse or promote products
nuclear@0 25 derived from this software without specific prior
nuclear@0 26 written permission of the assimp team.
nuclear@0 27
nuclear@0 28 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
nuclear@0 29 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
nuclear@0 30 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
nuclear@0 31 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
nuclear@0 32 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
nuclear@0 33 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
nuclear@0 34 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
nuclear@0 35 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
nuclear@0 36 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
nuclear@0 37 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
nuclear@0 38 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
nuclear@0 39 ---------------------------------------------------------------------------
nuclear@0 40 */
nuclear@0 41
nuclear@0 42 /** @file CSMLoader.cpp
nuclear@0 43 * Implementation of the CSM importer class.
nuclear@0 44 */
nuclear@0 45
nuclear@0 46 #include "AssimpPCH.h"
nuclear@0 47
nuclear@0 48 #ifndef ASSIMP_BUILD_NO_CSM_IMPORTER
nuclear@0 49
nuclear@0 50 #include "CSMLoader.h"
nuclear@0 51 #include "SkeletonMeshBuilder.h"
nuclear@0 52 #include "ParsingUtils.h"
nuclear@0 53 #include "fast_atof.h"
nuclear@0 54
nuclear@0 55 using namespace Assimp;
nuclear@0 56
nuclear@0 57 static const aiImporterDesc desc = {
nuclear@0 58 "CharacterStudio Motion Importer (MoCap)",
nuclear@0 59 "",
nuclear@0 60 "",
nuclear@0 61 "",
nuclear@0 62 aiImporterFlags_SupportTextFlavour,
nuclear@0 63 0,
nuclear@0 64 0,
nuclear@0 65 0,
nuclear@0 66 0,
nuclear@0 67 "csm"
nuclear@0 68 };
nuclear@0 69
nuclear@0 70
nuclear@0 71 // ------------------------------------------------------------------------------------------------
nuclear@0 72 // Constructor to be privately used by Importer
nuclear@0 73 CSMImporter::CSMImporter()
nuclear@0 74 : noSkeletonMesh()
nuclear@0 75 {}
nuclear@0 76
nuclear@0 77 // ------------------------------------------------------------------------------------------------
nuclear@0 78 // Destructor, private as well
nuclear@0 79 CSMImporter::~CSMImporter()
nuclear@0 80 {}
nuclear@0 81
nuclear@0 82 // ------------------------------------------------------------------------------------------------
nuclear@0 83 // Returns whether the class can handle the format of the given file.
nuclear@0 84 bool CSMImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const
nuclear@0 85 {
nuclear@0 86 // check file extension
nuclear@0 87 const std::string extension = GetExtension(pFile);
nuclear@0 88
nuclear@0 89 if( extension == "csm")
nuclear@0 90 return true;
nuclear@0 91
nuclear@0 92 if ((checkSig || !extension.length()) && pIOHandler) {
nuclear@0 93 const char* tokens[] = {"$Filename"};
nuclear@0 94 return SearchFileHeaderForToken(pIOHandler,pFile,tokens,1);
nuclear@0 95 }
nuclear@0 96 return false;
nuclear@0 97 }
nuclear@0 98
nuclear@0 99 // ------------------------------------------------------------------------------------------------
nuclear@0 100 // Build a string of all file extensions supported
nuclear@0 101 const aiImporterDesc* CSMImporter::GetInfo () const
nuclear@0 102 {
nuclear@0 103 return &desc;
nuclear@0 104 }
nuclear@0 105
nuclear@0 106 // ------------------------------------------------------------------------------------------------
nuclear@0 107 // Setup configuration properties for the loader
nuclear@0 108 void CSMImporter::SetupProperties(const Importer* pImp)
nuclear@0 109 {
nuclear@0 110 noSkeletonMesh = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_NO_SKELETON_MESHES,0) != 0;
nuclear@0 111 }
nuclear@0 112
nuclear@0 113 // ------------------------------------------------------------------------------------------------
nuclear@0 114 // Imports the given file into the given scene structure.
nuclear@0 115 void CSMImporter::InternReadFile( const std::string& pFile,
nuclear@0 116 aiScene* pScene, IOSystem* pIOHandler)
nuclear@0 117 {
nuclear@0 118 boost::scoped_ptr<IOStream> file( pIOHandler->Open( pFile, "rb"));
nuclear@0 119
nuclear@0 120 // Check whether we can read from the file
nuclear@0 121 if( file.get() == NULL) {
nuclear@0 122 throw DeadlyImportError( "Failed to open CSM file " + pFile + ".");
nuclear@0 123 }
nuclear@0 124
nuclear@0 125 // allocate storage and copy the contents of the file to a memory buffer
nuclear@0 126 std::vector<char> mBuffer2;
nuclear@0 127 TextFileToBuffer(file.get(),mBuffer2);
nuclear@0 128 const char* buffer = &mBuffer2[0];
nuclear@0 129
nuclear@0 130 aiAnimation* anim = new aiAnimation();
nuclear@0 131 int first = 0, last = 0x00ffffff;
nuclear@0 132
nuclear@0 133 // now process the file and look out for '$' sections
nuclear@0 134 while (1) {
nuclear@0 135 SkipSpaces(&buffer);
nuclear@0 136 if ('\0' == *buffer)
nuclear@0 137 break;
nuclear@0 138
nuclear@0 139 if ('$' == *buffer) {
nuclear@0 140 ++buffer;
nuclear@0 141 if (TokenMatchI(buffer,"firstframe",10)) {
nuclear@0 142 SkipSpaces(&buffer);
nuclear@0 143 first = strtol10(buffer,&buffer);
nuclear@0 144 }
nuclear@0 145 else if (TokenMatchI(buffer,"lastframe",9)) {
nuclear@0 146 SkipSpaces(&buffer);
nuclear@0 147 last = strtol10(buffer,&buffer);
nuclear@0 148 }
nuclear@0 149 else if (TokenMatchI(buffer,"rate",4)) {
nuclear@0 150 SkipSpaces(&buffer);
nuclear@0 151 float d;
nuclear@0 152 buffer = fast_atoreal_move<float>(buffer,d);
nuclear@0 153 anim->mTicksPerSecond = d;
nuclear@0 154 }
nuclear@0 155 else if (TokenMatchI(buffer,"order",5)) {
nuclear@0 156 std::vector< aiNodeAnim* > anims_temp;
nuclear@0 157 anims_temp.reserve(30);
nuclear@0 158 while (1) {
nuclear@0 159 SkipSpaces(&buffer);
nuclear@0 160 if (IsLineEnd(*buffer) && SkipSpacesAndLineEnd(&buffer) && *buffer == '$')
nuclear@0 161 break; // next section
nuclear@0 162
nuclear@0 163 // Construct a new node animation channel and setup its name
nuclear@0 164 anims_temp.push_back(new aiNodeAnim());
nuclear@0 165 aiNodeAnim* nda = anims_temp.back();
nuclear@0 166
nuclear@0 167 char* ot = nda->mNodeName.data;
nuclear@0 168 while (!IsSpaceOrNewLine(*buffer))
nuclear@0 169 *ot++ = *buffer++;
nuclear@0 170
nuclear@0 171 *ot = '\0';
nuclear@0 172 nda->mNodeName.length = (size_t)(ot-nda->mNodeName.data);
nuclear@0 173 }
nuclear@0 174
nuclear@0 175 anim->mNumChannels = anims_temp.size();
nuclear@0 176 if (!anim->mNumChannels)
nuclear@0 177 throw DeadlyImportError("CSM: Empty $order section");
nuclear@0 178
nuclear@0 179 // copy over to the output animation
nuclear@0 180 anim->mChannels = new aiNodeAnim*[anim->mNumChannels];
nuclear@0 181 ::memcpy(anim->mChannels,&anims_temp[0],sizeof(aiNodeAnim*)*anim->mNumChannels);
nuclear@0 182 }
nuclear@0 183 else if (TokenMatchI(buffer,"points",6)) {
nuclear@0 184 if (!anim->mNumChannels)
nuclear@0 185 throw DeadlyImportError("CSM: \'$order\' section is required to appear prior to \'$points\'");
nuclear@0 186
nuclear@0 187 // If we know how many frames we'll read, we can preallocate some storage
nuclear@0 188 unsigned int alloc = 100;
nuclear@0 189 if (last != 0x00ffffff)
nuclear@0 190 {
nuclear@0 191 alloc = last-first;
nuclear@0 192 alloc += alloc>>2u; // + 25%
nuclear@0 193 for (unsigned int i = 0; i < anim->mNumChannels;++i)
nuclear@0 194 anim->mChannels[i]->mPositionKeys = new aiVectorKey[alloc];
nuclear@0 195 }
nuclear@0 196
nuclear@0 197 unsigned int filled = 0;
nuclear@0 198
nuclear@0 199 // Now read all point data.
nuclear@0 200 while (1) {
nuclear@0 201 SkipSpaces(&buffer);
nuclear@0 202 if (IsLineEnd(*buffer) && (!SkipSpacesAndLineEnd(&buffer) || *buffer == '$')) {
nuclear@0 203 break; // next section
nuclear@0 204 }
nuclear@0 205
nuclear@0 206 // read frame
nuclear@0 207 const int frame = ::strtoul10(buffer,&buffer);
nuclear@0 208 last = std::max(frame,last);
nuclear@0 209 first = std::min(frame,last);
nuclear@0 210 for (unsigned int i = 0; i < anim->mNumChannels;++i) {
nuclear@0 211
nuclear@0 212 aiNodeAnim* s = anim->mChannels[i];
nuclear@0 213 if (s->mNumPositionKeys == alloc) { /* need to reallocate? */
nuclear@0 214
nuclear@0 215 aiVectorKey* old = s->mPositionKeys;
nuclear@0 216 s->mPositionKeys = new aiVectorKey[s->mNumPositionKeys = alloc*2];
nuclear@0 217 ::memcpy(s->mPositionKeys,old,sizeof(aiVectorKey)*alloc);
nuclear@0 218 delete[] old;
nuclear@0 219 }
nuclear@0 220
nuclear@0 221 // read x,y,z
nuclear@0 222 if(!SkipSpacesAndLineEnd(&buffer))
nuclear@0 223 throw DeadlyImportError("CSM: Unexpected EOF occured reading sample x coord");
nuclear@0 224
nuclear@0 225 if (TokenMatchI(buffer, "DROPOUT", 7)) {
nuclear@0 226 // seems this is invalid marker data; at least the doc says it's possible
nuclear@0 227 DefaultLogger::get()->warn("CSM: Encountered invalid marker data (DROPOUT)");
nuclear@0 228 }
nuclear@0 229 else {
nuclear@0 230 aiVectorKey* sub = s->mPositionKeys + s->mNumPositionKeys;
nuclear@0 231 sub->mTime = (double)frame;
nuclear@0 232 buffer = fast_atoreal_move<float>(buffer, (float&)sub->mValue.x);
nuclear@0 233
nuclear@0 234 if(!SkipSpacesAndLineEnd(&buffer))
nuclear@0 235 throw DeadlyImportError("CSM: Unexpected EOF occured reading sample y coord");
nuclear@0 236 buffer = fast_atoreal_move<float>(buffer, (float&)sub->mValue.y);
nuclear@0 237
nuclear@0 238 if(!SkipSpacesAndLineEnd(&buffer))
nuclear@0 239 throw DeadlyImportError("CSM: Unexpected EOF occured reading sample z coord");
nuclear@0 240 buffer = fast_atoreal_move<float>(buffer, (float&)sub->mValue.z);
nuclear@0 241
nuclear@0 242 ++s->mNumPositionKeys;
nuclear@0 243 }
nuclear@0 244 }
nuclear@0 245
nuclear@0 246 // update allocation granularity
nuclear@0 247 if (filled == alloc)
nuclear@0 248 alloc *= 2;
nuclear@0 249
nuclear@0 250 ++filled;
nuclear@0 251 }
nuclear@0 252 // all channels must be complete in order to continue safely.
nuclear@0 253 for (unsigned int i = 0; i < anim->mNumChannels;++i) {
nuclear@0 254
nuclear@0 255 if (!anim->mChannels[i]->mNumPositionKeys)
nuclear@0 256 throw DeadlyImportError("CSM: Invalid marker track");
nuclear@0 257 }
nuclear@0 258 }
nuclear@0 259 }
nuclear@0 260 else {
nuclear@0 261 // advance to the next line
nuclear@0 262 SkipLine(&buffer);
nuclear@0 263 }
nuclear@0 264 }
nuclear@0 265
nuclear@0 266 // Setup a proper animation duration
nuclear@0 267 anim->mDuration = last - std::min( first, 0 );
nuclear@0 268
nuclear@0 269 // build a dummy root node with the tiny markers as children
nuclear@0 270 pScene->mRootNode = new aiNode();
nuclear@0 271 pScene->mRootNode->mName.Set("$CSM_DummyRoot");
nuclear@0 272
nuclear@0 273 pScene->mRootNode->mNumChildren = anim->mNumChannels;
nuclear@0 274 pScene->mRootNode->mChildren = new aiNode* [anim->mNumChannels];
nuclear@0 275
nuclear@0 276 for (unsigned int i = 0; i < anim->mNumChannels;++i) {
nuclear@0 277 aiNodeAnim* na = anim->mChannels[i];
nuclear@0 278
nuclear@0 279 aiNode* nd = pScene->mRootNode->mChildren[i] = new aiNode();
nuclear@0 280 nd->mName = anim->mChannels[i]->mNodeName;
nuclear@0 281 nd->mParent = pScene->mRootNode;
nuclear@0 282
nuclear@0 283 aiMatrix4x4::Translation(na->mPositionKeys[0].mValue, nd->mTransformation);
nuclear@0 284 }
nuclear@0 285
nuclear@0 286 // Store the one and only animation in the scene
nuclear@0 287 pScene->mAnimations = new aiAnimation*[pScene->mNumAnimations=1];
nuclear@0 288 pScene->mAnimations[0] = anim;
nuclear@0 289 anim->mName.Set("$CSM_MasterAnim");
nuclear@0 290
nuclear@0 291 // mark the scene as incomplete and run SkeletonMeshBuilder on it
nuclear@0 292 pScene->mFlags |= AI_SCENE_FLAGS_INCOMPLETE;
nuclear@0 293
nuclear@0 294 if (!noSkeletonMesh) {
nuclear@0 295 SkeletonMeshBuilder maker(pScene,pScene->mRootNode,true);
nuclear@0 296 }
nuclear@0 297 }
nuclear@0 298
nuclear@0 299 #endif // !! ASSIMP_BUILD_NO_CSM_IMPORTER