vrshoot

annotate libs/assimp/BlenderDNA.h @ 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.h
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_H
nuclear@0 46 #define INCLUDED_AI_BLEND_DNA_H
nuclear@0 47
nuclear@0 48 #include "BaseImporter.h"
nuclear@0 49 #include "TinyFormatter.h"
nuclear@0 50
nuclear@0 51 // enable verbose log output. really verbose, so be careful.
nuclear@0 52 #ifdef _DEBUG
nuclear@0 53 # define ASSIMP_BUILD_BLENDER_DEBUG
nuclear@0 54 #endif
nuclear@0 55
nuclear@0 56 // #define ASSIMP_BUILD_BLENDER_NO_STATS
nuclear@0 57
nuclear@0 58 namespace Assimp {
nuclear@0 59 template <bool,bool> class StreamReader;
nuclear@0 60 typedef StreamReader<true,true> StreamReaderAny;
nuclear@0 61
nuclear@0 62 namespace Blender {
nuclear@0 63 class FileDatabase;
nuclear@0 64 struct FileBlockHead;
nuclear@0 65
nuclear@0 66 template <template <typename> class TOUT>
nuclear@0 67 class ObjectCache;
nuclear@0 68
nuclear@0 69 // -------------------------------------------------------------------------------
nuclear@0 70 /** Exception class used by the blender loader to selectively catch exceptions
nuclear@0 71 * thrown in its own code (DeadlyImportErrors thrown in general utility
nuclear@0 72 * functions are untouched then). If such an exception is not caught by
nuclear@0 73 * the loader itself, it will still be caught by Assimp due to its
nuclear@0 74 * ancestry. */
nuclear@0 75 // -------------------------------------------------------------------------------
nuclear@0 76 struct Error : DeadlyImportError
nuclear@0 77 {
nuclear@0 78 Error (const std::string& s)
nuclear@0 79 : DeadlyImportError(s)
nuclear@0 80 {}
nuclear@0 81 };
nuclear@0 82
nuclear@0 83 // -------------------------------------------------------------------------------
nuclear@0 84 /** The only purpose of this structure is to feed a virtual dtor into its
nuclear@0 85 * descendents. It serves as base class for all data structure fields. */
nuclear@0 86 // -------------------------------------------------------------------------------
nuclear@0 87 struct ElemBase
nuclear@0 88 {
nuclear@0 89 virtual ~ElemBase() {}
nuclear@0 90
nuclear@0 91 /** Type name of the element. The type
nuclear@0 92 * string points is the `c_str` of the `name` attribute of the
nuclear@0 93 * corresponding `Structure`, that is, it is only valid as long
nuclear@0 94 * as the DNA is not modified. The dna_type is only set if the
nuclear@0 95 * data type is not static, i.e. a boost::shared_ptr<ElemBase>
nuclear@0 96 * in the scene description would have its type resolved
nuclear@0 97 * at runtime, so this member is always set. */
nuclear@0 98 const char* dna_type;
nuclear@0 99 };
nuclear@0 100
nuclear@0 101
nuclear@0 102 // -------------------------------------------------------------------------------
nuclear@0 103 /** Represents a generic pointer to a memory location, which can be either 32
nuclear@0 104 * or 64 bits. These pointers are loaded from the BLEND file and finally
nuclear@0 105 * fixed to point to the real, converted representation of the objects
nuclear@0 106 * they used to point to.*/
nuclear@0 107 // -------------------------------------------------------------------------------
nuclear@0 108 struct Pointer
nuclear@0 109 {
nuclear@0 110 Pointer() : val() {}
nuclear@0 111 uint64_t val;
nuclear@0 112 };
nuclear@0 113
nuclear@0 114 // -------------------------------------------------------------------------------
nuclear@0 115 /** Represents a generic offset within a BLEND file */
nuclear@0 116 // -------------------------------------------------------------------------------
nuclear@0 117 struct FileOffset
nuclear@0 118 {
nuclear@0 119 FileOffset() : val() {}
nuclear@0 120 uint64_t val;
nuclear@0 121 };
nuclear@0 122
nuclear@0 123 // -------------------------------------------------------------------------------
nuclear@0 124 /** Dummy derivate of std::vector to be able to use it in templates simultaenously
nuclear@0 125 * with boost::shared_ptr, which takes only one template argument
nuclear@0 126 * while std::vector takes three. Also we need to provide some special member
nuclear@0 127 * functions of shared_ptr */
nuclear@0 128 // -------------------------------------------------------------------------------
nuclear@0 129 template <typename T>
nuclear@0 130 class vector : public std::vector<T>
nuclear@0 131 {
nuclear@0 132 public:
nuclear@0 133 using std::vector<T>::resize;
nuclear@0 134 using std::vector<T>::empty;
nuclear@0 135
nuclear@0 136 void reset() {
nuclear@0 137 resize(0);
nuclear@0 138 }
nuclear@0 139
nuclear@0 140 operator bool () const {
nuclear@0 141 return !empty();
nuclear@0 142 }
nuclear@0 143 };
nuclear@0 144
nuclear@0 145 // -------------------------------------------------------------------------------
nuclear@0 146 /** Mixed flags for use in #Field */
nuclear@0 147 // -------------------------------------------------------------------------------
nuclear@0 148 enum FieldFlags
nuclear@0 149 {
nuclear@0 150 FieldFlag_Pointer = 0x1,
nuclear@0 151 FieldFlag_Array = 0x2
nuclear@0 152 };
nuclear@0 153
nuclear@0 154 // -------------------------------------------------------------------------------
nuclear@0 155 /** Represents a single member of a data structure in a BLEND file */
nuclear@0 156 // -------------------------------------------------------------------------------
nuclear@0 157 struct Field
nuclear@0 158 {
nuclear@0 159 std::string name;
nuclear@0 160 std::string type;
nuclear@0 161
nuclear@0 162 size_t size;
nuclear@0 163 size_t offset;
nuclear@0 164
nuclear@0 165 /** Size of each array dimension. For flat arrays,
nuclear@0 166 * the second dimension is set to 1. */
nuclear@0 167 size_t array_sizes[2];
nuclear@0 168
nuclear@0 169 /** Any of the #FieldFlags enumerated values */
nuclear@0 170 unsigned int flags;
nuclear@0 171 };
nuclear@0 172
nuclear@0 173 // -------------------------------------------------------------------------------
nuclear@0 174 /** Range of possible behaviours for fields absend in the input file. Some are
nuclear@0 175 * mission critical so we need them, while others can silently be default
nuclear@0 176 * initialized and no animations are harmed. */
nuclear@0 177 // -------------------------------------------------------------------------------
nuclear@0 178 enum ErrorPolicy
nuclear@0 179 {
nuclear@0 180 /** Substitute default value and ignore */
nuclear@0 181 ErrorPolicy_Igno,
nuclear@0 182 /** Substitute default value and write to log */
nuclear@0 183 ErrorPolicy_Warn,
nuclear@0 184 /** Substitute a massive error message and crash the whole matrix. Its time for another zion */
nuclear@0 185 ErrorPolicy_Fail
nuclear@0 186 };
nuclear@0 187
nuclear@0 188 #ifdef ASSIMP_BUILD_BLENDER_DEBUG
nuclear@0 189 # define ErrorPolicy_Igno ErrorPolicy_Warn
nuclear@0 190 #endif
nuclear@0 191
nuclear@0 192 // -------------------------------------------------------------------------------
nuclear@0 193 /** Represents a data structure in a BLEND file. A Structure defines n fields
nuclear@0 194 * and their locatios and encodings the input stream. Usually, every
nuclear@0 195 * Structure instance pertains to one equally-named data structure in the
nuclear@0 196 * BlenderScene.h header. This class defines various utilities to map a
nuclear@0 197 * binary `blob` read from the file to such a structure instance with
nuclear@0 198 * meaningful contents. */
nuclear@0 199 // -------------------------------------------------------------------------------
nuclear@0 200 class Structure
nuclear@0 201 {
nuclear@0 202 template <template <typename> class> friend class ObjectCache;
nuclear@0 203
nuclear@0 204 public:
nuclear@0 205
nuclear@0 206 Structure()
nuclear@0 207 : cache_idx(-1)
nuclear@0 208 {}
nuclear@0 209
nuclear@0 210 public:
nuclear@0 211
nuclear@0 212 // publicly accessible members
nuclear@0 213 std::string name;
nuclear@0 214 vector< Field > fields;
nuclear@0 215 std::map<std::string, size_t> indices;
nuclear@0 216
nuclear@0 217 size_t size;
nuclear@0 218
nuclear@0 219 public:
nuclear@0 220
nuclear@0 221 // --------------------------------------------------------
nuclear@0 222 /** Access a field of the structure by its canonical name. The pointer version
nuclear@0 223 * returns NULL on failure while the reference version raises an import error. */
nuclear@0 224 inline const Field& operator [] (const std::string& ss) const;
nuclear@0 225 inline const Field* Get (const std::string& ss) const;
nuclear@0 226
nuclear@0 227 // --------------------------------------------------------
nuclear@0 228 /** Access a field of the structure by its index */
nuclear@0 229 inline const Field& operator [] (const size_t i) const;
nuclear@0 230
nuclear@0 231 // --------------------------------------------------------
nuclear@0 232 inline bool operator== (const Structure& other) const {
nuclear@0 233 return name == other.name; // name is meant to be an unique identifier
nuclear@0 234 }
nuclear@0 235
nuclear@0 236 // --------------------------------------------------------
nuclear@0 237 inline bool operator!= (const Structure& other) const {
nuclear@0 238 return name != other.name;
nuclear@0 239 }
nuclear@0 240
nuclear@0 241 public:
nuclear@0 242
nuclear@0 243 // --------------------------------------------------------
nuclear@0 244 /** Try to read an instance of the structure from the stream
nuclear@0 245 * and attempt to convert to `T`. This is done by
nuclear@0 246 * an appropriate specialization. If none is available,
nuclear@0 247 * a compiler complain is the result.
nuclear@0 248 * @param dest Destination value to be written
nuclear@0 249 * @param db File database, including input stream. */
nuclear@0 250 template <typename T> inline void Convert (T& dest,
nuclear@0 251 const FileDatabase& db) const;
nuclear@0 252
nuclear@0 253
nuclear@0 254
nuclear@0 255 // --------------------------------------------------------
nuclear@0 256 // generic converter
nuclear@0 257 template <typename T>
nuclear@0 258 void Convert(boost::shared_ptr<ElemBase> in,const FileDatabase& db) const;
nuclear@0 259
nuclear@0 260 // --------------------------------------------------------
nuclear@0 261 // generic allocator
nuclear@0 262 template <typename T> boost::shared_ptr<ElemBase> Allocate() const;
nuclear@0 263
nuclear@0 264
nuclear@0 265
nuclear@0 266 // --------------------------------------------------------
nuclear@0 267 // field parsing for 1d arrays
nuclear@0 268 template <int error_policy, typename T, size_t M>
nuclear@0 269 void ReadFieldArray(T (& out)[M], const char* name,
nuclear@0 270 const FileDatabase& db) const;
nuclear@0 271
nuclear@0 272 // --------------------------------------------------------
nuclear@0 273 // field parsing for 2d arrays
nuclear@0 274 template <int error_policy, typename T, size_t M, size_t N>
nuclear@0 275 void ReadFieldArray2(T (& out)[M][N], const char* name,
nuclear@0 276 const FileDatabase& db) const;
nuclear@0 277
nuclear@0 278 // --------------------------------------------------------
nuclear@0 279 // field parsing for pointer or dynamic array types
nuclear@0 280 // (boost::shared_ptr or boost::shared_array)
nuclear@0 281 template <int error_policy, template <typename> class TOUT, typename T>
nuclear@0 282 void ReadFieldPtr(TOUT<T>& out, const char* name,
nuclear@0 283 const FileDatabase& db) const;
nuclear@0 284
nuclear@0 285 // --------------------------------------------------------
nuclear@0 286 // field parsing for static arrays of pointer or dynamic
nuclear@0 287 // array types (boost::shared_ptr[] or boost::shared_array[])
nuclear@0 288 template <int error_policy, template <typename> class TOUT, typename T, size_t N>
nuclear@0 289 void ReadFieldPtr(TOUT<T> (&out)[N], const char* name,
nuclear@0 290 const FileDatabase& db) const;
nuclear@0 291
nuclear@0 292 // --------------------------------------------------------
nuclear@0 293 // field parsing for `normal` values
nuclear@0 294 template <int error_policy, typename T>
nuclear@0 295 void ReadField(T& out, const char* name,
nuclear@0 296 const FileDatabase& db) const;
nuclear@0 297
nuclear@0 298 private:
nuclear@0 299
nuclear@0 300 // --------------------------------------------------------
nuclear@0 301 template <template <typename> class TOUT, typename T>
nuclear@0 302 void ResolvePointer(TOUT<T>& out, const Pointer & ptrval,
nuclear@0 303 const FileDatabase& db, const Field& f) const;
nuclear@0 304
nuclear@0 305 // --------------------------------------------------------
nuclear@0 306 template <template <typename> class TOUT, typename T>
nuclear@0 307 void ResolvePointer(vector< TOUT<T> >& out, const Pointer & ptrval,
nuclear@0 308 const FileDatabase& db, const Field& f) const;
nuclear@0 309
nuclear@0 310 // --------------------------------------------------------
nuclear@0 311 void ResolvePointer( boost::shared_ptr< FileOffset >& out, const Pointer & ptrval,
nuclear@0 312 const FileDatabase& db, const Field& f) const;
nuclear@0 313
nuclear@0 314 // --------------------------------------------------------
nuclear@0 315 inline const FileBlockHead* LocateFileBlockForAddress(
nuclear@0 316 const Pointer & ptrval,
nuclear@0 317 const FileDatabase& db) const;
nuclear@0 318
nuclear@0 319 private:
nuclear@0 320
nuclear@0 321 // ------------------------------------------------------------------------------
nuclear@0 322 template <typename T> T* _allocate(boost::shared_ptr<T>& out, size_t& s) const {
nuclear@0 323 out = boost::shared_ptr<T>(new T());
nuclear@0 324 s = 1;
nuclear@0 325 return out.get();
nuclear@0 326 }
nuclear@0 327
nuclear@0 328 template <typename T> T* _allocate(vector<T>& out, size_t& s) const {
nuclear@0 329 out.resize(s);
nuclear@0 330 return s ? &out.front() : NULL;
nuclear@0 331 }
nuclear@0 332
nuclear@0 333 // --------------------------------------------------------
nuclear@0 334 template <int error_policy>
nuclear@0 335 struct _defaultInitializer {
nuclear@0 336
nuclear@0 337 template <typename T, unsigned int N>
nuclear@0 338 void operator ()(T (& out)[N], const char* = NULL) {
nuclear@0 339 for (unsigned int i = 0; i < N; ++i) {
nuclear@0 340 out[i] = T();
nuclear@0 341 }
nuclear@0 342 }
nuclear@0 343
nuclear@0 344 template <typename T, unsigned int N, unsigned int M>
nuclear@0 345 void operator ()(T (& out)[N][M], const char* = NULL) {
nuclear@0 346 for (unsigned int i = 0; i < N; ++i) {
nuclear@0 347 for (unsigned int j = 0; j < M; ++j) {
nuclear@0 348 out[i][j] = T();
nuclear@0 349 }
nuclear@0 350 }
nuclear@0 351 }
nuclear@0 352
nuclear@0 353 template <typename T>
nuclear@0 354 void operator ()(T& out, const char* = NULL) {
nuclear@0 355 out = T();
nuclear@0 356 }
nuclear@0 357 };
nuclear@0 358
nuclear@0 359 private:
nuclear@0 360
nuclear@0 361 mutable size_t cache_idx;
nuclear@0 362 };
nuclear@0 363
nuclear@0 364 // --------------------------------------------------------
nuclear@0 365 template <> struct Structure :: _defaultInitializer<ErrorPolicy_Warn> {
nuclear@0 366
nuclear@0 367 template <typename T>
nuclear@0 368 void operator ()(T& out, const char* reason = "<add reason>") {
nuclear@0 369 DefaultLogger::get()->warn(reason);
nuclear@0 370
nuclear@0 371 // ... and let the show go on
nuclear@0 372 _defaultInitializer<0 /*ErrorPolicy_Igno*/>()(out);
nuclear@0 373 }
nuclear@0 374 };
nuclear@0 375
nuclear@0 376 template <> struct Structure :: _defaultInitializer<ErrorPolicy_Fail> {
nuclear@0 377
nuclear@0 378 template <typename T>
nuclear@0 379 void operator ()(T& /*out*/,const char* = "") {
nuclear@0 380 // obviously, it is crucial that _DefaultInitializer is used
nuclear@0 381 // only from within a catch clause.
nuclear@0 382 throw;
nuclear@0 383 }
nuclear@0 384 };
nuclear@0 385
nuclear@0 386 // -------------------------------------------------------------------------------------------------------
nuclear@0 387 template <> inline void Structure :: ResolvePointer<boost::shared_ptr,ElemBase>(boost::shared_ptr<ElemBase>& out,
nuclear@0 388 const Pointer & ptrval,
nuclear@0 389 const FileDatabase& db,
nuclear@0 390 const Field& f
nuclear@0 391 ) const;
nuclear@0 392
nuclear@0 393
nuclear@0 394 // -------------------------------------------------------------------------------
nuclear@0 395 /** Represents the full data structure information for a single BLEND file.
nuclear@0 396 * This data is extracted from the DNA1 chunk in the file.
nuclear@0 397 * #DNAParser does the reading and represents currently the only place where
nuclear@0 398 * DNA is altered.*/
nuclear@0 399 // -------------------------------------------------------------------------------
nuclear@0 400 class DNA
nuclear@0 401 {
nuclear@0 402 public:
nuclear@0 403
nuclear@0 404 typedef void (Structure::*ConvertProcPtr) (
nuclear@0 405 boost::shared_ptr<ElemBase> in,
nuclear@0 406 const FileDatabase&
nuclear@0 407 ) const;
nuclear@0 408
nuclear@0 409 typedef boost::shared_ptr<ElemBase> (
nuclear@0 410 Structure::*AllocProcPtr) () const;
nuclear@0 411
nuclear@0 412 typedef std::pair< AllocProcPtr, ConvertProcPtr > FactoryPair;
nuclear@0 413
nuclear@0 414 public:
nuclear@0 415
nuclear@0 416 std::map<std::string, FactoryPair > converters;
nuclear@0 417 vector<Structure > structures;
nuclear@0 418 std::map<std::string, size_t> indices;
nuclear@0 419
nuclear@0 420 public:
nuclear@0 421
nuclear@0 422 // --------------------------------------------------------
nuclear@0 423 /** Access a structure by its canonical name, the pointer version returns NULL on failure
nuclear@0 424 * while the reference version raises an error. */
nuclear@0 425 inline const Structure& operator [] (const std::string& ss) const;
nuclear@0 426 inline const Structure* Get (const std::string& ss) const;
nuclear@0 427
nuclear@0 428 // --------------------------------------------------------
nuclear@0 429 /** Access a structure by its index */
nuclear@0 430 inline const Structure& operator [] (const size_t i) const;
nuclear@0 431
nuclear@0 432 public:
nuclear@0 433
nuclear@0 434 // --------------------------------------------------------
nuclear@0 435 /** Add structure definitions for all the primitive types,
nuclear@0 436 * i.e. integer, short, char, float */
nuclear@0 437 void AddPrimitiveStructures();
nuclear@0 438
nuclear@0 439 // --------------------------------------------------------
nuclear@0 440 /** Fill the @c converters member with converters for all
nuclear@0 441 * known data types. The implementation of this method is
nuclear@0 442 * in BlenderScene.cpp and is machine-generated.
nuclear@0 443 * Converters are used to quickly handle objects whose
nuclear@0 444 * exact data type is a runtime-property and not yet
nuclear@0 445 * known at compile time (consier Object::data).*/
nuclear@0 446 void RegisterConverters();
nuclear@0 447
nuclear@0 448
nuclear@0 449 // --------------------------------------------------------
nuclear@0 450 /** Take an input blob from the stream, interpret it according to
nuclear@0 451 * a its structure name and convert it to the intermediate
nuclear@0 452 * representation.
nuclear@0 453 * @param structure Destination structure definition
nuclear@0 454 * @param db File database.
nuclear@0 455 * @return A null pointer if no appropriate converter is available.*/
nuclear@0 456 boost::shared_ptr< ElemBase > ConvertBlobToStructure(
nuclear@0 457 const Structure& structure,
nuclear@0 458 const FileDatabase& db
nuclear@0 459 ) const;
nuclear@0 460
nuclear@0 461 // --------------------------------------------------------
nuclear@0 462 /** Find a suitable conversion function for a given Structure.
nuclear@0 463 * Such a converter function takes a blob from the input
nuclear@0 464 * stream, reads as much as it needs, and builds up a
nuclear@0 465 * complete object in intermediate representation.
nuclear@0 466 * @param structure Destination structure definition
nuclear@0 467 * @param db File database.
nuclear@0 468 * @return A null pointer in .first if no appropriate converter is available.*/
nuclear@0 469 FactoryPair GetBlobToStructureConverter(
nuclear@0 470 const Structure& structure,
nuclear@0 471 const FileDatabase& db
nuclear@0 472 ) const;
nuclear@0 473
nuclear@0 474
nuclear@0 475 #ifdef ASSIMP_BUILD_BLENDER_DEBUG
nuclear@0 476 // --------------------------------------------------------
nuclear@0 477 /** Dump the DNA to a text file. This is for debugging purposes.
nuclear@0 478 * The output file is `dna.txt` in the current working folder*/
nuclear@0 479 void DumpToFile();
nuclear@0 480 #endif
nuclear@0 481
nuclear@0 482 // --------------------------------------------------------
nuclear@0 483 /** Extract array dimensions from a C array declaration, such
nuclear@0 484 * as `...[4][6]`. Returned string would be `...[][]`.
nuclear@0 485 * @param out
nuclear@0 486 * @param array_sizes Receive maximally two array dimensions,
nuclear@0 487 * the second element is set to 1 if the array is flat.
nuclear@0 488 * Both are set to 1 if the input is not an array.
nuclear@0 489 * @throw DeadlyImportError if more than 2 dimensions are
nuclear@0 490 * encountered. */
nuclear@0 491 static void ExtractArraySize(
nuclear@0 492 const std::string& out,
nuclear@0 493 size_t array_sizes[2]
nuclear@0 494 );
nuclear@0 495 };
nuclear@0 496
nuclear@0 497 // special converters for primitive types
nuclear@0 498 template <> inline void Structure :: Convert<int> (int& dest,const FileDatabase& db) const;
nuclear@0 499 template <> inline void Structure :: Convert<short> (short& dest,const FileDatabase& db) const;
nuclear@0 500 template <> inline void Structure :: Convert<char> (char& dest,const FileDatabase& db) const;
nuclear@0 501 template <> inline void Structure :: Convert<float> (float& dest,const FileDatabase& db) const;
nuclear@0 502 template <> inline void Structure :: Convert<double> (double& dest,const FileDatabase& db) const;
nuclear@0 503 template <> inline void Structure :: Convert<Pointer> (Pointer& dest,const FileDatabase& db) const;
nuclear@0 504
nuclear@0 505 // -------------------------------------------------------------------------------
nuclear@0 506 /** Describes a master file block header. Each master file sections holds n
nuclear@0 507 * elements of a certain SDNA structure (or otherwise unspecified data). */
nuclear@0 508 // -------------------------------------------------------------------------------
nuclear@0 509 struct FileBlockHead
nuclear@0 510 {
nuclear@0 511 // points right after the header of the file block
nuclear@0 512 StreamReaderAny::pos start;
nuclear@0 513
nuclear@0 514 std::string id;
nuclear@0 515 size_t size;
nuclear@0 516
nuclear@0 517 // original memory address of the data
nuclear@0 518 Pointer address;
nuclear@0 519
nuclear@0 520 // index into DNA
nuclear@0 521 unsigned int dna_index;
nuclear@0 522
nuclear@0 523 // number of structure instances to follow
nuclear@0 524 size_t num;
nuclear@0 525
nuclear@0 526
nuclear@0 527
nuclear@0 528 // file blocks are sorted by address to quickly locate specific memory addresses
nuclear@0 529 bool operator < (const FileBlockHead& o) const {
nuclear@0 530 return address.val < o.address.val;
nuclear@0 531 }
nuclear@0 532
nuclear@0 533 // for std::upper_bound
nuclear@0 534 operator const Pointer& () const {
nuclear@0 535 return address;
nuclear@0 536 }
nuclear@0 537 };
nuclear@0 538
nuclear@0 539 // for std::upper_bound
nuclear@0 540 inline bool operator< (const Pointer& a, const Pointer& b) {
nuclear@0 541 return a.val < b.val;
nuclear@0 542 }
nuclear@0 543
nuclear@0 544 // -------------------------------------------------------------------------------
nuclear@0 545 /** Utility to read all master file blocks in turn. */
nuclear@0 546 // -------------------------------------------------------------------------------
nuclear@0 547 class SectionParser
nuclear@0 548 {
nuclear@0 549 public:
nuclear@0 550
nuclear@0 551 // --------------------------------------------------------
nuclear@0 552 /** @param stream Inout stream, must point to the
nuclear@0 553 * first section in the file. Call Next() once
nuclear@0 554 * to have it read.
nuclear@0 555 * @param ptr64 Pointer size in file is 64 bits? */
nuclear@0 556 SectionParser(StreamReaderAny& stream,bool ptr64)
nuclear@0 557 : stream(stream)
nuclear@0 558 , ptr64(ptr64)
nuclear@0 559 {
nuclear@0 560 current.size = current.start = 0;
nuclear@0 561 }
nuclear@0 562
nuclear@0 563 public:
nuclear@0 564
nuclear@0 565 // --------------------------------------------------------
nuclear@0 566 const FileBlockHead& GetCurrent() const {
nuclear@0 567 return current;
nuclear@0 568 }
nuclear@0 569
nuclear@0 570
nuclear@0 571 public:
nuclear@0 572
nuclear@0 573 // --------------------------------------------------------
nuclear@0 574 /** Advance to the next section.
nuclear@0 575 * @throw DeadlyImportError if the last chunk was passed. */
nuclear@0 576 void Next();
nuclear@0 577
nuclear@0 578 public:
nuclear@0 579
nuclear@0 580 FileBlockHead current;
nuclear@0 581 StreamReaderAny& stream;
nuclear@0 582 bool ptr64;
nuclear@0 583 };
nuclear@0 584
nuclear@0 585
nuclear@0 586 #ifndef ASSIMP_BUILD_BLENDER_NO_STATS
nuclear@0 587 // -------------------------------------------------------------------------------
nuclear@0 588 /** Import statistics, i.e. number of file blocks read*/
nuclear@0 589 // -------------------------------------------------------------------------------
nuclear@0 590 class Statistics {
nuclear@0 591
nuclear@0 592 public:
nuclear@0 593
nuclear@0 594 Statistics ()
nuclear@0 595 : fields_read ()
nuclear@0 596 , pointers_resolved ()
nuclear@0 597 , cache_hits ()
nuclear@0 598 // , blocks_read ()
nuclear@0 599 , cached_objects ()
nuclear@0 600 {}
nuclear@0 601
nuclear@0 602 public:
nuclear@0 603
nuclear@0 604 /** total number of fields we read */
nuclear@0 605 unsigned int fields_read;
nuclear@0 606
nuclear@0 607 /** total number of resolved pointers */
nuclear@0 608 unsigned int pointers_resolved;
nuclear@0 609
nuclear@0 610 /** number of pointers resolved from the cache */
nuclear@0 611 unsigned int cache_hits;
nuclear@0 612
nuclear@0 613 /** number of blocks (from FileDatabase::entries)
nuclear@0 614 we did actually read from. */
nuclear@0 615 // unsigned int blocks_read;
nuclear@0 616
nuclear@0 617 /** objects in FileData::cache */
nuclear@0 618 unsigned int cached_objects;
nuclear@0 619 };
nuclear@0 620 #endif
nuclear@0 621
nuclear@0 622 // -------------------------------------------------------------------------------
nuclear@0 623 /** The object cache - all objects addressed by pointers are added here. This
nuclear@0 624 * avoids circular references and avoids object duplication. */
nuclear@0 625 // -------------------------------------------------------------------------------
nuclear@0 626 template <template <typename> class TOUT>
nuclear@0 627 class ObjectCache
nuclear@0 628 {
nuclear@0 629 public:
nuclear@0 630
nuclear@0 631 typedef std::map< Pointer, TOUT<ElemBase> > StructureCache;
nuclear@0 632
nuclear@0 633 public:
nuclear@0 634
nuclear@0 635 ObjectCache(const FileDatabase& db)
nuclear@0 636 : db(db)
nuclear@0 637 {
nuclear@0 638 // currently there are only ~400 structure records per blend file.
nuclear@0 639 // we read only a small part of them and don't cache objects
nuclear@0 640 // which we don't need, so this should suffice.
nuclear@0 641 caches.reserve(64);
nuclear@0 642 }
nuclear@0 643
nuclear@0 644 public:
nuclear@0 645
nuclear@0 646 // --------------------------------------------------------
nuclear@0 647 /** Check whether a specific item is in the cache.
nuclear@0 648 * @param s Data type of the item
nuclear@0 649 * @param out Output pointer. Unchanged if the
nuclear@0 650 * cache doens't know the item yet.
nuclear@0 651 * @param ptr Item address to look for. */
nuclear@0 652 template <typename T> void get (
nuclear@0 653 const Structure& s,
nuclear@0 654 TOUT<T>& out,
nuclear@0 655 const Pointer& ptr) const;
nuclear@0 656
nuclear@0 657 // --------------------------------------------------------
nuclear@0 658 /** Add an item to the cache after the item has
nuclear@0 659 * been fully read. Do not insert anything that
nuclear@0 660 * may be faulty or might cause the loading
nuclear@0 661 * to abort.
nuclear@0 662 * @param s Data type of the item
nuclear@0 663 * @param out Item to insert into the cache
nuclear@0 664 * @param ptr address (cache key) of the item. */
nuclear@0 665 template <typename T> void set
nuclear@0 666 (const Structure& s,
nuclear@0 667 const TOUT<T>& out,
nuclear@0 668 const Pointer& ptr);
nuclear@0 669
nuclear@0 670 private:
nuclear@0 671
nuclear@0 672 mutable vector<StructureCache> caches;
nuclear@0 673 const FileDatabase& db;
nuclear@0 674 };
nuclear@0 675
nuclear@0 676 // -------------------------------------------------------------------------------
nuclear@0 677 // -------------------------------------------------------------------------------
nuclear@0 678 template <> class ObjectCache<Blender::vector>
nuclear@0 679 {
nuclear@0 680 public:
nuclear@0 681
nuclear@0 682 ObjectCache(const FileDatabase&) {}
nuclear@0 683
nuclear@0 684 template <typename T> void get(const Structure&, vector<T>&, const Pointer&) {}
nuclear@0 685 template <typename T> void set(const Structure&, const vector<T>&, const Pointer&) {}
nuclear@0 686 };
nuclear@0 687
nuclear@0 688 #ifdef _MSC_VER
nuclear@0 689 # pragma warning(disable:4355)
nuclear@0 690 #endif
nuclear@0 691
nuclear@0 692 // -------------------------------------------------------------------------------
nuclear@0 693 /** Memory representation of a full BLEND file and all its dependencies. The
nuclear@0 694 * output aiScene is constructed from an instance of this data structure. */
nuclear@0 695 // -------------------------------------------------------------------------------
nuclear@0 696 class FileDatabase
nuclear@0 697 {
nuclear@0 698 template <template <typename> class TOUT> friend class ObjectCache;
nuclear@0 699
nuclear@0 700 public:
nuclear@0 701
nuclear@0 702
nuclear@0 703 FileDatabase()
nuclear@0 704 : _cacheArrays(*this)
nuclear@0 705 , _cache(*this)
nuclear@0 706 , next_cache_idx()
nuclear@0 707 {}
nuclear@0 708
nuclear@0 709 public:
nuclear@0 710
nuclear@0 711 // publicly accessible fields
nuclear@0 712 bool i64bit;
nuclear@0 713 bool little;
nuclear@0 714
nuclear@0 715 DNA dna;
nuclear@0 716 boost::shared_ptr< StreamReaderAny > reader;
nuclear@0 717 vector< FileBlockHead > entries;
nuclear@0 718
nuclear@0 719 public:
nuclear@0 720
nuclear@0 721 Statistics& stats() const {
nuclear@0 722 return _stats;
nuclear@0 723 }
nuclear@0 724
nuclear@0 725 // For all our templates to work on both shared_ptr's and vector's
nuclear@0 726 // using the same code, a dummy cache for arrays is provided. Actually,
nuclear@0 727 // arrays of objects are never cached because we can't easily
nuclear@0 728 // ensure their proper destruction.
nuclear@0 729 template <typename T>
nuclear@0 730 ObjectCache<boost::shared_ptr>& cache(boost::shared_ptr<T>& /*in*/) const {
nuclear@0 731 return _cache;
nuclear@0 732 }
nuclear@0 733
nuclear@0 734 template <typename T>
nuclear@0 735 ObjectCache<vector>& cache(vector<T>& /*in*/) const {
nuclear@0 736 return _cacheArrays;
nuclear@0 737 }
nuclear@0 738
nuclear@0 739 private:
nuclear@0 740
nuclear@0 741
nuclear@0 742 #ifndef ASSIMP_BUILD_BLENDER_NO_STATS
nuclear@0 743 mutable Statistics _stats;
nuclear@0 744 #endif
nuclear@0 745
nuclear@0 746 mutable ObjectCache<vector> _cacheArrays;
nuclear@0 747 mutable ObjectCache<boost::shared_ptr> _cache;
nuclear@0 748
nuclear@0 749 mutable size_t next_cache_idx;
nuclear@0 750 };
nuclear@0 751
nuclear@0 752 #ifdef _MSC_VER
nuclear@0 753 # pragma warning(default:4355)
nuclear@0 754 #endif
nuclear@0 755
nuclear@0 756 // -------------------------------------------------------------------------------
nuclear@0 757 /** Factory to extract a #DNA from the DNA1 file block in a BLEND file. */
nuclear@0 758 // -------------------------------------------------------------------------------
nuclear@0 759 class DNAParser
nuclear@0 760 {
nuclear@0 761
nuclear@0 762 public:
nuclear@0 763
nuclear@0 764 /** Bind the parser to a empty DNA and an input stream */
nuclear@0 765 DNAParser(FileDatabase& db)
nuclear@0 766 : db(db)
nuclear@0 767 {}
nuclear@0 768
nuclear@0 769 public:
nuclear@0 770
nuclear@0 771 // --------------------------------------------------------
nuclear@0 772 /** Locate the DNA in the file and parse it. The input
nuclear@0 773 * stream is expected to point to the beginning of the DN1
nuclear@0 774 * chunk at the time this method is called and is
nuclear@0 775 * undefined afterwards.
nuclear@0 776 * @throw DeadlyImportError if the DNA cannot be read.
nuclear@0 777 * @note The position of the stream pointer is undefined
nuclear@0 778 * afterwards.*/
nuclear@0 779 void Parse ();
nuclear@0 780
nuclear@0 781 public:
nuclear@0 782
nuclear@0 783 /** Obtain a reference to the extracted DNA information */
nuclear@0 784 const Blender::DNA& GetDNA() const {
nuclear@0 785 return db.dna;
nuclear@0 786 }
nuclear@0 787
nuclear@0 788 private:
nuclear@0 789
nuclear@0 790 FileDatabase& db;
nuclear@0 791 };
nuclear@0 792
nuclear@0 793 } // end Blend
nuclear@0 794 } // end Assimp
nuclear@0 795
nuclear@0 796 #include "BlenderDNA.inl"
nuclear@0 797
nuclear@0 798 #endif