nuclear@0: /* nuclear@0: Open Asset Import Library (assimp) nuclear@0: ---------------------------------------------------------------------- nuclear@0: nuclear@0: Copyright (c) 2006-2012, assimp team nuclear@0: All rights reserved. nuclear@0: nuclear@0: Redistribution and use of this software in source and binary forms, nuclear@0: with or without modification, are permitted provided that the nuclear@0: following conditions are met: nuclear@0: nuclear@0: * Redistributions of source code must retain the above nuclear@0: copyright notice, this list of conditions and the nuclear@0: following disclaimer. nuclear@0: nuclear@0: * Redistributions in binary form must reproduce the above nuclear@0: copyright notice, this list of conditions and the nuclear@0: following disclaimer in the documentation and/or other nuclear@0: materials provided with the distribution. nuclear@0: nuclear@0: * Neither the name of the assimp team, nor the names of its nuclear@0: contributors may be used to endorse or promote products nuclear@0: derived from this software without specific prior nuclear@0: written permission of the assimp team. nuclear@0: nuclear@0: THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS nuclear@0: "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT nuclear@0: LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR nuclear@0: A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT nuclear@0: OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, nuclear@0: SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT nuclear@0: LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, nuclear@0: DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY nuclear@0: THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT nuclear@0: (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE nuclear@0: OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. nuclear@0: nuclear@0: ---------------------------------------------------------------------- nuclear@0: */ nuclear@0: nuclear@0: /** @file BlenderDNA.inl nuclear@0: * @brief Blender `DNA` (file format specification embedded in nuclear@0: * blend file itself) loader. nuclear@0: */ nuclear@0: #ifndef INCLUDED_AI_BLEND_DNA_INL nuclear@0: #define INCLUDED_AI_BLEND_DNA_INL nuclear@0: nuclear@0: namespace Assimp { nuclear@0: namespace Blender { nuclear@0: nuclear@0: //-------------------------------------------------------------------------------- nuclear@0: const Field& Structure :: operator [] (const std::string& ss) const nuclear@0: { nuclear@0: std::map::const_iterator it = indices.find(ss); nuclear@0: if (it == indices.end()) { nuclear@0: throw Error((Formatter::format(), nuclear@0: "BlendDNA: Did not find a field named `",ss,"` in structure `",name,"`" nuclear@0: )); nuclear@0: } nuclear@0: nuclear@0: return fields[(*it).second]; nuclear@0: } nuclear@0: nuclear@0: //-------------------------------------------------------------------------------- nuclear@0: const Field* Structure :: Get (const std::string& ss) const nuclear@0: { nuclear@0: std::map::const_iterator it = indices.find(ss); nuclear@0: return it == indices.end() ? NULL : &fields[(*it).second]; nuclear@0: } nuclear@0: nuclear@0: //-------------------------------------------------------------------------------- nuclear@0: const Field& Structure :: operator [] (const size_t i) const nuclear@0: { nuclear@0: if (i >= fields.size()) { nuclear@0: throw Error((Formatter::format(), nuclear@0: "BlendDNA: There is no field with index `",i,"` in structure `",name,"`" nuclear@0: )); nuclear@0: } nuclear@0: nuclear@0: return fields[i]; nuclear@0: } nuclear@0: nuclear@0: //-------------------------------------------------------------------------------- nuclear@0: template boost::shared_ptr Structure :: Allocate() const nuclear@0: { nuclear@0: return boost::shared_ptr(new T()); nuclear@0: } nuclear@0: nuclear@0: //-------------------------------------------------------------------------------- nuclear@0: template void Structure :: Convert( nuclear@0: boost::shared_ptr in, nuclear@0: const FileDatabase& db) const nuclear@0: { nuclear@0: Convert (*static_cast ( in.get() ),db); nuclear@0: } nuclear@0: nuclear@0: //-------------------------------------------------------------------------------- nuclear@0: template nuclear@0: void Structure :: ReadFieldArray(T (& out)[M], const char* name, const FileDatabase& db) const nuclear@0: { nuclear@0: const StreamReaderAny::pos old = db.reader->GetCurrentPos(); nuclear@0: try { nuclear@0: const Field& f = (*this)[name]; nuclear@0: const Structure& s = db.dna[f.type]; nuclear@0: nuclear@0: // is the input actually an array? nuclear@0: if (!(f.flags & FieldFlag_Array)) { nuclear@0: throw Error((Formatter::format(),"Field `",name,"` of structure `", nuclear@0: this->name,"` ought to be an array of size ",M nuclear@0: )); nuclear@0: } nuclear@0: nuclear@0: db.reader->IncPtr(f.offset); nuclear@0: nuclear@0: // size conversions are always allowed, regardless of error_policy nuclear@0: unsigned int i = 0; nuclear@0: for(; i < std::min(f.array_sizes[0],M); ++i) { nuclear@0: s.Convert(out[i],db); nuclear@0: } nuclear@0: for(; i < M; ++i) { nuclear@0: _defaultInitializer()(out[i]); nuclear@0: } nuclear@0: } nuclear@0: catch (const Error& e) { nuclear@0: _defaultInitializer()(out,e.what()); nuclear@0: } nuclear@0: nuclear@0: // and recover the previous stream position nuclear@0: db.reader->SetCurrentPos(old); nuclear@0: nuclear@0: #ifndef ASSIMP_BUILD_BLENDER_NO_STATS nuclear@0: ++db.stats().fields_read; nuclear@0: #endif nuclear@0: } nuclear@0: nuclear@0: //-------------------------------------------------------------------------------- nuclear@0: template nuclear@0: void Structure :: ReadFieldArray2(T (& out)[M][N], const char* name, const FileDatabase& db) const nuclear@0: { nuclear@0: const StreamReaderAny::pos old = db.reader->GetCurrentPos(); nuclear@0: try { nuclear@0: const Field& f = (*this)[name]; nuclear@0: const Structure& s = db.dna[f.type]; nuclear@0: nuclear@0: // is the input actually an array? nuclear@0: if (!(f.flags & FieldFlag_Array)) { nuclear@0: throw Error((Formatter::format(),"Field `",name,"` of structure `", nuclear@0: this->name,"` ought to be an array of size ",M,"*",N nuclear@0: )); nuclear@0: } nuclear@0: nuclear@0: db.reader->IncPtr(f.offset); nuclear@0: nuclear@0: // size conversions are always allowed, regardless of error_policy nuclear@0: unsigned int i = 0; nuclear@0: for(; i < std::min(f.array_sizes[0],M); ++i) { nuclear@0: unsigned int j = 0; nuclear@0: for(; j < std::min(f.array_sizes[1],N); ++j) { nuclear@0: s.Convert(out[i][j],db); nuclear@0: } nuclear@0: for(; j < N; ++j) { nuclear@0: _defaultInitializer()(out[i][j]); nuclear@0: } nuclear@0: } nuclear@0: for(; i < M; ++i) { nuclear@0: _defaultInitializer()(out[i]); nuclear@0: } nuclear@0: } nuclear@0: catch (const Error& e) { nuclear@0: _defaultInitializer()(out,e.what()); nuclear@0: } nuclear@0: nuclear@0: // and recover the previous stream position nuclear@0: db.reader->SetCurrentPos(old); nuclear@0: nuclear@0: #ifndef ASSIMP_BUILD_BLENDER_NO_STATS nuclear@0: ++db.stats().fields_read; nuclear@0: #endif nuclear@0: } nuclear@0: nuclear@0: //-------------------------------------------------------------------------------- nuclear@0: template class TOUT, typename T> nuclear@0: void Structure :: ReadFieldPtr(TOUT& out, const char* name, const FileDatabase& db) const nuclear@0: { nuclear@0: const StreamReaderAny::pos old = db.reader->GetCurrentPos(); nuclear@0: Pointer ptrval; nuclear@0: const Field* f; nuclear@0: try { nuclear@0: f = &(*this)[name]; nuclear@0: nuclear@0: // sanity check, should never happen if the genblenddna script is right nuclear@0: if (!(f->flags & FieldFlag_Pointer)) { nuclear@0: throw Error((Formatter::format(),"Field `",name,"` of structure `", nuclear@0: this->name,"` ought to be a pointer")); nuclear@0: } nuclear@0: nuclear@0: db.reader->IncPtr(f->offset); nuclear@0: Convert(ptrval,db); nuclear@0: // actually it is meaningless on which Structure the Convert is called nuclear@0: // because the `Pointer` argument triggers a special implementation. nuclear@0: } nuclear@0: catch (const Error& e) { nuclear@0: _defaultInitializer()(out,e.what()); nuclear@0: nuclear@0: out.reset(); nuclear@0: return; nuclear@0: } nuclear@0: nuclear@0: // resolve the pointer and load the corresponding structure nuclear@0: ResolvePointer(out,ptrval,db,*f); nuclear@0: nuclear@0: // and recover the previous stream position nuclear@0: db.reader->SetCurrentPos(old); nuclear@0: nuclear@0: #ifndef ASSIMP_BUILD_BLENDER_NO_STATS nuclear@0: ++db.stats().fields_read; nuclear@0: #endif nuclear@0: } nuclear@0: nuclear@0: //-------------------------------------------------------------------------------- nuclear@0: template class TOUT, typename T, size_t N> nuclear@0: void Structure :: ReadFieldPtr(TOUT (&out)[N], const char* name, nuclear@0: const FileDatabase& db) const nuclear@0: { nuclear@0: // XXX see if we can reduce this to call to the 'normal' ReadFieldPtr nuclear@0: const StreamReaderAny::pos old = db.reader->GetCurrentPos(); nuclear@0: Pointer ptrval[N]; nuclear@0: const Field* f; nuclear@0: try { nuclear@0: f = &(*this)[name]; nuclear@0: nuclear@0: // sanity check, should never happen if the genblenddna script is right nuclear@0: if ((FieldFlag_Pointer|FieldFlag_Pointer) != (f->flags & (FieldFlag_Pointer|FieldFlag_Pointer))) { nuclear@0: throw Error((Formatter::format(),"Field `",name,"` of structure `", nuclear@0: this->name,"` ought to be a pointer AND an array")); nuclear@0: } nuclear@0: nuclear@0: db.reader->IncPtr(f->offset); nuclear@0: nuclear@0: size_t i = 0; nuclear@0: for(; i < std::min(f->array_sizes[0],N); ++i) { nuclear@0: Convert(ptrval[i],db); nuclear@0: } nuclear@0: for(; i < N; ++i) { nuclear@0: _defaultInitializer()(ptrval[i]); nuclear@0: } nuclear@0: nuclear@0: // actually it is meaningless on which Structure the Convert is called nuclear@0: // because the `Pointer` argument triggers a special implementation. nuclear@0: } nuclear@0: catch (const Error& e) { nuclear@0: _defaultInitializer()(out,e.what()); nuclear@0: for(size_t i = 0; i < N; ++i) { nuclear@0: out[i].reset(); nuclear@0: } nuclear@0: return; nuclear@0: } nuclear@0: for(size_t i = 0; i < N; ++i) { nuclear@0: // resolve the pointer and load the corresponding structure nuclear@0: ResolvePointer(out[i],ptrval[i],db,*f); nuclear@0: } nuclear@0: nuclear@0: // and recover the previous stream position nuclear@0: db.reader->SetCurrentPos(old); nuclear@0: nuclear@0: #ifndef ASSIMP_BUILD_BLENDER_NO_STATS nuclear@0: ++db.stats().fields_read; nuclear@0: #endif nuclear@0: } nuclear@0: nuclear@0: //-------------------------------------------------------------------------------- nuclear@0: template nuclear@0: void Structure :: ReadField(T& out, const char* name, const FileDatabase& db) const nuclear@0: { nuclear@0: const StreamReaderAny::pos old = db.reader->GetCurrentPos(); nuclear@0: try { nuclear@0: const Field& f = (*this)[name]; nuclear@0: // find the structure definition pertaining to this field nuclear@0: const Structure& s = db.dna[f.type]; nuclear@0: nuclear@0: db.reader->IncPtr(f.offset); nuclear@0: s.Convert(out,db); nuclear@0: } nuclear@0: catch (const Error& e) { nuclear@0: _defaultInitializer()(out,e.what()); nuclear@0: } nuclear@0: nuclear@0: // and recover the previous stream position nuclear@0: db.reader->SetCurrentPos(old); nuclear@0: nuclear@0: #ifndef ASSIMP_BUILD_BLENDER_NO_STATS nuclear@0: ++db.stats().fields_read; nuclear@0: #endif nuclear@0: } nuclear@0: nuclear@0: nuclear@0: //-------------------------------------------------------------------------------- nuclear@0: template