diff options
author | sanine <sanine.not@pm.me> | 2022-04-16 11:55:09 -0500 |
---|---|---|
committer | sanine <sanine.not@pm.me> | 2022-04-16 11:55:09 -0500 |
commit | db81b925d776103326128bf629cbdda576a223e7 (patch) | |
tree | 58bea8155c686733310009f6bed7363f91fbeb9d /libs/assimp/code/AssetLib/Blender/BlenderDNA.inl | |
parent | 55860037b14fb3893ba21cf2654c83d349cc1082 (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.inl | 845 |
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 |