~ubuntu-branches/ubuntu/trusty/assimp/trusty-proposed

« back to all changes in this revision

Viewing changes to code/BlenderDNA.h

  • Committer: Package Import Robot
  • Author(s): IOhannes m zmoelnig (gpg-key at iem)
  • Date: 2011-08-23 16:51:26 UTC
  • Revision ID: package-import@ubuntu.com-20110823165126-rvbjt1qtcusine1c
Tags: upstream-2.0.863+dfsg
ImportĀ upstreamĀ versionĀ 2.0.863+dfsg

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
Open Asset Import Library (ASSIMP)
 
3
----------------------------------------------------------------------
 
4
 
 
5
Copyright (c) 2006-2010, ASSIMP Development Team
 
6
All rights reserved.
 
7
 
 
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:
 
11
 
 
12
* Redistributions of source code must retain the above
 
13
  copyright notice, this list of conditions and the
 
14
  following disclaimer.
 
15
 
 
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.
 
20
 
 
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.
 
25
 
 
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.
 
37
 
 
38
----------------------------------------------------------------------
 
39
*/
 
40
 
 
41
/** @file  BlenderDNA.h
 
42
 *  @brief Blender `DNA` (file format specification embedded in 
 
43
 *    blend file itself) loader.
 
44
 */
 
45
#ifndef INCLUDED_AI_BLEND_DNA_H
 
46
#define INCLUDED_AI_BLEND_DNA_H
 
47
 
 
48
#include "BaseImporter.h"
 
49
#include "TinyFormatter.h"
 
50
 
 
51
// enable verbose log output. really verbose, so be careful.
 
52
#ifdef _DEBUG
 
53
#       define ASSIMP_BUILD_BLENDER_DEBUG
 
54
#endif
 
55
 
 
56
// #define ASSIMP_BUILD_BLENDER_NO_STATS
 
57
 
 
58
namespace Assimp        {
 
59
        template <bool,bool> class StreamReader;
 
60
        typedef StreamReader<true,true> StreamReaderAny;
 
61
 
 
62
        namespace Blender {
 
63
                class  FileDatabase;
 
64
                struct FileBlockHead;
 
65
 
 
66
                template <template <typename> class TOUT>
 
67
                class ObjectCache;
 
68
 
 
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
 
74
 *  ancestry. */
 
75
// -------------------------------------------------------------------------------
 
76
struct Error : DeadlyImportError
 
77
{
 
78
        Error (const std::string& s)
 
79
                : DeadlyImportError(s)
 
80
        {}
 
81
};
 
82
 
 
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
// -------------------------------------------------------------------------------
 
87
struct ElemBase 
 
88
{
 
89
        virtual ~ElemBase() {}
 
90
 
 
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. */
 
98
        const char* dna_type;
 
99
};
 
100
 
 
101
 
 
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
// -------------------------------------------------------------------------------
 
108
struct Pointer
 
109
{
 
110
        Pointer() : val() {}
 
111
        uint64_t val;
 
112
};
 
113
 
 
114
// -------------------------------------------------------------------------------
 
115
/** Represents a generic offset within a BLEND file */
 
116
// -------------------------------------------------------------------------------
 
117
struct FileOffset
 
118
{
 
119
        FileOffset() : val() {}
 
120
        uint64_t val;
 
121
};
 
122
 
 
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>
 
131
{
 
132
public:
 
133
        using std::vector<T>::resize;
 
134
        using std::vector<T>::empty;
 
135
 
 
136
        void reset() {
 
137
                resize(0);
 
138
        }
 
139
 
 
140
        operator bool () const {
 
141
                return !empty();
 
142
        }
 
143
};
 
144
 
 
145
// -------------------------------------------------------------------------------
 
146
/** Mixed flags for use in #Field */
 
147
// -------------------------------------------------------------------------------
 
148
enum FieldFlags 
 
149
{
 
150
        FieldFlag_Pointer = 0x1,
 
151
        FieldFlag_Array   = 0x2
 
152
};
 
153
 
 
154
// -------------------------------------------------------------------------------
 
155
/** Represents a single member of a data structure in a BLEND file */
 
156
// -------------------------------------------------------------------------------
 
157
struct Field 
 
158
{       
 
159
        std::string name;
 
160
        std::string type;
 
161
 
 
162
        size_t size;
 
163
        size_t offset;
 
164
 
 
165
        /** Size of each array dimension. For flat arrays,
 
166
         *  the second dimension is set to 1. */
 
167
        size_t array_sizes[2];
 
168
 
 
169
        /** Any of the #FieldFlags enumerated values */
 
170
        unsigned int flags;
 
171
};
 
172
 
 
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
// -------------------------------------------------------------------------------
 
178
enum ErrorPolicy 
 
179
{
 
180
        /** Substitute default value and ignore */
 
181
        ErrorPolicy_Igno,
 
182
        /** Substitute default value and write to log */
 
183
        ErrorPolicy_Warn,
 
184
        /** Substitute a massive error message and crash the whole matrix. Its time for another zion */
 
185
        ErrorPolicy_Fail
 
186
};
 
187
 
 
188
#ifdef ASSIMP_BUILD_BLENDER_DEBUG
 
189
#       define ErrorPolicy_Igno ErrorPolicy_Warn
 
190
#endif
 
191
 
 
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
// -------------------------------------------------------------------------------
 
200
class Structure 
 
201
{
 
202
        template <template <typename> class> friend class ObjectCache;
 
203
 
 
204
public:
 
205
 
 
206
        Structure()
 
207
                :       cache_idx(-1)
 
208
        {}
 
209
 
 
210
public:
 
211
 
 
212
        // publicly accessible members
 
213
        std::string name;
 
214
        vector< Field > fields;
 
215
        std::map<std::string, size_t> indices;
 
216
 
 
217
        size_t size;
 
218
 
 
219
public:
 
220
 
 
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;
 
226
 
 
227
        // --------------------------------------------------------
 
228
        /** Access a field of the structure by its index */
 
229
        inline const Field& operator [] (const size_t i) const;
 
230
 
 
231
        // --------------------------------------------------------
 
232
        inline bool operator== (const Structure& other) const {
 
233
                return name == other.name; // name is meant to be an unique identifier
 
234
        }
 
235
 
 
236
        // --------------------------------------------------------
 
237
        inline bool operator!= (const Structure& other) const {
 
238
                return name != other.name;
 
239
        }
 
240
 
 
241
public:
 
242
 
 
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;
 
252
 
 
253
 
 
254
 
 
255
        // --------------------------------------------------------
 
256
        // generic converter
 
257
        template <typename T>
 
258
        void Convert(boost::shared_ptr<ElemBase> in,const FileDatabase& db) const;
 
259
 
 
260
        // --------------------------------------------------------
 
261
        // generic allocator
 
262
        template <typename T> boost::shared_ptr<ElemBase> Allocate() const;
 
263
 
 
264
 
 
265
 
 
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;
 
271
 
 
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;
 
277
 
 
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;
 
284
 
 
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;
 
291
 
 
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;
 
297
 
 
298
private:
 
299
 
 
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;
 
304
 
 
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;
 
309
 
 
310
        // --------------------------------------------------------
 
311
        void ResolvePointer( boost::shared_ptr< FileOffset >& out, const Pointer & ptrval, 
 
312
                const FileDatabase& db, const Field& f) const;
 
313
 
 
314
        // --------------------------------------------------------
 
315
        inline const FileBlockHead* LocateFileBlockForAddress(
 
316
                const Pointer & ptrval,
 
317
                const FileDatabase& db) const;
 
318
 
 
319
private:
 
320
 
 
321
        // ------------------------------------------------------------------------------
 
322
        template <typename T> T* _allocate(boost::shared_ptr<T>& out, size_t& s) const {
 
323
                out = boost::shared_ptr<T>(new T());
 
324
                s = 1;
 
325
                return out.get();
 
326
        }
 
327
 
 
328
        template <typename T> T* _allocate(vector<T>& out, size_t& s) const {
 
329
                out.resize(s);
 
330
                return s ? &out.front() : NULL;
 
331
        }
 
332
 
 
333
        // --------------------------------------------------------
 
334
        template <int error_policy>
 
335
        struct _defaultInitializer {
 
336
 
 
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) {
 
340
                                out[i] = T(); 
 
341
                        }
 
342
                }
 
343
 
 
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) {
 
348
                                        out[i][j] = T(); 
 
349
                                }
 
350
                        }
 
351
                }
 
352
 
 
353
                template <typename T>
 
354
                void operator ()(T& out, const char* = NULL) {
 
355
                        out = T();
 
356
                }
 
357
        };
 
358
 
 
359
private:
 
360
 
 
361
        mutable size_t cache_idx;
 
362
};
 
363
 
 
364
// --------------------------------------------------------
 
365
template <>  struct Structure :: _defaultInitializer<ErrorPolicy_Warn> {
 
366
 
 
367
        template <typename T>
 
368
        void operator ()(T& out, const char* reason = "<add reason>") {
 
369
                DefaultLogger::get()->warn(reason);
 
370
 
 
371
                // ... and let the show go on
 
372
                _defaultInitializer<0 /*ErrorPolicy_Igno*/>()(out);
 
373
        }
 
374
};
 
375
 
 
376
template <> struct Structure :: _defaultInitializer<ErrorPolicy_Fail> {
 
377
 
 
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.
 
382
                throw;
 
383
        }
 
384
};
 
385
 
 
386
// -------------------------------------------------------------------------------------------------------
 
387
template <> inline void Structure :: ResolvePointer<boost::shared_ptr,ElemBase>(boost::shared_ptr<ElemBase>& out, 
 
388
        const Pointer & ptrval, 
 
389
        const FileDatabase& db, 
 
390
        const Field& f
 
391
        ) const;
 
392
 
 
393
 
 
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 
 
398
 *  DNA is altered.*/
 
399
// -------------------------------------------------------------------------------
 
400
class DNA
 
401
{
 
402
public:
 
403
 
 
404
        typedef void (Structure::*ConvertProcPtr) (
 
405
                boost::shared_ptr<ElemBase> in, 
 
406
                const FileDatabase&
 
407
        ) const;
 
408
 
 
409
        typedef boost::shared_ptr<ElemBase> (
 
410
                Structure::*AllocProcPtr) () const;
 
411
        
 
412
        typedef std::pair< AllocProcPtr, ConvertProcPtr > FactoryPair;
 
413
 
 
414
public:
 
415
 
 
416
        std::map<std::string, FactoryPair > converters;
 
417
        vector<Structure > structures;
 
418
        std::map<std::string, size_t> indices;
 
419
 
 
420
public:
 
421
 
 
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;
 
427
 
 
428
        // --------------------------------------------------------
 
429
        /** Access a structure by its index */
 
430
        inline const Structure& operator [] (const size_t i) const;
 
431
 
 
432
public:
 
433
 
 
434
        // --------------------------------------------------------
 
435
        /** Add structure definitions for all the primitive types,
 
436
         *  i.e. integer, short, char, float */
 
437
        void AddPrimitiveStructures();
 
438
 
 
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();
 
447
 
 
448
 
 
449
        // --------------------------------------------------------
 
450
        /** Take an input blob from the stream, interpret it according to 
 
451
         *  a its structure name and convert it to the intermediate
 
452
         *  representation. 
 
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
 
459
                ) const;
 
460
 
 
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
 
472
                ) const;
 
473
 
 
474
 
 
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*/
 
479
        void DumpToFile();
 
480
#endif
 
481
 
 
482
        // --------------------------------------------------------
 
483
        /** Extract array dimensions from a C array declaration, such
 
484
         *  as `...[4][6]`. Returned string would be `...[][]`.
 
485
         *  @param out
 
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
 
490
         *    encountered. */
 
491
        static void ExtractArraySize(
 
492
                const std::string& out, 
 
493
                size_t array_sizes[2]
 
494
        );
 
495
};
 
496
 
 
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;
 
504
 
 
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
// -------------------------------------------------------------------------------
 
509
struct FileBlockHead 
 
510
{
 
511
        // points right after the header of the file block
 
512
        StreamReaderAny::pos start;
 
513
 
 
514
        std::string id;
 
515
        size_t size;
 
516
 
 
517
        // original memory address of the data
 
518
        Pointer address;
 
519
 
 
520
        // index into DNA
 
521
        unsigned int dna_index;
 
522
 
 
523
        // number of structure instances to follow
 
524
        size_t num;
 
525
 
 
526
 
 
527
 
 
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;
 
531
        }
 
532
 
 
533
        // for std::upper_bound
 
534
        operator const Pointer& () const {
 
535
                return address;
 
536
        }
 
537
};
 
538
 
 
539
// for std::upper_bound
 
540
inline bool operator< (const Pointer& a, const Pointer& b) {
 
541
        return a.val < b.val;
 
542
}
 
543
 
 
544
// -------------------------------------------------------------------------------
 
545
/** Utility to read all master file blocks in turn. */
 
546
// -------------------------------------------------------------------------------
 
547
class SectionParser 
 
548
{
 
549
public:
 
550
 
 
551
        // --------------------------------------------------------
 
552
        /** @param stream Inout stream, must point to the 
 
553
         *  first section in the file. Call Next() once
 
554
         *  to have it read. 
 
555
         *  @param ptr64 Pointer size in file is 64 bits? */
 
556
        SectionParser(StreamReaderAny& stream,bool ptr64)
 
557
                : stream(stream)
 
558
                , ptr64(ptr64)
 
559
        {
 
560
                current.size = current.start = 0;
 
561
        }
 
562
 
 
563
public:
 
564
 
 
565
        // --------------------------------------------------------
 
566
        const FileBlockHead& GetCurrent() const {
 
567
                return current;
 
568
        }
 
569
        
 
570
 
 
571
public:
 
572
 
 
573
        // --------------------------------------------------------
 
574
        /** Advance to the next section. 
 
575
         *  @throw DeadlyImportError if the last chunk was passed. */
 
576
        void Next();
 
577
 
 
578
public:
 
579
 
 
580
        FileBlockHead current;
 
581
        StreamReaderAny& stream;
 
582
        bool ptr64;
 
583
};
 
584
 
 
585
 
 
586
#ifndef ASSIMP_BUILD_BLENDER_NO_STATS
 
587
// -------------------------------------------------------------------------------
 
588
/** Import statistics, i.e. number of file blocks read*/
 
589
// -------------------------------------------------------------------------------
 
590
class Statistics {
 
591
 
 
592
public:
 
593
 
 
594
        Statistics () 
 
595
                : fields_read           ()
 
596
                , pointers_resolved     ()
 
597
                , cache_hits            ()
 
598
//              , blocks_read           ()
 
599
                , cached_objects        ()
 
600
        {}
 
601
 
 
602
public:
 
603
 
 
604
        /** total number of fields we read */
 
605
        unsigned int fields_read;
 
606
 
 
607
        /** total number of resolved pointers */
 
608
        unsigned int pointers_resolved;
 
609
 
 
610
        /** number of pointers resolved from the cache */
 
611
        unsigned int cache_hits;
 
612
 
 
613
        /** number of blocks (from  FileDatabase::entries) 
 
614
          we did actually read from. */
 
615
        // unsigned int blocks_read;
 
616
 
 
617
        /** objects in FileData::cache */
 
618
        unsigned int cached_objects;
 
619
};
 
620
#endif
 
621
 
 
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>
 
627
class ObjectCache 
 
628
{
 
629
public:
 
630
 
 
631
        typedef std::map< Pointer, TOUT<ElemBase> > StructureCache;
 
632
 
 
633
public:
 
634
 
 
635
        ObjectCache(const FileDatabase& db)
 
636
                : db(db)
 
637
        {
 
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.
 
641
                caches.reserve(64);
 
642
        }
 
643
 
 
644
public:
 
645
 
 
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 (
 
653
                const Structure& s, 
 
654
                TOUT<T>& out, 
 
655
                const Pointer& ptr) const;
 
656
 
 
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
 
661
         * to abort. 
 
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 
 
666
                (const Structure& s, 
 
667
                const TOUT<T>& out, 
 
668
                const Pointer& ptr);
 
669
 
 
670
private:
 
671
 
 
672
        mutable vector<StructureCache> caches;
 
673
        const FileDatabase& db;
 
674
};
 
675
 
 
676
// -------------------------------------------------------------------------------
 
677
// -------------------------------------------------------------------------------
 
678
template <> class ObjectCache<Blender::vector> 
 
679
{
 
680
public:
 
681
 
 
682
        ObjectCache(const FileDatabase&) {}
 
683
 
 
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&) {}
 
686
};
 
687
 
 
688
#ifdef _MSC_VER
 
689
#       pragma warning(disable:4355)
 
690
#endif
 
691
 
 
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
// -------------------------------------------------------------------------------
 
696
class FileDatabase 
 
697
{
 
698
        template <template <typename> class TOUT> friend class ObjectCache;
 
699
 
 
700
public:
 
701
 
 
702
 
 
703
        FileDatabase()
 
704
                : next_cache_idx()
 
705
                , _cacheArrays(*this)
 
706
                , _cache(*this)
 
707
        {} 
 
708
 
 
709
public:
 
710
 
 
711
        // publicly accessible fields
 
712
        bool i64bit;
 
713
        bool little;
 
714
 
 
715
        DNA dna;
 
716
        boost::shared_ptr< StreamReaderAny > reader;
 
717
        vector< FileBlockHead > entries;
 
718
 
 
719
public:
 
720
 
 
721
        Statistics& stats() const {
 
722
                return _stats;
 
723
        }
 
724
 
 
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 {
 
731
                return _cache;
 
732
        }
 
733
 
 
734
        template <typename T>
 
735
        ObjectCache<vector>& cache(vector<T>& in) const {
 
736
                return _cacheArrays;
 
737
        }
 
738
 
 
739
private:
 
740
 
 
741
        
 
742
#ifndef ASSIMP_BUILD_BLENDER_NO_STATS
 
743
        mutable Statistics _stats;
 
744
#endif
 
745
 
 
746
        mutable ObjectCache<vector> _cacheArrays;
 
747
        mutable ObjectCache<boost::shared_ptr> _cache;
 
748
 
 
749
        mutable size_t next_cache_idx;
 
750
};
 
751
 
 
752
#ifdef _MSC_VER
 
753
#       pragma warning(default:4355)
 
754
#endif
 
755
 
 
756
// -------------------------------------------------------------------------------
 
757
/** Factory to extract a #DNA from the DNA1 file block in a BLEND file. */
 
758
// -------------------------------------------------------------------------------
 
759
class DNAParser 
 
760
{
 
761
 
 
762
public:
 
763
 
 
764
        /** Bind the parser to a empty DNA and an input stream */
 
765
        DNAParser(FileDatabase& db)
 
766
                : db(db)
 
767
        {}
 
768
 
 
769
public:
 
770
 
 
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
 
778
         *    afterwards.*/
 
779
        void Parse ();
 
780
 
 
781
public:
 
782
 
 
783
        /** Obtain a reference to the extracted DNA information */
 
784
        const Blender::DNA& GetDNA() const {
 
785
                return db.dna;
 
786
        }
 
787
 
 
788
private:
 
789
 
 
790
        FileDatabase& db;
 
791
};
 
792
 
 
793
        } // end Blend
 
794
} // end Assimp
 
795
 
 
796
#include "BlenderDNA.inl"
 
797
 
 
798
#endif