summaryrefslogtreecommitdiff
path: root/libs/assimp/code/AssetLib/Blender/BlenderDNA.inl
diff options
context:
space:
mode:
authorsanine <sanine.not@pm.me>2022-04-16 11:55:09 -0500
committersanine <sanine.not@pm.me>2022-04-16 11:55:09 -0500
commitdb81b925d776103326128bf629cbdda576a223e7 (patch)
tree58bea8155c686733310009f6bed7363f91fbeb9d /libs/assimp/code/AssetLib/Blender/BlenderDNA.inl
parent55860037b14fb3893ba21cf2654c83d349cc1082 (diff)
move 3rd-party librarys into libs/ and add built-in honeysuckle
Diffstat (limited to 'libs/assimp/code/AssetLib/Blender/BlenderDNA.inl')
-rw-r--r--libs/assimp/code/AssetLib/Blender/BlenderDNA.inl845
1 files changed, 845 insertions, 0 deletions
diff --git a/libs/assimp/code/AssetLib/Blender/BlenderDNA.inl b/libs/assimp/code/AssetLib/Blender/BlenderDNA.inl
new file mode 100644
index 0000000..4f64987
--- /dev/null
+++ b/libs/assimp/code/AssetLib/Blender/BlenderDNA.inl
@@ -0,0 +1,845 @@
+/*
+Open Asset Import Library (assimp)
+----------------------------------------------------------------------
+
+Copyright (c) 2006-2022, 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.inl
+ * @brief Blender `DNA` (file format specification embedded in
+ * blend file itself) loader.
+ */
+#ifndef INCLUDED_AI_BLEND_DNA_INL
+#define INCLUDED_AI_BLEND_DNA_INL
+
+#include <memory>
+#include <assimp/TinyFormatter.h>
+
+namespace Assimp {
+namespace Blender {
+
+//--------------------------------------------------------------------------------
+const Field& Structure :: operator [] (const std::string& ss) const
+{
+ std::map<std::string, size_t>::const_iterator it = indices.find(ss);
+ if (it == indices.end()) {
+ throw Error("BlendDNA: Did not find a field named `",ss,"` in structure `",name,"`");
+ }
+
+ return fields[(*it).second];
+}
+
+//--------------------------------------------------------------------------------
+const Field* Structure :: Get (const std::string& ss) const
+{
+ std::map<std::string, size_t>::const_iterator it = indices.find(ss);
+ return it == indices.end() ? nullptr : &fields[(*it).second];
+}
+
+//--------------------------------------------------------------------------------
+const Field& Structure :: operator [] (const size_t i) const
+{
+ if (i >= fields.size()) {
+ throw Error("BlendDNA: There is no field with index `",i,"` in structure `",name,"`");
+ }
+
+ return fields[i];
+}
+
+//--------------------------------------------------------------------------------
+template <typename T> std::shared_ptr<ElemBase> Structure :: Allocate() const
+{
+ return std::shared_ptr<T>(new T());
+}
+
+//--------------------------------------------------------------------------------
+template <typename T> void Structure :: Convert(
+ std::shared_ptr<ElemBase> in,
+ const FileDatabase& db) const
+{
+ Convert<T> (*static_cast<T*> ( in.get() ),db);
+}
+
+//--------------------------------------------------------------------------------
+template <int error_policy, typename T, size_t M>
+void Structure :: ReadFieldArray(T (& out)[M], const char* name, const FileDatabase& db) const
+{
+ const StreamReaderAny::pos old = db.reader->GetCurrentPos();
+ try {
+ const Field& f = (*this)[name];
+ const Structure& s = db.dna[f.type];
+
+ // is the input actually an array?
+ if (!(f.flags & FieldFlag_Array)) {
+ throw Error("Field `",name,"` of structure `",this->name,"` ought to be an array of size ",M);
+ }
+
+ db.reader->IncPtr(f.offset);
+
+ // size conversions are always allowed, regardless of error_policy
+ unsigned int i = 0;
+ for(; i < std::min(f.array_sizes[0],M); ++i) {
+ s.Convert(out[i],db);
+ }
+ for(; i < M; ++i) {
+ _defaultInitializer<ErrorPolicy_Igno>()(out[i]);
+ }
+ }
+ catch (const Error& e) {
+ _defaultInitializer<error_policy>()(out,e.what());
+ }
+
+ // and recover the previous stream position
+ db.reader->SetCurrentPos(old);
+
+#ifndef ASSIMP_BUILD_BLENDER_NO_STATS
+ ++db.stats().fields_read;
+#endif
+}
+
+//--------------------------------------------------------------------------------
+template <int error_policy, typename T, size_t M, size_t N>
+void Structure :: ReadFieldArray2(T (& out)[M][N], const char* name, const FileDatabase& db) const
+{
+ const StreamReaderAny::pos old = db.reader->GetCurrentPos();
+ try {
+ const Field& f = (*this)[name];
+ const Structure& s = db.dna[f.type];
+
+ // is the input actually an array?
+ if (!(f.flags & FieldFlag_Array)) {
+ throw Error("Field `",name,"` of structure `",
+ this->name,"` ought to be an array of size ",M,"*",N
+ );
+ }
+
+ db.reader->IncPtr(f.offset);
+
+ // size conversions are always allowed, regardless of error_policy
+ unsigned int i = 0;
+ for(; i < std::min(f.array_sizes[0],M); ++i) {
+ unsigned int j = 0;
+ for(; j < std::min(f.array_sizes[1],N); ++j) {
+ s.Convert(out[i][j],db);
+ }
+ for(; j < N; ++j) {
+ _defaultInitializer<ErrorPolicy_Igno>()(out[i][j]);
+ }
+ }
+ for(; i < M; ++i) {
+ _defaultInitializer<ErrorPolicy_Igno>()(out[i]);
+ }
+ }
+ catch (const Error& e) {
+ _defaultInitializer<error_policy>()(out,e.what());
+ }
+
+ // and recover the previous stream position
+ db.reader->SetCurrentPos(old);
+
+#ifndef ASSIMP_BUILD_BLENDER_NO_STATS
+ ++db.stats().fields_read;
+#endif
+}
+
+//--------------------------------------------------------------------------------
+template <int error_policy, template <typename> class TOUT, typename T>
+bool Structure :: ReadFieldPtr(TOUT<T>& out, const char* name, const FileDatabase& db,
+ bool non_recursive /*= false*/) const
+{
+ const StreamReaderAny::pos old = db.reader->GetCurrentPos();
+ Pointer ptrval;
+ const Field* f;
+ try {
+ f = &(*this)[name];
+
+ // sanity check, should never happen if the genblenddna script is right
+ if (!(f->flags & FieldFlag_Pointer)) {
+ throw Error("Field `",name,"` of structure `",
+ this->name,"` ought to be a pointer");
+ }
+
+ db.reader->IncPtr(f->offset);
+ Convert(ptrval,db);
+ // actually it is meaningless on which Structure the Convert is called
+ // because the `Pointer` argument triggers a special implementation.
+ }
+ catch (const Error& e) {
+ _defaultInitializer<error_policy>()(out,e.what());
+
+ out.reset();
+ return false;
+ }
+
+ // resolve the pointer and load the corresponding structure
+ const bool res = ResolvePointer(out,ptrval,db,*f, non_recursive);
+
+ if(!non_recursive) {
+ // and recover the previous stream position
+ db.reader->SetCurrentPos(old);
+ }
+
+#ifndef ASSIMP_BUILD_BLENDER_NO_STATS
+ ++db.stats().fields_read;
+#endif
+
+ return res;
+}
+
+//--------------------------------------------------------------------------------
+template <int error_policy, template <typename> class TOUT, typename T, size_t N>
+bool Structure :: ReadFieldPtr(TOUT<T> (&out)[N], const char* name,
+ const FileDatabase& db) const
+{
+ // XXX see if we can reduce this to call to the 'normal' ReadFieldPtr
+ const StreamReaderAny::pos old = db.reader->GetCurrentPos();
+ Pointer ptrval[N];
+ const Field* f;
+ try {
+ f = &(*this)[name];
+
+#ifdef _DEBUG
+ // sanity check, should never happen if the genblenddna script is right
+ if ((FieldFlag_Pointer|FieldFlag_Pointer) != (f->flags & (FieldFlag_Pointer|FieldFlag_Pointer))) {
+ throw Error("Field `",name,"` of structure `",
+ this->name,"` ought to be a pointer AND an array");
+ }
+#endif // _DEBUG
+
+ db.reader->IncPtr(f->offset);
+
+ size_t i = 0;
+ for(; i < std::min(f->array_sizes[0],N); ++i) {
+ Convert(ptrval[i],db);
+ }
+ for(; i < N; ++i) {
+ _defaultInitializer<ErrorPolicy_Igno>()(ptrval[i]);
+ }
+
+ // actually it is meaningless on which Structure the Convert is called
+ // because the `Pointer` argument triggers a special implementation.
+ }
+ catch (const Error& e) {
+ _defaultInitializer<error_policy>()(out,e.what());
+ for(size_t i = 0; i < N; ++i) {
+ out[i].reset();
+ }
+ return false;
+ }
+
+ bool res = true;
+ for(size_t i = 0; i < N; ++i) {
+ // resolve the pointer and load the corresponding structure
+ res = ResolvePointer(out[i],ptrval[i],db,*f) && res;
+ }
+
+ // and recover the previous stream position
+ db.reader->SetCurrentPos(old);
+
+#ifndef ASSIMP_BUILD_BLENDER_NO_STATS
+ ++db.stats().fields_read;
+#endif
+ return res;
+}
+
+//--------------------------------------------------------------------------------
+template <int error_policy, typename T>
+void Structure :: ReadField(T& out, const char* name, const FileDatabase& db) const
+{
+ const StreamReaderAny::pos old = db.reader->GetCurrentPos();
+ try {
+ const Field& f = (*this)[name];
+ // find the structure definition pertaining to this field
+ const Structure& s = db.dna[f.type];
+
+ db.reader->IncPtr(f.offset);
+ s.Convert(out,db);
+ }
+ catch (const Error& e) {
+ _defaultInitializer<error_policy>()(out,e.what());
+ }
+
+ // and recover the previous stream position
+ db.reader->SetCurrentPos(old);
+
+#ifndef ASSIMP_BUILD_BLENDER_NO_STATS
+ ++db.stats().fields_read;
+#endif
+}
+
+
+//--------------------------------------------------------------------------------
+// field parsing for raw untyped data (like CustomDataLayer.data)
+template <int error_policy>
+bool Structure::ReadCustomDataPtr(std::shared_ptr<ElemBase>&out, int cdtype, const char* name, const FileDatabase& db) const {
+
+ const StreamReaderAny::pos old = db.reader->GetCurrentPos();
+
+ Pointer ptrval;
+ const Field* f;
+ try {
+ f = &(*this)[name];
+
+ // sanity check, should never happen if the genblenddna script is right
+ if (!(f->flags & FieldFlag_Pointer)) {
+ throw Error("Field `", name, "` of structure `",
+ this->name, "` ought to be a pointer");
+ }
+
+ db.reader->IncPtr(f->offset);
+ Convert(ptrval, db);
+ // actually it is meaningless on which Structure the Convert is called
+ // because the `Pointer` argument triggers a special implementation.
+ }
+ catch (const Error& e) {
+ _defaultInitializer<error_policy>()(out, e.what());
+ out.reset();
+ }
+
+ bool readOk = true;
+ if (ptrval.val) {
+ // get block for ptr
+ const FileBlockHead* block = LocateFileBlockForAddress(ptrval, db);
+ db.reader->SetCurrentPos(block->start + static_cast<size_t>((ptrval.val - block->address.val)));
+ // read block->num instances of given type to out
+ readOk = readCustomData(out, cdtype, block->num, db);
+ }
+
+ // and recover the previous stream position
+ db.reader->SetCurrentPos(old);
+
+#ifndef ASSIMP_BUILD_BLENDER_NO_STATS
+ ++db.stats().fields_read;
+#endif
+
+ return readOk;
+}
+
+//--------------------------------------------------------------------------------
+template <int error_policy, template <typename> class TOUT, typename T>
+bool Structure::ReadFieldPtrVector(vector<TOUT<T>>&out, const char* name, const FileDatabase& db) const {
+ out.clear();
+
+ const StreamReaderAny::pos old = db.reader->GetCurrentPos();
+
+ Pointer ptrval;
+ const Field* f;
+ try {
+ f = &(*this)[name];
+
+ // sanity check, should never happen if the genblenddna script is right
+ if (!(f->flags & FieldFlag_Pointer)) {
+ throw Error("Field `", name, "` of structure `",
+ this->name, "` ought to be a pointer");
+ }
+
+ db.reader->IncPtr(f->offset);
+ Convert(ptrval, db);
+ // actually it is meaningless on which Structure the Convert is called
+ // because the `Pointer` argument triggers a special implementation.
+ }
+ catch (const Error& e) {
+ _defaultInitializer<error_policy>()(out, e.what());
+ out.clear();
+ return false;
+ }
+
+
+ if (ptrval.val) {
+ // find the file block the pointer is pointing to
+ const FileBlockHead* block = LocateFileBlockForAddress(ptrval, db);
+ db.reader->SetCurrentPos(block->start + static_cast<size_t>((ptrval.val - block->address.val)));
+ // FIXME: basically, this could cause problems with 64 bit pointers on 32 bit systems.
+ // I really ought to improve StreamReader to work with 64 bit indices exclusively.
+
+ const Structure& s = db.dna[f->type];
+ for (size_t i = 0; i < block->num; ++i) {
+ TOUT<T> p(new T);
+ s.Convert(*p, db);
+ out.push_back(p);
+ }
+ }
+
+ db.reader->SetCurrentPos(old);
+
+#ifndef ASSIMP_BUILD_BLENDER_NO_STATS
+ ++db.stats().fields_read;
+#endif
+
+ return true;
+}
+
+
+//--------------------------------------------------------------------------------
+template <template <typename> class TOUT, typename T>
+bool Structure :: ResolvePointer(TOUT<T>& out, const Pointer & ptrval, const FileDatabase& db,
+ const Field& f,
+ bool non_recursive /*= false*/) const
+{
+ out.reset(); // ensure null pointers work
+ if (!ptrval.val) {
+ return false;
+ }
+ const Structure& s = db.dna[f.type];
+ // find the file block the pointer is pointing to
+ const FileBlockHead* block = LocateFileBlockForAddress(ptrval,db);
+
+ // also determine the target type from the block header
+ // and check if it matches the type which we expect.
+ const Structure& ss = db.dna[block->dna_index];
+ if (ss != s) {
+ throw Error("Expected target to be of type `",s.name,
+ "` but seemingly it is a `",ss.name,"` instead"
+ );
+ }
+
+ // try to retrieve the object from the cache
+ db.cache(out).get(s,out,ptrval);
+ if (out) {
+ return true;
+ }
+
+ // seek to this location, but save the previous stream pointer.
+ const StreamReaderAny::pos pold = db.reader->GetCurrentPos();
+ db.reader->SetCurrentPos(block->start+ static_cast<size_t>((ptrval.val - block->address.val) ));
+ // FIXME: basically, this could cause problems with 64 bit pointers on 32 bit systems.
+ // I really ought to improve StreamReader to work with 64 bit indices exclusively.
+
+ // continue conversion after allocating the required storage
+ size_t num = block->size / ss.size;
+ T* o = _allocate(out,num);
+
+ // cache the object before we convert it to avoid cyclic recursion.
+ db.cache(out).set(s,out,ptrval);
+
+ // if the non_recursive flag is set, we don't do anything but leave
+ // the cursor at the correct position to resolve the object.
+ if (!non_recursive) {
+ for (size_t i = 0; i < num; ++i,++o) {
+ s.Convert(*o,db);
+ }
+
+ db.reader->SetCurrentPos(pold);
+ }
+
+#ifndef ASSIMP_BUILD_BLENDER_NO_STATS
+ if(out) {
+ ++db.stats().pointers_resolved;
+ }
+#endif
+ return false;
+}
+
+
+//--------------------------------------------------------------------------------
+inline bool Structure :: ResolvePointer( std::shared_ptr< FileOffset >& out, const Pointer & ptrval,
+ const FileDatabase& db,
+ const Field&,
+ bool) const
+{
+ // Currently used exclusively by PackedFile::data to represent
+ // a simple offset into the mapped BLEND file.
+ out.reset();
+ if (!ptrval.val) {
+ return false;
+ }
+
+ // find the file block the pointer is pointing to
+ const FileBlockHead* block = LocateFileBlockForAddress(ptrval,db);
+
+ out = std::shared_ptr< FileOffset > (new FileOffset());
+ out->val = block->start+ static_cast<size_t>((ptrval.val - block->address.val) );
+ return false;
+}
+
+//--------------------------------------------------------------------------------
+template <template <typename> class TOUT, typename T>
+bool Structure :: ResolvePointer(vector< TOUT<T> >& out, const Pointer & ptrval,
+ const FileDatabase& db,
+ const Field& f,
+ bool) const
+{
+ // This is a function overload, not a template specialization. According to
+ // the partial ordering rules, it should be selected by the compiler
+ // for array-of-pointer inputs, i.e. Object::mats.
+
+ out.reset();
+ if (!ptrval.val) {
+ return false;
+ }
+
+ // find the file block the pointer is pointing to
+ const FileBlockHead* block = LocateFileBlockForAddress(ptrval,db);
+ const size_t num = block->size / (db.i64bit?8:4);
+
+ // keep the old stream position
+ const StreamReaderAny::pos pold = db.reader->GetCurrentPos();
+ db.reader->SetCurrentPos(block->start+ static_cast<size_t>((ptrval.val - block->address.val) ));
+
+ bool res = false;
+ // allocate raw storage for the array
+ out.resize(num);
+ for (size_t i = 0; i< num; ++i) {
+ Pointer val;
+ Convert(val,db);
+
+ // and resolve the pointees
+ res = ResolvePointer(out[i],val,db,f) && res;
+ }
+
+ db.reader->SetCurrentPos(pold);
+ return res;
+}
+
+//--------------------------------------------------------------------------------
+template <> bool Structure :: ResolvePointer<std::shared_ptr,ElemBase>(std::shared_ptr<ElemBase>& out,
+ const Pointer & ptrval,
+ const FileDatabase& db,
+ const Field&,
+ bool
+) const
+{
+ // Special case when the data type needs to be determined at runtime.
+ // Less secure than in the `strongly-typed` case.
+
+ out.reset();
+ if (!ptrval.val) {
+ return false;
+ }
+
+ // find the file block the pointer is pointing to
+ const FileBlockHead* block = LocateFileBlockForAddress(ptrval,db);
+
+ // determine the target type from the block header
+ const Structure& s = db.dna[block->dna_index];
+
+ // try to retrieve the object from the cache
+ db.cache(out).get(s,out,ptrval);
+ if (out) {
+ return true;
+ }
+
+ // seek to this location, but save the previous stream pointer.
+ const StreamReaderAny::pos pold = db.reader->GetCurrentPos();
+ db.reader->SetCurrentPos(block->start+ static_cast<size_t>((ptrval.val - block->address.val) ));
+ // FIXME: basically, this could cause problems with 64 bit pointers on 32 bit systems.
+ // I really ought to improve StreamReader to work with 64 bit indices exclusively.
+
+ // continue conversion after allocating the required storage
+ DNA::FactoryPair builders = db.dna.GetBlobToStructureConverter(s,db);
+ if (!builders.first) {
+ // this might happen if DNA::RegisterConverters hasn't been called so far
+ // or if the target type is not contained in `our` DNA.
+ out.reset();
+ ASSIMP_LOG_WARN( "Failed to find a converter for the `",s.name,"` structure" );
+ return false;
+ }
+
+ // allocate the object hull
+ out = (s.*builders.first)();
+
+ // cache the object immediately to prevent infinite recursion in a
+ // circular list with a single element (i.e. a self-referencing element).
+ db.cache(out).set(s,out,ptrval);
+
+ // and do the actual conversion
+ (s.*builders.second)(out,db);
+ db.reader->SetCurrentPos(pold);
+
+ // store a pointer to the name string of the actual type
+ // in the object itself. This allows the conversion code
+ // to perform additional type checking.
+ out->dna_type = s.name.c_str();
+
+
+#ifndef ASSIMP_BUILD_BLENDER_NO_STATS
+ ++db.stats().pointers_resolved;
+#endif
+ return false;
+}
+
+//--------------------------------------------------------------------------------
+const FileBlockHead* Structure :: LocateFileBlockForAddress(const Pointer & ptrval, const FileDatabase& db) const
+{
+ // the file blocks appear in list sorted by
+ // with ascending base addresses so we can run a
+ // binary search to locate the pointer quickly.
+
+ // NOTE: Blender seems to distinguish between side-by-side
+ // data (stored in the same data block) and far pointers,
+ // which are only used for structures starting with an ID.
+ // We don't need to make this distinction, our algorithm
+ // works regardless where the data is stored.
+ vector<FileBlockHead>::const_iterator it = std::lower_bound(db.entries.begin(),db.entries.end(),ptrval);
+ if (it == db.entries.end()) {
+ // this is crucial, pointers may not be invalid.
+ // this is either a corrupted file or an attempted attack.
+ throw DeadlyImportError("Failure resolving pointer 0x",
+ std::hex,ptrval.val,", no file block falls into this address range");
+ }
+ if (ptrval.val >= (*it).address.val + (*it).size) {
+ throw DeadlyImportError("Failure resolving pointer 0x",
+ std::hex,ptrval.val,", nearest file block starting at 0x",
+ (*it).address.val," ends at 0x",
+ (*it).address.val + (*it).size);
+ }
+ return &*it;
+}
+
+// ------------------------------------------------------------------------------------------------
+// NOTE: The MSVC debugger keeps showing up this annoying `a cast to a smaller data type has
+// caused a loss of data`-warning. Avoid this warning by a masking with an appropriate bitmask.
+
+template <typename T> struct signless;
+template <> struct signless<char> {typedef unsigned char type;};
+template <> struct signless<short> {typedef unsigned short type;};
+template <> struct signless<int> {typedef unsigned int type;};
+template <> struct signless<unsigned char> { typedef unsigned char type; };
+template <typename T>
+struct static_cast_silent {
+ template <typename V>
+ T operator()(V in) {
+ return static_cast<T>(in & static_cast<typename signless<T>::type>(-1));
+ }
+};
+
+template <> struct static_cast_silent<float> {
+ template <typename V> float operator()(V in) {
+ return static_cast<float> (in);
+ }
+};
+
+template <> struct static_cast_silent<double> {
+ template <typename V> double operator()(V in) {
+ return static_cast<double>(in);
+ }
+};
+
+// ------------------------------------------------------------------------------------------------
+template <typename T> inline void ConvertDispatcher(T& out, const Structure& in,const FileDatabase& db)
+{
+ if (in.name == "int") {
+ out = static_cast_silent<T>()(db.reader->GetU4());
+ }
+ else if (in.name == "short") {
+ out = static_cast_silent<T>()(db.reader->GetU2());
+ }
+ else if (in.name == "char") {
+ out = static_cast_silent<T>()(db.reader->GetU1());
+ }
+ else if (in.name == "float") {
+ out = static_cast<T>(db.reader->GetF4());
+ }
+ else if (in.name == "double") {
+ out = static_cast<T>(db.reader->GetF8());
+ }
+ else {
+ throw DeadlyImportError("Unknown source for conversion to primitive data type: ", in.name);
+ }
+}
+
+// ------------------------------------------------------------------------------------------------
+template <> inline void Structure :: Convert<int> (int& dest,const FileDatabase& db) const
+{
+ ConvertDispatcher(dest,*this,db);
+}
+
+// ------------------------------------------------------------------------------------------------
+template<> inline void Structure :: Convert<short> (short& dest,const FileDatabase& db) const
+{
+ // automatic rescaling from short to float and vice versa (seems to be used by normals)
+ if (name == "float") {
+ float f = db.reader->GetF4();
+ if ( f > 1.0f )
+ f = 1.0f;
+ dest = static_cast<short>( f * 32767.f);
+ //db.reader->IncPtr(-4);
+ return;
+ }
+ else if (name == "double") {
+ dest = static_cast<short>(db.reader->GetF8() * 32767.);
+ //db.reader->IncPtr(-8);
+ return;
+ }
+ ConvertDispatcher(dest,*this,db);
+}
+
+// ------------------------------------------------------------------------------------------------
+template <> inline void Structure :: Convert<char> (char& dest,const FileDatabase& db) const
+{
+ // automatic rescaling from char to float and vice versa (seems useful for RGB colors)
+ if (name == "float") {
+ dest = static_cast<char>(db.reader->GetF4() * 255.f);
+ return;
+ }
+ else if (name == "double") {
+ dest = static_cast<char>(db.reader->GetF8() * 255.f);
+ return;
+ }
+ ConvertDispatcher(dest,*this,db);
+}
+
+// ------------------------------------------------------------------------------------------------
+template <> inline void Structure::Convert<unsigned char>(unsigned char& dest, const FileDatabase& db) const
+{
+ // automatic rescaling from char to float and vice versa (seems useful for RGB colors)
+ if (name == "float") {
+ dest = static_cast<unsigned char>(db.reader->GetF4() * 255.f);
+ return;
+ }
+ else if (name == "double") {
+ dest = static_cast<unsigned char>(db.reader->GetF8() * 255.f);
+ return;
+ }
+ ConvertDispatcher(dest, *this, db);
+}
+
+
+// ------------------------------------------------------------------------------------------------
+template <> inline void Structure :: Convert<float> (float& dest,const FileDatabase& db) const
+{
+ // automatic rescaling from char to float and vice versa (seems useful for RGB colors)
+ if (name == "char") {
+ dest = db.reader->GetI1() / 255.f;
+ return;
+ }
+ // automatic rescaling from short to float and vice versa (used by normals)
+ else if (name == "short") {
+ dest = db.reader->GetI2() / 32767.f;
+ return;
+ }
+ ConvertDispatcher(dest,*this,db);
+}
+
+// ------------------------------------------------------------------------------------------------
+template <> inline void Structure :: Convert<double> (double& dest,const FileDatabase& db) const
+{
+ if (name == "char") {
+ dest = db.reader->GetI1() / 255.;
+ return;
+ }
+ else if (name == "short") {
+ dest = db.reader->GetI2() / 32767.;
+ return;
+ }
+ ConvertDispatcher(dest,*this,db);
+}
+
+// ------------------------------------------------------------------------------------------------
+template <> inline void Structure :: Convert<Pointer> (Pointer& dest,const FileDatabase& db) const
+{
+ if (db.i64bit) {
+ dest.val = db.reader->GetU8();
+ //db.reader->IncPtr(-8);
+ return;
+ }
+ dest.val = db.reader->GetU4();
+ //db.reader->IncPtr(-4);
+}
+
+//--------------------------------------------------------------------------------
+const Structure& DNA :: operator [] (const std::string& ss) const
+{
+ std::map<std::string, size_t>::const_iterator it = indices.find(ss);
+ if (it == indices.end()) {
+ throw Error("BlendDNA: Did not find a structure named `",ss,"`");
+ }
+
+ return structures[(*it).second];
+}
+
+//--------------------------------------------------------------------------------
+const Structure* DNA :: Get (const std::string& ss) const
+{
+ std::map<std::string, size_t>::const_iterator it = indices.find(ss);
+ return it == indices.end() ? nullptr : &structures[(*it).second];
+}
+
+//--------------------------------------------------------------------------------
+const Structure& DNA :: operator [] (const size_t i) const
+{
+ if (i >= structures.size()) {
+ throw Error("BlendDNA: There is no structure with index `",i,"`");
+ }
+
+ return structures[i];
+}
+
+//--------------------------------------------------------------------------------
+template <template <typename> class TOUT> template <typename T> void ObjectCache<TOUT> :: get (
+ const Structure& s,
+ TOUT<T>& out,
+ const Pointer& ptr
+) const {
+
+ if(s.cache_idx == static_cast<size_t>(-1)) {
+ s.cache_idx = db.next_cache_idx++;
+ caches.resize(db.next_cache_idx);
+ return;
+ }
+
+ typename StructureCache::const_iterator it = caches[s.cache_idx].find(ptr);
+ if (it != caches[s.cache_idx].end()) {
+ out = std::static_pointer_cast<T>( (*it).second );
+
+#ifndef ASSIMP_BUILD_BLENDER_NO_STATS
+ ++db.stats().cache_hits;
+#endif
+ }
+ // otherwise, out remains untouched
+}
+
+
+//--------------------------------------------------------------------------------
+template <template <typename> class TOUT> template <typename T> void ObjectCache<TOUT> :: set (
+ const Structure& s,
+ const TOUT<T>& out,
+ const Pointer& ptr
+) {
+ if(s.cache_idx == static_cast<size_t>(-1)) {
+ s.cache_idx = db.next_cache_idx++;
+ caches.resize(db.next_cache_idx);
+ }
+ caches[s.cache_idx][ptr] = std::static_pointer_cast<ElemBase>( out );
+
+#ifndef ASSIMP_BUILD_BLENDER_NO_STATS
+ ++db.stats().cached_objects;
+#endif
+}
+
+}}
+#endif