Răsfoiți Sursa

Refactor: Use LF for line endings

Richard 10 ani în urmă
părinte
comite
4ec76d88f0
2 a modificat fișierele cu 872 adăugiri și 872 ștergeri
  1. 734 734
      code/BlenderDNA.inl
  2. 138 138
      code/SmoothingGroups.inl

+ 734 - 734
code/BlenderDNA.inl

@@ -1,734 +1,734 @@
-/*
-Open Asset Import Library (assimp)
-----------------------------------------------------------------------
-
-Copyright (c) 2006-2015, 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 <boost/shared_ptr.hpp>
-
-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((Formatter::format(),
-			"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() ? NULL : &fields[(*it).second];
-}
-
-//--------------------------------------------------------------------------------
-const Field& Structure :: operator [] (const size_t i) const 
-{
-	if (i >= fields.size()) {
-		throw Error((Formatter::format(),
-			"BlendDNA: There is no field with index `",i,"` in structure `",name,"`"
-			));
-	}
-
-	return fields[i];
-}
-
-//--------------------------------------------------------------------------------
-template <typename T> boost::shared_ptr<ElemBase> Structure :: Allocate() const 
-{
-	return boost::shared_ptr<T>(new T()); 
-}
-
-//--------------------------------------------------------------------------------
-template <typename T> void Structure :: Convert(
-	boost::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((Formatter::format(),"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((Formatter::format(),"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((Formatter::format(),"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];
-
-		// 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<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
-}
-
-
-//--------------------------------------------------------------------------------
-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((Formatter::format(),"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( boost::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 =  boost::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<boost::shared_ptr,ElemBase>(boost::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();
-		DefaultLogger::get()->warn((Formatter::format(),
-			"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 pointee 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((Formatter::format(),"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((Formatter::format(),"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 <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") {
-		dest = static_cast<short>(db.reader->GetF4() * 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<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((Formatter::format(),
-			"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() ? NULL : &structures[(*it).second];
-}
-
-//--------------------------------------------------------------------------------
-const Structure& DNA :: operator [] (const size_t i) const 
-{
-	if (i >= structures.size()) {
-		throw Error((Formatter::format(),
-			"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 = boost::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] = boost::static_pointer_cast<ElemBase>( out ); 
-
-#ifndef ASSIMP_BUILD_BLENDER_NO_STATS
-	++db.stats().cached_objects;
-#endif
-}
-
-}}
-#endif
+/*
+Open Asset Import Library (assimp)
+----------------------------------------------------------------------
+
+Copyright (c) 2006-2015, 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 <boost/shared_ptr.hpp>
+
+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((Formatter::format(),
+			"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() ? NULL : &fields[(*it).second];
+}
+
+//--------------------------------------------------------------------------------
+const Field& Structure :: operator [] (const size_t i) const 
+{
+	if (i >= fields.size()) {
+		throw Error((Formatter::format(),
+			"BlendDNA: There is no field with index `",i,"` in structure `",name,"`"
+			));
+	}
+
+	return fields[i];
+}
+
+//--------------------------------------------------------------------------------
+template <typename T> boost::shared_ptr<ElemBase> Structure :: Allocate() const 
+{
+	return boost::shared_ptr<T>(new T()); 
+}
+
+//--------------------------------------------------------------------------------
+template <typename T> void Structure :: Convert(
+	boost::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((Formatter::format(),"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((Formatter::format(),"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((Formatter::format(),"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];
+
+		// 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<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
+}
+
+
+//--------------------------------------------------------------------------------
+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((Formatter::format(),"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( boost::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 =  boost::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<boost::shared_ptr,ElemBase>(boost::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();
+		DefaultLogger::get()->warn((Formatter::format(),
+			"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 pointee 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((Formatter::format(),"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((Formatter::format(),"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 <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") {
+		dest = static_cast<short>(db.reader->GetF4() * 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<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((Formatter::format(),
+			"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() ? NULL : &structures[(*it).second];
+}
+
+//--------------------------------------------------------------------------------
+const Structure& DNA :: operator [] (const size_t i) const 
+{
+	if (i >= structures.size()) {
+		throw Error((Formatter::format(),
+			"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 = boost::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] = boost::static_pointer_cast<ElemBase>( out ); 
+
+#ifndef ASSIMP_BUILD_BLENDER_NO_STATS
+	++db.stats().cached_objects;
+#endif
+}
+
+}}
+#endif

+ 138 - 138
code/SmoothingGroups.inl

@@ -1,138 +1,138 @@
-/*
----------------------------------------------------------------------------
-Open Asset Import Library (assimp)
----------------------------------------------------------------------------
-
-Copyright (c) 2006-2012, 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 Generation of normal vectors basing on smoothing groups */
-
-#ifndef AI_SMOOTHINGGROUPS_INL_INCLUDED
-#define AI_SMOOTHINGGROUPS_INL_INCLUDED
-
-// internal headers
-#include "SGSpatialSort.h"
-
-// CRT header
-#include <algorithm>
-
-using namespace Assimp;
-
-// ------------------------------------------------------------------------------------------------
-template <class T>
-void ComputeNormalsWithSmoothingsGroups(MeshWithSmoothingGroups<T>& sMesh)
-{
-	// First generate face normals
-	sMesh.mNormals.resize(sMesh.mPositions.size(),aiVector3D());
-	for( unsigned int a = 0; a < sMesh.mFaces.size(); a++)
-	{
-		T& face = sMesh.mFaces[a];
-
-		aiVector3D* pV1 = &sMesh.mPositions[face.mIndices[0]];
-		aiVector3D* pV2 = &sMesh.mPositions[face.mIndices[1]];
-		aiVector3D* pV3 = &sMesh.mPositions[face.mIndices[2]];
-
-		aiVector3D pDelta1 = *pV2 - *pV1;
-		aiVector3D pDelta2 = *pV3 - *pV1;
-		aiVector3D vNor = pDelta1 ^ pDelta2;
-
-		for (unsigned int c = 0; c < 3;++c)
-			sMesh.mNormals[face.mIndices[c]] = vNor;
-	}
-
-	// calculate the position bounds so we have a reliable epsilon to check position differences against 
-	aiVector3D minVec( 1e10f, 1e10f, 1e10f), maxVec( -1e10f, -1e10f, -1e10f);
-	for( unsigned int a = 0; a < sMesh.mPositions.size(); a++)
-	{
-		minVec.x = std::min( minVec.x, sMesh.mPositions[a].x);
-		minVec.y = std::min( minVec.y, sMesh.mPositions[a].y);
-		minVec.z = std::min( minVec.z, sMesh.mPositions[a].z);
-		maxVec.x = std::max( maxVec.x, sMesh.mPositions[a].x);
-		maxVec.y = std::max( maxVec.y, sMesh.mPositions[a].y);
-		maxVec.z = std::max( maxVec.z, sMesh.mPositions[a].z);
-	}
-	const float posEpsilon = (maxVec - minVec).Length() * 1e-5f;
-	std::vector<aiVector3D> avNormals;
-	avNormals.resize(sMesh.mNormals.size());
-	
-	// now generate the spatial sort tree
-	SGSpatialSort sSort;
-	for( typename std::vector<T>::iterator i =  sMesh.mFaces.begin();
-		i != sMesh.mFaces.end();++i)
-	{
-		for (unsigned int c = 0; c < 3;++c)
-			sSort.Add(sMesh.mPositions[(*i).mIndices[c]],(*i).mIndices[c],(*i).iSmoothGroup);
-	}
-	sSort.Prepare();
-
-	std::vector<bool> vertexDone(sMesh.mPositions.size(),false);
-	for( typename std::vector<T>::iterator i =  sMesh.mFaces.begin();
-		i != sMesh.mFaces.end();++i)
-	{
-		std::vector<unsigned int> poResult;
-		for (unsigned int c = 0; c < 3;++c)
-		{
-			unsigned int idx = (*i).mIndices[c];
-			if (vertexDone[idx])continue;
-
-			sSort.FindPositions(sMesh.mPositions[idx],(*i).iSmoothGroup,
-				posEpsilon,poResult);
-
-			aiVector3D vNormals;
-			for (std::vector<unsigned int>::const_iterator
-				a =  poResult.begin();
-				a != poResult.end();++a)
-			{
-				vNormals += sMesh.mNormals[(*a)];
-			}
-			vNormals.Normalize();
-
-			// write back into all affected normals
-			for (std::vector<unsigned int>::const_iterator
-				a =  poResult.begin();
-				a != poResult.end();++a)
-			{
-				idx = *a;
-				avNormals [idx] = vNormals;
-				vertexDone[idx] = true;
-			}
-		}
-	}
-	sMesh.mNormals = avNormals;
-}
-
-#endif // !! AI_SMOOTHINGGROUPS_INL_INCLUDED
+/*
+---------------------------------------------------------------------------
+Open Asset Import Library (assimp)
+---------------------------------------------------------------------------
+
+Copyright (c) 2006-2012, 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 Generation of normal vectors basing on smoothing groups */
+
+#ifndef AI_SMOOTHINGGROUPS_INL_INCLUDED
+#define AI_SMOOTHINGGROUPS_INL_INCLUDED
+
+// internal headers
+#include "SGSpatialSort.h"
+
+// CRT header
+#include <algorithm>
+
+using namespace Assimp;
+
+// ------------------------------------------------------------------------------------------------
+template <class T>
+void ComputeNormalsWithSmoothingsGroups(MeshWithSmoothingGroups<T>& sMesh)
+{
+	// First generate face normals
+	sMesh.mNormals.resize(sMesh.mPositions.size(),aiVector3D());
+	for( unsigned int a = 0; a < sMesh.mFaces.size(); a++)
+	{
+		T& face = sMesh.mFaces[a];
+
+		aiVector3D* pV1 = &sMesh.mPositions[face.mIndices[0]];
+		aiVector3D* pV2 = &sMesh.mPositions[face.mIndices[1]];
+		aiVector3D* pV3 = &sMesh.mPositions[face.mIndices[2]];
+
+		aiVector3D pDelta1 = *pV2 - *pV1;
+		aiVector3D pDelta2 = *pV3 - *pV1;
+		aiVector3D vNor = pDelta1 ^ pDelta2;
+
+		for (unsigned int c = 0; c < 3;++c)
+			sMesh.mNormals[face.mIndices[c]] = vNor;
+	}
+
+	// calculate the position bounds so we have a reliable epsilon to check position differences against 
+	aiVector3D minVec( 1e10f, 1e10f, 1e10f), maxVec( -1e10f, -1e10f, -1e10f);
+	for( unsigned int a = 0; a < sMesh.mPositions.size(); a++)
+	{
+		minVec.x = std::min( minVec.x, sMesh.mPositions[a].x);
+		minVec.y = std::min( minVec.y, sMesh.mPositions[a].y);
+		minVec.z = std::min( minVec.z, sMesh.mPositions[a].z);
+		maxVec.x = std::max( maxVec.x, sMesh.mPositions[a].x);
+		maxVec.y = std::max( maxVec.y, sMesh.mPositions[a].y);
+		maxVec.z = std::max( maxVec.z, sMesh.mPositions[a].z);
+	}
+	const float posEpsilon = (maxVec - minVec).Length() * 1e-5f;
+	std::vector<aiVector3D> avNormals;
+	avNormals.resize(sMesh.mNormals.size());
+	
+	// now generate the spatial sort tree
+	SGSpatialSort sSort;
+	for( typename std::vector<T>::iterator i =  sMesh.mFaces.begin();
+		i != sMesh.mFaces.end();++i)
+	{
+		for (unsigned int c = 0; c < 3;++c)
+			sSort.Add(sMesh.mPositions[(*i).mIndices[c]],(*i).mIndices[c],(*i).iSmoothGroup);
+	}
+	sSort.Prepare();
+
+	std::vector<bool> vertexDone(sMesh.mPositions.size(),false);
+	for( typename std::vector<T>::iterator i =  sMesh.mFaces.begin();
+		i != sMesh.mFaces.end();++i)
+	{
+		std::vector<unsigned int> poResult;
+		for (unsigned int c = 0; c < 3;++c)
+		{
+			unsigned int idx = (*i).mIndices[c];
+			if (vertexDone[idx])continue;
+
+			sSort.FindPositions(sMesh.mPositions[idx],(*i).iSmoothGroup,
+				posEpsilon,poResult);
+
+			aiVector3D vNormals;
+			for (std::vector<unsigned int>::const_iterator
+				a =  poResult.begin();
+				a != poResult.end();++a)
+			{
+				vNormals += sMesh.mNormals[(*a)];
+			}
+			vNormals.Normalize();
+
+			// write back into all affected normals
+			for (std::vector<unsigned int>::const_iterator
+				a =  poResult.begin();
+				a != poResult.end();++a)
+			{
+				idx = *a;
+				avNormals [idx] = vNormals;
+				vertexDone[idx] = true;
+			}
+		}
+	}
+	sMesh.mNormals = avNormals;
+}
+
+#endif // !! AI_SMOOTHINGGROUPS_INL_INCLUDED