vrshoot

annotate libs/assimp/BlenderDNA.inl @ 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 Open Asset Import Library (assimp)
nuclear@0 3 ----------------------------------------------------------------------
nuclear@0 4
nuclear@0 5 Copyright (c) 2006-2012, assimp team
nuclear@0 6 All rights reserved.
nuclear@0 7
nuclear@0 8 Redistribution and use of this software in source and binary forms,
nuclear@0 9 with or without modification, are permitted provided that the
nuclear@0 10 following conditions are met:
nuclear@0 11
nuclear@0 12 * Redistributions of source code must retain the above
nuclear@0 13 copyright notice, this list of conditions and the
nuclear@0 14 following disclaimer.
nuclear@0 15
nuclear@0 16 * Redistributions in binary form must reproduce the above
nuclear@0 17 copyright notice, this list of conditions and the
nuclear@0 18 following disclaimer in the documentation and/or other
nuclear@0 19 materials provided with the distribution.
nuclear@0 20
nuclear@0 21 * Neither the name of the assimp team, nor the names of its
nuclear@0 22 contributors may be used to endorse or promote products
nuclear@0 23 derived from this software without specific prior
nuclear@0 24 written permission of the assimp team.
nuclear@0 25
nuclear@0 26 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
nuclear@0 27 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
nuclear@0 28 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
nuclear@0 29 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
nuclear@0 30 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
nuclear@0 31 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
nuclear@0 32 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
nuclear@0 33 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
nuclear@0 34 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
nuclear@0 35 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
nuclear@0 36 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
nuclear@0 37
nuclear@0 38 ----------------------------------------------------------------------
nuclear@0 39 */
nuclear@0 40
nuclear@0 41 /** @file BlenderDNA.inl
nuclear@0 42 * @brief Blender `DNA` (file format specification embedded in
nuclear@0 43 * blend file itself) loader.
nuclear@0 44 */
nuclear@0 45 #ifndef INCLUDED_AI_BLEND_DNA_INL
nuclear@0 46 #define INCLUDED_AI_BLEND_DNA_INL
nuclear@0 47
nuclear@0 48 namespace Assimp {
nuclear@0 49 namespace Blender {
nuclear@0 50
nuclear@0 51 //--------------------------------------------------------------------------------
nuclear@0 52 const Field& Structure :: operator [] (const std::string& ss) const
nuclear@0 53 {
nuclear@0 54 std::map<std::string, size_t>::const_iterator it = indices.find(ss);
nuclear@0 55 if (it == indices.end()) {
nuclear@0 56 throw Error((Formatter::format(),
nuclear@0 57 "BlendDNA: Did not find a field named `",ss,"` in structure `",name,"`"
nuclear@0 58 ));
nuclear@0 59 }
nuclear@0 60
nuclear@0 61 return fields[(*it).second];
nuclear@0 62 }
nuclear@0 63
nuclear@0 64 //--------------------------------------------------------------------------------
nuclear@0 65 const Field* Structure :: Get (const std::string& ss) const
nuclear@0 66 {
nuclear@0 67 std::map<std::string, size_t>::const_iterator it = indices.find(ss);
nuclear@0 68 return it == indices.end() ? NULL : &fields[(*it).second];
nuclear@0 69 }
nuclear@0 70
nuclear@0 71 //--------------------------------------------------------------------------------
nuclear@0 72 const Field& Structure :: operator [] (const size_t i) const
nuclear@0 73 {
nuclear@0 74 if (i >= fields.size()) {
nuclear@0 75 throw Error((Formatter::format(),
nuclear@0 76 "BlendDNA: There is no field with index `",i,"` in structure `",name,"`"
nuclear@0 77 ));
nuclear@0 78 }
nuclear@0 79
nuclear@0 80 return fields[i];
nuclear@0 81 }
nuclear@0 82
nuclear@0 83 //--------------------------------------------------------------------------------
nuclear@0 84 template <typename T> boost::shared_ptr<ElemBase> Structure :: Allocate() const
nuclear@0 85 {
nuclear@0 86 return boost::shared_ptr<T>(new T());
nuclear@0 87 }
nuclear@0 88
nuclear@0 89 //--------------------------------------------------------------------------------
nuclear@0 90 template <typename T> void Structure :: Convert(
nuclear@0 91 boost::shared_ptr<ElemBase> in,
nuclear@0 92 const FileDatabase& db) const
nuclear@0 93 {
nuclear@0 94 Convert<T> (*static_cast<T*> ( in.get() ),db);
nuclear@0 95 }
nuclear@0 96
nuclear@0 97 //--------------------------------------------------------------------------------
nuclear@0 98 template <int error_policy, typename T, size_t M>
nuclear@0 99 void Structure :: ReadFieldArray(T (& out)[M], const char* name, const FileDatabase& db) const
nuclear@0 100 {
nuclear@0 101 const StreamReaderAny::pos old = db.reader->GetCurrentPos();
nuclear@0 102 try {
nuclear@0 103 const Field& f = (*this)[name];
nuclear@0 104 const Structure& s = db.dna[f.type];
nuclear@0 105
nuclear@0 106 // is the input actually an array?
nuclear@0 107 if (!(f.flags & FieldFlag_Array)) {
nuclear@0 108 throw Error((Formatter::format(),"Field `",name,"` of structure `",
nuclear@0 109 this->name,"` ought to be an array of size ",M
nuclear@0 110 ));
nuclear@0 111 }
nuclear@0 112
nuclear@0 113 db.reader->IncPtr(f.offset);
nuclear@0 114
nuclear@0 115 // size conversions are always allowed, regardless of error_policy
nuclear@0 116 unsigned int i = 0;
nuclear@0 117 for(; i < std::min(f.array_sizes[0],M); ++i) {
nuclear@0 118 s.Convert(out[i],db);
nuclear@0 119 }
nuclear@0 120 for(; i < M; ++i) {
nuclear@0 121 _defaultInitializer<ErrorPolicy_Igno>()(out[i]);
nuclear@0 122 }
nuclear@0 123 }
nuclear@0 124 catch (const Error& e) {
nuclear@0 125 _defaultInitializer<error_policy>()(out,e.what());
nuclear@0 126 }
nuclear@0 127
nuclear@0 128 // and recover the previous stream position
nuclear@0 129 db.reader->SetCurrentPos(old);
nuclear@0 130
nuclear@0 131 #ifndef ASSIMP_BUILD_BLENDER_NO_STATS
nuclear@0 132 ++db.stats().fields_read;
nuclear@0 133 #endif
nuclear@0 134 }
nuclear@0 135
nuclear@0 136 //--------------------------------------------------------------------------------
nuclear@0 137 template <int error_policy, typename T, size_t M, size_t N>
nuclear@0 138 void Structure :: ReadFieldArray2(T (& out)[M][N], const char* name, const FileDatabase& db) const
nuclear@0 139 {
nuclear@0 140 const StreamReaderAny::pos old = db.reader->GetCurrentPos();
nuclear@0 141 try {
nuclear@0 142 const Field& f = (*this)[name];
nuclear@0 143 const Structure& s = db.dna[f.type];
nuclear@0 144
nuclear@0 145 // is the input actually an array?
nuclear@0 146 if (!(f.flags & FieldFlag_Array)) {
nuclear@0 147 throw Error((Formatter::format(),"Field `",name,"` of structure `",
nuclear@0 148 this->name,"` ought to be an array of size ",M,"*",N
nuclear@0 149 ));
nuclear@0 150 }
nuclear@0 151
nuclear@0 152 db.reader->IncPtr(f.offset);
nuclear@0 153
nuclear@0 154 // size conversions are always allowed, regardless of error_policy
nuclear@0 155 unsigned int i = 0;
nuclear@0 156 for(; i < std::min(f.array_sizes[0],M); ++i) {
nuclear@0 157 unsigned int j = 0;
nuclear@0 158 for(; j < std::min(f.array_sizes[1],N); ++j) {
nuclear@0 159 s.Convert(out[i][j],db);
nuclear@0 160 }
nuclear@0 161 for(; j < N; ++j) {
nuclear@0 162 _defaultInitializer<ErrorPolicy_Igno>()(out[i][j]);
nuclear@0 163 }
nuclear@0 164 }
nuclear@0 165 for(; i < M; ++i) {
nuclear@0 166 _defaultInitializer<ErrorPolicy_Igno>()(out[i]);
nuclear@0 167 }
nuclear@0 168 }
nuclear@0 169 catch (const Error& e) {
nuclear@0 170 _defaultInitializer<error_policy>()(out,e.what());
nuclear@0 171 }
nuclear@0 172
nuclear@0 173 // and recover the previous stream position
nuclear@0 174 db.reader->SetCurrentPos(old);
nuclear@0 175
nuclear@0 176 #ifndef ASSIMP_BUILD_BLENDER_NO_STATS
nuclear@0 177 ++db.stats().fields_read;
nuclear@0 178 #endif
nuclear@0 179 }
nuclear@0 180
nuclear@0 181 //--------------------------------------------------------------------------------
nuclear@0 182 template <int error_policy, template <typename> class TOUT, typename T>
nuclear@0 183 void Structure :: ReadFieldPtr(TOUT<T>& out, const char* name, const FileDatabase& db) const
nuclear@0 184 {
nuclear@0 185 const StreamReaderAny::pos old = db.reader->GetCurrentPos();
nuclear@0 186 Pointer ptrval;
nuclear@0 187 const Field* f;
nuclear@0 188 try {
nuclear@0 189 f = &(*this)[name];
nuclear@0 190
nuclear@0 191 // sanity check, should never happen if the genblenddna script is right
nuclear@0 192 if (!(f->flags & FieldFlag_Pointer)) {
nuclear@0 193 throw Error((Formatter::format(),"Field `",name,"` of structure `",
nuclear@0 194 this->name,"` ought to be a pointer"));
nuclear@0 195 }
nuclear@0 196
nuclear@0 197 db.reader->IncPtr(f->offset);
nuclear@0 198 Convert(ptrval,db);
nuclear@0 199 // actually it is meaningless on which Structure the Convert is called
nuclear@0 200 // because the `Pointer` argument triggers a special implementation.
nuclear@0 201 }
nuclear@0 202 catch (const Error& e) {
nuclear@0 203 _defaultInitializer<error_policy>()(out,e.what());
nuclear@0 204
nuclear@0 205 out.reset();
nuclear@0 206 return;
nuclear@0 207 }
nuclear@0 208
nuclear@0 209 // resolve the pointer and load the corresponding structure
nuclear@0 210 ResolvePointer(out,ptrval,db,*f);
nuclear@0 211
nuclear@0 212 // and recover the previous stream position
nuclear@0 213 db.reader->SetCurrentPos(old);
nuclear@0 214
nuclear@0 215 #ifndef ASSIMP_BUILD_BLENDER_NO_STATS
nuclear@0 216 ++db.stats().fields_read;
nuclear@0 217 #endif
nuclear@0 218 }
nuclear@0 219
nuclear@0 220 //--------------------------------------------------------------------------------
nuclear@0 221 template <int error_policy, template <typename> class TOUT, typename T, size_t N>
nuclear@0 222 void Structure :: ReadFieldPtr(TOUT<T> (&out)[N], const char* name,
nuclear@0 223 const FileDatabase& db) const
nuclear@0 224 {
nuclear@0 225 // XXX see if we can reduce this to call to the 'normal' ReadFieldPtr
nuclear@0 226 const StreamReaderAny::pos old = db.reader->GetCurrentPos();
nuclear@0 227 Pointer ptrval[N];
nuclear@0 228 const Field* f;
nuclear@0 229 try {
nuclear@0 230 f = &(*this)[name];
nuclear@0 231
nuclear@0 232 // sanity check, should never happen if the genblenddna script is right
nuclear@0 233 if ((FieldFlag_Pointer|FieldFlag_Pointer) != (f->flags & (FieldFlag_Pointer|FieldFlag_Pointer))) {
nuclear@0 234 throw Error((Formatter::format(),"Field `",name,"` of structure `",
nuclear@0 235 this->name,"` ought to be a pointer AND an array"));
nuclear@0 236 }
nuclear@0 237
nuclear@0 238 db.reader->IncPtr(f->offset);
nuclear@0 239
nuclear@0 240 size_t i = 0;
nuclear@0 241 for(; i < std::min(f->array_sizes[0],N); ++i) {
nuclear@0 242 Convert(ptrval[i],db);
nuclear@0 243 }
nuclear@0 244 for(; i < N; ++i) {
nuclear@0 245 _defaultInitializer<ErrorPolicy_Igno>()(ptrval[i]);
nuclear@0 246 }
nuclear@0 247
nuclear@0 248 // actually it is meaningless on which Structure the Convert is called
nuclear@0 249 // because the `Pointer` argument triggers a special implementation.
nuclear@0 250 }
nuclear@0 251 catch (const Error& e) {
nuclear@0 252 _defaultInitializer<error_policy>()(out,e.what());
nuclear@0 253 for(size_t i = 0; i < N; ++i) {
nuclear@0 254 out[i].reset();
nuclear@0 255 }
nuclear@0 256 return;
nuclear@0 257 }
nuclear@0 258 for(size_t i = 0; i < N; ++i) {
nuclear@0 259 // resolve the pointer and load the corresponding structure
nuclear@0 260 ResolvePointer(out[i],ptrval[i],db,*f);
nuclear@0 261 }
nuclear@0 262
nuclear@0 263 // and recover the previous stream position
nuclear@0 264 db.reader->SetCurrentPos(old);
nuclear@0 265
nuclear@0 266 #ifndef ASSIMP_BUILD_BLENDER_NO_STATS
nuclear@0 267 ++db.stats().fields_read;
nuclear@0 268 #endif
nuclear@0 269 }
nuclear@0 270
nuclear@0 271 //--------------------------------------------------------------------------------
nuclear@0 272 template <int error_policy, typename T>
nuclear@0 273 void Structure :: ReadField(T& out, const char* name, const FileDatabase& db) const
nuclear@0 274 {
nuclear@0 275 const StreamReaderAny::pos old = db.reader->GetCurrentPos();
nuclear@0 276 try {
nuclear@0 277 const Field& f = (*this)[name];
nuclear@0 278 // find the structure definition pertaining to this field
nuclear@0 279 const Structure& s = db.dna[f.type];
nuclear@0 280
nuclear@0 281 db.reader->IncPtr(f.offset);
nuclear@0 282 s.Convert(out,db);
nuclear@0 283 }
nuclear@0 284 catch (const Error& e) {
nuclear@0 285 _defaultInitializer<error_policy>()(out,e.what());
nuclear@0 286 }
nuclear@0 287
nuclear@0 288 // and recover the previous stream position
nuclear@0 289 db.reader->SetCurrentPos(old);
nuclear@0 290
nuclear@0 291 #ifndef ASSIMP_BUILD_BLENDER_NO_STATS
nuclear@0 292 ++db.stats().fields_read;
nuclear@0 293 #endif
nuclear@0 294 }
nuclear@0 295
nuclear@0 296
nuclear@0 297 //--------------------------------------------------------------------------------
nuclear@0 298 template <template <typename> class TOUT, typename T>
nuclear@0 299 void Structure :: ResolvePointer(TOUT<T>& out, const Pointer & ptrval, const FileDatabase& db, const Field& f) const
nuclear@0 300 {
nuclear@0 301 out.reset();
nuclear@0 302 if (!ptrval.val) {
nuclear@0 303 return;
nuclear@0 304 }
nuclear@0 305 const Structure& s = db.dna[f.type];
nuclear@0 306 // find the file block the pointer is pointing to
nuclear@0 307 const FileBlockHead* block = LocateFileBlockForAddress(ptrval,db);
nuclear@0 308
nuclear@0 309 // also determine the target type from the block header
nuclear@0 310 // and check if it matches the type which we expect.
nuclear@0 311 const Structure& ss = db.dna[block->dna_index];
nuclear@0 312 if (ss != s) {
nuclear@0 313 throw Error((Formatter::format(),"Expected target to be of type `",s.name,
nuclear@0 314 "` but seemingly it is a `",ss.name,"` instead"
nuclear@0 315 ));
nuclear@0 316 }
nuclear@0 317
nuclear@0 318 // try to retrieve the object from the cache
nuclear@0 319 db.cache(out).get(s,out,ptrval);
nuclear@0 320 if (out) {
nuclear@0 321 return;
nuclear@0 322 }
nuclear@0 323
nuclear@0 324 // seek to this location, but save the previous stream pointer.
nuclear@0 325 const StreamReaderAny::pos pold = db.reader->GetCurrentPos();
nuclear@0 326 db.reader->SetCurrentPos(block->start+ static_cast<size_t>((ptrval.val - block->address.val) ));
nuclear@0 327 // FIXME: basically, this could cause problems with 64 bit pointers on 32 bit systems.
nuclear@0 328 // I really ought to improve StreamReader to work with 64 bit indices exclusively.
nuclear@0 329
nuclear@0 330 // continue conversion after allocating the required storage
nuclear@0 331 size_t num = block->size / ss.size;
nuclear@0 332 T* o = _allocate(out,num);
nuclear@0 333
nuclear@0 334 // cache the object before we convert it to avoid cyclic recursion.
nuclear@0 335 db.cache(out).set(s,out,ptrval);
nuclear@0 336
nuclear@0 337 for (size_t i = 0; i < num; ++i,++o) {
nuclear@0 338 s.Convert(*o,db);
nuclear@0 339 }
nuclear@0 340
nuclear@0 341 db.reader->SetCurrentPos(pold);
nuclear@0 342
nuclear@0 343 #ifndef ASSIMP_BUILD_BLENDER_NO_STATS
nuclear@0 344 if(out) {
nuclear@0 345 ++db.stats().pointers_resolved;
nuclear@0 346 }
nuclear@0 347 #endif
nuclear@0 348 }
nuclear@0 349
nuclear@0 350 //--------------------------------------------------------------------------------
nuclear@0 351 inline void Structure :: ResolvePointer( boost::shared_ptr< FileOffset >& out, const Pointer & ptrval, const FileDatabase& db, const Field& /*f*/) const
nuclear@0 352 {
nuclear@0 353 // Currently used exclusively by PackedFile::data to represent
nuclear@0 354 // a simple offset into the mapped BLEND file.
nuclear@0 355 out.reset();
nuclear@0 356 if (!ptrval.val) {
nuclear@0 357 return;
nuclear@0 358 }
nuclear@0 359
nuclear@0 360 // find the file block the pointer is pointing to
nuclear@0 361 const FileBlockHead* block = LocateFileBlockForAddress(ptrval,db);
nuclear@0 362
nuclear@0 363 out = boost::shared_ptr< FileOffset > (new FileOffset());
nuclear@0 364 out->val = block->start+ static_cast<size_t>((ptrval.val - block->address.val) );
nuclear@0 365 }
nuclear@0 366
nuclear@0 367 //--------------------------------------------------------------------------------
nuclear@0 368 template <template <typename> class TOUT, typename T>
nuclear@0 369 void Structure :: ResolvePointer(vector< TOUT<T> >& out, const Pointer & ptrval, const FileDatabase& db, const Field& f) const
nuclear@0 370 {
nuclear@0 371 // This is a function overload, not a template specialization. According to
nuclear@0 372 // the partial ordering rules, it should be selected by the compiler
nuclear@0 373 // for array-of-pointer inputs, i.e. Object::mats.
nuclear@0 374
nuclear@0 375 out.reset();
nuclear@0 376 if (!ptrval.val) {
nuclear@0 377 return;
nuclear@0 378 }
nuclear@0 379
nuclear@0 380 // find the file block the pointer is pointing to
nuclear@0 381 const FileBlockHead* block = LocateFileBlockForAddress(ptrval,db);
nuclear@0 382 const size_t num = block->size / (db.i64bit?8:4);
nuclear@0 383
nuclear@0 384 // keep the old stream position
nuclear@0 385 const StreamReaderAny::pos pold = db.reader->GetCurrentPos();
nuclear@0 386 db.reader->SetCurrentPos(block->start+ static_cast<size_t>((ptrval.val - block->address.val) ));
nuclear@0 387
nuclear@0 388 // allocate raw storage for the array
nuclear@0 389 out.resize(num);
nuclear@0 390 for (size_t i = 0; i< num; ++i) {
nuclear@0 391 Pointer val;
nuclear@0 392 Convert(val,db);
nuclear@0 393
nuclear@0 394 // and resolve the pointees
nuclear@0 395 ResolvePointer(out[i],val,db,f);
nuclear@0 396 }
nuclear@0 397
nuclear@0 398 db.reader->SetCurrentPos(pold);
nuclear@0 399 }
nuclear@0 400
nuclear@0 401 //--------------------------------------------------------------------------------
nuclear@0 402 template <> void Structure :: ResolvePointer<boost::shared_ptr,ElemBase>(boost::shared_ptr<ElemBase>& out,
nuclear@0 403 const Pointer & ptrval,
nuclear@0 404 const FileDatabase& db,
nuclear@0 405 const Field& /*f*/
nuclear@0 406 ) const
nuclear@0 407 {
nuclear@0 408 // Special case when the data type needs to be determined at runtime.
nuclear@0 409 // Less secure than in the `strongly-typed` case.
nuclear@0 410
nuclear@0 411 out.reset();
nuclear@0 412 if (!ptrval.val) {
nuclear@0 413 return;
nuclear@0 414 }
nuclear@0 415
nuclear@0 416 // find the file block the pointer is pointing to
nuclear@0 417 const FileBlockHead* block = LocateFileBlockForAddress(ptrval,db);
nuclear@0 418
nuclear@0 419 // determine the target type from the block header
nuclear@0 420 const Structure& s = db.dna[block->dna_index];
nuclear@0 421
nuclear@0 422 // try to retrieve the object from the cache
nuclear@0 423 db.cache(out).get(s,out,ptrval);
nuclear@0 424 if (out) {
nuclear@0 425 return;
nuclear@0 426 }
nuclear@0 427
nuclear@0 428 // seek to this location, but save the previous stream pointer.
nuclear@0 429 const StreamReaderAny::pos pold = db.reader->GetCurrentPos();
nuclear@0 430 db.reader->SetCurrentPos(block->start+ static_cast<size_t>((ptrval.val - block->address.val) ));
nuclear@0 431 // FIXME: basically, this could cause problems with 64 bit pointers on 32 bit systems.
nuclear@0 432 // I really ought to improve StreamReader to work with 64 bit indices exclusively.
nuclear@0 433
nuclear@0 434 // continue conversion after allocating the required storage
nuclear@0 435 DNA::FactoryPair builders = db.dna.GetBlobToStructureConverter(s,db);
nuclear@0 436 if (!builders.first) {
nuclear@0 437 // this might happen if DNA::RegisterConverters hasn't been called so far
nuclear@0 438 // or if the target type is not contained in `our` DNA.
nuclear@0 439 out.reset();
nuclear@0 440 DefaultLogger::get()->warn((Formatter::format(),
nuclear@0 441 "Failed to find a converter for the `",s.name,"` structure"
nuclear@0 442 ));
nuclear@0 443 return;
nuclear@0 444 }
nuclear@0 445
nuclear@0 446 // allocate the object hull
nuclear@0 447 out = (s.*builders.first)();
nuclear@0 448
nuclear@0 449 // cache the object immediately to prevent infinite recursion in a
nuclear@0 450 // circular list with a single element (i.e. a self-referencing element).
nuclear@0 451 db.cache(out).set(s,out,ptrval);
nuclear@0 452
nuclear@0 453 // and do the actual conversion
nuclear@0 454 (s.*builders.second)(out,db);
nuclear@0 455 db.reader->SetCurrentPos(pold);
nuclear@0 456
nuclear@0 457 // store a pointer to the name string of the actual type
nuclear@0 458 // in the object itself. This allows the conversion code
nuclear@0 459 // to perform additional type checking.
nuclear@0 460 out->dna_type = s.name.c_str();
nuclear@0 461
nuclear@0 462
nuclear@0 463
nuclear@0 464 #ifndef ASSIMP_BUILD_BLENDER_NO_STATS
nuclear@0 465 ++db.stats().pointers_resolved;
nuclear@0 466 #endif
nuclear@0 467 }
nuclear@0 468
nuclear@0 469 //--------------------------------------------------------------------------------
nuclear@0 470 const FileBlockHead* Structure :: LocateFileBlockForAddress(const Pointer & ptrval, const FileDatabase& db) const
nuclear@0 471 {
nuclear@0 472 // the file blocks appear in list sorted by
nuclear@0 473 // with ascending base addresses so we can run a
nuclear@0 474 // binary search to locate the pointee quickly.
nuclear@0 475
nuclear@0 476 // NOTE: Blender seems to distinguish between side-by-side
nuclear@0 477 // data (stored in the same data block) and far pointers,
nuclear@0 478 // which are only used for structures starting with an ID.
nuclear@0 479 // We don't need to make this distinction, our algorithm
nuclear@0 480 // works regardless where the data is stored.
nuclear@0 481 vector<FileBlockHead>::const_iterator it = std::lower_bound(db.entries.begin(),db.entries.end(),ptrval);
nuclear@0 482 if (it == db.entries.end()) {
nuclear@0 483 // this is crucial, pointers may not be invalid.
nuclear@0 484 // this is either a corrupted file or an attempted attack.
nuclear@0 485 throw DeadlyImportError((Formatter::format(),"Failure resolving pointer 0x",
nuclear@0 486 std::hex,ptrval.val,", no file block falls into this address range"
nuclear@0 487 ));
nuclear@0 488 }
nuclear@0 489 if (ptrval.val >= (*it).address.val + (*it).size) {
nuclear@0 490 throw DeadlyImportError((Formatter::format(),"Failure resolving pointer 0x",
nuclear@0 491 std::hex,ptrval.val,", nearest file block starting at 0x",
nuclear@0 492 (*it).address.val," ends at 0x",
nuclear@0 493 (*it).address.val + (*it).size
nuclear@0 494 ));
nuclear@0 495 }
nuclear@0 496 return &*it;
nuclear@0 497 }
nuclear@0 498
nuclear@0 499 // ------------------------------------------------------------------------------------------------
nuclear@0 500 // NOTE: The MSVC debugger keeps showing up this annoying `a cast to a smaller data type has
nuclear@0 501 // caused a loss of data`-warning. Avoid this warning by a masking with an appropriate bitmask.
nuclear@0 502
nuclear@0 503 template <typename T> struct signless;
nuclear@0 504 template <> struct signless<char> {typedef unsigned char type;};
nuclear@0 505 template <> struct signless<short> {typedef unsigned short type;};
nuclear@0 506 template <> struct signless<int> {typedef unsigned int type;};
nuclear@0 507
nuclear@0 508 template <typename T>
nuclear@0 509 struct static_cast_silent {
nuclear@0 510 template <typename V>
nuclear@0 511 T operator()(V in) {
nuclear@0 512 return static_cast<T>(in & static_cast<typename signless<T>::type>(-1));
nuclear@0 513 }
nuclear@0 514 };
nuclear@0 515
nuclear@0 516 template <> struct static_cast_silent<float> {
nuclear@0 517 template <typename V> float operator()(V in) {
nuclear@0 518 return static_cast<float> (in);
nuclear@0 519 }
nuclear@0 520 };
nuclear@0 521
nuclear@0 522 template <> struct static_cast_silent<double> {
nuclear@0 523 template <typename V> double operator()(V in) {
nuclear@0 524 return static_cast<double>(in);
nuclear@0 525 }
nuclear@0 526 };
nuclear@0 527
nuclear@0 528 // ------------------------------------------------------------------------------------------------
nuclear@0 529 template <typename T> inline void ConvertDispatcher(T& out, const Structure& in,const FileDatabase& db)
nuclear@0 530 {
nuclear@0 531 if (in.name == "int") {
nuclear@0 532 out = static_cast_silent<T>()(db.reader->GetU4());
nuclear@0 533 }
nuclear@0 534 else if (in.name == "short") {
nuclear@0 535 out = static_cast_silent<T>()(db.reader->GetU2());
nuclear@0 536 }
nuclear@0 537 else if (in.name == "char") {
nuclear@0 538 out = static_cast_silent<T>()(db.reader->GetU1());
nuclear@0 539 }
nuclear@0 540 else if (in.name == "float") {
nuclear@0 541 out = static_cast<T>(db.reader->GetF4());
nuclear@0 542 }
nuclear@0 543 else if (in.name == "double") {
nuclear@0 544 out = static_cast<T>(db.reader->GetF8());
nuclear@0 545 }
nuclear@0 546 else {
nuclear@0 547 throw DeadlyImportError("Unknown source for conversion to primitive data type: "+in.name);
nuclear@0 548 }
nuclear@0 549 }
nuclear@0 550
nuclear@0 551 // ------------------------------------------------------------------------------------------------
nuclear@0 552 template <> inline void Structure :: Convert<int> (int& dest,const FileDatabase& db) const
nuclear@0 553 {
nuclear@0 554 ConvertDispatcher(dest,*this,db);
nuclear@0 555 }
nuclear@0 556
nuclear@0 557 // ------------------------------------------------------------------------------------------------
nuclear@0 558 template <> inline void Structure :: Convert<short> (short& dest,const FileDatabase& db) const
nuclear@0 559 {
nuclear@0 560 // automatic rescaling from short to float and vice versa (seems to be used by normals)
nuclear@0 561 if (name == "float") {
nuclear@0 562 dest = static_cast<short>(db.reader->GetF4() * 32767.f);
nuclear@0 563 //db.reader->IncPtr(-4);
nuclear@0 564 return;
nuclear@0 565 }
nuclear@0 566 else if (name == "double") {
nuclear@0 567 dest = static_cast<short>(db.reader->GetF8() * 32767.);
nuclear@0 568 //db.reader->IncPtr(-8);
nuclear@0 569 return;
nuclear@0 570 }
nuclear@0 571 ConvertDispatcher(dest,*this,db);
nuclear@0 572 }
nuclear@0 573
nuclear@0 574 // ------------------------------------------------------------------------------------------------
nuclear@0 575 template <> inline void Structure :: Convert<char> (char& dest,const FileDatabase& db) const
nuclear@0 576 {
nuclear@0 577 // automatic rescaling from char to float and vice versa (seems useful for RGB colors)
nuclear@0 578 if (name == "float") {
nuclear@0 579 dest = static_cast<char>(db.reader->GetF4() * 255.f);
nuclear@0 580 return;
nuclear@0 581 }
nuclear@0 582 else if (name == "double") {
nuclear@0 583 dest = static_cast<char>(db.reader->GetF8() * 255.f);
nuclear@0 584 return;
nuclear@0 585 }
nuclear@0 586 ConvertDispatcher(dest,*this,db);
nuclear@0 587 }
nuclear@0 588
nuclear@0 589 // ------------------------------------------------------------------------------------------------
nuclear@0 590 template <> inline void Structure :: Convert<float> (float& dest,const FileDatabase& db) const
nuclear@0 591 {
nuclear@0 592 // automatic rescaling from char to float and vice versa (seems useful for RGB colors)
nuclear@0 593 if (name == "char") {
nuclear@0 594 dest = db.reader->GetI1() / 255.f;
nuclear@0 595 return;
nuclear@0 596 }
nuclear@0 597 // automatic rescaling from short to float and vice versa (used by normals)
nuclear@0 598 else if (name == "short") {
nuclear@0 599 dest = db.reader->GetI2() / 32767.f;
nuclear@0 600 return;
nuclear@0 601 }
nuclear@0 602 ConvertDispatcher(dest,*this,db);
nuclear@0 603 }
nuclear@0 604
nuclear@0 605 // ------------------------------------------------------------------------------------------------
nuclear@0 606 template <> inline void Structure :: Convert<double> (double& dest,const FileDatabase& db) const
nuclear@0 607 {
nuclear@0 608 if (name == "char") {
nuclear@0 609 dest = db.reader->GetI1() / 255.;
nuclear@0 610 return;
nuclear@0 611 }
nuclear@0 612 else if (name == "short") {
nuclear@0 613 dest = db.reader->GetI2() / 32767.;
nuclear@0 614 return;
nuclear@0 615 }
nuclear@0 616 ConvertDispatcher(dest,*this,db);
nuclear@0 617 }
nuclear@0 618
nuclear@0 619 // ------------------------------------------------------------------------------------------------
nuclear@0 620 template <> inline void Structure :: Convert<Pointer> (Pointer& dest,const FileDatabase& db) const
nuclear@0 621 {
nuclear@0 622 if (db.i64bit) {
nuclear@0 623 dest.val = db.reader->GetU8();
nuclear@0 624 //db.reader->IncPtr(-8);
nuclear@0 625 return;
nuclear@0 626 }
nuclear@0 627 dest.val = db.reader->GetU4();
nuclear@0 628 //db.reader->IncPtr(-4);
nuclear@0 629 }
nuclear@0 630
nuclear@0 631 //--------------------------------------------------------------------------------
nuclear@0 632 const Structure& DNA :: operator [] (const std::string& ss) const
nuclear@0 633 {
nuclear@0 634 std::map<std::string, size_t>::const_iterator it = indices.find(ss);
nuclear@0 635 if (it == indices.end()) {
nuclear@0 636 throw Error((Formatter::format(),
nuclear@0 637 "BlendDNA: Did not find a structure named `",ss,"`"
nuclear@0 638 ));
nuclear@0 639 }
nuclear@0 640
nuclear@0 641 return structures[(*it).second];
nuclear@0 642 }
nuclear@0 643
nuclear@0 644 //--------------------------------------------------------------------------------
nuclear@0 645 const Structure* DNA :: Get (const std::string& ss) const
nuclear@0 646 {
nuclear@0 647 std::map<std::string, size_t>::const_iterator it = indices.find(ss);
nuclear@0 648 return it == indices.end() ? NULL : &structures[(*it).second];
nuclear@0 649 }
nuclear@0 650
nuclear@0 651 //--------------------------------------------------------------------------------
nuclear@0 652 const Structure& DNA :: operator [] (const size_t i) const
nuclear@0 653 {
nuclear@0 654 if (i >= structures.size()) {
nuclear@0 655 throw Error((Formatter::format(),
nuclear@0 656 "BlendDNA: There is no structure with index `",i,"`"
nuclear@0 657 ));
nuclear@0 658 }
nuclear@0 659
nuclear@0 660 return structures[i];
nuclear@0 661 }
nuclear@0 662
nuclear@0 663 //--------------------------------------------------------------------------------
nuclear@0 664 template <template <typename> class TOUT> template <typename T> void ObjectCache<TOUT> :: get (
nuclear@0 665 const Structure& s,
nuclear@0 666 TOUT<T>& out,
nuclear@0 667 const Pointer& ptr
nuclear@0 668 ) const {
nuclear@0 669
nuclear@0 670 if(s.cache_idx == static_cast<size_t>(-1)) {
nuclear@0 671 s.cache_idx = db.next_cache_idx++;
nuclear@0 672 caches.resize(db.next_cache_idx);
nuclear@0 673 return;
nuclear@0 674 }
nuclear@0 675
nuclear@0 676 typename StructureCache::const_iterator it = caches[s.cache_idx].find(ptr);
nuclear@0 677 if (it != caches[s.cache_idx].end()) {
nuclear@0 678 out = boost::static_pointer_cast<T>( (*it).second );
nuclear@0 679
nuclear@0 680 #ifndef ASSIMP_BUILD_BLENDER_NO_STATS
nuclear@0 681 ++db.stats().cache_hits;
nuclear@0 682 #endif
nuclear@0 683 }
nuclear@0 684 // otherwise, out remains untouched
nuclear@0 685 }
nuclear@0 686
nuclear@0 687
nuclear@0 688 //--------------------------------------------------------------------------------
nuclear@0 689 template <template <typename> class TOUT> template <typename T> void ObjectCache<TOUT> :: set (
nuclear@0 690 const Structure& s,
nuclear@0 691 const TOUT<T>& out,
nuclear@0 692 const Pointer& ptr
nuclear@0 693 ) {
nuclear@0 694 if(s.cache_idx == static_cast<size_t>(-1)) {
nuclear@0 695 s.cache_idx = db.next_cache_idx++;
nuclear@0 696 caches.resize(db.next_cache_idx);
nuclear@0 697 }
nuclear@0 698 caches[s.cache_idx][ptr] = boost::static_pointer_cast<ElemBase>( out );
nuclear@0 699
nuclear@0 700 #ifndef ASSIMP_BUILD_BLENDER_NO_STATS
nuclear@0 701 ++db.stats().cached_objects;
nuclear@0 702 #endif
nuclear@0 703 }
nuclear@0 704
nuclear@0 705 }}
nuclear@0 706 #endif