2
Open Asset Import Library (ASSIMP)
3
----------------------------------------------------------------------
5
Copyright (c) 2006-2010, ASSIMP Development Team
8
Redistribution and use of this software in source and binary forms,
9
with or without modification, are permitted provided that the
10
following conditions are met:
12
* Redistributions of source code must retain the above
13
copyright notice, this list of conditions and the
16
* Redistributions in binary form must reproduce the above
17
copyright notice, this list of conditions and the
18
following disclaimer in the documentation and/or other
19
materials provided with the distribution.
21
* Neither the name of the ASSIMP team, nor the names of its
22
contributors may be used to endorse or promote products
23
derived from this software without specific prior
24
written permission of the ASSIMP Development Team.
26
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
27
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
28
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
29
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
30
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
31
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
32
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
33
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
34
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
35
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
36
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
38
----------------------------------------------------------------------
41
/** @file BlenderDNA.h
42
* @brief Blender `DNA` (file format specification embedded in
43
* blend file itself) loader.
45
#ifndef INCLUDED_AI_BLEND_DNA_H
46
#define INCLUDED_AI_BLEND_DNA_H
48
#include "BaseImporter.h"
49
#include "TinyFormatter.h"
51
// enable verbose log output. really verbose, so be careful.
53
# define ASSIMP_BUILD_BLENDER_DEBUG
56
// #define ASSIMP_BUILD_BLENDER_NO_STATS
59
template <bool,bool> class StreamReader;
60
typedef StreamReader<true,true> StreamReaderAny;
66
template <template <typename> class TOUT>
69
// -------------------------------------------------------------------------------
70
/** Exception class used by the blender loader to selectively catch exceptions
71
* thrown in its own code (DeadlyImportErrors thrown in general utility
72
* functions are untouched then). If such an exception is not caught by
73
* the loader itself, it will still be caught by Assimp due to its
75
// -------------------------------------------------------------------------------
76
struct Error : DeadlyImportError
78
Error (const std::string& s)
79
: DeadlyImportError(s)
83
// -------------------------------------------------------------------------------
84
/** The only purpose of this structure is to feed a virtual dtor into its
85
* descendents. It serves as base class for all data structure fields. */
86
// -------------------------------------------------------------------------------
89
virtual ~ElemBase() {}
91
/** Type name of the element. The type
92
* string points is the `c_str` of the `name` attribute of the
93
* corresponding `Structure`, that is, it is only valid as long
94
* as the DNA is not modified. The dna_type is only set if the
95
* data type is not static, i.e. a boost::shared_ptr<ElemBase>
96
* in the scene description would have its type resolved
97
* at runtime, so this member is always set. */
102
// -------------------------------------------------------------------------------
103
/** Represents a generic pointer to a memory location, which can be either 32
104
* or 64 bits. These pointers are loaded from the BLEND file and finally
105
* fixed to point to the real, converted representation of the objects
106
* they used to point to.*/
107
// -------------------------------------------------------------------------------
114
// -------------------------------------------------------------------------------
115
/** Represents a generic offset within a BLEND file */
116
// -------------------------------------------------------------------------------
119
FileOffset() : val() {}
123
// -------------------------------------------------------------------------------
124
/** Dummy derivate of std::vector to be able to use it in templates simultaenously
125
* with boost::shared_ptr, which takes only one template argument
126
* while std::vector takes three. Also we need to provide some special member
127
* functions of shared_ptr */
128
// -------------------------------------------------------------------------------
129
template <typename T>
130
class vector : public std::vector<T>
133
using std::vector<T>::resize;
134
using std::vector<T>::empty;
140
operator bool () const {
145
// -------------------------------------------------------------------------------
146
/** Mixed flags for use in #Field */
147
// -------------------------------------------------------------------------------
150
FieldFlag_Pointer = 0x1,
151
FieldFlag_Array = 0x2
154
// -------------------------------------------------------------------------------
155
/** Represents a single member of a data structure in a BLEND file */
156
// -------------------------------------------------------------------------------
165
/** Size of each array dimension. For flat arrays,
166
* the second dimension is set to 1. */
167
size_t array_sizes[2];
169
/** Any of the #FieldFlags enumerated values */
173
// -------------------------------------------------------------------------------
174
/** Range of possible behaviours for fields absend in the input file. Some are
175
* mission critical so we need them, while others can silently be default
176
* initialized and no animations are harmed. */
177
// -------------------------------------------------------------------------------
180
/** Substitute default value and ignore */
182
/** Substitute default value and write to log */
184
/** Substitute a massive error message and crash the whole matrix. Its time for another zion */
188
#ifdef ASSIMP_BUILD_BLENDER_DEBUG
189
# define ErrorPolicy_Igno ErrorPolicy_Warn
192
// -------------------------------------------------------------------------------
193
/** Represents a data structure in a BLEND file. A Structure defines n fields
194
* and their locatios and encodings the input stream. Usually, every
195
* Structure instance pertains to one equally-named data structure in the
196
* BlenderScene.h header. This class defines various utilities to map a
197
* binary `blob` read from the file to such a structure instance with
198
* meaningful contents. */
199
// -------------------------------------------------------------------------------
202
template <template <typename> class> friend class ObjectCache;
212
// publicly accessible members
214
vector< Field > fields;
215
std::map<std::string, size_t> indices;
221
// --------------------------------------------------------
222
/** Access a field of the structure by its canonical name. The pointer version
223
* returns NULL on failure while the reference version raises an import error. */
224
inline const Field& operator [] (const std::string& ss) const;
225
inline const Field* Get (const std::string& ss) const;
227
// --------------------------------------------------------
228
/** Access a field of the structure by its index */
229
inline const Field& operator [] (const size_t i) const;
231
// --------------------------------------------------------
232
inline bool operator== (const Structure& other) const {
233
return name == other.name; // name is meant to be an unique identifier
236
// --------------------------------------------------------
237
inline bool operator!= (const Structure& other) const {
238
return name != other.name;
243
// --------------------------------------------------------
244
/** Try to read an instance of the structure from the stream
245
* and attempt to convert to `T`. This is done by
246
* an appropriate specialization. If none is available,
247
* a compiler complain is the result.
248
* @param dest Destination value to be written
249
* @param db File database, including input stream. */
250
template <typename T> inline void Convert (T& dest,
251
const FileDatabase& db) const;
255
// --------------------------------------------------------
257
template <typename T>
258
void Convert(boost::shared_ptr<ElemBase> in,const FileDatabase& db) const;
260
// --------------------------------------------------------
262
template <typename T> boost::shared_ptr<ElemBase> Allocate() const;
266
// --------------------------------------------------------
267
// field parsing for 1d arrays
268
template <int error_policy, typename T, size_t M>
269
void ReadFieldArray(T (& out)[M], const char* name,
270
const FileDatabase& db) const;
272
// --------------------------------------------------------
273
// field parsing for 2d arrays
274
template <int error_policy, typename T, size_t M, size_t N>
275
void ReadFieldArray2(T (& out)[M][N], const char* name,
276
const FileDatabase& db) const;
278
// --------------------------------------------------------
279
// field parsing for pointer or dynamic array types
280
// (boost::shared_ptr or boost::shared_array)
281
template <int error_policy, template <typename> class TOUT, typename T>
282
void ReadFieldPtr(TOUT<T>& out, const char* name,
283
const FileDatabase& db) const;
285
// --------------------------------------------------------
286
// field parsing for static arrays of pointer or dynamic
287
// array types (boost::shared_ptr[] or boost::shared_array[])
288
template <int error_policy, template <typename> class TOUT, typename T, size_t N>
289
void ReadFieldPtr(TOUT<T> (&out)[N], const char* name,
290
const FileDatabase& db) const;
292
// --------------------------------------------------------
293
// field parsing for `normal` values
294
template <int error_policy, typename T>
295
void ReadField(T& out, const char* name,
296
const FileDatabase& db) const;
300
// --------------------------------------------------------
301
template <template <typename> class TOUT, typename T>
302
void ResolvePointer(TOUT<T>& out, const Pointer & ptrval,
303
const FileDatabase& db, const Field& f) const;
305
// --------------------------------------------------------
306
template <template <typename> class TOUT, typename T>
307
void ResolvePointer(vector< TOUT<T> >& out, const Pointer & ptrval,
308
const FileDatabase& db, const Field& f) const;
310
// --------------------------------------------------------
311
void ResolvePointer( boost::shared_ptr< FileOffset >& out, const Pointer & ptrval,
312
const FileDatabase& db, const Field& f) const;
314
// --------------------------------------------------------
315
inline const FileBlockHead* LocateFileBlockForAddress(
316
const Pointer & ptrval,
317
const FileDatabase& db) const;
321
// ------------------------------------------------------------------------------
322
template <typename T> T* _allocate(boost::shared_ptr<T>& out, size_t& s) const {
323
out = boost::shared_ptr<T>(new T());
328
template <typename T> T* _allocate(vector<T>& out, size_t& s) const {
330
return s ? &out.front() : NULL;
333
// --------------------------------------------------------
334
template <int error_policy>
335
struct _defaultInitializer {
337
template <typename T, unsigned int N>
338
void operator ()(T (& out)[N], const char* = NULL) {
339
for (unsigned int i = 0; i < N; ++i) {
344
template <typename T, unsigned int N, unsigned int M>
345
void operator ()(T (& out)[N][M], const char* = NULL) {
346
for (unsigned int i = 0; i < N; ++i) {
347
for (unsigned int j = 0; j < M; ++j) {
353
template <typename T>
354
void operator ()(T& out, const char* = NULL) {
361
mutable size_t cache_idx;
364
// --------------------------------------------------------
365
template <> struct Structure :: _defaultInitializer<ErrorPolicy_Warn> {
367
template <typename T>
368
void operator ()(T& out, const char* reason = "<add reason>") {
369
DefaultLogger::get()->warn(reason);
371
// ... and let the show go on
372
_defaultInitializer<0 /*ErrorPolicy_Igno*/>()(out);
376
template <> struct Structure :: _defaultInitializer<ErrorPolicy_Fail> {
378
template <typename T>
379
void operator ()(T& out,const char* = "") {
380
// obviously, it is crucial that _DefaultInitializer is used
381
// only from within a catch clause.
386
// -------------------------------------------------------------------------------------------------------
387
template <> inline void Structure :: ResolvePointer<boost::shared_ptr,ElemBase>(boost::shared_ptr<ElemBase>& out,
388
const Pointer & ptrval,
389
const FileDatabase& db,
394
// -------------------------------------------------------------------------------
395
/** Represents the full data structure information for a single BLEND file.
396
* This data is extracted from the DNA1 chunk in the file.
397
* #DNAParser does the reading and represents currently the only place where
399
// -------------------------------------------------------------------------------
404
typedef void (Structure::*ConvertProcPtr) (
405
boost::shared_ptr<ElemBase> in,
409
typedef boost::shared_ptr<ElemBase> (
410
Structure::*AllocProcPtr) () const;
412
typedef std::pair< AllocProcPtr, ConvertProcPtr > FactoryPair;
416
std::map<std::string, FactoryPair > converters;
417
vector<Structure > structures;
418
std::map<std::string, size_t> indices;
422
// --------------------------------------------------------
423
/** Access a structure by its canonical name, the pointer version returns NULL on failure
424
* while the reference version raises an error. */
425
inline const Structure& operator [] (const std::string& ss) const;
426
inline const Structure* Get (const std::string& ss) const;
428
// --------------------------------------------------------
429
/** Access a structure by its index */
430
inline const Structure& operator [] (const size_t i) const;
434
// --------------------------------------------------------
435
/** Add structure definitions for all the primitive types,
436
* i.e. integer, short, char, float */
437
void AddPrimitiveStructures();
439
// --------------------------------------------------------
440
/** Fill the @c converters member with converters for all
441
* known data types. The implementation of this method is
442
* in BlenderScene.cpp and is machine-generated.
443
* Converters are used to quickly handle objects whose
444
* exact data type is a runtime-property and not yet
445
* known at compile time (consier Object::data).*/
446
void RegisterConverters();
449
// --------------------------------------------------------
450
/** Take an input blob from the stream, interpret it according to
451
* a its structure name and convert it to the intermediate
453
* @param structure Destination structure definition
454
* @param db File database.
455
* @return A null pointer if no appropriate converter is available.*/
456
boost::shared_ptr< ElemBase > ConvertBlobToStructure(
457
const Structure& structure,
458
const FileDatabase& db
461
// --------------------------------------------------------
462
/** Find a suitable conversion function for a given Structure.
463
* Such a converter function takes a blob from the input
464
* stream, reads as much as it needs, and builds up a
465
* complete object in intermediate representation.
466
* @param structure Destination structure definition
467
* @param db File database.
468
* @return A null pointer in .first if no appropriate converter is available.*/
469
FactoryPair GetBlobToStructureConverter(
470
const Structure& structure,
471
const FileDatabase& db
475
#ifdef ASSIMP_BUILD_BLENDER_DEBUG
476
// --------------------------------------------------------
477
/** Dump the DNA to a text file. This is for debugging purposes.
478
* The output file is `dna.txt` in the current working folder*/
482
// --------------------------------------------------------
483
/** Extract array dimensions from a C array declaration, such
484
* as `...[4][6]`. Returned string would be `...[][]`.
486
* @param array_sizes Receive maximally two array dimensions,
487
* the second element is set to 1 if the array is flat.
488
* Both are set to 1 if the input is not an array.
489
* @throw DeadlyImportError if more than 2 dimensions are
491
static void ExtractArraySize(
492
const std::string& out,
493
size_t array_sizes[2]
497
// special converters for primitive types
498
template <> inline void Structure :: Convert<int> (int& dest,const FileDatabase& db) const;
499
template <> inline void Structure :: Convert<short> (short& dest,const FileDatabase& db) const;
500
template <> inline void Structure :: Convert<char> (char& dest,const FileDatabase& db) const;
501
template <> inline void Structure :: Convert<float> (float& dest,const FileDatabase& db) const;
502
template <> inline void Structure :: Convert<double> (double& dest,const FileDatabase& db) const;
503
template <> inline void Structure :: Convert<Pointer> (Pointer& dest,const FileDatabase& db) const;
505
// -------------------------------------------------------------------------------
506
/** Describes a master file block header. Each master file sections holds n
507
* elements of a certain SDNA structure (or otherwise unspecified data). */
508
// -------------------------------------------------------------------------------
511
// points right after the header of the file block
512
StreamReaderAny::pos start;
517
// original memory address of the data
521
unsigned int dna_index;
523
// number of structure instances to follow
528
// file blocks are sorted by address to quickly locate specific memory addresses
529
bool operator < (const FileBlockHead& o) const {
530
return address.val < o.address.val;
533
// for std::upper_bound
534
operator const Pointer& () const {
539
// for std::upper_bound
540
inline bool operator< (const Pointer& a, const Pointer& b) {
541
return a.val < b.val;
544
// -------------------------------------------------------------------------------
545
/** Utility to read all master file blocks in turn. */
546
// -------------------------------------------------------------------------------
551
// --------------------------------------------------------
552
/** @param stream Inout stream, must point to the
553
* first section in the file. Call Next() once
555
* @param ptr64 Pointer size in file is 64 bits? */
556
SectionParser(StreamReaderAny& stream,bool ptr64)
560
current.size = current.start = 0;
565
// --------------------------------------------------------
566
const FileBlockHead& GetCurrent() const {
573
// --------------------------------------------------------
574
/** Advance to the next section.
575
* @throw DeadlyImportError if the last chunk was passed. */
580
FileBlockHead current;
581
StreamReaderAny& stream;
586
#ifndef ASSIMP_BUILD_BLENDER_NO_STATS
587
// -------------------------------------------------------------------------------
588
/** Import statistics, i.e. number of file blocks read*/
589
// -------------------------------------------------------------------------------
596
, pointers_resolved ()
604
/** total number of fields we read */
605
unsigned int fields_read;
607
/** total number of resolved pointers */
608
unsigned int pointers_resolved;
610
/** number of pointers resolved from the cache */
611
unsigned int cache_hits;
613
/** number of blocks (from FileDatabase::entries)
614
we did actually read from. */
615
// unsigned int blocks_read;
617
/** objects in FileData::cache */
618
unsigned int cached_objects;
622
// -------------------------------------------------------------------------------
623
/** The object cache - all objects addressed by pointers are added here. This
624
* avoids circular references and avoids object duplication. */
625
// -------------------------------------------------------------------------------
626
template <template <typename> class TOUT>
631
typedef std::map< Pointer, TOUT<ElemBase> > StructureCache;
635
ObjectCache(const FileDatabase& db)
638
// currently there are only ~400 structure records per blend file.
639
// we read only a small part of them and don't cache objects
640
// which we don't need, so this should suffice.
646
// --------------------------------------------------------
647
/** Check whether a specific item is in the cache.
648
* @param s Data type of the item
649
* @param out Output pointer. Unchanged if the
650
* cache doens't know the item yet.
651
* @param ptr Item address to look for. */
652
template <typename T> void get (
655
const Pointer& ptr) const;
657
// --------------------------------------------------------
658
/** Add an item to the cache after the item has
659
* been fully read. Do not insert anything that
660
* may be faulty or might cause the loading
662
* @param s Data type of the item
663
* @param out Item to insert into the cache
664
* @param ptr address (cache key) of the item. */
665
template <typename T> void set
672
mutable vector<StructureCache> caches;
673
const FileDatabase& db;
676
// -------------------------------------------------------------------------------
677
// -------------------------------------------------------------------------------
678
template <> class ObjectCache<Blender::vector>
682
ObjectCache(const FileDatabase&) {}
684
template <typename T> void get(const Structure&, vector<T>&t, const Pointer&) {}
685
template <typename T> void set(const Structure&, const vector<T>&, const Pointer&) {}
689
# pragma warning(disable:4355)
692
// -------------------------------------------------------------------------------
693
/** Memory representation of a full BLEND file and all its dependencies. The
694
* output aiScene is constructed from an instance of this data structure. */
695
// -------------------------------------------------------------------------------
698
template <template <typename> class TOUT> friend class ObjectCache;
705
, _cacheArrays(*this)
711
// publicly accessible fields
716
boost::shared_ptr< StreamReaderAny > reader;
717
vector< FileBlockHead > entries;
721
Statistics& stats() const {
725
// For all our templates to work on both shared_ptr's and vector's
726
// using the same code, a dummy cache for arrays is provided. Actually,
727
// arrays of objects are never cached because we can't easily
728
// ensure their proper destruction.
729
template <typename T>
730
ObjectCache<boost::shared_ptr>& cache(boost::shared_ptr<T>& in) const {
734
template <typename T>
735
ObjectCache<vector>& cache(vector<T>& in) const {
742
#ifndef ASSIMP_BUILD_BLENDER_NO_STATS
743
mutable Statistics _stats;
746
mutable ObjectCache<vector> _cacheArrays;
747
mutable ObjectCache<boost::shared_ptr> _cache;
749
mutable size_t next_cache_idx;
753
# pragma warning(default:4355)
756
// -------------------------------------------------------------------------------
757
/** Factory to extract a #DNA from the DNA1 file block in a BLEND file. */
758
// -------------------------------------------------------------------------------
764
/** Bind the parser to a empty DNA and an input stream */
765
DNAParser(FileDatabase& db)
771
// --------------------------------------------------------
772
/** Locate the DNA in the file and parse it. The input
773
* stream is expected to point to the beginning of the DN1
774
* chunk at the time this method is called and is
775
* undefined afterwards.
776
* @throw DeadlyImportError if the DNA cannot be read.
777
* @note The position of the stream pointer is undefined
783
/** Obtain a reference to the extracted DNA information */
784
const Blender::DNA& GetDNA() const {
796
#include "BlenderDNA.inl"