diff --git a/code/BlenderDNA.cpp b/code/BlenderDNA.cpp index 105abc9b8..c8bf6fc05 100644 --- a/code/BlenderDNA.cpp +++ b/code/BlenderDNA.cpp @@ -274,12 +274,25 @@ boost::shared_ptr< ElemBase > DNA :: ConvertBlobToStructure( const FileDatabase& db ) const { - std::map::const_iterator it = converters.find(structure.name); + std::map::const_iterator it = converters.find(structure.name); if (it == converters.end()) { return boost::shared_ptr< ElemBase >(); } - return (structure.*((*it).second))(db); + boost::shared_ptr< ElemBase > ret = (structure.*((*it).second.first))(); + (structure.*((*it).second.second))(ret,db); + + return ret; +} + +// ------------------------------------------------------------------------------------------------ +DNA::FactoryPair DNA :: GetBlobToStructureConverter( + const Structure& structure, + const FileDatabase& db +) const +{ + std::map::const_iterator it = converters.find(structure.name); + return it == converters.end() ? FactoryPair(NULL,NULL) : (*it).second; } // basing on http://www.blender.org/development/architecture/notes-on-sdna/ diff --git a/code/BlenderDNA.h b/code/BlenderDNA.h index bfc61ecba..ce16d10f8 100644 --- a/code/BlenderDNA.h +++ b/code/BlenderDNA.h @@ -94,7 +94,7 @@ struct ElemBase * as the DNA is not modified. The dna_type is only set if the * data type is not static, i.e. a boost::shared_ptr * in the scene description would have its type resolved - * at runtime. */ + * at runtime, so this member is always set. */ const char* dna_type; }; @@ -219,8 +219,10 @@ public: public: // -------------------------------------------------------- - /** Access a field of the structure by its canonical name */ + /** 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 */ @@ -248,10 +250,18 @@ public: template inline void Convert (T& dest, const FileDatabase& db) const; + + // -------------------------------------------------------- + // generic converter template - boost::shared_ptr Convert( - const FileDatabase& db) const; + void Convert(boost::shared_ptr in,const FileDatabase& db) const; + + // -------------------------------------------------------- + // generic allocator + template boost::shared_ptr Allocate() const; + + // -------------------------------------------------------- // field parsing for 1d arrays @@ -391,17 +401,29 @@ class DNA { public: - typedef boost::shared_ptr (Structure::*ConvertProcPtr) (const FileDatabase& ) const; + typedef void (Structure::*ConvertProcPtr) ( + boost::shared_ptr in, + const FileDatabase& + ) const; + + typedef boost::shared_ptr ( + Structure::*AllocProcPtr) () const; - std::map converters; + typedef std::pair< AllocProcPtr, ConvertProcPtr > FactoryPair; + +public: + + std::map converters; vector structures; std::map indices; public: // -------------------------------------------------------- - /** Access a structure by its canonical name */ + /** 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 */ @@ -425,8 +447,9 @@ public: // -------------------------------------------------------- - /** Take an input blob, interpret it according to a its structure name and - * convert it to the intermediate representation. + /** 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.*/ @@ -435,6 +458,19 @@ public: 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 // -------------------------------------------------------- diff --git a/code/BlenderDNA.inl b/code/BlenderDNA.inl index 58a4f8162..6a73f15a2 100644 --- a/code/BlenderDNA.inl +++ b/code/BlenderDNA.inl @@ -61,6 +61,13 @@ const Field& Structure :: operator [] (const std::string& ss) const return fields[(*it).second]; } +//-------------------------------------------------------------------------------- +const Field* Structure :: Get (const std::string& ss) const +{ + std::map::const_iterator it = indices.find(ss); + return it == indices.end() ? NULL : &fields[(*it).second]; +} + //-------------------------------------------------------------------------------- const Field& Structure :: operator [] (const size_t i) const { @@ -74,14 +81,17 @@ const Field& Structure :: operator [] (const size_t i) const } //-------------------------------------------------------------------------------- -template boost::shared_ptr Structure :: Convert( +template boost::shared_ptr Structure :: Allocate() const +{ + return boost::shared_ptr(new T()); +} + +//-------------------------------------------------------------------------------- +template void Structure :: Convert( + boost::shared_ptr in, const FileDatabase& db) const { - // FIXME: use boost::make_shared - boost::shared_ptr s = boost::shared_ptr(new T()); - Convert (*s.get(),db); - - return s; + Convert (*static_cast ( in.get() ),db); } //-------------------------------------------------------------------------------- @@ -422,9 +432,8 @@ template <> void Structure :: ResolvePointer(boost:: // I really ought to improve StreamReader to work with 64 bit indices exclusively. // continue conversion after allocating the required storage - out = db.dna.ConvertBlobToStructure(s,db); - db.reader->SetCurrentPos(pold); - if (!out) { + 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(); @@ -434,14 +443,23 @@ template <> void Structure :: ResolvePointer(boost:: return; } + // 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(); - // 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; @@ -612,6 +630,13 @@ const Structure& DNA :: operator [] (const std::string& ss) const return structures[(*it).second]; } +//-------------------------------------------------------------------------------- +const Structure* DNA :: Get (const std::string& ss) const +{ + std::map::const_iterator it = indices.find(ss); + return it == indices.end() ? NULL : &structures[(*it).second]; +} + //-------------------------------------------------------------------------------- const Structure& DNA :: operator [] (const size_t i) const { diff --git a/code/BlenderIntermediate.h b/code/BlenderIntermediate.h new file mode 100644 index 000000000..194bb8ffe --- /dev/null +++ b/code/BlenderIntermediate.h @@ -0,0 +1,183 @@ +/* +Open Asset Import Library (ASSIMP) +---------------------------------------------------------------------- + +Copyright (c) 2006-2010, ASSIMP Development 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 Development 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 BlenderIntermediate.h + * @brief Internal utility structures for the BlenderLoader. It also serves + * as master include file for the whole (internal) Blender subsystem. + */ +#ifndef INCLUDED_AI_BLEND_INTERMEDIATE_H +#define INCLUDED_AI_BLEND_INTERMEDIATE_H + +#include "BlenderLoader.h" +#include "BlenderDNA.h" +#include "BlenderScene.h" +#include "BlenderSceneGen.h" + +#define for_each(x,y) BOOST_FOREACH(x,y) + +namespace Assimp { +namespace Blender { + + // -------------------------------------------------------------------- + /** Mini smart-array to avoid pulling in even more boost stuff. usable with vector and deque */ + // -------------------------------------------------------------------- + template