diff --git a/code/BlenderDNA.h b/code/BlenderDNA.h index 8796fb288..bfc61ecba 100644 --- a/code/BlenderDNA.h +++ b/code/BlenderDNA.h @@ -111,6 +111,15 @@ struct Pointer uint64_t val; }; +// ------------------------------------------------------------------------------- +/** Represents a generic offset within a BLEND file */ +// ------------------------------------------------------------------------------- +struct FileOffset +{ + FileOffset() : val() {} + uint64_t val; +}; + // ------------------------------------------------------------------------------- /** Dummy derivate of std::vector to be able to use it in templates simultaenously * with boost::shared_ptr, which takes only one template argument @@ -263,6 +272,13 @@ public: void ReadFieldPtr(TOUT& out, const char* name, const FileDatabase& db) const; + // -------------------------------------------------------- + // field parsing for static arrays of pointer or dynamic + // array types (boost::shared_ptr[] or boost::shared_array[]) + template class TOUT, typename T, size_t N> + void ReadFieldPtr(TOUT (&out)[N], const char* name, + const FileDatabase& db) const; + // -------------------------------------------------------- // field parsing for `normal` values template @@ -281,6 +297,10 @@ private: void ResolvePointer(vector< TOUT >& out, const Pointer & ptrval, const FileDatabase& db, const Field& f) const; + // -------------------------------------------------------- + void ResolvePointer( boost::shared_ptr< FileOffset >& out, const Pointer & ptrval, + const FileDatabase& db, const Field& f) const; + // -------------------------------------------------------- inline const FileBlockHead* LocateFileBlockForAddress( const Pointer & ptrval, diff --git a/code/BlenderDNA.inl b/code/BlenderDNA.inl index 9adfc913e..58a4f8162 100644 --- a/code/BlenderDNA.inl +++ b/code/BlenderDNA.inl @@ -181,8 +181,7 @@ void Structure :: ReadFieldPtr(TOUT& out, const char* name, const FileDatabas // sanity check, should never happen if the genblenddna script is right if (!(f->flags & FieldFlag_Pointer)) { throw Error((Formatter::format(),"Field `",name,"` of structure `", - this->name,"` ought to be a pointer" - )); + this->name,"` ought to be a pointer")); } db.reader->IncPtr(f->offset); @@ -204,9 +203,57 @@ void Structure :: ReadFieldPtr(TOUT& out, const char* name, const FileDatabas db.reader->SetCurrentPos(old); #ifndef ASSIMP_BUILD_BLENDER_NO_STATS - if (out) { - ++db.stats().pointers_resolved; + ++db.stats().fields_read; +#endif +} + +//-------------------------------------------------------------------------------- +template class TOUT, typename T, size_t N> +void Structure :: ReadFieldPtr(TOUT (&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]; + + // sanity check, should never happen if the genblenddna script is right + if ((FieldFlag_Pointer|FieldFlag_Pointer) != (f->flags & (FieldFlag_Pointer|FieldFlag_Pointer))) { + throw Error((Formatter::format(),"Field `",name,"` of structure `", + this->name,"` ought to be a pointer AND an array")); + } + + 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()(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()(out,e.what()); + for(size_t i = 0; i < N; ++i) { + out[i].reset(); + } + return; + } + for(size_t i = 0; i < N; ++i) { + // resolve the pointer and load the corresponding structure + ResolvePointer(out[i],ptrval[i],db,*f); + } + + // and recover the previous stream position + db.reader->SetCurrentPos(old); + +#ifndef ASSIMP_BUILD_BLENDER_NO_STATS ++db.stats().fields_read; #endif } @@ -282,6 +329,29 @@ void Structure :: ResolvePointer(TOUT& out, const Pointer & ptrval, const Fil } db.reader->SetCurrentPos(pold); + +#ifndef ASSIMP_BUILD_BLENDER_NO_STATS + if(out) { + ++db.stats().pointers_resolved; + } +#endif +} + +//-------------------------------------------------------------------------------- +inline void Structure :: ResolvePointer( boost::shared_ptr< FileOffset >& out, const Pointer & ptrval, const FileDatabase& db, const Field& f) const +{ + // Currently used exclusively by PackedFile::data to represent + // a simple offset into the mapped BLEND file. + out.reset(); + if (!ptrval.val) { + return; + } + + // find the file block the pointer is pointing to + const FileBlockHead* block = LocateFileBlockForAddress(ptrval,db); + + out = boost::shared_ptr< FileOffset > (new FileOffset()); + out->val = block->start+ static_cast((ptrval.val - block->address.val) ); } //-------------------------------------------------------------------------------- @@ -372,6 +442,10 @@ template <> void Structure :: ResolvePointer(boost:: // cache the object now that construction is complete // FIXME we need to do this in ConvertBlobToStructure db.cache(out).set(s,out,ptrval); + +#ifndef ASSIMP_BUILD_BLENDER_NO_STATS + ++db.stats().pointers_resolved; +#endif } //-------------------------------------------------------------------------------- diff --git a/code/BlenderLoader.cpp b/code/BlenderLoader.cpp index ebd24736a..1292e7733 100644 --- a/code/BlenderLoader.cpp +++ b/code/BlenderLoader.cpp @@ -75,9 +75,12 @@ static const aiLoaderDesc blenderDesc = { namespace Assimp { namespace Blender { + // -------------------------------------------------------------------- /** Mini smart-array to avoid pulling in even more boost stuff. usable with vector and deque */ + // -------------------------------------------------------------------- template