vrshoot

annotate 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
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.cpp
nuclear@0 42 * @brief Implementation of the Blender `DNA`, that is its own
nuclear@0 43 * serialized set of data structures.
nuclear@0 44 */
nuclear@0 45 #include "AssimpPCH.h"
nuclear@0 46
nuclear@0 47 #ifndef ASSIMP_BUILD_NO_BLEND_IMPORTER
nuclear@0 48 #include "BlenderDNA.h"
nuclear@0 49 #include "StreamReader.h"
nuclear@0 50 #include "fast_atof.h"
nuclear@0 51
nuclear@0 52 using namespace Assimp;
nuclear@0 53 using namespace Assimp::Blender;
nuclear@0 54 using namespace Assimp::Formatter;
nuclear@0 55
nuclear@0 56 #define for_each BOOST_FOREACH
nuclear@0 57 bool match4(StreamReaderAny& stream, const char* string) {
nuclear@0 58 char tmp[] = {
nuclear@0 59 (stream).GetI1(),
nuclear@0 60 (stream).GetI1(),
nuclear@0 61 (stream).GetI1(),
nuclear@0 62 (stream).GetI1()
nuclear@0 63 };
nuclear@0 64 return (tmp[0]==string[0] && tmp[1]==string[1] && tmp[2]==string[2] && tmp[3]==string[3]);
nuclear@0 65 }
nuclear@0 66
nuclear@0 67 struct Type {
nuclear@0 68 size_t size;
nuclear@0 69 std::string name;
nuclear@0 70 };
nuclear@0 71
nuclear@0 72 // ------------------------------------------------------------------------------------------------
nuclear@0 73 void DNAParser :: Parse ()
nuclear@0 74 {
nuclear@0 75 StreamReaderAny& stream = *db.reader.get();
nuclear@0 76 DNA& dna = db.dna;
nuclear@0 77
nuclear@0 78 if(!match4(stream,"SDNA")) {
nuclear@0 79 throw DeadlyImportError("BlenderDNA: Expected SDNA chunk");
nuclear@0 80 }
nuclear@0 81
nuclear@0 82 // name dictionary
nuclear@0 83 if(!match4(stream,"NAME")) {
nuclear@0 84 throw DeadlyImportError("BlenderDNA: Expected NAME field");
nuclear@0 85 }
nuclear@0 86
nuclear@0 87 std::vector<std::string> names (stream.GetI4());
nuclear@0 88 for_each(std::string& s, names) {
nuclear@0 89 while (char c = stream.GetI1()) {
nuclear@0 90 s += c;
nuclear@0 91 }
nuclear@0 92 }
nuclear@0 93
nuclear@0 94 // type dictionary
nuclear@0 95 for (;stream.GetCurrentPos() & 0x3; stream.GetI1());
nuclear@0 96 if(!match4(stream,"TYPE")) {
nuclear@0 97 throw DeadlyImportError("BlenderDNA: Expected TYPE field");
nuclear@0 98 }
nuclear@0 99
nuclear@0 100 std::vector<Type> types (stream.GetI4());
nuclear@0 101 for_each(Type& s, types) {
nuclear@0 102 while (char c = stream.GetI1()) {
nuclear@0 103 s.name += c;
nuclear@0 104 }
nuclear@0 105 }
nuclear@0 106
nuclear@0 107 // type length dictionary
nuclear@0 108 for (;stream.GetCurrentPos() & 0x3; stream.GetI1());
nuclear@0 109 if(!match4(stream,"TLEN")) {
nuclear@0 110 throw DeadlyImportError("BlenderDNA: Expected TLEN field");
nuclear@0 111 }
nuclear@0 112
nuclear@0 113 for_each(Type& s, types) {
nuclear@0 114 s.size = stream.GetI2();
nuclear@0 115 }
nuclear@0 116
nuclear@0 117 // structures dictionary
nuclear@0 118 for (;stream.GetCurrentPos() & 0x3; stream.GetI1());
nuclear@0 119 if(!match4(stream,"STRC")) {
nuclear@0 120 throw DeadlyImportError("BlenderDNA: Expected STRC field");
nuclear@0 121 }
nuclear@0 122
nuclear@0 123 size_t end = stream.GetI4(), fields = 0;
nuclear@0 124
nuclear@0 125 dna.structures.reserve(end);
nuclear@0 126 for(size_t i = 0; i != end; ++i) {
nuclear@0 127
nuclear@0 128 uint16_t n = stream.GetI2();
nuclear@0 129 if (n >= types.size()) {
nuclear@0 130 throw DeadlyImportError((format(),
nuclear@0 131 "BlenderDNA: Invalid type index in structure name" ,n,
nuclear@0 132 " (there are only ", types.size(), " entries)"
nuclear@0 133 ));
nuclear@0 134 }
nuclear@0 135
nuclear@0 136 // maintain separate indexes
nuclear@0 137 dna.indices[types[n].name] = dna.structures.size();
nuclear@0 138
nuclear@0 139 dna.structures.push_back(Structure());
nuclear@0 140 Structure& s = dna.structures.back();
nuclear@0 141 s.name = types[n].name;
nuclear@0 142 //s.index = dna.structures.size()-1;
nuclear@0 143
nuclear@0 144 n = stream.GetI2();
nuclear@0 145 s.fields.reserve(n);
nuclear@0 146
nuclear@0 147 size_t offset = 0;
nuclear@0 148 for (size_t m = 0; m < n; ++m, ++fields) {
nuclear@0 149
nuclear@0 150 uint16_t j = stream.GetI2();
nuclear@0 151 if (j >= types.size()) {
nuclear@0 152 throw DeadlyImportError((format(),
nuclear@0 153 "BlenderDNA: Invalid type index in structure field ", j,
nuclear@0 154 " (there are only ", types.size(), " entries)"
nuclear@0 155 ));
nuclear@0 156 }
nuclear@0 157 s.fields.push_back(Field());
nuclear@0 158 Field& f = s.fields.back();
nuclear@0 159 f.offset = offset;
nuclear@0 160
nuclear@0 161 f.type = types[j].name;
nuclear@0 162 f.size = types[j].size;
nuclear@0 163
nuclear@0 164 j = stream.GetI2();
nuclear@0 165 if (j >= names.size()) {
nuclear@0 166 throw DeadlyImportError((format(),
nuclear@0 167 "BlenderDNA: Invalid name index in structure field ", j,
nuclear@0 168 " (there are only ", names.size(), " entries)"
nuclear@0 169 ));
nuclear@0 170 }
nuclear@0 171
nuclear@0 172 f.name = names[j];
nuclear@0 173 f.flags = 0u;
nuclear@0 174
nuclear@0 175 // pointers always specify the size of the pointee instead of their own.
nuclear@0 176 // The pointer asterisk remains a property of the lookup name.
nuclear@0 177 if (f.name[0] == '*') {
nuclear@0 178 f.size = db.i64bit ? 8 : 4;
nuclear@0 179 f.flags |= FieldFlag_Pointer;
nuclear@0 180 }
nuclear@0 181
nuclear@0 182 // arrays, however, specify the size of a single element so we
nuclear@0 183 // need to parse the (possibly multi-dimensional) array declaration
nuclear@0 184 // in order to obtain the actual size of the array in the file.
nuclear@0 185 // Also we need to alter the lookup name to include no array
nuclear@0 186 // brackets anymore or size fixup won't work (if our size does
nuclear@0 187 // not match the size read from the DNA).
nuclear@0 188 if (*f.name.rbegin() == ']') {
nuclear@0 189 const std::string::size_type rb = f.name.find('[');
nuclear@0 190 if (rb == std::string::npos) {
nuclear@0 191 throw DeadlyImportError((format(),
nuclear@0 192 "BlenderDNA: Encountered invalid array declaration ",
nuclear@0 193 f.name
nuclear@0 194 ));
nuclear@0 195 }
nuclear@0 196
nuclear@0 197 f.flags |= FieldFlag_Array;
nuclear@0 198 DNA::ExtractArraySize(f.name,f.array_sizes);
nuclear@0 199 f.name = f.name.substr(0,rb);
nuclear@0 200
nuclear@0 201 f.size *= f.array_sizes[0] * f.array_sizes[1];
nuclear@0 202 }
nuclear@0 203
nuclear@0 204 // maintain separate indexes
nuclear@0 205 s.indices[f.name] = s.fields.size()-1;
nuclear@0 206 offset += f.size;
nuclear@0 207 }
nuclear@0 208 s.size = offset;
nuclear@0 209 }
nuclear@0 210
nuclear@0 211 DefaultLogger::get()->debug((format(),"BlenderDNA: Got ",dna.structures.size(),
nuclear@0 212 " structures with totally ",fields," fields"));
nuclear@0 213
nuclear@0 214 #ifdef ASSIMP_BUILD_BLENDER_DEBUG
nuclear@0 215 dna.DumpToFile();
nuclear@0 216 #endif
nuclear@0 217
nuclear@0 218 dna.AddPrimitiveStructures();
nuclear@0 219 dna.RegisterConverters();
nuclear@0 220 }
nuclear@0 221
nuclear@0 222
nuclear@0 223 #ifdef ASSIMP_BUILD_BLENDER_DEBUG
nuclear@0 224
nuclear@0 225 #include <fstream>
nuclear@0 226 // ------------------------------------------------------------------------------------------------
nuclear@0 227 void DNA :: DumpToFile()
nuclear@0 228 {
nuclear@0 229 // we dont't bother using the VFS here for this is only for debugging.
nuclear@0 230 // (and all your bases are belong to us).
nuclear@0 231
nuclear@0 232 std::ofstream f("dna.txt");
nuclear@0 233 if (f.fail()) {
nuclear@0 234 DefaultLogger::get()->error("Could not dump dna to dna.txt");
nuclear@0 235 return;
nuclear@0 236 }
nuclear@0 237 f << "Field format: type name offset size" << "\n";
nuclear@0 238 f << "Structure format: name size" << "\n";
nuclear@0 239
nuclear@0 240 for_each(const Structure& s, structures) {
nuclear@0 241 f << s.name << " " << s.size << "\n\n";
nuclear@0 242 for_each(const Field& ff, s.fields) {
nuclear@0 243 f << "\t" << ff.type << " " << ff.name << " " << ff.offset << " " << ff.size << std::endl;
nuclear@0 244 }
nuclear@0 245 f << std::endl;
nuclear@0 246 }
nuclear@0 247 DefaultLogger::get()->info("BlenderDNA: Dumped dna to dna.txt");
nuclear@0 248 }
nuclear@0 249 #endif
nuclear@0 250
nuclear@0 251 // ------------------------------------------------------------------------------------------------
nuclear@0 252 /*static*/ void DNA :: ExtractArraySize(
nuclear@0 253 const std::string& out,
nuclear@0 254 size_t array_sizes[2]
nuclear@0 255 )
nuclear@0 256 {
nuclear@0 257 array_sizes[0] = array_sizes[1] = 1;
nuclear@0 258 std::string::size_type pos = out.find('[');
nuclear@0 259 if (pos++ == std::string::npos) {
nuclear@0 260 return;
nuclear@0 261 }
nuclear@0 262 array_sizes[0] = strtoul10(&out[pos]);
nuclear@0 263
nuclear@0 264 pos = out.find('[',pos);
nuclear@0 265 if (pos++ == std::string::npos) {
nuclear@0 266 return;
nuclear@0 267 }
nuclear@0 268 array_sizes[1] = strtoul10(&out[pos]);
nuclear@0 269 }
nuclear@0 270
nuclear@0 271 // ------------------------------------------------------------------------------------------------
nuclear@0 272 boost::shared_ptr< ElemBase > DNA :: ConvertBlobToStructure(
nuclear@0 273 const Structure& structure,
nuclear@0 274 const FileDatabase& db
nuclear@0 275 ) const
nuclear@0 276 {
nuclear@0 277 std::map<std::string, FactoryPair >::const_iterator it = converters.find(structure.name);
nuclear@0 278 if (it == converters.end()) {
nuclear@0 279 return boost::shared_ptr< ElemBase >();
nuclear@0 280 }
nuclear@0 281
nuclear@0 282 boost::shared_ptr< ElemBase > ret = (structure.*((*it).second.first))();
nuclear@0 283 (structure.*((*it).second.second))(ret,db);
nuclear@0 284
nuclear@0 285 return ret;
nuclear@0 286 }
nuclear@0 287
nuclear@0 288 // ------------------------------------------------------------------------------------------------
nuclear@0 289 DNA::FactoryPair DNA :: GetBlobToStructureConverter(
nuclear@0 290 const Structure& structure,
nuclear@0 291 const FileDatabase& /*db*/
nuclear@0 292 ) const
nuclear@0 293 {
nuclear@0 294 std::map<std::string, FactoryPair>::const_iterator it = converters.find(structure.name);
nuclear@0 295 return it == converters.end() ? FactoryPair() : (*it).second;
nuclear@0 296 }
nuclear@0 297
nuclear@0 298 // basing on http://www.blender.org/development/architecture/notes-on-sdna/
nuclear@0 299 // ------------------------------------------------------------------------------------------------
nuclear@0 300 void DNA :: AddPrimitiveStructures()
nuclear@0 301 {
nuclear@0 302 // NOTE: these are just dummies. Their presence enforces
nuclear@0 303 // Structure::Convert<target_type> to be called on these
nuclear@0 304 // empty structures. These converters are special
nuclear@0 305 // overloads which scan the name of the structure and
nuclear@0 306 // perform the required data type conversion if one
nuclear@0 307 // of these special names is found in the structure
nuclear@0 308 // in question.
nuclear@0 309
nuclear@0 310 indices["int"] = structures.size();
nuclear@0 311 structures.push_back( Structure() );
nuclear@0 312 structures.back().name = "int";
nuclear@0 313 structures.back().size = 4;
nuclear@0 314
nuclear@0 315 indices["short"] = structures.size();
nuclear@0 316 structures.push_back( Structure() );
nuclear@0 317 structures.back().name = "short";
nuclear@0 318 structures.back().size = 2;
nuclear@0 319
nuclear@0 320
nuclear@0 321 indices["char"] = structures.size();
nuclear@0 322 structures.push_back( Structure() );
nuclear@0 323 structures.back().name = "char";
nuclear@0 324 structures.back().size = 1;
nuclear@0 325
nuclear@0 326
nuclear@0 327 indices["float"] = structures.size();
nuclear@0 328 structures.push_back( Structure() );
nuclear@0 329 structures.back().name = "float";
nuclear@0 330 structures.back().size = 4;
nuclear@0 331
nuclear@0 332
nuclear@0 333 indices["double"] = structures.size();
nuclear@0 334 structures.push_back( Structure() );
nuclear@0 335 structures.back().name = "double";
nuclear@0 336 structures.back().size = 8;
nuclear@0 337
nuclear@0 338 // no long, seemingly.
nuclear@0 339 }
nuclear@0 340
nuclear@0 341 // ------------------------------------------------------------------------------------------------
nuclear@0 342 void SectionParser :: Next()
nuclear@0 343 {
nuclear@0 344 stream.SetCurrentPos(current.start + current.size);
nuclear@0 345
nuclear@0 346 const char tmp[] = {
nuclear@0 347 stream.GetI1(),
nuclear@0 348 stream.GetI1(),
nuclear@0 349 stream.GetI1(),
nuclear@0 350 stream.GetI1()
nuclear@0 351 };
nuclear@0 352 current.id = std::string(tmp,tmp[3]?4:tmp[2]?3:tmp[1]?2:1);
nuclear@0 353
nuclear@0 354 current.size = stream.GetI4();
nuclear@0 355 current.address.val = ptr64 ? stream.GetU8() : stream.GetU4();
nuclear@0 356
nuclear@0 357 current.dna_index = stream.GetI4();
nuclear@0 358 current.num = stream.GetI4();
nuclear@0 359
nuclear@0 360 current.start = stream.GetCurrentPos();
nuclear@0 361 if (stream.GetRemainingSizeToLimit() < current.size) {
nuclear@0 362 throw DeadlyImportError("BLEND: invalid size of file block");
nuclear@0 363 }
nuclear@0 364
nuclear@0 365 #ifdef ASSIMP_BUILD_BLENDER_DEBUG
nuclear@0 366 DefaultLogger::get()->debug(current.id);
nuclear@0 367 #endif
nuclear@0 368 }
nuclear@0 369
nuclear@0 370
nuclear@0 371
nuclear@0 372 #endif