vrshoot

diff 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 diff
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/libs/assimp/BlenderDNA.cpp	Sat Feb 01 19:58:19 2014 +0200
     1.3 @@ -0,0 +1,372 @@
     1.4 +/*
     1.5 +Open Asset Import Library (assimp)
     1.6 +----------------------------------------------------------------------
     1.7 +
     1.8 +Copyright (c) 2006-2012, assimp team
     1.9 +All rights reserved.
    1.10 +
    1.11 +Redistribution and use of this software in source and binary forms, 
    1.12 +with or without modification, are permitted provided that the 
    1.13 +following conditions are met:
    1.14 +
    1.15 +* Redistributions of source code must retain the above
    1.16 +  copyright notice, this list of conditions and the
    1.17 +  following disclaimer.
    1.18 +
    1.19 +* Redistributions in binary form must reproduce the above
    1.20 +  copyright notice, this list of conditions and the
    1.21 +  following disclaimer in the documentation and/or other
    1.22 +  materials provided with the distribution.
    1.23 +
    1.24 +* Neither the name of the assimp team, nor the names of its
    1.25 +  contributors may be used to endorse or promote products
    1.26 +  derived from this software without specific prior
    1.27 +  written permission of the assimp team.
    1.28 +
    1.29 +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
    1.30 +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
    1.31 +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
    1.32 +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 
    1.33 +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
    1.34 +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 
    1.35 +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
    1.36 +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 
    1.37 +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 
    1.38 +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 
    1.39 +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    1.40 +
    1.41 +----------------------------------------------------------------------
    1.42 +*/
    1.43 +
    1.44 +/** @file  BlenderDNA.cpp
    1.45 + *  @brief Implementation of the Blender `DNA`, that is its own
    1.46 + *    serialized set of data structures.
    1.47 + */
    1.48 +#include "AssimpPCH.h"
    1.49 +
    1.50 +#ifndef ASSIMP_BUILD_NO_BLEND_IMPORTER
    1.51 +#include "BlenderDNA.h"
    1.52 +#include "StreamReader.h"
    1.53 +#include "fast_atof.h"
    1.54 +
    1.55 +using namespace Assimp;
    1.56 +using namespace Assimp::Blender;
    1.57 +using namespace Assimp::Formatter;
    1.58 +
    1.59 +#define for_each BOOST_FOREACH
    1.60 +bool match4(StreamReaderAny& stream, const char* string) {
    1.61 +	char tmp[] = { 
    1.62 +		(stream).GetI1(), 
    1.63 +		(stream).GetI1(),  
    1.64 +		(stream).GetI1(), 
    1.65 +		(stream).GetI1()
    1.66 +	};
    1.67 +	return (tmp[0]==string[0] && tmp[1]==string[1] && tmp[2]==string[2] && tmp[3]==string[3]);
    1.68 +}
    1.69 +
    1.70 +struct Type {
    1.71 +	size_t size;
    1.72 +	std::string name;
    1.73 +};
    1.74 +
    1.75 +// ------------------------------------------------------------------------------------------------
    1.76 +void DNAParser :: Parse () 
    1.77 +{
    1.78 +	StreamReaderAny& stream = *db.reader.get();
    1.79 +	DNA& dna = db.dna;
    1.80 +
    1.81 +	if(!match4(stream,"SDNA")) {
    1.82 +		throw DeadlyImportError("BlenderDNA: Expected SDNA chunk");
    1.83 +	}
    1.84 +
    1.85 +	// name dictionary
    1.86 +	if(!match4(stream,"NAME")) {
    1.87 +		throw DeadlyImportError("BlenderDNA: Expected NAME field");
    1.88 +	}
    1.89 +	
    1.90 +	std::vector<std::string> names (stream.GetI4());
    1.91 +	for_each(std::string& s, names) {
    1.92 +		while (char c = stream.GetI1()) {
    1.93 +			s += c;
    1.94 +		}
    1.95 +	}
    1.96 +
    1.97 +	// type dictionary
    1.98 +	for (;stream.GetCurrentPos() & 0x3; stream.GetI1());
    1.99 +	if(!match4(stream,"TYPE")) {
   1.100 +		throw DeadlyImportError("BlenderDNA: Expected TYPE field");
   1.101 +	}
   1.102 +	
   1.103 +	std::vector<Type> types (stream.GetI4());
   1.104 +	for_each(Type& s, types) {
   1.105 +		while (char c = stream.GetI1()) {
   1.106 +			s.name += c;
   1.107 +		}
   1.108 +	}
   1.109 +
   1.110 +	// type length dictionary
   1.111 +	for (;stream.GetCurrentPos() & 0x3; stream.GetI1());
   1.112 +	if(!match4(stream,"TLEN")) {
   1.113 +		throw DeadlyImportError("BlenderDNA: Expected TLEN field");
   1.114 +	}
   1.115 +	
   1.116 +	for_each(Type& s, types) {
   1.117 +		s.size = stream.GetI2();
   1.118 +	}
   1.119 +
   1.120 +	// structures dictionary
   1.121 +	for (;stream.GetCurrentPos() & 0x3; stream.GetI1());
   1.122 +	if(!match4(stream,"STRC")) {
   1.123 +		throw DeadlyImportError("BlenderDNA: Expected STRC field");
   1.124 +	}
   1.125 +
   1.126 +	size_t end = stream.GetI4(), fields = 0;
   1.127 +
   1.128 +	dna.structures.reserve(end);
   1.129 +	for(size_t i = 0; i != end; ++i) {
   1.130 +		
   1.131 +		uint16_t n = stream.GetI2();
   1.132 +		if (n >= types.size()) {
   1.133 +			throw DeadlyImportError((format(),
   1.134 +				"BlenderDNA: Invalid type index in structure name" ,n, 
   1.135 +				" (there are only ", types.size(), " entries)"
   1.136 +			));
   1.137 +		}
   1.138 +
   1.139 +		// maintain separate indexes
   1.140 +		dna.indices[types[n].name] = dna.structures.size();
   1.141 +
   1.142 +		dna.structures.push_back(Structure());
   1.143 +		Structure& s = dna.structures.back();
   1.144 +		s.name  = types[n].name;
   1.145 +		//s.index = dna.structures.size()-1;
   1.146 +
   1.147 +		n = stream.GetI2();
   1.148 +		s.fields.reserve(n);
   1.149 +
   1.150 +		size_t offset = 0;
   1.151 +		for (size_t m = 0; m < n; ++m, ++fields) {
   1.152 +
   1.153 +			uint16_t j = stream.GetI2();
   1.154 +			if (j >= types.size()) {
   1.155 +				throw DeadlyImportError((format(), 
   1.156 +					"BlenderDNA: Invalid type index in structure field ", j, 
   1.157 +					" (there are only ", types.size(), " entries)"
   1.158 +				));
   1.159 +			}
   1.160 +			s.fields.push_back(Field());
   1.161 +			Field& f = s.fields.back();
   1.162 +			f.offset = offset;
   1.163 +
   1.164 +			f.type = types[j].name;
   1.165 +			f.size = types[j].size;
   1.166 +
   1.167 +			j = stream.GetI2();
   1.168 +			if (j >= names.size()) {
   1.169 +				throw DeadlyImportError((format(), 
   1.170 +					"BlenderDNA: Invalid name index in structure field ", j, 
   1.171 +					" (there are only ", names.size(), " entries)"
   1.172 +				));
   1.173 +			}
   1.174 +
   1.175 +			f.name = names[j];
   1.176 +			f.flags = 0u;
   1.177 +			
   1.178 +			// pointers always specify the size of the pointee instead of their own.
   1.179 +			// The pointer asterisk remains a property of the lookup name.
   1.180 +			if (f.name[0] == '*') {
   1.181 +				f.size = db.i64bit ? 8 : 4;
   1.182 +				f.flags |= FieldFlag_Pointer;
   1.183 +			}
   1.184 +
   1.185 +			// arrays, however, specify the size of a single element so we
   1.186 +			// need to parse the (possibly multi-dimensional) array declaration
   1.187 +			// in order to obtain the actual size of the array in the file.
   1.188 +			// Also we need to alter the lookup name to include no array
   1.189 +			// brackets anymore or size fixup won't work (if our size does 
   1.190 +			// not match the size read from the DNA).
   1.191 +			if (*f.name.rbegin() == ']') {
   1.192 +				const std::string::size_type rb = f.name.find('[');
   1.193 +				if (rb == std::string::npos) {
   1.194 +					throw DeadlyImportError((format(), 
   1.195 +						"BlenderDNA: Encountered invalid array declaration ",
   1.196 +						f.name
   1.197 +					));
   1.198 +				}
   1.199 +
   1.200 +				f.flags |= FieldFlag_Array; 
   1.201 +				DNA::ExtractArraySize(f.name,f.array_sizes);
   1.202 +				f.name = f.name.substr(0,rb);
   1.203 +
   1.204 +				f.size *= f.array_sizes[0] * f.array_sizes[1];
   1.205 +			}
   1.206 +
   1.207 +			// maintain separate indexes
   1.208 +			s.indices[f.name] = s.fields.size()-1;
   1.209 +			offset += f.size;
   1.210 +		}
   1.211 +		s.size = offset;
   1.212 +	}
   1.213 +
   1.214 +	DefaultLogger::get()->debug((format(),"BlenderDNA: Got ",dna.structures.size(),
   1.215 +		" structures with totally ",fields," fields"));
   1.216 +
   1.217 +#ifdef ASSIMP_BUILD_BLENDER_DEBUG
   1.218 +	dna.DumpToFile();
   1.219 +#endif
   1.220 +
   1.221 +	dna.AddPrimitiveStructures();
   1.222 +	dna.RegisterConverters();
   1.223 +}
   1.224 +
   1.225 +
   1.226 +#ifdef ASSIMP_BUILD_BLENDER_DEBUG
   1.227 +
   1.228 +#include <fstream>
   1.229 +// ------------------------------------------------------------------------------------------------
   1.230 +void DNA :: DumpToFile()
   1.231 +{
   1.232 +	// we dont't bother using the VFS here for this is only for debugging.
   1.233 +	// (and all your bases are belong to us).
   1.234 +
   1.235 +	std::ofstream f("dna.txt");
   1.236 +	if (f.fail()) {
   1.237 +		DefaultLogger::get()->error("Could not dump dna to dna.txt");
   1.238 +		return;
   1.239 +	}
   1.240 +	f << "Field format: type name offset size" << "\n";
   1.241 +	f << "Structure format: name size" << "\n";
   1.242 +
   1.243 +	for_each(const Structure& s, structures) {
   1.244 +		f << s.name << " " << s.size << "\n\n";
   1.245 +		for_each(const Field& ff, s.fields) {
   1.246 +			f << "\t" << ff.type << " " << ff.name << " " << ff.offset << " " << ff.size << std::endl;
   1.247 +		}
   1.248 +		f << std::endl;
   1.249 +	}
   1.250 +	DefaultLogger::get()->info("BlenderDNA: Dumped dna to dna.txt");
   1.251 +}
   1.252 +#endif
   1.253 +
   1.254 +// ------------------------------------------------------------------------------------------------
   1.255 +/*static*/ void  DNA :: ExtractArraySize(
   1.256 +	const std::string& out, 
   1.257 +	size_t array_sizes[2]
   1.258 +)
   1.259 +{
   1.260 +	array_sizes[0] = array_sizes[1] = 1;
   1.261 +	std::string::size_type pos = out.find('[');
   1.262 +	if (pos++ == std::string::npos) {
   1.263 +		return;
   1.264 +	}
   1.265 +	array_sizes[0] = strtoul10(&out[pos]);
   1.266 +
   1.267 +	pos = out.find('[',pos);
   1.268 +	if (pos++ == std::string::npos) {
   1.269 +		return;
   1.270 +	}
   1.271 +	array_sizes[1] = strtoul10(&out[pos]);
   1.272 +}
   1.273 +
   1.274 +// ------------------------------------------------------------------------------------------------
   1.275 +boost::shared_ptr< ElemBase > DNA :: ConvertBlobToStructure(
   1.276 +	const Structure& structure,
   1.277 +	const FileDatabase& db
   1.278 +) const 
   1.279 +{
   1.280 +	std::map<std::string, FactoryPair >::const_iterator it = converters.find(structure.name);
   1.281 +	if (it == converters.end()) {
   1.282 +		return boost::shared_ptr< ElemBase >();
   1.283 +	}
   1.284 +
   1.285 +	boost::shared_ptr< ElemBase > ret = (structure.*((*it).second.first))();
   1.286 +	(structure.*((*it).second.second))(ret,db);
   1.287 +	
   1.288 +	return ret;
   1.289 +}
   1.290 +
   1.291 +// ------------------------------------------------------------------------------------------------
   1.292 +DNA::FactoryPair DNA :: GetBlobToStructureConverter(
   1.293 +	const Structure& structure,
   1.294 +	const FileDatabase& /*db*/
   1.295 +) const 
   1.296 +{
   1.297 +	std::map<std::string,  FactoryPair>::const_iterator it = converters.find(structure.name);
   1.298 +	return it == converters.end() ? FactoryPair() : (*it).second;
   1.299 +}
   1.300 +
   1.301 +// basing on http://www.blender.org/development/architecture/notes-on-sdna/
   1.302 +// ------------------------------------------------------------------------------------------------
   1.303 +void DNA :: AddPrimitiveStructures()
   1.304 +{
   1.305 +	// NOTE: these are just dummies. Their presence enforces
   1.306 +	// Structure::Convert<target_type> to be called on these
   1.307 +	// empty structures. These converters are special 
   1.308 +	// overloads which scan the name of the structure and
   1.309 +	// perform the required data type conversion if one
   1.310 +	// of these special names is found in the structure
   1.311 +	// in question.
   1.312 +
   1.313 +	indices["int"] = structures.size();
   1.314 +	structures.push_back( Structure() );
   1.315 +	structures.back().name = "int";
   1.316 +	structures.back().size = 4;
   1.317 +
   1.318 +	indices["short"] = structures.size();
   1.319 +	structures.push_back( Structure() );
   1.320 +	structures.back().name = "short";
   1.321 +	structures.back().size = 2;
   1.322 +
   1.323 +
   1.324 +	indices["char"] = structures.size();
   1.325 +	structures.push_back( Structure() );
   1.326 +	structures.back().name = "char";
   1.327 +	structures.back().size = 1;
   1.328 +
   1.329 +
   1.330 +	indices["float"] = structures.size();
   1.331 +	structures.push_back( Structure() );
   1.332 +	structures.back().name = "float";
   1.333 +	structures.back().size = 4;
   1.334 +
   1.335 +
   1.336 +	indices["double"] = structures.size();
   1.337 +	structures.push_back( Structure() );
   1.338 +	structures.back().name = "double";
   1.339 +	structures.back().size = 8;
   1.340 +
   1.341 +	// no long, seemingly.
   1.342 +}
   1.343 +
   1.344 +// ------------------------------------------------------------------------------------------------
   1.345 +void SectionParser :: Next()
   1.346 +{
   1.347 +	stream.SetCurrentPos(current.start + current.size);
   1.348 +
   1.349 +	const char tmp[] = {
   1.350 +		stream.GetI1(),
   1.351 +		stream.GetI1(),
   1.352 +		stream.GetI1(),
   1.353 +		stream.GetI1()
   1.354 +	};
   1.355 +	current.id = std::string(tmp,tmp[3]?4:tmp[2]?3:tmp[1]?2:1);
   1.356 +
   1.357 +	current.size = stream.GetI4();
   1.358 +	current.address.val = ptr64 ? stream.GetU8() : stream.GetU4();
   1.359 +
   1.360 +	current.dna_index = stream.GetI4();
   1.361 +	current.num = stream.GetI4();
   1.362 +
   1.363 +	current.start = stream.GetCurrentPos();
   1.364 +	if (stream.GetRemainingSizeToLimit() < current.size) {
   1.365 +		throw DeadlyImportError("BLEND: invalid size of file block");
   1.366 +	}
   1.367 +
   1.368 +#ifdef ASSIMP_BUILD_BLENDER_DEBUG
   1.369 +	DefaultLogger::get()->debug(current.id);
   1.370 +#endif
   1.371 +}
   1.372 +
   1.373 +
   1.374 +
   1.375 +#endif