rev |
line source |
nuclear@0
|
1 /*
|
nuclear@0
|
2 Open Asset Import Library (assimp)
|
nuclear@0
|
3 ----------------------------------------------------------------------
|
nuclear@0
|
4
|
nuclear@0
|
5 Copyright (c) 2006-2012, assimp team
|
nuclear@0
|
6 All rights reserved.
|
nuclear@0
|
7
|
nuclear@0
|
8 Redistribution and use of this software in source and binary forms,
|
nuclear@0
|
9 with or without modification, are permitted provided that the
|
nuclear@0
|
10 following conditions are met:
|
nuclear@0
|
11
|
nuclear@0
|
12 * Redistributions of source code must retain the above
|
nuclear@0
|
13 copyright notice, this list of conditions and the
|
nuclear@0
|
14 following disclaimer.
|
nuclear@0
|
15
|
nuclear@0
|
16 * Redistributions in binary form must reproduce the above
|
nuclear@0
|
17 copyright notice, this list of conditions and the
|
nuclear@0
|
18 following disclaimer in the documentation and/or other
|
nuclear@0
|
19 materials provided with the distribution.
|
nuclear@0
|
20
|
nuclear@0
|
21 * Neither the name of the assimp team, nor the names of its
|
nuclear@0
|
22 contributors may be used to endorse or promote products
|
nuclear@0
|
23 derived from this software without specific prior
|
nuclear@0
|
24 written permission of the assimp team.
|
nuclear@0
|
25
|
nuclear@0
|
26 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
nuclear@0
|
27 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
nuclear@0
|
28 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
nuclear@0
|
29 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
nuclear@0
|
30 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
nuclear@0
|
31 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
nuclear@0
|
32 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
nuclear@0
|
33 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
nuclear@0
|
34 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
nuclear@0
|
35 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
nuclear@0
|
36 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
nuclear@0
|
37
|
nuclear@0
|
38 ----------------------------------------------------------------------
|
nuclear@0
|
39 */
|
nuclear@0
|
40
|
nuclear@0
|
41 /** @file BlenderDNA.inl
|
nuclear@0
|
42 * @brief Blender `DNA` (file format specification embedded in
|
nuclear@0
|
43 * blend file itself) loader.
|
nuclear@0
|
44 */
|
nuclear@0
|
45 #ifndef INCLUDED_AI_BLEND_DNA_INL
|
nuclear@0
|
46 #define INCLUDED_AI_BLEND_DNA_INL
|
nuclear@0
|
47
|
nuclear@0
|
48 namespace Assimp {
|
nuclear@0
|
49 namespace Blender {
|
nuclear@0
|
50
|
nuclear@0
|
51 //--------------------------------------------------------------------------------
|
nuclear@0
|
52 const Field& Structure :: operator [] (const std::string& ss) const
|
nuclear@0
|
53 {
|
nuclear@0
|
54 std::map<std::string, size_t>::const_iterator it = indices.find(ss);
|
nuclear@0
|
55 if (it == indices.end()) {
|
nuclear@0
|
56 throw Error((Formatter::format(),
|
nuclear@0
|
57 "BlendDNA: Did not find a field named `",ss,"` in structure `",name,"`"
|
nuclear@0
|
58 ));
|
nuclear@0
|
59 }
|
nuclear@0
|
60
|
nuclear@0
|
61 return fields[(*it).second];
|
nuclear@0
|
62 }
|
nuclear@0
|
63
|
nuclear@0
|
64 //--------------------------------------------------------------------------------
|
nuclear@0
|
65 const Field* Structure :: Get (const std::string& ss) const
|
nuclear@0
|
66 {
|
nuclear@0
|
67 std::map<std::string, size_t>::const_iterator it = indices.find(ss);
|
nuclear@0
|
68 return it == indices.end() ? NULL : &fields[(*it).second];
|
nuclear@0
|
69 }
|
nuclear@0
|
70
|
nuclear@0
|
71 //--------------------------------------------------------------------------------
|
nuclear@0
|
72 const Field& Structure :: operator [] (const size_t i) const
|
nuclear@0
|
73 {
|
nuclear@0
|
74 if (i >= fields.size()) {
|
nuclear@0
|
75 throw Error((Formatter::format(),
|
nuclear@0
|
76 "BlendDNA: There is no field with index `",i,"` in structure `",name,"`"
|
nuclear@0
|
77 ));
|
nuclear@0
|
78 }
|
nuclear@0
|
79
|
nuclear@0
|
80 return fields[i];
|
nuclear@0
|
81 }
|
nuclear@0
|
82
|
nuclear@0
|
83 //--------------------------------------------------------------------------------
|
nuclear@0
|
84 template <typename T> boost::shared_ptr<ElemBase> Structure :: Allocate() const
|
nuclear@0
|
85 {
|
nuclear@0
|
86 return boost::shared_ptr<T>(new T());
|
nuclear@0
|
87 }
|
nuclear@0
|
88
|
nuclear@0
|
89 //--------------------------------------------------------------------------------
|
nuclear@0
|
90 template <typename T> void Structure :: Convert(
|
nuclear@0
|
91 boost::shared_ptr<ElemBase> in,
|
nuclear@0
|
92 const FileDatabase& db) const
|
nuclear@0
|
93 {
|
nuclear@0
|
94 Convert<T> (*static_cast<T*> ( in.get() ),db);
|
nuclear@0
|
95 }
|
nuclear@0
|
96
|
nuclear@0
|
97 //--------------------------------------------------------------------------------
|
nuclear@0
|
98 template <int error_policy, typename T, size_t M>
|
nuclear@0
|
99 void Structure :: ReadFieldArray(T (& out)[M], const char* name, const FileDatabase& db) const
|
nuclear@0
|
100 {
|
nuclear@0
|
101 const StreamReaderAny::pos old = db.reader->GetCurrentPos();
|
nuclear@0
|
102 try {
|
nuclear@0
|
103 const Field& f = (*this)[name];
|
nuclear@0
|
104 const Structure& s = db.dna[f.type];
|
nuclear@0
|
105
|
nuclear@0
|
106 // is the input actually an array?
|
nuclear@0
|
107 if (!(f.flags & FieldFlag_Array)) {
|
nuclear@0
|
108 throw Error((Formatter::format(),"Field `",name,"` of structure `",
|
nuclear@0
|
109 this->name,"` ought to be an array of size ",M
|
nuclear@0
|
110 ));
|
nuclear@0
|
111 }
|
nuclear@0
|
112
|
nuclear@0
|
113 db.reader->IncPtr(f.offset);
|
nuclear@0
|
114
|
nuclear@0
|
115 // size conversions are always allowed, regardless of error_policy
|
nuclear@0
|
116 unsigned int i = 0;
|
nuclear@0
|
117 for(; i < std::min(f.array_sizes[0],M); ++i) {
|
nuclear@0
|
118 s.Convert(out[i],db);
|
nuclear@0
|
119 }
|
nuclear@0
|
120 for(; i < M; ++i) {
|
nuclear@0
|
121 _defaultInitializer<ErrorPolicy_Igno>()(out[i]);
|
nuclear@0
|
122 }
|
nuclear@0
|
123 }
|
nuclear@0
|
124 catch (const Error& e) {
|
nuclear@0
|
125 _defaultInitializer<error_policy>()(out,e.what());
|
nuclear@0
|
126 }
|
nuclear@0
|
127
|
nuclear@0
|
128 // and recover the previous stream position
|
nuclear@0
|
129 db.reader->SetCurrentPos(old);
|
nuclear@0
|
130
|
nuclear@0
|
131 #ifndef ASSIMP_BUILD_BLENDER_NO_STATS
|
nuclear@0
|
132 ++db.stats().fields_read;
|
nuclear@0
|
133 #endif
|
nuclear@0
|
134 }
|
nuclear@0
|
135
|
nuclear@0
|
136 //--------------------------------------------------------------------------------
|
nuclear@0
|
137 template <int error_policy, typename T, size_t M, size_t N>
|
nuclear@0
|
138 void Structure :: ReadFieldArray2(T (& out)[M][N], const char* name, const FileDatabase& db) const
|
nuclear@0
|
139 {
|
nuclear@0
|
140 const StreamReaderAny::pos old = db.reader->GetCurrentPos();
|
nuclear@0
|
141 try {
|
nuclear@0
|
142 const Field& f = (*this)[name];
|
nuclear@0
|
143 const Structure& s = db.dna[f.type];
|
nuclear@0
|
144
|
nuclear@0
|
145 // is the input actually an array?
|
nuclear@0
|
146 if (!(f.flags & FieldFlag_Array)) {
|
nuclear@0
|
147 throw Error((Formatter::format(),"Field `",name,"` of structure `",
|
nuclear@0
|
148 this->name,"` ought to be an array of size ",M,"*",N
|
nuclear@0
|
149 ));
|
nuclear@0
|
150 }
|
nuclear@0
|
151
|
nuclear@0
|
152 db.reader->IncPtr(f.offset);
|
nuclear@0
|
153
|
nuclear@0
|
154 // size conversions are always allowed, regardless of error_policy
|
nuclear@0
|
155 unsigned int i = 0;
|
nuclear@0
|
156 for(; i < std::min(f.array_sizes[0],M); ++i) {
|
nuclear@0
|
157 unsigned int j = 0;
|
nuclear@0
|
158 for(; j < std::min(f.array_sizes[1],N); ++j) {
|
nuclear@0
|
159 s.Convert(out[i][j],db);
|
nuclear@0
|
160 }
|
nuclear@0
|
161 for(; j < N; ++j) {
|
nuclear@0
|
162 _defaultInitializer<ErrorPolicy_Igno>()(out[i][j]);
|
nuclear@0
|
163 }
|
nuclear@0
|
164 }
|
nuclear@0
|
165 for(; i < M; ++i) {
|
nuclear@0
|
166 _defaultInitializer<ErrorPolicy_Igno>()(out[i]);
|
nuclear@0
|
167 }
|
nuclear@0
|
168 }
|
nuclear@0
|
169 catch (const Error& e) {
|
nuclear@0
|
170 _defaultInitializer<error_policy>()(out,e.what());
|
nuclear@0
|
171 }
|
nuclear@0
|
172
|
nuclear@0
|
173 // and recover the previous stream position
|
nuclear@0
|
174 db.reader->SetCurrentPos(old);
|
nuclear@0
|
175
|
nuclear@0
|
176 #ifndef ASSIMP_BUILD_BLENDER_NO_STATS
|
nuclear@0
|
177 ++db.stats().fields_read;
|
nuclear@0
|
178 #endif
|
nuclear@0
|
179 }
|
nuclear@0
|
180
|
nuclear@0
|
181 //--------------------------------------------------------------------------------
|
nuclear@0
|
182 template <int error_policy, template <typename> class TOUT, typename T>
|
nuclear@0
|
183 void Structure :: ReadFieldPtr(TOUT<T>& out, const char* name, const FileDatabase& db) const
|
nuclear@0
|
184 {
|
nuclear@0
|
185 const StreamReaderAny::pos old = db.reader->GetCurrentPos();
|
nuclear@0
|
186 Pointer ptrval;
|
nuclear@0
|
187 const Field* f;
|
nuclear@0
|
188 try {
|
nuclear@0
|
189 f = &(*this)[name];
|
nuclear@0
|
190
|
nuclear@0
|
191 // sanity check, should never happen if the genblenddna script is right
|
nuclear@0
|
192 if (!(f->flags & FieldFlag_Pointer)) {
|
nuclear@0
|
193 throw Error((Formatter::format(),"Field `",name,"` of structure `",
|
nuclear@0
|
194 this->name,"` ought to be a pointer"));
|
nuclear@0
|
195 }
|
nuclear@0
|
196
|
nuclear@0
|
197 db.reader->IncPtr(f->offset);
|
nuclear@0
|
198 Convert(ptrval,db);
|
nuclear@0
|
199 // actually it is meaningless on which Structure the Convert is called
|
nuclear@0
|
200 // because the `Pointer` argument triggers a special implementation.
|
nuclear@0
|
201 }
|
nuclear@0
|
202 catch (const Error& e) {
|
nuclear@0
|
203 _defaultInitializer<error_policy>()(out,e.what());
|
nuclear@0
|
204
|
nuclear@0
|
205 out.reset();
|
nuclear@0
|
206 return;
|
nuclear@0
|
207 }
|
nuclear@0
|
208
|
nuclear@0
|
209 // resolve the pointer and load the corresponding structure
|
nuclear@0
|
210 ResolvePointer(out,ptrval,db,*f);
|
nuclear@0
|
211
|
nuclear@0
|
212 // and recover the previous stream position
|
nuclear@0
|
213 db.reader->SetCurrentPos(old);
|
nuclear@0
|
214
|
nuclear@0
|
215 #ifndef ASSIMP_BUILD_BLENDER_NO_STATS
|
nuclear@0
|
216 ++db.stats().fields_read;
|
nuclear@0
|
217 #endif
|
nuclear@0
|
218 }
|
nuclear@0
|
219
|
nuclear@0
|
220 //--------------------------------------------------------------------------------
|
nuclear@0
|
221 template <int error_policy, template <typename> class TOUT, typename T, size_t N>
|
nuclear@0
|
222 void Structure :: ReadFieldPtr(TOUT<T> (&out)[N], const char* name,
|
nuclear@0
|
223 const FileDatabase& db) const
|
nuclear@0
|
224 {
|
nuclear@0
|
225 // XXX see if we can reduce this to call to the 'normal' ReadFieldPtr
|
nuclear@0
|
226 const StreamReaderAny::pos old = db.reader->GetCurrentPos();
|
nuclear@0
|
227 Pointer ptrval[N];
|
nuclear@0
|
228 const Field* f;
|
nuclear@0
|
229 try {
|
nuclear@0
|
230 f = &(*this)[name];
|
nuclear@0
|
231
|
nuclear@0
|
232 // sanity check, should never happen if the genblenddna script is right
|
nuclear@0
|
233 if ((FieldFlag_Pointer|FieldFlag_Pointer) != (f->flags & (FieldFlag_Pointer|FieldFlag_Pointer))) {
|
nuclear@0
|
234 throw Error((Formatter::format(),"Field `",name,"` of structure `",
|
nuclear@0
|
235 this->name,"` ought to be a pointer AND an array"));
|
nuclear@0
|
236 }
|
nuclear@0
|
237
|
nuclear@0
|
238 db.reader->IncPtr(f->offset);
|
nuclear@0
|
239
|
nuclear@0
|
240 size_t i = 0;
|
nuclear@0
|
241 for(; i < std::min(f->array_sizes[0],N); ++i) {
|
nuclear@0
|
242 Convert(ptrval[i],db);
|
nuclear@0
|
243 }
|
nuclear@0
|
244 for(; i < N; ++i) {
|
nuclear@0
|
245 _defaultInitializer<ErrorPolicy_Igno>()(ptrval[i]);
|
nuclear@0
|
246 }
|
nuclear@0
|
247
|
nuclear@0
|
248 // actually it is meaningless on which Structure the Convert is called
|
nuclear@0
|
249 // because the `Pointer` argument triggers a special implementation.
|
nuclear@0
|
250 }
|
nuclear@0
|
251 catch (const Error& e) {
|
nuclear@0
|
252 _defaultInitializer<error_policy>()(out,e.what());
|
nuclear@0
|
253 for(size_t i = 0; i < N; ++i) {
|
nuclear@0
|
254 out[i].reset();
|
nuclear@0
|
255 }
|
nuclear@0
|
256 return;
|
nuclear@0
|
257 }
|
nuclear@0
|
258 for(size_t i = 0; i < N; ++i) {
|
nuclear@0
|
259 // resolve the pointer and load the corresponding structure
|
nuclear@0
|
260 ResolvePointer(out[i],ptrval[i],db,*f);
|
nuclear@0
|
261 }
|
nuclear@0
|
262
|
nuclear@0
|
263 // and recover the previous stream position
|
nuclear@0
|
264 db.reader->SetCurrentPos(old);
|
nuclear@0
|
265
|
nuclear@0
|
266 #ifndef ASSIMP_BUILD_BLENDER_NO_STATS
|
nuclear@0
|
267 ++db.stats().fields_read;
|
nuclear@0
|
268 #endif
|
nuclear@0
|
269 }
|
nuclear@0
|
270
|
nuclear@0
|
271 //--------------------------------------------------------------------------------
|
nuclear@0
|
272 template <int error_policy, typename T>
|
nuclear@0
|
273 void Structure :: ReadField(T& out, const char* name, const FileDatabase& db) const
|
nuclear@0
|
274 {
|
nuclear@0
|
275 const StreamReaderAny::pos old = db.reader->GetCurrentPos();
|
nuclear@0
|
276 try {
|
nuclear@0
|
277 const Field& f = (*this)[name];
|
nuclear@0
|
278 // find the structure definition pertaining to this field
|
nuclear@0
|
279 const Structure& s = db.dna[f.type];
|
nuclear@0
|
280
|
nuclear@0
|
281 db.reader->IncPtr(f.offset);
|
nuclear@0
|
282 s.Convert(out,db);
|
nuclear@0
|
283 }
|
nuclear@0
|
284 catch (const Error& e) {
|
nuclear@0
|
285 _defaultInitializer<error_policy>()(out,e.what());
|
nuclear@0
|
286 }
|
nuclear@0
|
287
|
nuclear@0
|
288 // and recover the previous stream position
|
nuclear@0
|
289 db.reader->SetCurrentPos(old);
|
nuclear@0
|
290
|
nuclear@0
|
291 #ifndef ASSIMP_BUILD_BLENDER_NO_STATS
|
nuclear@0
|
292 ++db.stats().fields_read;
|
nuclear@0
|
293 #endif
|
nuclear@0
|
294 }
|
nuclear@0
|
295
|
nuclear@0
|
296
|
nuclear@0
|
297 //--------------------------------------------------------------------------------
|
nuclear@0
|
298 template <template <typename> class TOUT, typename T>
|
nuclear@0
|
299 void Structure :: ResolvePointer(TOUT<T>& out, const Pointer & ptrval, const FileDatabase& db, const Field& f) const
|
nuclear@0
|
300 {
|
nuclear@0
|
301 out.reset();
|
nuclear@0
|
302 if (!ptrval.val) {
|
nuclear@0
|
303 return;
|
nuclear@0
|
304 }
|
nuclear@0
|
305 const Structure& s = db.dna[f.type];
|
nuclear@0
|
306 // find the file block the pointer is pointing to
|
nuclear@0
|
307 const FileBlockHead* block = LocateFileBlockForAddress(ptrval,db);
|
nuclear@0
|
308
|
nuclear@0
|
309 // also determine the target type from the block header
|
nuclear@0
|
310 // and check if it matches the type which we expect.
|
nuclear@0
|
311 const Structure& ss = db.dna[block->dna_index];
|
nuclear@0
|
312 if (ss != s) {
|
nuclear@0
|
313 throw Error((Formatter::format(),"Expected target to be of type `",s.name,
|
nuclear@0
|
314 "` but seemingly it is a `",ss.name,"` instead"
|
nuclear@0
|
315 ));
|
nuclear@0
|
316 }
|
nuclear@0
|
317
|
nuclear@0
|
318 // try to retrieve the object from the cache
|
nuclear@0
|
319 db.cache(out).get(s,out,ptrval);
|
nuclear@0
|
320 if (out) {
|
nuclear@0
|
321 return;
|
nuclear@0
|
322 }
|
nuclear@0
|
323
|
nuclear@0
|
324 // seek to this location, but save the previous stream pointer.
|
nuclear@0
|
325 const StreamReaderAny::pos pold = db.reader->GetCurrentPos();
|
nuclear@0
|
326 db.reader->SetCurrentPos(block->start+ static_cast<size_t>((ptrval.val - block->address.val) ));
|
nuclear@0
|
327 // FIXME: basically, this could cause problems with 64 bit pointers on 32 bit systems.
|
nuclear@0
|
328 // I really ought to improve StreamReader to work with 64 bit indices exclusively.
|
nuclear@0
|
329
|
nuclear@0
|
330 // continue conversion after allocating the required storage
|
nuclear@0
|
331 size_t num = block->size / ss.size;
|
nuclear@0
|
332 T* o = _allocate(out,num);
|
nuclear@0
|
333
|
nuclear@0
|
334 // cache the object before we convert it to avoid cyclic recursion.
|
nuclear@0
|
335 db.cache(out).set(s,out,ptrval);
|
nuclear@0
|
336
|
nuclear@0
|
337 for (size_t i = 0; i < num; ++i,++o) {
|
nuclear@0
|
338 s.Convert(*o,db);
|
nuclear@0
|
339 }
|
nuclear@0
|
340
|
nuclear@0
|
341 db.reader->SetCurrentPos(pold);
|
nuclear@0
|
342
|
nuclear@0
|
343 #ifndef ASSIMP_BUILD_BLENDER_NO_STATS
|
nuclear@0
|
344 if(out) {
|
nuclear@0
|
345 ++db.stats().pointers_resolved;
|
nuclear@0
|
346 }
|
nuclear@0
|
347 #endif
|
nuclear@0
|
348 }
|
nuclear@0
|
349
|
nuclear@0
|
350 //--------------------------------------------------------------------------------
|
nuclear@0
|
351 inline void Structure :: ResolvePointer( boost::shared_ptr< FileOffset >& out, const Pointer & ptrval, const FileDatabase& db, const Field& /*f*/) const
|
nuclear@0
|
352 {
|
nuclear@0
|
353 // Currently used exclusively by PackedFile::data to represent
|
nuclear@0
|
354 // a simple offset into the mapped BLEND file.
|
nuclear@0
|
355 out.reset();
|
nuclear@0
|
356 if (!ptrval.val) {
|
nuclear@0
|
357 return;
|
nuclear@0
|
358 }
|
nuclear@0
|
359
|
nuclear@0
|
360 // find the file block the pointer is pointing to
|
nuclear@0
|
361 const FileBlockHead* block = LocateFileBlockForAddress(ptrval,db);
|
nuclear@0
|
362
|
nuclear@0
|
363 out = boost::shared_ptr< FileOffset > (new FileOffset());
|
nuclear@0
|
364 out->val = block->start+ static_cast<size_t>((ptrval.val - block->address.val) );
|
nuclear@0
|
365 }
|
nuclear@0
|
366
|
nuclear@0
|
367 //--------------------------------------------------------------------------------
|
nuclear@0
|
368 template <template <typename> class TOUT, typename T>
|
nuclear@0
|
369 void Structure :: ResolvePointer(vector< TOUT<T> >& out, const Pointer & ptrval, const FileDatabase& db, const Field& f) const
|
nuclear@0
|
370 {
|
nuclear@0
|
371 // This is a function overload, not a template specialization. According to
|
nuclear@0
|
372 // the partial ordering rules, it should be selected by the compiler
|
nuclear@0
|
373 // for array-of-pointer inputs, i.e. Object::mats.
|
nuclear@0
|
374
|
nuclear@0
|
375 out.reset();
|
nuclear@0
|
376 if (!ptrval.val) {
|
nuclear@0
|
377 return;
|
nuclear@0
|
378 }
|
nuclear@0
|
379
|
nuclear@0
|
380 // find the file block the pointer is pointing to
|
nuclear@0
|
381 const FileBlockHead* block = LocateFileBlockForAddress(ptrval,db);
|
nuclear@0
|
382 const size_t num = block->size / (db.i64bit?8:4);
|
nuclear@0
|
383
|
nuclear@0
|
384 // keep the old stream position
|
nuclear@0
|
385 const StreamReaderAny::pos pold = db.reader->GetCurrentPos();
|
nuclear@0
|
386 db.reader->SetCurrentPos(block->start+ static_cast<size_t>((ptrval.val - block->address.val) ));
|
nuclear@0
|
387
|
nuclear@0
|
388 // allocate raw storage for the array
|
nuclear@0
|
389 out.resize(num);
|
nuclear@0
|
390 for (size_t i = 0; i< num; ++i) {
|
nuclear@0
|
391 Pointer val;
|
nuclear@0
|
392 Convert(val,db);
|
nuclear@0
|
393
|
nuclear@0
|
394 // and resolve the pointees
|
nuclear@0
|
395 ResolvePointer(out[i],val,db,f);
|
nuclear@0
|
396 }
|
nuclear@0
|
397
|
nuclear@0
|
398 db.reader->SetCurrentPos(pold);
|
nuclear@0
|
399 }
|
nuclear@0
|
400
|
nuclear@0
|
401 //--------------------------------------------------------------------------------
|
nuclear@0
|
402 template <> void Structure :: ResolvePointer<boost::shared_ptr,ElemBase>(boost::shared_ptr<ElemBase>& out,
|
nuclear@0
|
403 const Pointer & ptrval,
|
nuclear@0
|
404 const FileDatabase& db,
|
nuclear@0
|
405 const Field& /*f*/
|
nuclear@0
|
406 ) const
|
nuclear@0
|
407 {
|
nuclear@0
|
408 // Special case when the data type needs to be determined at runtime.
|
nuclear@0
|
409 // Less secure than in the `strongly-typed` case.
|
nuclear@0
|
410
|
nuclear@0
|
411 out.reset();
|
nuclear@0
|
412 if (!ptrval.val) {
|
nuclear@0
|
413 return;
|
nuclear@0
|
414 }
|
nuclear@0
|
415
|
nuclear@0
|
416 // find the file block the pointer is pointing to
|
nuclear@0
|
417 const FileBlockHead* block = LocateFileBlockForAddress(ptrval,db);
|
nuclear@0
|
418
|
nuclear@0
|
419 // determine the target type from the block header
|
nuclear@0
|
420 const Structure& s = db.dna[block->dna_index];
|
nuclear@0
|
421
|
nuclear@0
|
422 // try to retrieve the object from the cache
|
nuclear@0
|
423 db.cache(out).get(s,out,ptrval);
|
nuclear@0
|
424 if (out) {
|
nuclear@0
|
425 return;
|
nuclear@0
|
426 }
|
nuclear@0
|
427
|
nuclear@0
|
428 // seek to this location, but save the previous stream pointer.
|
nuclear@0
|
429 const StreamReaderAny::pos pold = db.reader->GetCurrentPos();
|
nuclear@0
|
430 db.reader->SetCurrentPos(block->start+ static_cast<size_t>((ptrval.val - block->address.val) ));
|
nuclear@0
|
431 // FIXME: basically, this could cause problems with 64 bit pointers on 32 bit systems.
|
nuclear@0
|
432 // I really ought to improve StreamReader to work with 64 bit indices exclusively.
|
nuclear@0
|
433
|
nuclear@0
|
434 // continue conversion after allocating the required storage
|
nuclear@0
|
435 DNA::FactoryPair builders = db.dna.GetBlobToStructureConverter(s,db);
|
nuclear@0
|
436 if (!builders.first) {
|
nuclear@0
|
437 // this might happen if DNA::RegisterConverters hasn't been called so far
|
nuclear@0
|
438 // or if the target type is not contained in `our` DNA.
|
nuclear@0
|
439 out.reset();
|
nuclear@0
|
440 DefaultLogger::get()->warn((Formatter::format(),
|
nuclear@0
|
441 "Failed to find a converter for the `",s.name,"` structure"
|
nuclear@0
|
442 ));
|
nuclear@0
|
443 return;
|
nuclear@0
|
444 }
|
nuclear@0
|
445
|
nuclear@0
|
446 // allocate the object hull
|
nuclear@0
|
447 out = (s.*builders.first)();
|
nuclear@0
|
448
|
nuclear@0
|
449 // cache the object immediately to prevent infinite recursion in a
|
nuclear@0
|
450 // circular list with a single element (i.e. a self-referencing element).
|
nuclear@0
|
451 db.cache(out).set(s,out,ptrval);
|
nuclear@0
|
452
|
nuclear@0
|
453 // and do the actual conversion
|
nuclear@0
|
454 (s.*builders.second)(out,db);
|
nuclear@0
|
455 db.reader->SetCurrentPos(pold);
|
nuclear@0
|
456
|
nuclear@0
|
457 // store a pointer to the name string of the actual type
|
nuclear@0
|
458 // in the object itself. This allows the conversion code
|
nuclear@0
|
459 // to perform additional type checking.
|
nuclear@0
|
460 out->dna_type = s.name.c_str();
|
nuclear@0
|
461
|
nuclear@0
|
462
|
nuclear@0
|
463
|
nuclear@0
|
464 #ifndef ASSIMP_BUILD_BLENDER_NO_STATS
|
nuclear@0
|
465 ++db.stats().pointers_resolved;
|
nuclear@0
|
466 #endif
|
nuclear@0
|
467 }
|
nuclear@0
|
468
|
nuclear@0
|
469 //--------------------------------------------------------------------------------
|
nuclear@0
|
470 const FileBlockHead* Structure :: LocateFileBlockForAddress(const Pointer & ptrval, const FileDatabase& db) const
|
nuclear@0
|
471 {
|
nuclear@0
|
472 // the file blocks appear in list sorted by
|
nuclear@0
|
473 // with ascending base addresses so we can run a
|
nuclear@0
|
474 // binary search to locate the pointee quickly.
|
nuclear@0
|
475
|
nuclear@0
|
476 // NOTE: Blender seems to distinguish between side-by-side
|
nuclear@0
|
477 // data (stored in the same data block) and far pointers,
|
nuclear@0
|
478 // which are only used for structures starting with an ID.
|
nuclear@0
|
479 // We don't need to make this distinction, our algorithm
|
nuclear@0
|
480 // works regardless where the data is stored.
|
nuclear@0
|
481 vector<FileBlockHead>::const_iterator it = std::lower_bound(db.entries.begin(),db.entries.end(),ptrval);
|
nuclear@0
|
482 if (it == db.entries.end()) {
|
nuclear@0
|
483 // this is crucial, pointers may not be invalid.
|
nuclear@0
|
484 // this is either a corrupted file or an attempted attack.
|
nuclear@0
|
485 throw DeadlyImportError((Formatter::format(),"Failure resolving pointer 0x",
|
nuclear@0
|
486 std::hex,ptrval.val,", no file block falls into this address range"
|
nuclear@0
|
487 ));
|
nuclear@0
|
488 }
|
nuclear@0
|
489 if (ptrval.val >= (*it).address.val + (*it).size) {
|
nuclear@0
|
490 throw DeadlyImportError((Formatter::format(),"Failure resolving pointer 0x",
|
nuclear@0
|
491 std::hex,ptrval.val,", nearest file block starting at 0x",
|
nuclear@0
|
492 (*it).address.val," ends at 0x",
|
nuclear@0
|
493 (*it).address.val + (*it).size
|
nuclear@0
|
494 ));
|
nuclear@0
|
495 }
|
nuclear@0
|
496 return &*it;
|
nuclear@0
|
497 }
|
nuclear@0
|
498
|
nuclear@0
|
499 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
500 // NOTE: The MSVC debugger keeps showing up this annoying `a cast to a smaller data type has
|
nuclear@0
|
501 // caused a loss of data`-warning. Avoid this warning by a masking with an appropriate bitmask.
|
nuclear@0
|
502
|
nuclear@0
|
503 template <typename T> struct signless;
|
nuclear@0
|
504 template <> struct signless<char> {typedef unsigned char type;};
|
nuclear@0
|
505 template <> struct signless<short> {typedef unsigned short type;};
|
nuclear@0
|
506 template <> struct signless<int> {typedef unsigned int type;};
|
nuclear@0
|
507
|
nuclear@0
|
508 template <typename T>
|
nuclear@0
|
509 struct static_cast_silent {
|
nuclear@0
|
510 template <typename V>
|
nuclear@0
|
511 T operator()(V in) {
|
nuclear@0
|
512 return static_cast<T>(in & static_cast<typename signless<T>::type>(-1));
|
nuclear@0
|
513 }
|
nuclear@0
|
514 };
|
nuclear@0
|
515
|
nuclear@0
|
516 template <> struct static_cast_silent<float> {
|
nuclear@0
|
517 template <typename V> float operator()(V in) {
|
nuclear@0
|
518 return static_cast<float> (in);
|
nuclear@0
|
519 }
|
nuclear@0
|
520 };
|
nuclear@0
|
521
|
nuclear@0
|
522 template <> struct static_cast_silent<double> {
|
nuclear@0
|
523 template <typename V> double operator()(V in) {
|
nuclear@0
|
524 return static_cast<double>(in);
|
nuclear@0
|
525 }
|
nuclear@0
|
526 };
|
nuclear@0
|
527
|
nuclear@0
|
528 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
529 template <typename T> inline void ConvertDispatcher(T& out, const Structure& in,const FileDatabase& db)
|
nuclear@0
|
530 {
|
nuclear@0
|
531 if (in.name == "int") {
|
nuclear@0
|
532 out = static_cast_silent<T>()(db.reader->GetU4());
|
nuclear@0
|
533 }
|
nuclear@0
|
534 else if (in.name == "short") {
|
nuclear@0
|
535 out = static_cast_silent<T>()(db.reader->GetU2());
|
nuclear@0
|
536 }
|
nuclear@0
|
537 else if (in.name == "char") {
|
nuclear@0
|
538 out = static_cast_silent<T>()(db.reader->GetU1());
|
nuclear@0
|
539 }
|
nuclear@0
|
540 else if (in.name == "float") {
|
nuclear@0
|
541 out = static_cast<T>(db.reader->GetF4());
|
nuclear@0
|
542 }
|
nuclear@0
|
543 else if (in.name == "double") {
|
nuclear@0
|
544 out = static_cast<T>(db.reader->GetF8());
|
nuclear@0
|
545 }
|
nuclear@0
|
546 else {
|
nuclear@0
|
547 throw DeadlyImportError("Unknown source for conversion to primitive data type: "+in.name);
|
nuclear@0
|
548 }
|
nuclear@0
|
549 }
|
nuclear@0
|
550
|
nuclear@0
|
551 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
552 template <> inline void Structure :: Convert<int> (int& dest,const FileDatabase& db) const
|
nuclear@0
|
553 {
|
nuclear@0
|
554 ConvertDispatcher(dest,*this,db);
|
nuclear@0
|
555 }
|
nuclear@0
|
556
|
nuclear@0
|
557 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
558 template <> inline void Structure :: Convert<short> (short& dest,const FileDatabase& db) const
|
nuclear@0
|
559 {
|
nuclear@0
|
560 // automatic rescaling from short to float and vice versa (seems to be used by normals)
|
nuclear@0
|
561 if (name == "float") {
|
nuclear@0
|
562 dest = static_cast<short>(db.reader->GetF4() * 32767.f);
|
nuclear@0
|
563 //db.reader->IncPtr(-4);
|
nuclear@0
|
564 return;
|
nuclear@0
|
565 }
|
nuclear@0
|
566 else if (name == "double") {
|
nuclear@0
|
567 dest = static_cast<short>(db.reader->GetF8() * 32767.);
|
nuclear@0
|
568 //db.reader->IncPtr(-8);
|
nuclear@0
|
569 return;
|
nuclear@0
|
570 }
|
nuclear@0
|
571 ConvertDispatcher(dest,*this,db);
|
nuclear@0
|
572 }
|
nuclear@0
|
573
|
nuclear@0
|
574 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
575 template <> inline void Structure :: Convert<char> (char& dest,const FileDatabase& db) const
|
nuclear@0
|
576 {
|
nuclear@0
|
577 // automatic rescaling from char to float and vice versa (seems useful for RGB colors)
|
nuclear@0
|
578 if (name == "float") {
|
nuclear@0
|
579 dest = static_cast<char>(db.reader->GetF4() * 255.f);
|
nuclear@0
|
580 return;
|
nuclear@0
|
581 }
|
nuclear@0
|
582 else if (name == "double") {
|
nuclear@0
|
583 dest = static_cast<char>(db.reader->GetF8() * 255.f);
|
nuclear@0
|
584 return;
|
nuclear@0
|
585 }
|
nuclear@0
|
586 ConvertDispatcher(dest,*this,db);
|
nuclear@0
|
587 }
|
nuclear@0
|
588
|
nuclear@0
|
589 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
590 template <> inline void Structure :: Convert<float> (float& dest,const FileDatabase& db) const
|
nuclear@0
|
591 {
|
nuclear@0
|
592 // automatic rescaling from char to float and vice versa (seems useful for RGB colors)
|
nuclear@0
|
593 if (name == "char") {
|
nuclear@0
|
594 dest = db.reader->GetI1() / 255.f;
|
nuclear@0
|
595 return;
|
nuclear@0
|
596 }
|
nuclear@0
|
597 // automatic rescaling from short to float and vice versa (used by normals)
|
nuclear@0
|
598 else if (name == "short") {
|
nuclear@0
|
599 dest = db.reader->GetI2() / 32767.f;
|
nuclear@0
|
600 return;
|
nuclear@0
|
601 }
|
nuclear@0
|
602 ConvertDispatcher(dest,*this,db);
|
nuclear@0
|
603 }
|
nuclear@0
|
604
|
nuclear@0
|
605 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
606 template <> inline void Structure :: Convert<double> (double& dest,const FileDatabase& db) const
|
nuclear@0
|
607 {
|
nuclear@0
|
608 if (name == "char") {
|
nuclear@0
|
609 dest = db.reader->GetI1() / 255.;
|
nuclear@0
|
610 return;
|
nuclear@0
|
611 }
|
nuclear@0
|
612 else if (name == "short") {
|
nuclear@0
|
613 dest = db.reader->GetI2() / 32767.;
|
nuclear@0
|
614 return;
|
nuclear@0
|
615 }
|
nuclear@0
|
616 ConvertDispatcher(dest,*this,db);
|
nuclear@0
|
617 }
|
nuclear@0
|
618
|
nuclear@0
|
619 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
620 template <> inline void Structure :: Convert<Pointer> (Pointer& dest,const FileDatabase& db) const
|
nuclear@0
|
621 {
|
nuclear@0
|
622 if (db.i64bit) {
|
nuclear@0
|
623 dest.val = db.reader->GetU8();
|
nuclear@0
|
624 //db.reader->IncPtr(-8);
|
nuclear@0
|
625 return;
|
nuclear@0
|
626 }
|
nuclear@0
|
627 dest.val = db.reader->GetU4();
|
nuclear@0
|
628 //db.reader->IncPtr(-4);
|
nuclear@0
|
629 }
|
nuclear@0
|
630
|
nuclear@0
|
631 //--------------------------------------------------------------------------------
|
nuclear@0
|
632 const Structure& DNA :: operator [] (const std::string& ss) const
|
nuclear@0
|
633 {
|
nuclear@0
|
634 std::map<std::string, size_t>::const_iterator it = indices.find(ss);
|
nuclear@0
|
635 if (it == indices.end()) {
|
nuclear@0
|
636 throw Error((Formatter::format(),
|
nuclear@0
|
637 "BlendDNA: Did not find a structure named `",ss,"`"
|
nuclear@0
|
638 ));
|
nuclear@0
|
639 }
|
nuclear@0
|
640
|
nuclear@0
|
641 return structures[(*it).second];
|
nuclear@0
|
642 }
|
nuclear@0
|
643
|
nuclear@0
|
644 //--------------------------------------------------------------------------------
|
nuclear@0
|
645 const Structure* DNA :: Get (const std::string& ss) const
|
nuclear@0
|
646 {
|
nuclear@0
|
647 std::map<std::string, size_t>::const_iterator it = indices.find(ss);
|
nuclear@0
|
648 return it == indices.end() ? NULL : &structures[(*it).second];
|
nuclear@0
|
649 }
|
nuclear@0
|
650
|
nuclear@0
|
651 //--------------------------------------------------------------------------------
|
nuclear@0
|
652 const Structure& DNA :: operator [] (const size_t i) const
|
nuclear@0
|
653 {
|
nuclear@0
|
654 if (i >= structures.size()) {
|
nuclear@0
|
655 throw Error((Formatter::format(),
|
nuclear@0
|
656 "BlendDNA: There is no structure with index `",i,"`"
|
nuclear@0
|
657 ));
|
nuclear@0
|
658 }
|
nuclear@0
|
659
|
nuclear@0
|
660 return structures[i];
|
nuclear@0
|
661 }
|
nuclear@0
|
662
|
nuclear@0
|
663 //--------------------------------------------------------------------------------
|
nuclear@0
|
664 template <template <typename> class TOUT> template <typename T> void ObjectCache<TOUT> :: get (
|
nuclear@0
|
665 const Structure& s,
|
nuclear@0
|
666 TOUT<T>& out,
|
nuclear@0
|
667 const Pointer& ptr
|
nuclear@0
|
668 ) const {
|
nuclear@0
|
669
|
nuclear@0
|
670 if(s.cache_idx == static_cast<size_t>(-1)) {
|
nuclear@0
|
671 s.cache_idx = db.next_cache_idx++;
|
nuclear@0
|
672 caches.resize(db.next_cache_idx);
|
nuclear@0
|
673 return;
|
nuclear@0
|
674 }
|
nuclear@0
|
675
|
nuclear@0
|
676 typename StructureCache::const_iterator it = caches[s.cache_idx].find(ptr);
|
nuclear@0
|
677 if (it != caches[s.cache_idx].end()) {
|
nuclear@0
|
678 out = boost::static_pointer_cast<T>( (*it).second );
|
nuclear@0
|
679
|
nuclear@0
|
680 #ifndef ASSIMP_BUILD_BLENDER_NO_STATS
|
nuclear@0
|
681 ++db.stats().cache_hits;
|
nuclear@0
|
682 #endif
|
nuclear@0
|
683 }
|
nuclear@0
|
684 // otherwise, out remains untouched
|
nuclear@0
|
685 }
|
nuclear@0
|
686
|
nuclear@0
|
687
|
nuclear@0
|
688 //--------------------------------------------------------------------------------
|
nuclear@0
|
689 template <template <typename> class TOUT> template <typename T> void ObjectCache<TOUT> :: set (
|
nuclear@0
|
690 const Structure& s,
|
nuclear@0
|
691 const TOUT<T>& out,
|
nuclear@0
|
692 const Pointer& ptr
|
nuclear@0
|
693 ) {
|
nuclear@0
|
694 if(s.cache_idx == static_cast<size_t>(-1)) {
|
nuclear@0
|
695 s.cache_idx = db.next_cache_idx++;
|
nuclear@0
|
696 caches.resize(db.next_cache_idx);
|
nuclear@0
|
697 }
|
nuclear@0
|
698 caches[s.cache_idx][ptr] = boost::static_pointer_cast<ElemBase>( out );
|
nuclear@0
|
699
|
nuclear@0
|
700 #ifndef ASSIMP_BUILD_BLENDER_NO_STATS
|
nuclear@0
|
701 ++db.stats().cached_objects;
|
nuclear@0
|
702 #endif
|
nuclear@0
|
703 }
|
nuclear@0
|
704
|
nuclear@0
|
705 }}
|
nuclear@0
|
706 #endif
|