diff options
Diffstat (limited to 'NvCloth/samples/external/assimp-4.1.0/code/BlenderDNA.h')
| -rw-r--r-- | NvCloth/samples/external/assimp-4.1.0/code/BlenderDNA.h | 810 |
1 files changed, 810 insertions, 0 deletions
diff --git a/NvCloth/samples/external/assimp-4.1.0/code/BlenderDNA.h b/NvCloth/samples/external/assimp-4.1.0/code/BlenderDNA.h new file mode 100644 index 0000000..bac8d78 --- /dev/null +++ b/NvCloth/samples/external/assimp-4.1.0/code/BlenderDNA.h @@ -0,0 +1,810 @@ +/* +Open Asset Import Library (assimp) +---------------------------------------------------------------------- + +Copyright (c) 2006-2017, assimp team + +All rights reserved. + +Redistribution and use of this software in source and binary forms, +with or without modification, are permitted provided that the +following conditions are met: + +* Redistributions of source code must retain the above + copyright notice, this list of conditions and the + following disclaimer. + +* Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the + following disclaimer in the documentation and/or other + materials provided with the distribution. + +* Neither the name of the assimp team, nor the names of its + contributors may be used to endorse or promote products + derived from this software without specific prior + written permission of the assimp team. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +---------------------------------------------------------------------- +*/ + +/** @file BlenderDNA.h + * @brief Blender `DNA` (file format specification embedded in + * blend file itself) loader. + */ +#ifndef INCLUDED_AI_BLEND_DNA_H +#define INCLUDED_AI_BLEND_DNA_H + +#include "BaseImporter.h" +#include "StreamReader.h" +#include <assimp/DefaultLogger.hpp> +#include <stdint.h> +#include <memory> +#include <map> + +// enable verbose log output. really verbose, so be careful. +#ifdef ASSIMP_BUILD_DEBUG +# define ASSIMP_BUILD_BLENDER_DEBUG +#endif + +// #define ASSIMP_BUILD_BLENDER_NO_STATS + +namespace Assimp { + +template <bool,bool> class StreamReader; +typedef StreamReader<true,true> StreamReaderAny; + +namespace Blender { + +class FileDatabase; +struct FileBlockHead; + +template <template <typename> class TOUT> +class ObjectCache; + +// ------------------------------------------------------------------------------- +/** Exception class used by the blender loader to selectively catch exceptions + * thrown in its own code (DeadlyImportErrors thrown in general utility + * functions are untouched then). If such an exception is not caught by + * the loader itself, it will still be caught by Assimp due to its + * ancestry. */ +// ------------------------------------------------------------------------------- +struct Error : DeadlyImportError { + Error (const std::string& s) + : DeadlyImportError(s) { + // empty + } +}; + +// ------------------------------------------------------------------------------- +/** The only purpose of this structure is to feed a virtual dtor into its + * descendents. It serves as base class for all data structure fields. */ +// ------------------------------------------------------------------------------- +struct ElemBase { + ElemBase() + : dna_type(nullptr) + { + // empty + } + + virtual ~ElemBase() { + // empty + } + + /** Type name of the element. The type + * string points is the `c_str` of the `name` attribute of the + * corresponding `Structure`, that is, it is only valid as long + * as the DNA is not modified. The dna_type is only set if the + * data type is not static, i.e. a std::shared_ptr<ElemBase> + * in the scene description would have its type resolved + * at runtime, so this member is always set. */ + const char* dna_type; +}; + +// ------------------------------------------------------------------------------- +/** Represents a generic pointer to a memory location, which can be either 32 + * or 64 bits. These pointers are loaded from the BLEND file and finally + * fixed to point to the real, converted representation of the objects + * they used to point to.*/ +// ------------------------------------------------------------------------------- +struct Pointer { + Pointer() + : val() { + // empty + } + uint64_t val; +}; + +// ------------------------------------------------------------------------------- +/** Represents a generic offset within a BLEND file */ +// ------------------------------------------------------------------------------- +struct FileOffset { + FileOffset() + : val() { + // empty + } + uint64_t val; +}; + +// ------------------------------------------------------------------------------- +/** Dummy derivate of std::vector to be able to use it in templates simultaenously + * with std::shared_ptr, which takes only one template argument + * while std::vector takes three. Also we need to provide some special member + * functions of shared_ptr */ +// ------------------------------------------------------------------------------- +template <typename T> +class vector : public std::vector<T> { +public: + using std::vector<T>::resize; + using std::vector<T>::empty; + + void reset() { + resize(0); + } + + operator bool () const { + return !empty(); + } +}; + +// ------------------------------------------------------------------------------- +/** Mixed flags for use in #Field */ +// ------------------------------------------------------------------------------- +enum FieldFlags { + FieldFlag_Pointer = 0x1, + FieldFlag_Array = 0x2 +}; + +// ------------------------------------------------------------------------------- +/** Represents a single member of a data structure in a BLEND file */ +// ------------------------------------------------------------------------------- +struct Field { + std::string name; + std::string type; + + size_t size; + size_t offset; + + /** Size of each array dimension. For flat arrays, + * the second dimension is set to 1. */ + size_t array_sizes[2]; + + /** Any of the #FieldFlags enumerated values */ + unsigned int flags; +}; + +// ------------------------------------------------------------------------------- +/** Range of possible behaviours for fields absend in the input file. Some are + * mission critical so we need them, while others can silently be default + * initialized and no animations are harmed. */ +// ------------------------------------------------------------------------------- +enum ErrorPolicy { + /** Substitute default value and ignore */ + ErrorPolicy_Igno, + /** Substitute default value and write to log */ + ErrorPolicy_Warn, + /** Substitute a massive error message and crash the whole matrix. Its time for another zion */ + ErrorPolicy_Fail +}; + +#ifdef ASSIMP_BUILD_BLENDER_DEBUG +# define ErrorPolicy_Igno ErrorPolicy_Warn +#endif + +// ------------------------------------------------------------------------------- +/** Represents a data structure in a BLEND file. A Structure defines n fields + * and their locatios and encodings the input stream. Usually, every + * Structure instance pertains to one equally-named data structure in the + * BlenderScene.h header. This class defines various utilities to map a + * binary `blob` read from the file to such a structure instance with + * meaningful contents. */ +// ------------------------------------------------------------------------------- +class Structure { + template <template <typename> class> friend class ObjectCache; + +public: + Structure() + : cache_idx(static_cast<size_t>(-1) ){ + // empty + } + +public: + + // publicly accessible members + std::string name; + vector< Field > fields; + std::map<std::string, size_t> indices; + + size_t size; + +public: + + // -------------------------------------------------------- + /** Access a field of the structure by its canonical name. The pointer version + * returns NULL on failure while the reference version raises an import error. */ + inline const Field& operator [] (const std::string& ss) const; + inline const Field* Get (const std::string& ss) const; + + // -------------------------------------------------------- + /** Access a field of the structure by its index */ + inline const Field& operator [] (const size_t i) const; + + // -------------------------------------------------------- + inline bool operator== (const Structure& other) const { + return name == other.name; // name is meant to be an unique identifier + } + + // -------------------------------------------------------- + inline bool operator!= (const Structure& other) const { + return name != other.name; + } + +public: + + // -------------------------------------------------------- + /** Try to read an instance of the structure from the stream + * and attempt to convert to `T`. This is done by + * an appropriate specialization. If none is available, + * a compiler complain is the result. + * @param dest Destination value to be written + * @param db File database, including input stream. */ + template <typename T> void Convert (T& dest, const FileDatabase& db) const; + + // -------------------------------------------------------- + // generic converter + template <typename T> + void Convert(std::shared_ptr<ElemBase> in,const FileDatabase& db) const; + + // -------------------------------------------------------- + // generic allocator + template <typename T> std::shared_ptr<ElemBase> Allocate() const; + + + + // -------------------------------------------------------- + // field parsing for 1d arrays + template <int error_policy, typename T, size_t M> + void ReadFieldArray(T (& out)[M], const char* name, + const FileDatabase& db) const; + + // -------------------------------------------------------- + // field parsing for 2d arrays + template <int error_policy, typename T, size_t M, size_t N> + void ReadFieldArray2(T (& out)[M][N], const char* name, + const FileDatabase& db) const; + + // -------------------------------------------------------- + // field parsing for pointer or dynamic array types + // (std::shared_ptr) + // The return value indicates whether the data was already cached. + template <int error_policy, template <typename> class TOUT, typename T> + bool ReadFieldPtr(TOUT<T>& out, const char* name, + const FileDatabase& db, + bool non_recursive = false) const; + + // -------------------------------------------------------- + // field parsing for static arrays of pointer or dynamic + // array types (std::shared_ptr[]) + // The return value indicates whether the data was already cached. + template <int error_policy, template <typename> class TOUT, typename T, size_t N> + bool ReadFieldPtr(TOUT<T> (&out)[N], const char* name, + const FileDatabase& db) const; + + // -------------------------------------------------------- + // field parsing for `normal` values + // The return value indicates whether the data was already cached. + template <int error_policy, typename T> + void ReadField(T& out, const char* name, + const FileDatabase& db) const; + +private: + + // -------------------------------------------------------- + template <template <typename> class TOUT, typename T> + bool ResolvePointer(TOUT<T>& out, const Pointer & ptrval, + const FileDatabase& db, const Field& f, + bool non_recursive = false) const; + + // -------------------------------------------------------- + template <template <typename> class TOUT, typename T> + bool ResolvePointer(vector< TOUT<T> >& out, const Pointer & ptrval, + const FileDatabase& db, const Field& f, bool) const; + + // -------------------------------------------------------- + bool ResolvePointer( std::shared_ptr< FileOffset >& out, const Pointer & ptrval, + const FileDatabase& db, const Field& f, bool) const; + + // -------------------------------------------------------- + inline const FileBlockHead* LocateFileBlockForAddress( + const Pointer & ptrval, + const FileDatabase& db) const; + +private: + + // ------------------------------------------------------------------------------ + template <typename T> T* _allocate(std::shared_ptr<T>& out, size_t& s) const { + out = std::shared_ptr<T>(new T()); + s = 1; + return out.get(); + } + + template <typename T> T* _allocate(vector<T>& out, size_t& s) const { + out.resize(s); + return s ? &out.front() : NULL; + } + + // -------------------------------------------------------- + template <int error_policy> + struct _defaultInitializer { + + template <typename T, unsigned int N> + void operator ()(T (& out)[N], const char* = NULL) { + for (unsigned int i = 0; i < N; ++i) { + out[i] = T(); + } + } + + template <typename T, unsigned int N, unsigned int M> + void operator ()(T (& out)[N][M], const char* = NULL) { + for (unsigned int i = 0; i < N; ++i) { + for (unsigned int j = 0; j < M; ++j) { + out[i][j] = T(); + } + } + } + + template <typename T> + void operator ()(T& out, const char* = NULL) { + out = T(); + } + }; + +private: + + mutable size_t cache_idx; +}; + +// -------------------------------------------------------- +template <> struct Structure :: _defaultInitializer<ErrorPolicy_Warn> { + + template <typename T> + void operator ()(T& out, const char* reason = "<add reason>") { + DefaultLogger::get()->warn(reason); + + // ... and let the show go on + _defaultInitializer<0 /*ErrorPolicy_Igno*/>()(out); + } +}; + +template <> struct Structure :: _defaultInitializer<ErrorPolicy_Fail> { + + template <typename T> + void operator ()(T& /*out*/,const char* = "") { + // obviously, it is crucial that _DefaultInitializer is used + // only from within a catch clause. + throw; + } +}; + +// ------------------------------------------------------------------------------------------------------- +template <> inline bool Structure :: ResolvePointer<std::shared_ptr,ElemBase>(std::shared_ptr<ElemBase>& out, + const Pointer & ptrval, + const FileDatabase& db, + const Field& f, + bool + ) const; + + +// ------------------------------------------------------------------------------- +/** Represents the full data structure information for a single BLEND file. + * This data is extracted from the DNA1 chunk in the file. + * #DNAParser does the reading and represents currently the only place where + * DNA is altered.*/ +// ------------------------------------------------------------------------------- +class DNA +{ +public: + + typedef void (Structure::*ConvertProcPtr) ( + std::shared_ptr<ElemBase> in, + const FileDatabase& + ) const; + + typedef std::shared_ptr<ElemBase> ( + Structure::*AllocProcPtr) () const; + + typedef std::pair< AllocProcPtr, ConvertProcPtr > FactoryPair; + +public: + + std::map<std::string, FactoryPair > converters; + vector<Structure > structures; + std::map<std::string, size_t> indices; + +public: + + // -------------------------------------------------------- + /** Access a structure by its canonical name, the pointer version returns NULL on failure + * while the reference version raises an error. */ + inline const Structure& operator [] (const std::string& ss) const; + inline const Structure* Get (const std::string& ss) const; + + // -------------------------------------------------------- + /** Access a structure by its index */ + inline const Structure& operator [] (const size_t i) const; + +public: + + // -------------------------------------------------------- + /** Add structure definitions for all the primitive types, + * i.e. integer, short, char, float */ + void AddPrimitiveStructures(); + + // -------------------------------------------------------- + /** Fill the @c converters member with converters for all + * known data types. The implementation of this method is + * in BlenderScene.cpp and is machine-generated. + * Converters are used to quickly handle objects whose + * exact data type is a runtime-property and not yet + * known at compile time (consier Object::data).*/ + void RegisterConverters(); + + + // -------------------------------------------------------- + /** Take an input blob from the stream, interpret it according to + * a its structure name and convert it to the intermediate + * representation. + * @param structure Destination structure definition + * @param db File database. + * @return A null pointer if no appropriate converter is available.*/ + std::shared_ptr< ElemBase > ConvertBlobToStructure( + const Structure& structure, + const FileDatabase& db + ) const; + + // -------------------------------------------------------- + /** Find a suitable conversion function for a given Structure. + * Such a converter function takes a blob from the input + * stream, reads as much as it needs, and builds up a + * complete object in intermediate representation. + * @param structure Destination structure definition + * @param db File database. + * @return A null pointer in .first if no appropriate converter is available.*/ + FactoryPair GetBlobToStructureConverter( + const Structure& structure, + const FileDatabase& db + ) const; + + +#ifdef ASSIMP_BUILD_BLENDER_DEBUG + // -------------------------------------------------------- + /** Dump the DNA to a text file. This is for debugging purposes. + * The output file is `dna.txt` in the current working folder*/ + void DumpToFile(); +#endif + + // -------------------------------------------------------- + /** Extract array dimensions from a C array declaration, such + * as `...[4][6]`. Returned string would be `...[][]`. + * @param out + * @param array_sizes Receive maximally two array dimensions, + * the second element is set to 1 if the array is flat. + * Both are set to 1 if the input is not an array. + * @throw DeadlyImportError if more than 2 dimensions are + * encountered. */ + static void ExtractArraySize( + const std::string& out, + size_t array_sizes[2] + ); +}; + +// special converters for primitive types +template <> inline void Structure :: Convert<int> (int& dest,const FileDatabase& db) const; +template <> inline void Structure :: Convert<short> (short& dest,const FileDatabase& db) const; +template <> inline void Structure :: Convert<char> (char& dest,const FileDatabase& db) const; +template <> inline void Structure :: Convert<float> (float& dest,const FileDatabase& db) const; +template <> inline void Structure :: Convert<double> (double& dest,const FileDatabase& db) const; +template <> inline void Structure :: Convert<Pointer> (Pointer& dest,const FileDatabase& db) const; + +// ------------------------------------------------------------------------------- +/** Describes a master file block header. Each master file sections holds n + * elements of a certain SDNA structure (or otherwise unspecified data). */ +// ------------------------------------------------------------------------------- +struct FileBlockHead +{ + // points right after the header of the file block + StreamReaderAny::pos start; + + std::string id; + size_t size; + + // original memory address of the data + Pointer address; + + // index into DNA + unsigned int dna_index; + + // number of structure instances to follow + size_t num; + + + + // file blocks are sorted by address to quickly locate specific memory addresses + bool operator < (const FileBlockHead& o) const { + return address.val < o.address.val; + } + + // for std::upper_bound + operator const Pointer& () const { + return address; + } +}; + +// for std::upper_bound +inline bool operator< (const Pointer& a, const Pointer& b) { + return a.val < b.val; +} + +// ------------------------------------------------------------------------------- +/** Utility to read all master file blocks in turn. */ +// ------------------------------------------------------------------------------- +class SectionParser +{ +public: + + // -------------------------------------------------------- + /** @param stream Inout stream, must point to the + * first section in the file. Call Next() once + * to have it read. + * @param ptr64 Pointer size in file is 64 bits? */ + SectionParser(StreamReaderAny& stream,bool ptr64) + : stream(stream) + , ptr64(ptr64) + { + current.size = current.start = 0; + } + +public: + + // -------------------------------------------------------- + const FileBlockHead& GetCurrent() const { + return current; + } + + +public: + + // -------------------------------------------------------- + /** Advance to the next section. + * @throw DeadlyImportError if the last chunk was passed. */ + void Next(); + +public: + + FileBlockHead current; + StreamReaderAny& stream; + bool ptr64; +}; + + +#ifndef ASSIMP_BUILD_BLENDER_NO_STATS +// ------------------------------------------------------------------------------- +/** Import statistics, i.e. number of file blocks read*/ +// ------------------------------------------------------------------------------- +class Statistics { + +public: + + Statistics () + : fields_read () + , pointers_resolved () + , cache_hits () +// , blocks_read () + , cached_objects () + {} + +public: + + /** total number of fields we read */ + unsigned int fields_read; + + /** total number of resolved pointers */ + unsigned int pointers_resolved; + + /** number of pointers resolved from the cache */ + unsigned int cache_hits; + + /** number of blocks (from FileDatabase::entries) + we did actually read from. */ + // unsigned int blocks_read; + + /** objects in FileData::cache */ + unsigned int cached_objects; +}; +#endif + +// ------------------------------------------------------------------------------- +/** The object cache - all objects addressed by pointers are added here. This + * avoids circular references and avoids object duplication. */ +// ------------------------------------------------------------------------------- +template <template <typename> class TOUT> +class ObjectCache +{ +public: + + typedef std::map< Pointer, TOUT<ElemBase> > StructureCache; + +public: + + ObjectCache(const FileDatabase& db) + : db(db) + { + // currently there are only ~400 structure records per blend file. + // we read only a small part of them and don't cache objects + // which we don't need, so this should suffice. + caches.reserve(64); + } + +public: + + // -------------------------------------------------------- + /** Check whether a specific item is in the cache. + * @param s Data type of the item + * @param out Output pointer. Unchanged if the + * cache doens't know the item yet. + * @param ptr Item address to look for. */ + template <typename T> void get ( + const Structure& s, + TOUT<T>& out, + const Pointer& ptr) const; + + // -------------------------------------------------------- + /** Add an item to the cache after the item has + * been fully read. Do not insert anything that + * may be faulty or might cause the loading + * to abort. + * @param s Data type of the item + * @param out Item to insert into the cache + * @param ptr address (cache key) of the item. */ + template <typename T> void set + (const Structure& s, + const TOUT<T>& out, + const Pointer& ptr); + +private: + + mutable vector<StructureCache> caches; + const FileDatabase& db; +}; + +// ------------------------------------------------------------------------------- +// ------------------------------------------------------------------------------- +template <> class ObjectCache<Blender::vector> +{ +public: + + ObjectCache(const FileDatabase&) {} + + template <typename T> void get(const Structure&, vector<T>&, const Pointer&) {} + template <typename T> void set(const Structure&, const vector<T>&, const Pointer&) {} +}; + +#ifdef _MSC_VER +# pragma warning(disable:4355) +#endif + +// ------------------------------------------------------------------------------- +/** Memory representation of a full BLEND file and all its dependencies. The + * output aiScene is constructed from an instance of this data structure. */ +// ------------------------------------------------------------------------------- +class FileDatabase +{ + template <template <typename> class TOUT> friend class ObjectCache; + +public: + FileDatabase() + : _cacheArrays(*this) + , _cache(*this) + , next_cache_idx() + {} + +public: + // publicly accessible fields + bool i64bit; + bool little; + + DNA dna; + std::shared_ptr< StreamReaderAny > reader; + vector< FileBlockHead > entries; + +public: + + Statistics& stats() const { + return _stats; + } + + // For all our templates to work on both shared_ptr's and vector's + // using the same code, a dummy cache for arrays is provided. Actually, + // arrays of objects are never cached because we can't easily + // ensure their proper destruction. + template <typename T> + ObjectCache<std::shared_ptr>& cache(std::shared_ptr<T>& /*in*/) const { + return _cache; + } + + template <typename T> + ObjectCache<vector>& cache(vector<T>& /*in*/) const { + return _cacheArrays; + } + +private: + + +#ifndef ASSIMP_BUILD_BLENDER_NO_STATS + mutable Statistics _stats; +#endif + + mutable ObjectCache<vector> _cacheArrays; + mutable ObjectCache<std::shared_ptr> _cache; + + mutable size_t next_cache_idx; +}; + +#ifdef _MSC_VER +# pragma warning(default:4355) +#endif + +// ------------------------------------------------------------------------------- +/** Factory to extract a #DNA from the DNA1 file block in a BLEND file. */ +// ------------------------------------------------------------------------------- +class DNAParser +{ + +public: + + /** Bind the parser to a empty DNA and an input stream */ + DNAParser(FileDatabase& db) + : db(db) + {} + +public: + + // -------------------------------------------------------- + /** Locate the DNA in the file and parse it. The input + * stream is expected to point to the beginning of the DN1 + * chunk at the time this method is called and is + * undefined afterwards. + * @throw DeadlyImportError if the DNA cannot be read. + * @note The position of the stream pointer is undefined + * afterwards.*/ + void Parse (); + +public: + + /** Obtain a reference to the extracted DNA information */ + const Blender::DNA& GetDNA() const { + return db.dna; + } + +private: + + FileDatabase& db; +}; + + } // end Blend +} // end Assimp + +#include "BlenderDNA.inl" + +#endif |