vrshoot

annotate libs/assimp/FBXParser.cpp @ 1:e7ca128b8713

looks nice :)
author John Tsiombikas <nuclear@member.fsf.org>
date Sun, 02 Feb 2014 00:35:22 +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 FBXParser.cpp
nuclear@0 42 * @brief Implementation of the FBX parser and the rudimentary DOM that we use
nuclear@0 43 */
nuclear@0 44 #include "AssimpPCH.h"
nuclear@0 45
nuclear@0 46 #ifndef ASSIMP_BUILD_NO_FBX_IMPORTER
nuclear@0 47
nuclear@0 48
nuclear@0 49 #ifdef ASSIMP_BUILD_NO_OWN_ZLIB
nuclear@0 50 # include <zlib.h>
nuclear@0 51 #else
nuclear@0 52 # include "../contrib/zlib/zlib.h"
nuclear@0 53 #endif
nuclear@0 54
nuclear@0 55
nuclear@0 56 #include "FBXTokenizer.h"
nuclear@0 57 #include "FBXParser.h"
nuclear@0 58 #include "FBXUtil.h"
nuclear@0 59
nuclear@0 60 #include "ParsingUtils.h"
nuclear@0 61 #include "fast_atof.h"
nuclear@0 62
nuclear@0 63 using namespace Assimp;
nuclear@0 64 using namespace Assimp::FBX;
nuclear@0 65
nuclear@0 66 namespace {
nuclear@0 67
nuclear@0 68
nuclear@0 69 // ------------------------------------------------------------------------------------------------
nuclear@0 70 // signal parse error, this is always unrecoverable. Throws DeadlyImportError.
nuclear@0 71 void ParseError(const std::string& message, const Token& token)
nuclear@0 72 {
nuclear@0 73 throw DeadlyImportError(Util::AddTokenText("FBX-Parser",message,&token));
nuclear@0 74 }
nuclear@0 75
nuclear@0 76 // ------------------------------------------------------------------------------------------------
nuclear@0 77 void ParseError(const std::string& message, const Element* element = NULL)
nuclear@0 78 {
nuclear@0 79 if(element) {
nuclear@0 80 ParseError(message,element->KeyToken());
nuclear@0 81 }
nuclear@0 82 throw DeadlyImportError("FBX-Parser " + message);
nuclear@0 83 }
nuclear@0 84
nuclear@0 85
nuclear@0 86 // ------------------------------------------------------------------------------------------------
nuclear@0 87 // print warning, do return
nuclear@0 88 void ParseWarning(const std::string& message, const Token& token)
nuclear@0 89 {
nuclear@0 90 if(DefaultLogger::get()) {
nuclear@0 91 DefaultLogger::get()->warn(Util::AddTokenText("FBX-Parser",message,&token));
nuclear@0 92 }
nuclear@0 93 }
nuclear@0 94
nuclear@0 95 // ------------------------------------------------------------------------------------------------
nuclear@0 96 void ParseWarning(const std::string& message, const Element* element = NULL)
nuclear@0 97 {
nuclear@0 98 if(element) {
nuclear@0 99 ParseWarning(message,element->KeyToken());
nuclear@0 100 return;
nuclear@0 101 }
nuclear@0 102 if(DefaultLogger::get()) {
nuclear@0 103 DefaultLogger::get()->warn("FBX-Parser: " + message);
nuclear@0 104 }
nuclear@0 105 }
nuclear@0 106
nuclear@0 107 // ------------------------------------------------------------------------------------------------
nuclear@0 108 void ParseError(const std::string& message, TokenPtr token)
nuclear@0 109 {
nuclear@0 110 if(token) {
nuclear@0 111 ParseError(message, *token);
nuclear@0 112 }
nuclear@0 113 ParseError(message);
nuclear@0 114 }
nuclear@0 115
nuclear@0 116 }
nuclear@0 117
nuclear@0 118 namespace Assimp {
nuclear@0 119 namespace FBX {
nuclear@0 120
nuclear@0 121 // ------------------------------------------------------------------------------------------------
nuclear@0 122 Element::Element(const Token& key_token, Parser& parser)
nuclear@0 123 : key_token(key_token)
nuclear@0 124 {
nuclear@0 125 TokenPtr n = NULL;
nuclear@0 126 do {
nuclear@0 127 n = parser.AdvanceToNextToken();
nuclear@0 128 if(!n) {
nuclear@0 129 ParseError("unexpected end of file, expected closing bracket",parser.LastToken());
nuclear@0 130 }
nuclear@0 131
nuclear@0 132 if (n->Type() == TokenType_DATA) {
nuclear@0 133 tokens.push_back(n);
nuclear@0 134
nuclear@0 135 n = parser.AdvanceToNextToken();
nuclear@0 136 if(!n) {
nuclear@0 137 ParseError("unexpected end of file, expected bracket, comma or key",parser.LastToken());
nuclear@0 138 }
nuclear@0 139
nuclear@0 140 const TokenType ty = n->Type();
nuclear@0 141 if (ty != TokenType_OPEN_BRACKET && ty != TokenType_CLOSE_BRACKET && ty != TokenType_COMMA && ty != TokenType_KEY) {
nuclear@0 142 ParseError("unexpected token; expected bracket, comma or key",n);
nuclear@0 143 }
nuclear@0 144 }
nuclear@0 145
nuclear@0 146 if (n->Type() == TokenType_OPEN_BRACKET) {
nuclear@0 147 compound.reset(new Scope(parser));
nuclear@0 148
nuclear@0 149 // current token should be a TOK_CLOSE_BRACKET
nuclear@0 150 n = parser.CurrentToken();
nuclear@0 151 ai_assert(n);
nuclear@0 152
nuclear@0 153 if (n->Type() != TokenType_CLOSE_BRACKET) {
nuclear@0 154 ParseError("expected closing bracket",n);
nuclear@0 155 }
nuclear@0 156
nuclear@0 157 parser.AdvanceToNextToken();
nuclear@0 158 return;
nuclear@0 159 }
nuclear@0 160 }
nuclear@0 161 while(n->Type() != TokenType_KEY && n->Type() != TokenType_CLOSE_BRACKET);
nuclear@0 162 }
nuclear@0 163
nuclear@0 164 // ------------------------------------------------------------------------------------------------
nuclear@0 165 Element::~Element()
nuclear@0 166 {
nuclear@0 167 // no need to delete tokens, they are owned by the parser
nuclear@0 168 }
nuclear@0 169
nuclear@0 170 // ------------------------------------------------------------------------------------------------
nuclear@0 171 Scope::Scope(Parser& parser,bool topLevel)
nuclear@0 172 {
nuclear@0 173 if(!topLevel) {
nuclear@0 174 TokenPtr t = parser.CurrentToken();
nuclear@0 175 if (t->Type() != TokenType_OPEN_BRACKET) {
nuclear@0 176 ParseError("expected open bracket",t);
nuclear@0 177 }
nuclear@0 178 }
nuclear@0 179
nuclear@0 180 TokenPtr n = parser.AdvanceToNextToken();
nuclear@0 181 if(n == NULL) {
nuclear@0 182 ParseError("unexpected end of file");
nuclear@0 183 }
nuclear@0 184
nuclear@0 185 // note: empty scopes are allowed
nuclear@0 186 while(n->Type() != TokenType_CLOSE_BRACKET) {
nuclear@0 187 if (n->Type() != TokenType_KEY) {
nuclear@0 188 ParseError("unexpected token, expected TOK_KEY",n);
nuclear@0 189 }
nuclear@0 190
nuclear@0 191 const std::string& str = n->StringContents();
nuclear@0 192 elements.insert(ElementMap::value_type(str,new_Element(*n,parser)));
nuclear@0 193
nuclear@0 194 // Element() should stop at the next Key token (or right after a Close token)
nuclear@0 195 n = parser.CurrentToken();
nuclear@0 196 if(n == NULL) {
nuclear@0 197 if (topLevel) {
nuclear@0 198 return;
nuclear@0 199 }
nuclear@0 200 ParseError("unexpected end of file",parser.LastToken());
nuclear@0 201 }
nuclear@0 202 }
nuclear@0 203 }
nuclear@0 204
nuclear@0 205 // ------------------------------------------------------------------------------------------------
nuclear@0 206 Scope::~Scope()
nuclear@0 207 {
nuclear@0 208 BOOST_FOREACH(ElementMap::value_type& v, elements) {
nuclear@0 209 delete v.second;
nuclear@0 210 }
nuclear@0 211 }
nuclear@0 212
nuclear@0 213
nuclear@0 214 // ------------------------------------------------------------------------------------------------
nuclear@0 215 Parser::Parser (const TokenList& tokens, bool is_binary)
nuclear@0 216 : tokens(tokens)
nuclear@0 217 , last()
nuclear@0 218 , current()
nuclear@0 219 , cursor(tokens.begin())
nuclear@0 220 , is_binary(is_binary)
nuclear@0 221 {
nuclear@0 222 root.reset(new Scope(*this,true));
nuclear@0 223 }
nuclear@0 224
nuclear@0 225
nuclear@0 226 // ------------------------------------------------------------------------------------------------
nuclear@0 227 Parser::~Parser()
nuclear@0 228 {
nuclear@0 229 }
nuclear@0 230
nuclear@0 231
nuclear@0 232 // ------------------------------------------------------------------------------------------------
nuclear@0 233 TokenPtr Parser::AdvanceToNextToken()
nuclear@0 234 {
nuclear@0 235 last = current;
nuclear@0 236 if (cursor == tokens.end()) {
nuclear@0 237 current = NULL;
nuclear@0 238 }
nuclear@0 239 else {
nuclear@0 240 current = *cursor++;
nuclear@0 241 }
nuclear@0 242 return current;
nuclear@0 243 }
nuclear@0 244
nuclear@0 245
nuclear@0 246 // ------------------------------------------------------------------------------------------------
nuclear@0 247 TokenPtr Parser::CurrentToken() const
nuclear@0 248 {
nuclear@0 249 return current;
nuclear@0 250 }
nuclear@0 251
nuclear@0 252
nuclear@0 253 // ------------------------------------------------------------------------------------------------
nuclear@0 254 TokenPtr Parser::LastToken() const
nuclear@0 255 {
nuclear@0 256 return last;
nuclear@0 257 }
nuclear@0 258
nuclear@0 259
nuclear@0 260 // ------------------------------------------------------------------------------------------------
nuclear@0 261 uint64_t ParseTokenAsID(const Token& t, const char*& err_out)
nuclear@0 262 {
nuclear@0 263 err_out = NULL;
nuclear@0 264
nuclear@0 265 if (t.Type() != TokenType_DATA) {
nuclear@0 266 err_out = "expected TOK_DATA token";
nuclear@0 267 return 0L;
nuclear@0 268 }
nuclear@0 269
nuclear@0 270 if(t.IsBinary())
nuclear@0 271 {
nuclear@0 272 const char* data = t.begin();
nuclear@0 273 if (data[0] != 'L') {
nuclear@0 274 err_out = "failed to parse ID, unexpected data type, expected L(ong) (binary)";
nuclear@0 275 return 0L;
nuclear@0 276 }
nuclear@0 277
nuclear@0 278 ai_assert(t.end() - data == 9);
nuclear@0 279
nuclear@0 280 BE_NCONST uint64_t id = *reinterpret_cast<const uint64_t*>(data+1);
nuclear@0 281 AI_SWAP8(id);
nuclear@0 282 return id;
nuclear@0 283 }
nuclear@0 284
nuclear@0 285 // XXX: should use size_t here
nuclear@0 286 unsigned int length = static_cast<unsigned int>(t.end() - t.begin());
nuclear@0 287 ai_assert(length > 0);
nuclear@0 288
nuclear@0 289 const char* out;
nuclear@0 290 const uint64_t id = strtoul10_64(t.begin(),&out,&length);
nuclear@0 291 if (out > t.end()) {
nuclear@0 292 err_out = "failed to parse ID (text)";
nuclear@0 293 return 0L;
nuclear@0 294 }
nuclear@0 295
nuclear@0 296 return id;
nuclear@0 297 }
nuclear@0 298
nuclear@0 299
nuclear@0 300 // ------------------------------------------------------------------------------------------------
nuclear@0 301 size_t ParseTokenAsDim(const Token& t, const char*& err_out)
nuclear@0 302 {
nuclear@0 303 // same as ID parsing, except there is a trailing asterisk
nuclear@0 304 err_out = NULL;
nuclear@0 305
nuclear@0 306 if (t.Type() != TokenType_DATA) {
nuclear@0 307 err_out = "expected TOK_DATA token";
nuclear@0 308 return 0;
nuclear@0 309 }
nuclear@0 310
nuclear@0 311 if(t.IsBinary())
nuclear@0 312 {
nuclear@0 313 const char* data = t.begin();
nuclear@0 314 if (data[0] != 'L') {
nuclear@0 315 err_out = "failed to parse ID, unexpected data type, expected L(ong) (binary)";
nuclear@0 316 return 0;
nuclear@0 317 }
nuclear@0 318
nuclear@0 319 ai_assert(t.end() - data == 9);
nuclear@0 320 BE_NCONST uint64_t id = *reinterpret_cast<const uint64_t*>(data+1);
nuclear@0 321 AI_SWAP8(id);
nuclear@0 322 return static_cast<size_t>(id);
nuclear@0 323 }
nuclear@0 324
nuclear@0 325 if(*t.begin() != '*') {
nuclear@0 326 err_out = "expected asterisk before array dimension";
nuclear@0 327 return 0;
nuclear@0 328 }
nuclear@0 329
nuclear@0 330 // XXX: should use size_t here
nuclear@0 331 unsigned int length = static_cast<unsigned int>(t.end() - t.begin());
nuclear@0 332 if(length == 0) {
nuclear@0 333 err_out = "expected valid integer number after asterisk";
nuclear@0 334 return 0;
nuclear@0 335 }
nuclear@0 336
nuclear@0 337 const char* out;
nuclear@0 338 const size_t id = static_cast<size_t>(strtoul10_64(t.begin() + 1,&out,&length));
nuclear@0 339 if (out > t.end()) {
nuclear@0 340 err_out = "failed to parse ID";
nuclear@0 341 return 0;
nuclear@0 342 }
nuclear@0 343
nuclear@0 344 return id;
nuclear@0 345 }
nuclear@0 346
nuclear@0 347
nuclear@0 348 // ------------------------------------------------------------------------------------------------
nuclear@0 349 float ParseTokenAsFloat(const Token& t, const char*& err_out)
nuclear@0 350 {
nuclear@0 351 err_out = NULL;
nuclear@0 352
nuclear@0 353 if (t.Type() != TokenType_DATA) {
nuclear@0 354 err_out = "expected TOK_DATA token";
nuclear@0 355 return 0.0f;
nuclear@0 356 }
nuclear@0 357
nuclear@0 358 if(t.IsBinary())
nuclear@0 359 {
nuclear@0 360 const char* data = t.begin();
nuclear@0 361 if (data[0] != 'F' && data[0] != 'D') {
nuclear@0 362 err_out = "failed to parse F(loat) or D(ouble), unexpected data type (binary)";
nuclear@0 363 return 0.0f;
nuclear@0 364 }
nuclear@0 365
nuclear@0 366 if (data[0] == 'F') {
nuclear@0 367 ai_assert(t.end() - data == 5);
nuclear@0 368 // no byte swapping needed for ieee floats
nuclear@0 369 float res;
nuclear@0 370 memcpy(&res, data + 1, sizeof res);
nuclear@0 371 return res;
nuclear@0 372 }
nuclear@0 373 else {
nuclear@0 374 ai_assert(t.end() - data == 9);
nuclear@0 375 // no byte swapping needed for ieee floats
nuclear@0 376 double res;
nuclear@0 377 memcpy(&res, data + 1, sizeof res);
nuclear@0 378 return (float)res;
nuclear@0 379 }
nuclear@0 380 }
nuclear@0 381
nuclear@0 382 // need to copy the input string to a temporary buffer
nuclear@0 383 // first - next in the fbx token stream comes ',',
nuclear@0 384 // which fast_atof could interpret as decimal point.
nuclear@0 385 #define MAX_FLOAT_LENGTH 31
nuclear@0 386 char temp[MAX_FLOAT_LENGTH + 1];
nuclear@0 387 const size_t length = static_cast<size_t>(t.end()-t.begin());
nuclear@0 388 std::copy(t.begin(),t.end(),temp);
nuclear@0 389 temp[std::min(static_cast<size_t>(MAX_FLOAT_LENGTH),length)] = '\0';
nuclear@0 390
nuclear@0 391 return fast_atof(temp);
nuclear@0 392 }
nuclear@0 393
nuclear@0 394
nuclear@0 395 // ------------------------------------------------------------------------------------------------
nuclear@0 396 int ParseTokenAsInt(const Token& t, const char*& err_out)
nuclear@0 397 {
nuclear@0 398 err_out = NULL;
nuclear@0 399
nuclear@0 400 if (t.Type() != TokenType_DATA) {
nuclear@0 401 err_out = "expected TOK_DATA token";
nuclear@0 402 return 0;
nuclear@0 403 }
nuclear@0 404
nuclear@0 405 if(t.IsBinary())
nuclear@0 406 {
nuclear@0 407 const char* data = t.begin();
nuclear@0 408 if (data[0] != 'I') {
nuclear@0 409 err_out = "failed to parse I(nt), unexpected data type (binary)";
nuclear@0 410 return 0;
nuclear@0 411 }
nuclear@0 412
nuclear@0 413 ai_assert(t.end() - data == 5);
nuclear@0 414 BE_NCONST int32_t ival = *reinterpret_cast<const int32_t*>(data+1);
nuclear@0 415 AI_SWAP4(ival);
nuclear@0 416 return static_cast<int>(ival);
nuclear@0 417 }
nuclear@0 418
nuclear@0 419 ai_assert(static_cast<size_t>(t.end() - t.begin()) > 0);
nuclear@0 420
nuclear@0 421 const char* out;
nuclear@0 422 const int intval = strtol10(t.begin(),&out);
nuclear@0 423 if (out != t.end()) {
nuclear@0 424 err_out = "failed to parse ID";
nuclear@0 425 return 0;
nuclear@0 426 }
nuclear@0 427
nuclear@0 428 return intval;
nuclear@0 429 }
nuclear@0 430
nuclear@0 431
nuclear@0 432 // ------------------------------------------------------------------------------------------------
nuclear@0 433 std::string ParseTokenAsString(const Token& t, const char*& err_out)
nuclear@0 434 {
nuclear@0 435 err_out = NULL;
nuclear@0 436
nuclear@0 437 if (t.Type() != TokenType_DATA) {
nuclear@0 438 err_out = "expected TOK_DATA token";
nuclear@0 439 return "";
nuclear@0 440 }
nuclear@0 441
nuclear@0 442 if(t.IsBinary())
nuclear@0 443 {
nuclear@0 444 const char* data = t.begin();
nuclear@0 445 if (data[0] != 'S') {
nuclear@0 446 err_out = "failed to parse S(tring), unexpected data type (binary)";
nuclear@0 447 return "";
nuclear@0 448 }
nuclear@0 449
nuclear@0 450 ai_assert(t.end() - data >= 5);
nuclear@0 451
nuclear@0 452 // read string length
nuclear@0 453 BE_NCONST int32_t len = *reinterpret_cast<const int32_t*>(data+1);
nuclear@0 454 AI_SWAP4(len);
nuclear@0 455
nuclear@0 456 ai_assert(t.end() - data == 5 + len);
nuclear@0 457 return std::string(data + 5, len);
nuclear@0 458 }
nuclear@0 459
nuclear@0 460 const size_t length = static_cast<size_t>(t.end() - t.begin());
nuclear@0 461 if(length < 2) {
nuclear@0 462 err_out = "token is too short to hold a string";
nuclear@0 463 return "";
nuclear@0 464 }
nuclear@0 465
nuclear@0 466 const char* s = t.begin(), *e = t.end() - 1;
nuclear@0 467 if (*s != '\"' || *e != '\"') {
nuclear@0 468 err_out = "expected double quoted string";
nuclear@0 469 return "";
nuclear@0 470 }
nuclear@0 471
nuclear@0 472 return std::string(s+1,length-2);
nuclear@0 473 }
nuclear@0 474
nuclear@0 475
nuclear@0 476 namespace {
nuclear@0 477
nuclear@0 478 // ------------------------------------------------------------------------------------------------
nuclear@0 479 // read the type code and element count of a binary data array and stop there
nuclear@0 480 void ReadBinaryDataArrayHead(const char*& data, const char* end, char& type, uint32_t& count,
nuclear@0 481 const Element& el)
nuclear@0 482 {
nuclear@0 483 if (static_cast<size_t>(end-data) < 5) {
nuclear@0 484 ParseError("binary data array is too short, need five (5) bytes for type signature and element count",&el);
nuclear@0 485 }
nuclear@0 486
nuclear@0 487 // data type
nuclear@0 488 type = *data;
nuclear@0 489
nuclear@0 490 // read number of elements
nuclear@0 491 BE_NCONST uint32_t len = *reinterpret_cast<const uint32_t*>(data+1);
nuclear@0 492 AI_SWAP4(len);
nuclear@0 493
nuclear@0 494 count = len;
nuclear@0 495 data += 5;
nuclear@0 496 }
nuclear@0 497
nuclear@0 498
nuclear@0 499 // ------------------------------------------------------------------------------------------------
nuclear@0 500 // read binary data array, assume cursor points to the 'compression mode' field (i.e. behind the header)
nuclear@0 501 void ReadBinaryDataArray(char type, uint32_t count, const char*& data, const char* end,
nuclear@0 502 std::vector<char>& buff,
nuclear@0 503 const Element& el)
nuclear@0 504 {
nuclear@0 505 ai_assert(static_cast<size_t>(end-data) >= 4); // runtime check for this happens at tokenization stage
nuclear@0 506
nuclear@0 507 BE_NCONST uint32_t encmode = *reinterpret_cast<const uint32_t*>(data);
nuclear@0 508 AI_SWAP4(encmode);
nuclear@0 509 data += 4;
nuclear@0 510
nuclear@0 511 // next comes the compressed length
nuclear@0 512 BE_NCONST uint32_t comp_len = *reinterpret_cast<const uint32_t*>(data);
nuclear@0 513 AI_SWAP4(comp_len);
nuclear@0 514 data += 4;
nuclear@0 515
nuclear@0 516 ai_assert(data + comp_len == end);
nuclear@0 517
nuclear@0 518 // determine the length of the uncompressed data by looking at the type signature
nuclear@0 519 uint32_t stride;
nuclear@0 520 switch(type)
nuclear@0 521 {
nuclear@0 522 case 'f':
nuclear@0 523 case 'i':
nuclear@0 524 stride = 4;
nuclear@0 525 break;
nuclear@0 526
nuclear@0 527 case 'd':
nuclear@0 528 case 'l':
nuclear@0 529 stride = 8;
nuclear@0 530 break;
nuclear@0 531
nuclear@0 532 default:
nuclear@0 533 ai_assert(false);
nuclear@0 534 };
nuclear@0 535
nuclear@0 536 const uint32_t full_length = stride * count;
nuclear@0 537 buff.resize(full_length);
nuclear@0 538
nuclear@0 539 if(encmode == 0) {
nuclear@0 540 ai_assert(full_length == comp_len);
nuclear@0 541
nuclear@0 542 // plain data, no compression
nuclear@0 543 std::copy(data, end, buff.begin());
nuclear@0 544 }
nuclear@0 545 else if(encmode == 1) {
nuclear@0 546 // zlib/deflate, next comes ZIP head (0x78 0x01)
nuclear@0 547 // see http://www.ietf.org/rfc/rfc1950.txt
nuclear@0 548
nuclear@0 549 z_stream zstream;
nuclear@0 550 zstream.opaque = Z_NULL;
nuclear@0 551 zstream.zalloc = Z_NULL;
nuclear@0 552 zstream.zfree = Z_NULL;
nuclear@0 553 zstream.data_type = Z_BINARY;
nuclear@0 554
nuclear@0 555 // http://hewgill.com/journal/entries/349-how-to-decompress-gzip-stream-with-zlib
nuclear@0 556 inflateInit(&zstream);
nuclear@0 557
nuclear@0 558 zstream.next_in = reinterpret_cast<Bytef*>( const_cast<char*>(data) );
nuclear@0 559 zstream.avail_in = comp_len;
nuclear@0 560
nuclear@0 561 zstream.avail_out = buff.size();
nuclear@0 562 zstream.next_out = reinterpret_cast<Bytef*>(&*buff.begin());
nuclear@0 563 const int ret = inflate(&zstream, Z_FINISH);
nuclear@0 564
nuclear@0 565 if (ret != Z_STREAM_END && ret != Z_OK) {
nuclear@0 566 ParseError("failure decompressing compressed data section");
nuclear@0 567 }
nuclear@0 568
nuclear@0 569 // terminate zlib
nuclear@0 570 inflateEnd(&zstream);
nuclear@0 571 }
nuclear@0 572 #ifdef _DEBUG
nuclear@0 573 else {
nuclear@0 574 // runtime check for this happens at tokenization stage
nuclear@0 575 ai_assert(false);
nuclear@0 576 }
nuclear@0 577 #endif
nuclear@0 578
nuclear@0 579 data += comp_len;
nuclear@0 580 ai_assert(data == end);
nuclear@0 581 }
nuclear@0 582
nuclear@0 583 } // !anon
nuclear@0 584
nuclear@0 585
nuclear@0 586 // ------------------------------------------------------------------------------------------------
nuclear@0 587 // read an array of float3 tuples
nuclear@0 588 void ParseVectorDataArray(std::vector<aiVector3D>& out, const Element& el)
nuclear@0 589 {
nuclear@0 590 out.clear();
nuclear@0 591
nuclear@0 592 const TokenList& tok = el.Tokens();
nuclear@0 593 if(tok.empty()) {
nuclear@0 594 ParseError("unexpected empty element",&el);
nuclear@0 595 }
nuclear@0 596
nuclear@0 597 if(tok[0]->IsBinary()) {
nuclear@0 598 const char* data = tok[0]->begin(), *end = tok[0]->end();
nuclear@0 599
nuclear@0 600 char type;
nuclear@0 601 uint32_t count;
nuclear@0 602 ReadBinaryDataArrayHead(data, end, type, count, el);
nuclear@0 603
nuclear@0 604 if(count % 3 != 0) {
nuclear@0 605 ParseError("number of floats is not a multiple of three (3) (binary)",&el);
nuclear@0 606 }
nuclear@0 607
nuclear@0 608 if(!count) {
nuclear@0 609 return;
nuclear@0 610 }
nuclear@0 611
nuclear@0 612 if (type != 'd' && type != 'f') {
nuclear@0 613 ParseError("expected float or double array (binary)",&el);
nuclear@0 614 }
nuclear@0 615
nuclear@0 616 std::vector<char> buff;
nuclear@0 617 ReadBinaryDataArray(type, count, data, end, buff, el);
nuclear@0 618
nuclear@0 619 ai_assert(data == end);
nuclear@0 620 ai_assert(buff.size() == count * (type == 'd' ? 8 : 4));
nuclear@0 621
nuclear@0 622 const uint32_t count3 = count / 3;
nuclear@0 623 out.reserve(count3);
nuclear@0 624
nuclear@0 625 if (type == 'd') {
nuclear@0 626 const double* d = reinterpret_cast<const double*>(&buff[0]);
nuclear@0 627 for (unsigned int i = 0; i < count3; ++i, d += 3) {
nuclear@0 628 out.push_back(aiVector3D(static_cast<float>(d[0]),
nuclear@0 629 static_cast<float>(d[1]),
nuclear@0 630 static_cast<float>(d[2])));
nuclear@0 631 }
nuclear@0 632 }
nuclear@0 633 else if (type == 'f') {
nuclear@0 634 const float* f = reinterpret_cast<const float*>(&buff[0]);
nuclear@0 635 for (unsigned int i = 0; i < count3; ++i, f += 3) {
nuclear@0 636 out.push_back(aiVector3D(f[0],f[1],f[2]));
nuclear@0 637 }
nuclear@0 638 }
nuclear@0 639
nuclear@0 640 return;
nuclear@0 641 }
nuclear@0 642
nuclear@0 643 const size_t dim = ParseTokenAsDim(*tok[0]);
nuclear@0 644
nuclear@0 645 // may throw bad_alloc if the input is rubbish, but this need
nuclear@0 646 // not to be prevented - importing would fail but we wouldn't
nuclear@0 647 // crash since assimp handles this case properly.
nuclear@0 648 out.reserve(dim);
nuclear@0 649
nuclear@0 650 const Scope& scope = GetRequiredScope(el);
nuclear@0 651 const Element& a = GetRequiredElement(scope,"a",&el);
nuclear@0 652
nuclear@0 653 if (a.Tokens().size() % 3 != 0) {
nuclear@0 654 ParseError("number of floats is not a multiple of three (3)",&el);
nuclear@0 655 }
nuclear@0 656 for (TokenList::const_iterator it = a.Tokens().begin(), end = a.Tokens().end(); it != end; ) {
nuclear@0 657 aiVector3D v;
nuclear@0 658 v.x = ParseTokenAsFloat(**it++);
nuclear@0 659 v.y = ParseTokenAsFloat(**it++);
nuclear@0 660 v.z = ParseTokenAsFloat(**it++);
nuclear@0 661
nuclear@0 662 out.push_back(v);
nuclear@0 663 }
nuclear@0 664 }
nuclear@0 665
nuclear@0 666
nuclear@0 667 // ------------------------------------------------------------------------------------------------
nuclear@0 668 // read an array of color4 tuples
nuclear@0 669 void ParseVectorDataArray(std::vector<aiColor4D>& out, const Element& el)
nuclear@0 670 {
nuclear@0 671 out.clear();
nuclear@0 672 const TokenList& tok = el.Tokens();
nuclear@0 673 if(tok.empty()) {
nuclear@0 674 ParseError("unexpected empty element",&el);
nuclear@0 675 }
nuclear@0 676
nuclear@0 677 if(tok[0]->IsBinary()) {
nuclear@0 678 const char* data = tok[0]->begin(), *end = tok[0]->end();
nuclear@0 679
nuclear@0 680 char type;
nuclear@0 681 uint32_t count;
nuclear@0 682 ReadBinaryDataArrayHead(data, end, type, count, el);
nuclear@0 683
nuclear@0 684 if(count % 4 != 0) {
nuclear@0 685 ParseError("number of floats is not a multiple of four (4) (binary)",&el);
nuclear@0 686 }
nuclear@0 687
nuclear@0 688 if(!count) {
nuclear@0 689 return;
nuclear@0 690 }
nuclear@0 691
nuclear@0 692 if (type != 'd' && type != 'f') {
nuclear@0 693 ParseError("expected float or double array (binary)",&el);
nuclear@0 694 }
nuclear@0 695
nuclear@0 696 std::vector<char> buff;
nuclear@0 697 ReadBinaryDataArray(type, count, data, end, buff, el);
nuclear@0 698
nuclear@0 699 ai_assert(data == end);
nuclear@0 700 ai_assert(buff.size() == count * (type == 'd' ? 8 : 4));
nuclear@0 701
nuclear@0 702 const uint32_t count4 = count / 4;
nuclear@0 703 out.reserve(count4);
nuclear@0 704
nuclear@0 705 if (type == 'd') {
nuclear@0 706 const double* d = reinterpret_cast<const double*>(&buff[0]);
nuclear@0 707 for (unsigned int i = 0; i < count4; ++i, d += 4) {
nuclear@0 708 out.push_back(aiColor4D(static_cast<float>(d[0]),
nuclear@0 709 static_cast<float>(d[1]),
nuclear@0 710 static_cast<float>(d[2]),
nuclear@0 711 static_cast<float>(d[3])));
nuclear@0 712 }
nuclear@0 713 }
nuclear@0 714 else if (type == 'f') {
nuclear@0 715 const float* f = reinterpret_cast<const float*>(&buff[0]);
nuclear@0 716 for (unsigned int i = 0; i < count4; ++i, f += 4) {
nuclear@0 717 out.push_back(aiColor4D(f[0],f[1],f[2],f[3]));
nuclear@0 718 }
nuclear@0 719 }
nuclear@0 720 return;
nuclear@0 721 }
nuclear@0 722
nuclear@0 723 const size_t dim = ParseTokenAsDim(*tok[0]);
nuclear@0 724
nuclear@0 725 // see notes in ParseVectorDataArray() above
nuclear@0 726 out.reserve(dim);
nuclear@0 727
nuclear@0 728 const Scope& scope = GetRequiredScope(el);
nuclear@0 729 const Element& a = GetRequiredElement(scope,"a",&el);
nuclear@0 730
nuclear@0 731 if (a.Tokens().size() % 4 != 0) {
nuclear@0 732 ParseError("number of floats is not a multiple of four (4)",&el);
nuclear@0 733 }
nuclear@0 734 for (TokenList::const_iterator it = a.Tokens().begin(), end = a.Tokens().end(); it != end; ) {
nuclear@0 735 aiColor4D v;
nuclear@0 736 v.r = ParseTokenAsFloat(**it++);
nuclear@0 737 v.g = ParseTokenAsFloat(**it++);
nuclear@0 738 v.b = ParseTokenAsFloat(**it++);
nuclear@0 739 v.a = ParseTokenAsFloat(**it++);
nuclear@0 740
nuclear@0 741 out.push_back(v);
nuclear@0 742 }
nuclear@0 743 }
nuclear@0 744
nuclear@0 745
nuclear@0 746 // ------------------------------------------------------------------------------------------------
nuclear@0 747 // read an array of float2 tuples
nuclear@0 748 void ParseVectorDataArray(std::vector<aiVector2D>& out, const Element& el)
nuclear@0 749 {
nuclear@0 750 out.clear();
nuclear@0 751 const TokenList& tok = el.Tokens();
nuclear@0 752 if(tok.empty()) {
nuclear@0 753 ParseError("unexpected empty element",&el);
nuclear@0 754 }
nuclear@0 755
nuclear@0 756 if(tok[0]->IsBinary()) {
nuclear@0 757 const char* data = tok[0]->begin(), *end = tok[0]->end();
nuclear@0 758
nuclear@0 759 char type;
nuclear@0 760 uint32_t count;
nuclear@0 761 ReadBinaryDataArrayHead(data, end, type, count, el);
nuclear@0 762
nuclear@0 763 if(count % 2 != 0) {
nuclear@0 764 ParseError("number of floats is not a multiple of two (2) (binary)",&el);
nuclear@0 765 }
nuclear@0 766
nuclear@0 767 if(!count) {
nuclear@0 768 return;
nuclear@0 769 }
nuclear@0 770
nuclear@0 771 if (type != 'd' && type != 'f') {
nuclear@0 772 ParseError("expected float or double array (binary)",&el);
nuclear@0 773 }
nuclear@0 774
nuclear@0 775 std::vector<char> buff;
nuclear@0 776 ReadBinaryDataArray(type, count, data, end, buff, el);
nuclear@0 777
nuclear@0 778 ai_assert(data == end);
nuclear@0 779 ai_assert(buff.size() == count * (type == 'd' ? 8 : 4));
nuclear@0 780
nuclear@0 781 const uint32_t count2 = count / 2;
nuclear@0 782 out.reserve(count2);
nuclear@0 783
nuclear@0 784 if (type == 'd') {
nuclear@0 785 const double* d = reinterpret_cast<const double*>(&buff[0]);
nuclear@0 786 for (unsigned int i = 0; i < count2; ++i, d += 2) {
nuclear@0 787 out.push_back(aiVector2D(static_cast<float>(d[0]),
nuclear@0 788 static_cast<float>(d[1])));
nuclear@0 789 }
nuclear@0 790 }
nuclear@0 791 else if (type == 'f') {
nuclear@0 792 const float* f = reinterpret_cast<const float*>(&buff[0]);
nuclear@0 793 for (unsigned int i = 0; i < count2; ++i, f += 2) {
nuclear@0 794 out.push_back(aiVector2D(f[0],f[1]));
nuclear@0 795 }
nuclear@0 796 }
nuclear@0 797
nuclear@0 798 return;
nuclear@0 799 }
nuclear@0 800
nuclear@0 801 const size_t dim = ParseTokenAsDim(*tok[0]);
nuclear@0 802
nuclear@0 803 // see notes in ParseVectorDataArray() above
nuclear@0 804 out.reserve(dim);
nuclear@0 805
nuclear@0 806 const Scope& scope = GetRequiredScope(el);
nuclear@0 807 const Element& a = GetRequiredElement(scope,"a",&el);
nuclear@0 808
nuclear@0 809 if (a.Tokens().size() % 2 != 0) {
nuclear@0 810 ParseError("number of floats is not a multiple of two (2)",&el);
nuclear@0 811 }
nuclear@0 812 for (TokenList::const_iterator it = a.Tokens().begin(), end = a.Tokens().end(); it != end; ) {
nuclear@0 813 aiVector2D v;
nuclear@0 814 v.x = ParseTokenAsFloat(**it++);
nuclear@0 815 v.y = ParseTokenAsFloat(**it++);
nuclear@0 816
nuclear@0 817 out.push_back(v);
nuclear@0 818 }
nuclear@0 819 }
nuclear@0 820
nuclear@0 821
nuclear@0 822 // ------------------------------------------------------------------------------------------------
nuclear@0 823 // read an array of ints
nuclear@0 824 void ParseVectorDataArray(std::vector<int>& out, const Element& el)
nuclear@0 825 {
nuclear@0 826 out.clear();
nuclear@0 827 const TokenList& tok = el.Tokens();
nuclear@0 828 if(tok.empty()) {
nuclear@0 829 ParseError("unexpected empty element",&el);
nuclear@0 830 }
nuclear@0 831
nuclear@0 832 if(tok[0]->IsBinary()) {
nuclear@0 833 const char* data = tok[0]->begin(), *end = tok[0]->end();
nuclear@0 834
nuclear@0 835 char type;
nuclear@0 836 uint32_t count;
nuclear@0 837 ReadBinaryDataArrayHead(data, end, type, count, el);
nuclear@0 838
nuclear@0 839 if(!count) {
nuclear@0 840 return;
nuclear@0 841 }
nuclear@0 842
nuclear@0 843 if (type != 'i') {
nuclear@0 844 ParseError("expected int array (binary)",&el);
nuclear@0 845 }
nuclear@0 846
nuclear@0 847 std::vector<char> buff;
nuclear@0 848 ReadBinaryDataArray(type, count, data, end, buff, el);
nuclear@0 849
nuclear@0 850 ai_assert(data == end);
nuclear@0 851 ai_assert(buff.size() == count * 4);
nuclear@0 852
nuclear@0 853 out.reserve(count);
nuclear@0 854
nuclear@0 855 const int32_t* ip = reinterpret_cast<const int32_t*>(&buff[0]);
nuclear@0 856 for (unsigned int i = 0; i < count; ++i, ++ip) {
nuclear@0 857 BE_NCONST int32_t val = *ip;
nuclear@0 858 AI_SWAP4(val);
nuclear@0 859 out.push_back(val);
nuclear@0 860 }
nuclear@0 861
nuclear@0 862 return;
nuclear@0 863 }
nuclear@0 864
nuclear@0 865 const size_t dim = ParseTokenAsDim(*tok[0]);
nuclear@0 866
nuclear@0 867 // see notes in ParseVectorDataArray()
nuclear@0 868 out.reserve(dim);
nuclear@0 869
nuclear@0 870 const Scope& scope = GetRequiredScope(el);
nuclear@0 871 const Element& a = GetRequiredElement(scope,"a",&el);
nuclear@0 872
nuclear@0 873 for (TokenList::const_iterator it = a.Tokens().begin(), end = a.Tokens().end(); it != end; ) {
nuclear@0 874 const int ival = ParseTokenAsInt(**it++);
nuclear@0 875 out.push_back(ival);
nuclear@0 876 }
nuclear@0 877 }
nuclear@0 878
nuclear@0 879
nuclear@0 880 // ------------------------------------------------------------------------------------------------
nuclear@0 881 // read an array of floats
nuclear@0 882 void ParseVectorDataArray(std::vector<float>& out, const Element& el)
nuclear@0 883 {
nuclear@0 884 out.clear();
nuclear@0 885 const TokenList& tok = el.Tokens();
nuclear@0 886 if(tok.empty()) {
nuclear@0 887 ParseError("unexpected empty element",&el);
nuclear@0 888 }
nuclear@0 889
nuclear@0 890 if(tok[0]->IsBinary()) {
nuclear@0 891 const char* data = tok[0]->begin(), *end = tok[0]->end();
nuclear@0 892
nuclear@0 893 char type;
nuclear@0 894 uint32_t count;
nuclear@0 895 ReadBinaryDataArrayHead(data, end, type, count, el);
nuclear@0 896
nuclear@0 897 if(!count) {
nuclear@0 898 return;
nuclear@0 899 }
nuclear@0 900
nuclear@0 901 if (type != 'd' && type != 'f') {
nuclear@0 902 ParseError("expected float or double array (binary)",&el);
nuclear@0 903 }
nuclear@0 904
nuclear@0 905 std::vector<char> buff;
nuclear@0 906 ReadBinaryDataArray(type, count, data, end, buff, el);
nuclear@0 907
nuclear@0 908 ai_assert(data == end);
nuclear@0 909 ai_assert(buff.size() == count * (type == 'd' ? 8 : 4));
nuclear@0 910
nuclear@0 911 if (type == 'd') {
nuclear@0 912 const double* d = reinterpret_cast<const double*>(&buff[0]);
nuclear@0 913 for (unsigned int i = 0; i < count; ++i, ++d) {
nuclear@0 914 out.push_back(static_cast<float>(*d));
nuclear@0 915 }
nuclear@0 916 }
nuclear@0 917 else if (type == 'f') {
nuclear@0 918 const float* f = reinterpret_cast<const float*>(&buff[0]);
nuclear@0 919 for (unsigned int i = 0; i < count; ++i, ++f) {
nuclear@0 920 out.push_back(*f);
nuclear@0 921 }
nuclear@0 922 }
nuclear@0 923
nuclear@0 924 return;
nuclear@0 925 }
nuclear@0 926
nuclear@0 927 const size_t dim = ParseTokenAsDim(*tok[0]);
nuclear@0 928
nuclear@0 929 // see notes in ParseVectorDataArray()
nuclear@0 930 out.reserve(dim);
nuclear@0 931
nuclear@0 932 const Scope& scope = GetRequiredScope(el);
nuclear@0 933 const Element& a = GetRequiredElement(scope,"a",&el);
nuclear@0 934
nuclear@0 935 for (TokenList::const_iterator it = a.Tokens().begin(), end = a.Tokens().end(); it != end; ) {
nuclear@0 936 const float ival = ParseTokenAsFloat(**it++);
nuclear@0 937 out.push_back(ival);
nuclear@0 938 }
nuclear@0 939 }
nuclear@0 940
nuclear@0 941
nuclear@0 942 // ------------------------------------------------------------------------------------------------
nuclear@0 943 // read an array of uints
nuclear@0 944 void ParseVectorDataArray(std::vector<unsigned int>& out, const Element& el)
nuclear@0 945 {
nuclear@0 946 out.clear();
nuclear@0 947 const TokenList& tok = el.Tokens();
nuclear@0 948 if(tok.empty()) {
nuclear@0 949 ParseError("unexpected empty element",&el);
nuclear@0 950 }
nuclear@0 951
nuclear@0 952 if(tok[0]->IsBinary()) {
nuclear@0 953 const char* data = tok[0]->begin(), *end = tok[0]->end();
nuclear@0 954
nuclear@0 955 char type;
nuclear@0 956 uint32_t count;
nuclear@0 957 ReadBinaryDataArrayHead(data, end, type, count, el);
nuclear@0 958
nuclear@0 959 if(!count) {
nuclear@0 960 return;
nuclear@0 961 }
nuclear@0 962
nuclear@0 963 if (type != 'i') {
nuclear@0 964 ParseError("expected (u)int array (binary)",&el);
nuclear@0 965 }
nuclear@0 966
nuclear@0 967 std::vector<char> buff;
nuclear@0 968 ReadBinaryDataArray(type, count, data, end, buff, el);
nuclear@0 969
nuclear@0 970 ai_assert(data == end);
nuclear@0 971 ai_assert(buff.size() == count * 4);
nuclear@0 972
nuclear@0 973 out.reserve(count);
nuclear@0 974
nuclear@0 975 const int32_t* ip = reinterpret_cast<const int32_t*>(&buff[0]);
nuclear@0 976 for (unsigned int i = 0; i < count; ++i, ++ip) {
nuclear@0 977 BE_NCONST int32_t val = *ip;
nuclear@0 978 if(val < 0) {
nuclear@0 979 ParseError("encountered negative integer index (binary)");
nuclear@0 980 }
nuclear@0 981
nuclear@0 982 AI_SWAP4(val);
nuclear@0 983 out.push_back(val);
nuclear@0 984 }
nuclear@0 985
nuclear@0 986 return;
nuclear@0 987 }
nuclear@0 988
nuclear@0 989 const size_t dim = ParseTokenAsDim(*tok[0]);
nuclear@0 990
nuclear@0 991 // see notes in ParseVectorDataArray()
nuclear@0 992 out.reserve(dim);
nuclear@0 993
nuclear@0 994 const Scope& scope = GetRequiredScope(el);
nuclear@0 995 const Element& a = GetRequiredElement(scope,"a",&el);
nuclear@0 996
nuclear@0 997 for (TokenList::const_iterator it = a.Tokens().begin(), end = a.Tokens().end(); it != end; ) {
nuclear@0 998 const int ival = ParseTokenAsInt(**it++);
nuclear@0 999 if(ival < 0) {
nuclear@0 1000 ParseError("encountered negative integer index");
nuclear@0 1001 }
nuclear@0 1002 out.push_back(static_cast<unsigned int>(ival));
nuclear@0 1003 }
nuclear@0 1004 }
nuclear@0 1005
nuclear@0 1006
nuclear@0 1007 // ------------------------------------------------------------------------------------------------
nuclear@0 1008 // read an array of uint64_ts
nuclear@0 1009 void ParseVectorDataArray(std::vector<uint64_t>& out, const Element& el)
nuclear@0 1010 {
nuclear@0 1011 out.clear();
nuclear@0 1012 const TokenList& tok = el.Tokens();
nuclear@0 1013 if(tok.empty()) {
nuclear@0 1014 ParseError("unexpected empty element",&el);
nuclear@0 1015 }
nuclear@0 1016
nuclear@0 1017 if(tok[0]->IsBinary()) {
nuclear@0 1018 const char* data = tok[0]->begin(), *end = tok[0]->end();
nuclear@0 1019
nuclear@0 1020 char type;
nuclear@0 1021 uint32_t count;
nuclear@0 1022 ReadBinaryDataArrayHead(data, end, type, count, el);
nuclear@0 1023
nuclear@0 1024 if(!count) {
nuclear@0 1025 return;
nuclear@0 1026 }
nuclear@0 1027
nuclear@0 1028 if (type != 'l') {
nuclear@0 1029 ParseError("expected long array (binary)",&el);
nuclear@0 1030 }
nuclear@0 1031
nuclear@0 1032 std::vector<char> buff;
nuclear@0 1033 ReadBinaryDataArray(type, count, data, end, buff, el);
nuclear@0 1034
nuclear@0 1035 ai_assert(data == end);
nuclear@0 1036 ai_assert(buff.size() == count * 8);
nuclear@0 1037
nuclear@0 1038 out.reserve(count);
nuclear@0 1039
nuclear@0 1040 const uint64_t* ip = reinterpret_cast<const uint64_t*>(&buff[0]);
nuclear@0 1041 for (unsigned int i = 0; i < count; ++i, ++ip) {
nuclear@0 1042 BE_NCONST uint64_t val = *ip;
nuclear@0 1043 AI_SWAP8(val);
nuclear@0 1044 out.push_back(val);
nuclear@0 1045 }
nuclear@0 1046
nuclear@0 1047 return;
nuclear@0 1048 }
nuclear@0 1049
nuclear@0 1050 const size_t dim = ParseTokenAsDim(*tok[0]);
nuclear@0 1051
nuclear@0 1052 // see notes in ParseVectorDataArray()
nuclear@0 1053 out.reserve(dim);
nuclear@0 1054
nuclear@0 1055 const Scope& scope = GetRequiredScope(el);
nuclear@0 1056 const Element& a = GetRequiredElement(scope,"a",&el);
nuclear@0 1057
nuclear@0 1058 for (TokenList::const_iterator it = a.Tokens().begin(), end = a.Tokens().end(); it != end; ) {
nuclear@0 1059 const uint64_t ival = ParseTokenAsID(**it++);
nuclear@0 1060
nuclear@0 1061 out.push_back(ival);
nuclear@0 1062 }
nuclear@0 1063 }
nuclear@0 1064
nuclear@0 1065
nuclear@0 1066 // ------------------------------------------------------------------------------------------------
nuclear@0 1067 aiMatrix4x4 ReadMatrix(const Element& element)
nuclear@0 1068 {
nuclear@0 1069 std::vector<float> values;
nuclear@0 1070 ParseVectorDataArray(values,element);
nuclear@0 1071
nuclear@0 1072 if(values.size() != 16) {
nuclear@0 1073 ParseError("expected 16 matrix elements");
nuclear@0 1074 }
nuclear@0 1075
nuclear@0 1076 aiMatrix4x4 result;
nuclear@0 1077
nuclear@0 1078
nuclear@0 1079 result.a1 = values[0];
nuclear@0 1080 result.a2 = values[1];
nuclear@0 1081 result.a3 = values[2];
nuclear@0 1082 result.a4 = values[3];
nuclear@0 1083
nuclear@0 1084 result.b1 = values[4];
nuclear@0 1085 result.b2 = values[5];
nuclear@0 1086 result.b3 = values[6];
nuclear@0 1087 result.b4 = values[7];
nuclear@0 1088
nuclear@0 1089 result.c1 = values[8];
nuclear@0 1090 result.c2 = values[9];
nuclear@0 1091 result.c3 = values[10];
nuclear@0 1092 result.c4 = values[11];
nuclear@0 1093
nuclear@0 1094 result.d1 = values[12];
nuclear@0 1095 result.d2 = values[13];
nuclear@0 1096 result.d3 = values[14];
nuclear@0 1097 result.d4 = values[15];
nuclear@0 1098
nuclear@0 1099 result.Transpose();
nuclear@0 1100 return result;
nuclear@0 1101 }
nuclear@0 1102
nuclear@0 1103
nuclear@0 1104 // ------------------------------------------------------------------------------------------------
nuclear@0 1105 // wrapper around ParseTokenAsString() with ParseError handling
nuclear@0 1106 std::string ParseTokenAsString(const Token& t)
nuclear@0 1107 {
nuclear@0 1108 const char* err;
nuclear@0 1109 const std::string& i = ParseTokenAsString(t,err);
nuclear@0 1110 if(err) {
nuclear@0 1111 ParseError(err,t);
nuclear@0 1112 }
nuclear@0 1113 return i;
nuclear@0 1114 }
nuclear@0 1115
nuclear@0 1116
nuclear@0 1117 // ------------------------------------------------------------------------------------------------
nuclear@0 1118 // extract a required element from a scope, abort if the element cannot be found
nuclear@0 1119 const Element& GetRequiredElement(const Scope& sc, const std::string& index, const Element* element /*= NULL*/)
nuclear@0 1120 {
nuclear@0 1121 const Element* el = sc[index];
nuclear@0 1122 if(!el) {
nuclear@0 1123 ParseError("did not find required element \"" + index + "\"",element);
nuclear@0 1124 }
nuclear@0 1125 return *el;
nuclear@0 1126 }
nuclear@0 1127
nuclear@0 1128
nuclear@0 1129 // ------------------------------------------------------------------------------------------------
nuclear@0 1130 // extract required compound scope
nuclear@0 1131 const Scope& GetRequiredScope(const Element& el)
nuclear@0 1132 {
nuclear@0 1133 const Scope* const s = el.Compound();
nuclear@0 1134 if(!s) {
nuclear@0 1135 ParseError("expected compound scope",&el);
nuclear@0 1136 }
nuclear@0 1137
nuclear@0 1138 return *s;
nuclear@0 1139 }
nuclear@0 1140
nuclear@0 1141
nuclear@0 1142 // ------------------------------------------------------------------------------------------------
nuclear@0 1143 // get token at a particular index
nuclear@0 1144 const Token& GetRequiredToken(const Element& el, unsigned int index)
nuclear@0 1145 {
nuclear@0 1146 const TokenList& t = el.Tokens();
nuclear@0 1147 if(index >= t.size()) {
nuclear@0 1148 ParseError(Formatter::format( "missing token at index " ) << index,&el);
nuclear@0 1149 }
nuclear@0 1150
nuclear@0 1151 return *t[index];
nuclear@0 1152 }
nuclear@0 1153
nuclear@0 1154
nuclear@0 1155 // ------------------------------------------------------------------------------------------------
nuclear@0 1156 // wrapper around ParseTokenAsID() with ParseError handling
nuclear@0 1157 uint64_t ParseTokenAsID(const Token& t)
nuclear@0 1158 {
nuclear@0 1159 const char* err;
nuclear@0 1160 const uint64_t i = ParseTokenAsID(t,err);
nuclear@0 1161 if(err) {
nuclear@0 1162 ParseError(err,t);
nuclear@0 1163 }
nuclear@0 1164 return i;
nuclear@0 1165 }
nuclear@0 1166
nuclear@0 1167
nuclear@0 1168 // ------------------------------------------------------------------------------------------------
nuclear@0 1169 // wrapper around ParseTokenAsDim() with ParseError handling
nuclear@0 1170 size_t ParseTokenAsDim(const Token& t)
nuclear@0 1171 {
nuclear@0 1172 const char* err;
nuclear@0 1173 const size_t i = ParseTokenAsDim(t,err);
nuclear@0 1174 if(err) {
nuclear@0 1175 ParseError(err,t);
nuclear@0 1176 }
nuclear@0 1177 return i;
nuclear@0 1178 }
nuclear@0 1179
nuclear@0 1180
nuclear@0 1181 // ------------------------------------------------------------------------------------------------
nuclear@0 1182 // wrapper around ParseTokenAsFloat() with ParseError handling
nuclear@0 1183 float ParseTokenAsFloat(const Token& t)
nuclear@0 1184 {
nuclear@0 1185 const char* err;
nuclear@0 1186 const float i = ParseTokenAsFloat(t,err);
nuclear@0 1187 if(err) {
nuclear@0 1188 ParseError(err,t);
nuclear@0 1189 }
nuclear@0 1190 return i;
nuclear@0 1191 }
nuclear@0 1192
nuclear@0 1193
nuclear@0 1194 // ------------------------------------------------------------------------------------------------
nuclear@0 1195 // wrapper around ParseTokenAsInt() with ParseError handling
nuclear@0 1196 int ParseTokenAsInt(const Token& t)
nuclear@0 1197 {
nuclear@0 1198 const char* err;
nuclear@0 1199 const int i = ParseTokenAsInt(t,err);
nuclear@0 1200 if(err) {
nuclear@0 1201 ParseError(err,t);
nuclear@0 1202 }
nuclear@0 1203 return i;
nuclear@0 1204 }
nuclear@0 1205
nuclear@0 1206
nuclear@0 1207
nuclear@0 1208 } // !FBX
nuclear@0 1209 } // !Assimp
nuclear@0 1210
nuclear@0 1211 #endif
nuclear@0 1212