vrshoot
view libs/assimp/BlenderDNA.cpp @ 0:b2f14e535253
initial commit
author | John Tsiombikas <nuclear@member.fsf.org> |
---|---|
date | Sat, 01 Feb 2014 19:58:19 +0200 |
parents | |
children |
line source
1 /*
2 Open Asset Import Library (assimp)
3 ----------------------------------------------------------------------
5 Copyright (c) 2006-2012, assimp team
6 All rights reserved.
8 Redistribution and use of this software in source and binary forms,
9 with or without modification, are permitted provided that the
10 following conditions are met:
12 * Redistributions of source code must retain the above
13 copyright notice, this list of conditions and the
14 following disclaimer.
16 * Redistributions in binary form must reproduce the above
17 copyright notice, this list of conditions and the
18 following disclaimer in the documentation and/or other
19 materials provided with the distribution.
21 * Neither the name of the assimp team, nor the names of its
22 contributors may be used to endorse or promote products
23 derived from this software without specific prior
24 written permission of the assimp team.
26 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
27 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
28 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
29 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
30 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
31 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
32 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
33 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
34 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
35 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
36 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
38 ----------------------------------------------------------------------
39 */
41 /** @file BlenderDNA.cpp
42 * @brief Implementation of the Blender `DNA`, that is its own
43 * serialized set of data structures.
44 */
45 #include "AssimpPCH.h"
47 #ifndef ASSIMP_BUILD_NO_BLEND_IMPORTER
48 #include "BlenderDNA.h"
49 #include "StreamReader.h"
50 #include "fast_atof.h"
52 using namespace Assimp;
53 using namespace Assimp::Blender;
54 using namespace Assimp::Formatter;
56 #define for_each BOOST_FOREACH
57 bool match4(StreamReaderAny& stream, const char* string) {
58 char tmp[] = {
59 (stream).GetI1(),
60 (stream).GetI1(),
61 (stream).GetI1(),
62 (stream).GetI1()
63 };
64 return (tmp[0]==string[0] && tmp[1]==string[1] && tmp[2]==string[2] && tmp[3]==string[3]);
65 }
67 struct Type {
68 size_t size;
69 std::string name;
70 };
72 // ------------------------------------------------------------------------------------------------
73 void DNAParser :: Parse ()
74 {
75 StreamReaderAny& stream = *db.reader.get();
76 DNA& dna = db.dna;
78 if(!match4(stream,"SDNA")) {
79 throw DeadlyImportError("BlenderDNA: Expected SDNA chunk");
80 }
82 // name dictionary
83 if(!match4(stream,"NAME")) {
84 throw DeadlyImportError("BlenderDNA: Expected NAME field");
85 }
87 std::vector<std::string> names (stream.GetI4());
88 for_each(std::string& s, names) {
89 while (char c = stream.GetI1()) {
90 s += c;
91 }
92 }
94 // type dictionary
95 for (;stream.GetCurrentPos() & 0x3; stream.GetI1());
96 if(!match4(stream,"TYPE")) {
97 throw DeadlyImportError("BlenderDNA: Expected TYPE field");
98 }
100 std::vector<Type> types (stream.GetI4());
101 for_each(Type& s, types) {
102 while (char c = stream.GetI1()) {
103 s.name += c;
104 }
105 }
107 // type length dictionary
108 for (;stream.GetCurrentPos() & 0x3; stream.GetI1());
109 if(!match4(stream,"TLEN")) {
110 throw DeadlyImportError("BlenderDNA: Expected TLEN field");
111 }
113 for_each(Type& s, types) {
114 s.size = stream.GetI2();
115 }
117 // structures dictionary
118 for (;stream.GetCurrentPos() & 0x3; stream.GetI1());
119 if(!match4(stream,"STRC")) {
120 throw DeadlyImportError("BlenderDNA: Expected STRC field");
121 }
123 size_t end = stream.GetI4(), fields = 0;
125 dna.structures.reserve(end);
126 for(size_t i = 0; i != end; ++i) {
128 uint16_t n = stream.GetI2();
129 if (n >= types.size()) {
130 throw DeadlyImportError((format(),
131 "BlenderDNA: Invalid type index in structure name" ,n,
132 " (there are only ", types.size(), " entries)"
133 ));
134 }
136 // maintain separate indexes
137 dna.indices[types[n].name] = dna.structures.size();
139 dna.structures.push_back(Structure());
140 Structure& s = dna.structures.back();
141 s.name = types[n].name;
142 //s.index = dna.structures.size()-1;
144 n = stream.GetI2();
145 s.fields.reserve(n);
147 size_t offset = 0;
148 for (size_t m = 0; m < n; ++m, ++fields) {
150 uint16_t j = stream.GetI2();
151 if (j >= types.size()) {
152 throw DeadlyImportError((format(),
153 "BlenderDNA: Invalid type index in structure field ", j,
154 " (there are only ", types.size(), " entries)"
155 ));
156 }
157 s.fields.push_back(Field());
158 Field& f = s.fields.back();
159 f.offset = offset;
161 f.type = types[j].name;
162 f.size = types[j].size;
164 j = stream.GetI2();
165 if (j >= names.size()) {
166 throw DeadlyImportError((format(),
167 "BlenderDNA: Invalid name index in structure field ", j,
168 " (there are only ", names.size(), " entries)"
169 ));
170 }
172 f.name = names[j];
173 f.flags = 0u;
175 // pointers always specify the size of the pointee instead of their own.
176 // The pointer asterisk remains a property of the lookup name.
177 if (f.name[0] == '*') {
178 f.size = db.i64bit ? 8 : 4;
179 f.flags |= FieldFlag_Pointer;
180 }
182 // arrays, however, specify the size of a single element so we
183 // need to parse the (possibly multi-dimensional) array declaration
184 // in order to obtain the actual size of the array in the file.
185 // Also we need to alter the lookup name to include no array
186 // brackets anymore or size fixup won't work (if our size does
187 // not match the size read from the DNA).
188 if (*f.name.rbegin() == ']') {
189 const std::string::size_type rb = f.name.find('[');
190 if (rb == std::string::npos) {
191 throw DeadlyImportError((format(),
192 "BlenderDNA: Encountered invalid array declaration ",
193 f.name
194 ));
195 }
197 f.flags |= FieldFlag_Array;
198 DNA::ExtractArraySize(f.name,f.array_sizes);
199 f.name = f.name.substr(0,rb);
201 f.size *= f.array_sizes[0] * f.array_sizes[1];
202 }
204 // maintain separate indexes
205 s.indices[f.name] = s.fields.size()-1;
206 offset += f.size;
207 }
208 s.size = offset;
209 }
211 DefaultLogger::get()->debug((format(),"BlenderDNA: Got ",dna.structures.size(),
212 " structures with totally ",fields," fields"));
214 #ifdef ASSIMP_BUILD_BLENDER_DEBUG
215 dna.DumpToFile();
216 #endif
218 dna.AddPrimitiveStructures();
219 dna.RegisterConverters();
220 }
223 #ifdef ASSIMP_BUILD_BLENDER_DEBUG
225 #include <fstream>
226 // ------------------------------------------------------------------------------------------------
227 void DNA :: DumpToFile()
228 {
229 // we dont't bother using the VFS here for this is only for debugging.
230 // (and all your bases are belong to us).
232 std::ofstream f("dna.txt");
233 if (f.fail()) {
234 DefaultLogger::get()->error("Could not dump dna to dna.txt");
235 return;
236 }
237 f << "Field format: type name offset size" << "\n";
238 f << "Structure format: name size" << "\n";
240 for_each(const Structure& s, structures) {
241 f << s.name << " " << s.size << "\n\n";
242 for_each(const Field& ff, s.fields) {
243 f << "\t" << ff.type << " " << ff.name << " " << ff.offset << " " << ff.size << std::endl;
244 }
245 f << std::endl;
246 }
247 DefaultLogger::get()->info("BlenderDNA: Dumped dna to dna.txt");
248 }
249 #endif
251 // ------------------------------------------------------------------------------------------------
252 /*static*/ void DNA :: ExtractArraySize(
253 const std::string& out,
254 size_t array_sizes[2]
255 )
256 {
257 array_sizes[0] = array_sizes[1] = 1;
258 std::string::size_type pos = out.find('[');
259 if (pos++ == std::string::npos) {
260 return;
261 }
262 array_sizes[0] = strtoul10(&out[pos]);
264 pos = out.find('[',pos);
265 if (pos++ == std::string::npos) {
266 return;
267 }
268 array_sizes[1] = strtoul10(&out[pos]);
269 }
271 // ------------------------------------------------------------------------------------------------
272 boost::shared_ptr< ElemBase > DNA :: ConvertBlobToStructure(
273 const Structure& structure,
274 const FileDatabase& db
275 ) const
276 {
277 std::map<std::string, FactoryPair >::const_iterator it = converters.find(structure.name);
278 if (it == converters.end()) {
279 return boost::shared_ptr< ElemBase >();
280 }
282 boost::shared_ptr< ElemBase > ret = (structure.*((*it).second.first))();
283 (structure.*((*it).second.second))(ret,db);
285 return ret;
286 }
288 // ------------------------------------------------------------------------------------------------
289 DNA::FactoryPair DNA :: GetBlobToStructureConverter(
290 const Structure& structure,
291 const FileDatabase& /*db*/
292 ) const
293 {
294 std::map<std::string, FactoryPair>::const_iterator it = converters.find(structure.name);
295 return it == converters.end() ? FactoryPair() : (*it).second;
296 }
298 // basing on http://www.blender.org/development/architecture/notes-on-sdna/
299 // ------------------------------------------------------------------------------------------------
300 void DNA :: AddPrimitiveStructures()
301 {
302 // NOTE: these are just dummies. Their presence enforces
303 // Structure::Convert<target_type> to be called on these
304 // empty structures. These converters are special
305 // overloads which scan the name of the structure and
306 // perform the required data type conversion if one
307 // of these special names is found in the structure
308 // in question.
310 indices["int"] = structures.size();
311 structures.push_back( Structure() );
312 structures.back().name = "int";
313 structures.back().size = 4;
315 indices["short"] = structures.size();
316 structures.push_back( Structure() );
317 structures.back().name = "short";
318 structures.back().size = 2;
321 indices["char"] = structures.size();
322 structures.push_back( Structure() );
323 structures.back().name = "char";
324 structures.back().size = 1;
327 indices["float"] = structures.size();
328 structures.push_back( Structure() );
329 structures.back().name = "float";
330 structures.back().size = 4;
333 indices["double"] = structures.size();
334 structures.push_back( Structure() );
335 structures.back().name = "double";
336 structures.back().size = 8;
338 // no long, seemingly.
339 }
341 // ------------------------------------------------------------------------------------------------
342 void SectionParser :: Next()
343 {
344 stream.SetCurrentPos(current.start + current.size);
346 const char tmp[] = {
347 stream.GetI1(),
348 stream.GetI1(),
349 stream.GetI1(),
350 stream.GetI1()
351 };
352 current.id = std::string(tmp,tmp[3]?4:tmp[2]?3:tmp[1]?2:1);
354 current.size = stream.GetI4();
355 current.address.val = ptr64 ? stream.GetU8() : stream.GetU4();
357 current.dna_index = stream.GetI4();
358 current.num = stream.GetI4();
360 current.start = stream.GetCurrentPos();
361 if (stream.GetRemainingSizeToLimit() < current.size) {
362 throw DeadlyImportError("BLEND: invalid size of file block");
363 }
365 #ifdef ASSIMP_BUILD_BLENDER_DEBUG
366 DefaultLogger::get()->debug(current.id);
367 #endif
368 }
372 #endif