vrshoot

annotate libs/assimp/ColladaParser.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 ---------------------------------------------------------------------------
nuclear@0 3 Open Asset Import Library (assimp)
nuclear@0 4 ---------------------------------------------------------------------------
nuclear@0 5
nuclear@0 6 Copyright (c) 2006-2012, assimp team
nuclear@0 7
nuclear@0 8 All rights reserved.
nuclear@0 9
nuclear@0 10 Redistribution and use of this software in source and binary forms,
nuclear@0 11 with or without modification, are permitted provided that the following
nuclear@0 12 conditions are met:
nuclear@0 13
nuclear@0 14 * Redistributions of source code must retain the above
nuclear@0 15 copyright notice, this list of conditions and the
nuclear@0 16 following disclaimer.
nuclear@0 17
nuclear@0 18 * Redistributions in binary form must reproduce the above
nuclear@0 19 copyright notice, this list of conditions and the
nuclear@0 20 following disclaimer in the documentation and/or other
nuclear@0 21 materials provided with the distribution.
nuclear@0 22
nuclear@0 23 * Neither the name of the assimp team, nor the names of its
nuclear@0 24 contributors may be used to endorse or promote products
nuclear@0 25 derived from this software without specific prior
nuclear@0 26 written permission of the assimp team.
nuclear@0 27
nuclear@0 28 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
nuclear@0 29 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
nuclear@0 30 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
nuclear@0 31 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
nuclear@0 32 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
nuclear@0 33 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
nuclear@0 34 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
nuclear@0 35 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
nuclear@0 36 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
nuclear@0 37 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
nuclear@0 38 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
nuclear@0 39 ---------------------------------------------------------------------------
nuclear@0 40 */
nuclear@0 41
nuclear@0 42 /** @file ColladaParser.cpp
nuclear@0 43 * @brief Implementation of the Collada parser helper
nuclear@0 44 */
nuclear@0 45
nuclear@0 46 #include "AssimpPCH.h"
nuclear@0 47 #ifndef ASSIMP_BUILD_NO_COLLADA_IMPORTER
nuclear@0 48
nuclear@0 49 #include "ColladaParser.h"
nuclear@0 50 #include "fast_atof.h"
nuclear@0 51 #include "ParsingUtils.h"
nuclear@0 52
nuclear@0 53 using namespace Assimp;
nuclear@0 54 using namespace Assimp::Collada;
nuclear@0 55
nuclear@0 56 // ------------------------------------------------------------------------------------------------
nuclear@0 57 // Constructor to be privately used by Importer
nuclear@0 58 ColladaParser::ColladaParser( IOSystem* pIOHandler, const std::string& pFile)
nuclear@0 59 : mFileName( pFile)
nuclear@0 60 {
nuclear@0 61 mRootNode = NULL;
nuclear@0 62 mUnitSize = 1.0f;
nuclear@0 63 mUpDirection = UP_Z;
nuclear@0 64
nuclear@0 65 // We assume the newest file format by default
nuclear@0 66 mFormat = FV_1_5_n;
nuclear@0 67
nuclear@0 68 // open the file
nuclear@0 69 boost::scoped_ptr<IOStream> file( pIOHandler->Open( pFile));
nuclear@0 70 if( file.get() == NULL)
nuclear@0 71 throw DeadlyImportError( "Failed to open file " + pFile + ".");
nuclear@0 72
nuclear@0 73 // generate a XML reader for it
nuclear@0 74 boost::scoped_ptr<CIrrXML_IOStreamReader> mIOWrapper( new CIrrXML_IOStreamReader( file.get()));
nuclear@0 75 mReader = irr::io::createIrrXMLReader( mIOWrapper.get());
nuclear@0 76 if( !mReader)
nuclear@0 77 ThrowException( "Collada: Unable to open file.");
nuclear@0 78
nuclear@0 79 // start reading
nuclear@0 80 ReadContents();
nuclear@0 81 }
nuclear@0 82
nuclear@0 83 // ------------------------------------------------------------------------------------------------
nuclear@0 84 // Destructor, private as well
nuclear@0 85 ColladaParser::~ColladaParser()
nuclear@0 86 {
nuclear@0 87 delete mReader;
nuclear@0 88 for( NodeLibrary::iterator it = mNodeLibrary.begin(); it != mNodeLibrary.end(); ++it)
nuclear@0 89 delete it->second;
nuclear@0 90 for( MeshLibrary::iterator it = mMeshLibrary.begin(); it != mMeshLibrary.end(); ++it)
nuclear@0 91 delete it->second;
nuclear@0 92 }
nuclear@0 93
nuclear@0 94 // ------------------------------------------------------------------------------------------------
nuclear@0 95 // Read bool from text contents of current element
nuclear@0 96 bool ColladaParser::ReadBoolFromTextContent()
nuclear@0 97 {
nuclear@0 98 const char* cur = GetTextContent();
nuclear@0 99 return (!ASSIMP_strincmp(cur,"true",4) || '0' != *cur);
nuclear@0 100 }
nuclear@0 101
nuclear@0 102 // ------------------------------------------------------------------------------------------------
nuclear@0 103 // Read float from text contents of current element
nuclear@0 104 float ColladaParser::ReadFloatFromTextContent()
nuclear@0 105 {
nuclear@0 106 const char* cur = GetTextContent();
nuclear@0 107 return fast_atof(cur);
nuclear@0 108 }
nuclear@0 109
nuclear@0 110 // ------------------------------------------------------------------------------------------------
nuclear@0 111 // Reads the contents of the file
nuclear@0 112 void ColladaParser::ReadContents()
nuclear@0 113 {
nuclear@0 114 while( mReader->read())
nuclear@0 115 {
nuclear@0 116 // handle the root element "COLLADA"
nuclear@0 117 if( mReader->getNodeType() == irr::io::EXN_ELEMENT)
nuclear@0 118 {
nuclear@0 119 if( IsElement( "COLLADA"))
nuclear@0 120 {
nuclear@0 121 // check for 'version' attribute
nuclear@0 122 const int attrib = TestAttribute("version");
nuclear@0 123 if (attrib != -1) {
nuclear@0 124 const char* version = mReader->getAttributeValue(attrib);
nuclear@0 125
nuclear@0 126 if (!::strncmp(version,"1.5",3)) {
nuclear@0 127 mFormat = FV_1_5_n;
nuclear@0 128 DefaultLogger::get()->debug("Collada schema version is 1.5.n");
nuclear@0 129 }
nuclear@0 130 else if (!::strncmp(version,"1.4",3)) {
nuclear@0 131 mFormat = FV_1_4_n;
nuclear@0 132 DefaultLogger::get()->debug("Collada schema version is 1.4.n");
nuclear@0 133 }
nuclear@0 134 else if (!::strncmp(version,"1.3",3)) {
nuclear@0 135 mFormat = FV_1_3_n;
nuclear@0 136 DefaultLogger::get()->debug("Collada schema version is 1.3.n");
nuclear@0 137 }
nuclear@0 138 }
nuclear@0 139
nuclear@0 140 ReadStructure();
nuclear@0 141 } else
nuclear@0 142 {
nuclear@0 143 DefaultLogger::get()->debug( boost::str( boost::format( "Ignoring global element <%s>.") % mReader->getNodeName()));
nuclear@0 144 SkipElement();
nuclear@0 145 }
nuclear@0 146 } else
nuclear@0 147 {
nuclear@0 148 // skip everything else silently
nuclear@0 149 }
nuclear@0 150 }
nuclear@0 151 }
nuclear@0 152
nuclear@0 153 // ------------------------------------------------------------------------------------------------
nuclear@0 154 // Reads the structure of the file
nuclear@0 155 void ColladaParser::ReadStructure()
nuclear@0 156 {
nuclear@0 157 while( mReader->read())
nuclear@0 158 {
nuclear@0 159 // beginning of elements
nuclear@0 160 if( mReader->getNodeType() == irr::io::EXN_ELEMENT)
nuclear@0 161 {
nuclear@0 162 if( IsElement( "asset"))
nuclear@0 163 ReadAssetInfo();
nuclear@0 164 else if( IsElement( "library_animations"))
nuclear@0 165 ReadAnimationLibrary();
nuclear@0 166 else if( IsElement( "library_controllers"))
nuclear@0 167 ReadControllerLibrary();
nuclear@0 168 else if( IsElement( "library_images"))
nuclear@0 169 ReadImageLibrary();
nuclear@0 170 else if( IsElement( "library_materials"))
nuclear@0 171 ReadMaterialLibrary();
nuclear@0 172 else if( IsElement( "library_effects"))
nuclear@0 173 ReadEffectLibrary();
nuclear@0 174 else if( IsElement( "library_geometries"))
nuclear@0 175 ReadGeometryLibrary();
nuclear@0 176 else if( IsElement( "library_visual_scenes"))
nuclear@0 177 ReadSceneLibrary();
nuclear@0 178 else if( IsElement( "library_lights"))
nuclear@0 179 ReadLightLibrary();
nuclear@0 180 else if( IsElement( "library_cameras"))
nuclear@0 181 ReadCameraLibrary();
nuclear@0 182 else if( IsElement( "library_nodes"))
nuclear@0 183 ReadSceneNode(NULL); /* some hacking to reuse this piece of code */
nuclear@0 184 else if( IsElement( "scene"))
nuclear@0 185 ReadScene();
nuclear@0 186 else
nuclear@0 187 SkipElement();
nuclear@0 188 }
nuclear@0 189 else if( mReader->getNodeType() == irr::io::EXN_ELEMENT_END)
nuclear@0 190 {
nuclear@0 191 break;
nuclear@0 192 }
nuclear@0 193 }
nuclear@0 194 }
nuclear@0 195
nuclear@0 196 // ------------------------------------------------------------------------------------------------
nuclear@0 197 // Reads asset informations such as coordinate system informations and legal blah
nuclear@0 198 void ColladaParser::ReadAssetInfo()
nuclear@0 199 {
nuclear@0 200 if( mReader->isEmptyElement())
nuclear@0 201 return;
nuclear@0 202
nuclear@0 203 while( mReader->read())
nuclear@0 204 {
nuclear@0 205 if( mReader->getNodeType() == irr::io::EXN_ELEMENT)
nuclear@0 206 {
nuclear@0 207 if( IsElement( "unit"))
nuclear@0 208 {
nuclear@0 209 // read unit data from the element's attributes
nuclear@0 210 const int attrIndex = TestAttribute( "meter");
nuclear@0 211 if (attrIndex == -1) {
nuclear@0 212 mUnitSize = 1.f;
nuclear@0 213 }
nuclear@0 214 else {
nuclear@0 215 mUnitSize = mReader->getAttributeValueAsFloat( attrIndex);
nuclear@0 216 }
nuclear@0 217
nuclear@0 218 // consume the trailing stuff
nuclear@0 219 if( !mReader->isEmptyElement())
nuclear@0 220 SkipElement();
nuclear@0 221 }
nuclear@0 222 else if( IsElement( "up_axis"))
nuclear@0 223 {
nuclear@0 224 // read content, strip whitespace, compare
nuclear@0 225 const char* content = GetTextContent();
nuclear@0 226 if( strncmp( content, "X_UP", 4) == 0)
nuclear@0 227 mUpDirection = UP_X;
nuclear@0 228 else if( strncmp( content, "Y_UP", 4) == 0)
nuclear@0 229 mUpDirection = UP_Y;
nuclear@0 230 else
nuclear@0 231 mUpDirection = UP_Z;
nuclear@0 232
nuclear@0 233 // check element end
nuclear@0 234 TestClosing( "up_axis");
nuclear@0 235 } else
nuclear@0 236 {
nuclear@0 237 SkipElement();
nuclear@0 238 }
nuclear@0 239 }
nuclear@0 240 else if( mReader->getNodeType() == irr::io::EXN_ELEMENT_END)
nuclear@0 241 {
nuclear@0 242 if( strcmp( mReader->getNodeName(), "asset") != 0)
nuclear@0 243 ThrowException( "Expected end of <asset> element.");
nuclear@0 244
nuclear@0 245 break;
nuclear@0 246 }
nuclear@0 247 }
nuclear@0 248 }
nuclear@0 249
nuclear@0 250 // ------------------------------------------------------------------------------------------------
nuclear@0 251 // Reads the animation library
nuclear@0 252 void ColladaParser::ReadAnimationLibrary()
nuclear@0 253 {
nuclear@0 254 if (mReader->isEmptyElement())
nuclear@0 255 return;
nuclear@0 256
nuclear@0 257 while( mReader->read())
nuclear@0 258 {
nuclear@0 259 if( mReader->getNodeType() == irr::io::EXN_ELEMENT)
nuclear@0 260 {
nuclear@0 261 if( IsElement( "animation"))
nuclear@0 262 {
nuclear@0 263 // delegate the reading. Depending on the inner elements it will be a container or a anim channel
nuclear@0 264 ReadAnimation( &mAnims);
nuclear@0 265 } else
nuclear@0 266 {
nuclear@0 267 // ignore the rest
nuclear@0 268 SkipElement();
nuclear@0 269 }
nuclear@0 270 }
nuclear@0 271 else if( mReader->getNodeType() == irr::io::EXN_ELEMENT_END)
nuclear@0 272 {
nuclear@0 273 if( strcmp( mReader->getNodeName(), "library_animations") != 0)
nuclear@0 274 ThrowException( "Expected end of <library_animations> element.");
nuclear@0 275
nuclear@0 276 break;
nuclear@0 277 }
nuclear@0 278 }
nuclear@0 279 }
nuclear@0 280
nuclear@0 281 // ------------------------------------------------------------------------------------------------
nuclear@0 282 // Reads an animation into the given parent structure
nuclear@0 283 void ColladaParser::ReadAnimation( Collada::Animation* pParent)
nuclear@0 284 {
nuclear@0 285 if( mReader->isEmptyElement())
nuclear@0 286 return;
nuclear@0 287
nuclear@0 288 // an <animation> element may be a container for grouping sub-elements or an animation channel
nuclear@0 289 // this is the channel collection by ID, in case it has channels
nuclear@0 290 typedef std::map<std::string, AnimationChannel> ChannelMap;
nuclear@0 291 ChannelMap channels;
nuclear@0 292 // this is the anim container in case we're a container
nuclear@0 293 Animation* anim = NULL;
nuclear@0 294
nuclear@0 295 // optional name given as an attribute
nuclear@0 296 std::string animName;
nuclear@0 297 int indexName = TestAttribute( "name");
nuclear@0 298 int indexID = TestAttribute( "id");
nuclear@0 299 if( indexName >= 0)
nuclear@0 300 animName = mReader->getAttributeValue( indexName);
nuclear@0 301 else if( indexID >= 0)
nuclear@0 302 animName = mReader->getAttributeValue( indexID);
nuclear@0 303 else
nuclear@0 304 animName = "animation";
nuclear@0 305
nuclear@0 306 while( mReader->read())
nuclear@0 307 {
nuclear@0 308 if( mReader->getNodeType() == irr::io::EXN_ELEMENT)
nuclear@0 309 {
nuclear@0 310 // we have subanimations
nuclear@0 311 if( IsElement( "animation"))
nuclear@0 312 {
nuclear@0 313 // create container from our element
nuclear@0 314 if( !anim)
nuclear@0 315 {
nuclear@0 316 anim = new Animation;
nuclear@0 317 anim->mName = animName;
nuclear@0 318 pParent->mSubAnims.push_back( anim);
nuclear@0 319 }
nuclear@0 320
nuclear@0 321 // recurse into the subelement
nuclear@0 322 ReadAnimation( anim);
nuclear@0 323 }
nuclear@0 324 else if( IsElement( "source"))
nuclear@0 325 {
nuclear@0 326 // possible animation data - we'll never know. Better store it
nuclear@0 327 ReadSource();
nuclear@0 328 }
nuclear@0 329 else if( IsElement( "sampler"))
nuclear@0 330 {
nuclear@0 331 // read the ID to assign the corresponding collada channel afterwards.
nuclear@0 332 int indexID = GetAttribute( "id");
nuclear@0 333 std::string id = mReader->getAttributeValue( indexID);
nuclear@0 334 ChannelMap::iterator newChannel = channels.insert( std::make_pair( id, AnimationChannel())).first;
nuclear@0 335
nuclear@0 336 // have it read into a channel
nuclear@0 337 ReadAnimationSampler( newChannel->second);
nuclear@0 338 }
nuclear@0 339 else if( IsElement( "channel"))
nuclear@0 340 {
nuclear@0 341 // the binding element whose whole purpose is to provide the target to animate
nuclear@0 342 // Thanks, Collada! A directly posted information would have been too simple, I guess.
nuclear@0 343 // Better add another indirection to that! Can't have enough of those.
nuclear@0 344 int indexTarget = GetAttribute( "target");
nuclear@0 345 int indexSource = GetAttribute( "source");
nuclear@0 346 const char* sourceId = mReader->getAttributeValue( indexSource);
nuclear@0 347 if( sourceId[0] == '#')
nuclear@0 348 sourceId++;
nuclear@0 349 ChannelMap::iterator cit = channels.find( sourceId);
nuclear@0 350 if( cit != channels.end())
nuclear@0 351 cit->second.mTarget = mReader->getAttributeValue( indexTarget);
nuclear@0 352
nuclear@0 353 if( !mReader->isEmptyElement())
nuclear@0 354 SkipElement();
nuclear@0 355 }
nuclear@0 356 else
nuclear@0 357 {
nuclear@0 358 // ignore the rest
nuclear@0 359 SkipElement();
nuclear@0 360 }
nuclear@0 361 }
nuclear@0 362 else if( mReader->getNodeType() == irr::io::EXN_ELEMENT_END)
nuclear@0 363 {
nuclear@0 364 if( strcmp( mReader->getNodeName(), "animation") != 0)
nuclear@0 365 ThrowException( "Expected end of <animation> element.");
nuclear@0 366
nuclear@0 367 break;
nuclear@0 368 }
nuclear@0 369 }
nuclear@0 370
nuclear@0 371 // it turned out to have channels - add them
nuclear@0 372 if( !channels.empty())
nuclear@0 373 {
nuclear@0 374 // special filtering for stupid exporters packing each channel into a separate animation
nuclear@0 375 if( channels.size() == 1)
nuclear@0 376 {
nuclear@0 377 pParent->mChannels.push_back( channels.begin()->second);
nuclear@0 378 } else
nuclear@0 379 {
nuclear@0 380 // else create the animation, if not done yet, and store the channels
nuclear@0 381 if( !anim)
nuclear@0 382 {
nuclear@0 383 anim = new Animation;
nuclear@0 384 anim->mName = animName;
nuclear@0 385 pParent->mSubAnims.push_back( anim);
nuclear@0 386 }
nuclear@0 387 for( ChannelMap::const_iterator it = channels.begin(); it != channels.end(); ++it)
nuclear@0 388 anim->mChannels.push_back( it->second);
nuclear@0 389 }
nuclear@0 390 }
nuclear@0 391 }
nuclear@0 392
nuclear@0 393 // ------------------------------------------------------------------------------------------------
nuclear@0 394 // Reads an animation sampler into the given anim channel
nuclear@0 395 void ColladaParser::ReadAnimationSampler( Collada::AnimationChannel& pChannel)
nuclear@0 396 {
nuclear@0 397 while( mReader->read())
nuclear@0 398 {
nuclear@0 399 if( mReader->getNodeType() == irr::io::EXN_ELEMENT)
nuclear@0 400 {
nuclear@0 401 if( IsElement( "input"))
nuclear@0 402 {
nuclear@0 403 int indexSemantic = GetAttribute( "semantic");
nuclear@0 404 const char* semantic = mReader->getAttributeValue( indexSemantic);
nuclear@0 405 int indexSource = GetAttribute( "source");
nuclear@0 406 const char* source = mReader->getAttributeValue( indexSource);
nuclear@0 407 if( source[0] != '#')
nuclear@0 408 ThrowException( "Unsupported URL format");
nuclear@0 409 source++;
nuclear@0 410
nuclear@0 411 if( strcmp( semantic, "INPUT") == 0)
nuclear@0 412 pChannel.mSourceTimes = source;
nuclear@0 413 else if( strcmp( semantic, "OUTPUT") == 0)
nuclear@0 414 pChannel.mSourceValues = source;
nuclear@0 415
nuclear@0 416 if( !mReader->isEmptyElement())
nuclear@0 417 SkipElement();
nuclear@0 418 }
nuclear@0 419 else
nuclear@0 420 {
nuclear@0 421 // ignore the rest
nuclear@0 422 SkipElement();
nuclear@0 423 }
nuclear@0 424 }
nuclear@0 425 else if( mReader->getNodeType() == irr::io::EXN_ELEMENT_END)
nuclear@0 426 {
nuclear@0 427 if( strcmp( mReader->getNodeName(), "sampler") != 0)
nuclear@0 428 ThrowException( "Expected end of <sampler> element.");
nuclear@0 429
nuclear@0 430 break;
nuclear@0 431 }
nuclear@0 432 }
nuclear@0 433 }
nuclear@0 434
nuclear@0 435 // ------------------------------------------------------------------------------------------------
nuclear@0 436 // Reads the skeleton controller library
nuclear@0 437 void ColladaParser::ReadControllerLibrary()
nuclear@0 438 {
nuclear@0 439 if (mReader->isEmptyElement())
nuclear@0 440 return;
nuclear@0 441
nuclear@0 442 while( mReader->read())
nuclear@0 443 {
nuclear@0 444 if( mReader->getNodeType() == irr::io::EXN_ELEMENT)
nuclear@0 445 {
nuclear@0 446 if( IsElement( "controller"))
nuclear@0 447 {
nuclear@0 448 // read ID. Ask the spec if it's neccessary or optional... you might be surprised.
nuclear@0 449 int attrID = GetAttribute( "id");
nuclear@0 450 std::string id = mReader->getAttributeValue( attrID);
nuclear@0 451
nuclear@0 452 // create an entry and store it in the library under its ID
nuclear@0 453 mControllerLibrary[id] = Controller();
nuclear@0 454
nuclear@0 455 // read on from there
nuclear@0 456 ReadController( mControllerLibrary[id]);
nuclear@0 457 } else
nuclear@0 458 {
nuclear@0 459 // ignore the rest
nuclear@0 460 SkipElement();
nuclear@0 461 }
nuclear@0 462 }
nuclear@0 463 else if( mReader->getNodeType() == irr::io::EXN_ELEMENT_END)
nuclear@0 464 {
nuclear@0 465 if( strcmp( mReader->getNodeName(), "library_controllers") != 0)
nuclear@0 466 ThrowException( "Expected end of <library_controllers> element.");
nuclear@0 467
nuclear@0 468 break;
nuclear@0 469 }
nuclear@0 470 }
nuclear@0 471 }
nuclear@0 472
nuclear@0 473 // ------------------------------------------------------------------------------------------------
nuclear@0 474 // Reads a controller into the given mesh structure
nuclear@0 475 void ColladaParser::ReadController( Collada::Controller& pController)
nuclear@0 476 {
nuclear@0 477 while( mReader->read())
nuclear@0 478 {
nuclear@0 479 if( mReader->getNodeType() == irr::io::EXN_ELEMENT)
nuclear@0 480 {
nuclear@0 481 // two types of controllers: "skin" and "morph". Only the first one is relevant, we skip the other
nuclear@0 482 if( IsElement( "morph"))
nuclear@0 483 {
nuclear@0 484 // should skip everything inside, so there's no danger of catching elements inbetween
nuclear@0 485 SkipElement();
nuclear@0 486 }
nuclear@0 487 else if( IsElement( "skin"))
nuclear@0 488 {
nuclear@0 489 // read the mesh it refers to. According to the spec this could also be another
nuclear@0 490 // controller, but I refuse to implement every single idea they've come up with
nuclear@0 491 int sourceIndex = GetAttribute( "source");
nuclear@0 492 pController.mMeshId = mReader->getAttributeValue( sourceIndex) + 1;
nuclear@0 493 }
nuclear@0 494 else if( IsElement( "bind_shape_matrix"))
nuclear@0 495 {
nuclear@0 496 // content is 16 floats to define a matrix... it seems to be important for some models
nuclear@0 497 const char* content = GetTextContent();
nuclear@0 498
nuclear@0 499 // read the 16 floats
nuclear@0 500 for( unsigned int a = 0; a < 16; a++)
nuclear@0 501 {
nuclear@0 502 // read a number
nuclear@0 503 content = fast_atoreal_move<float>( content, pController.mBindShapeMatrix[a]);
nuclear@0 504 // skip whitespace after it
nuclear@0 505 SkipSpacesAndLineEnd( &content);
nuclear@0 506 }
nuclear@0 507
nuclear@0 508 TestClosing( "bind_shape_matrix");
nuclear@0 509 }
nuclear@0 510 else if( IsElement( "source"))
nuclear@0 511 {
nuclear@0 512 // data array - we have specialists to handle this
nuclear@0 513 ReadSource();
nuclear@0 514 }
nuclear@0 515 else if( IsElement( "joints"))
nuclear@0 516 {
nuclear@0 517 ReadControllerJoints( pController);
nuclear@0 518 }
nuclear@0 519 else if( IsElement( "vertex_weights"))
nuclear@0 520 {
nuclear@0 521 ReadControllerWeights( pController);
nuclear@0 522 }
nuclear@0 523 else
nuclear@0 524 {
nuclear@0 525 // ignore the rest
nuclear@0 526 SkipElement();
nuclear@0 527 }
nuclear@0 528 }
nuclear@0 529 else if( mReader->getNodeType() == irr::io::EXN_ELEMENT_END)
nuclear@0 530 {
nuclear@0 531 if( strcmp( mReader->getNodeName(), "controller") == 0)
nuclear@0 532 break;
nuclear@0 533 else if( strcmp( mReader->getNodeName(), "skin") != 0)
nuclear@0 534 ThrowException( "Expected end of <controller> element.");
nuclear@0 535 }
nuclear@0 536 }
nuclear@0 537 }
nuclear@0 538
nuclear@0 539 // ------------------------------------------------------------------------------------------------
nuclear@0 540 // Reads the joint definitions for the given controller
nuclear@0 541 void ColladaParser::ReadControllerJoints( Collada::Controller& pController)
nuclear@0 542 {
nuclear@0 543 while( mReader->read())
nuclear@0 544 {
nuclear@0 545 if( mReader->getNodeType() == irr::io::EXN_ELEMENT)
nuclear@0 546 {
nuclear@0 547 // Input channels for joint data. Two possible semantics: "JOINT" and "INV_BIND_MATRIX"
nuclear@0 548 if( IsElement( "input"))
nuclear@0 549 {
nuclear@0 550 int indexSemantic = GetAttribute( "semantic");
nuclear@0 551 const char* attrSemantic = mReader->getAttributeValue( indexSemantic);
nuclear@0 552 int indexSource = GetAttribute( "source");
nuclear@0 553 const char* attrSource = mReader->getAttributeValue( indexSource);
nuclear@0 554
nuclear@0 555 // local URLS always start with a '#'. We don't support global URLs
nuclear@0 556 if( attrSource[0] != '#')
nuclear@0 557 ThrowException( boost::str( boost::format( "Unsupported URL format in \"%s\" in source attribute of <joints> data <input> element") % attrSource));
nuclear@0 558 attrSource++;
nuclear@0 559
nuclear@0 560 // parse source URL to corresponding source
nuclear@0 561 if( strcmp( attrSemantic, "JOINT") == 0)
nuclear@0 562 pController.mJointNameSource = attrSource;
nuclear@0 563 else if( strcmp( attrSemantic, "INV_BIND_MATRIX") == 0)
nuclear@0 564 pController.mJointOffsetMatrixSource = attrSource;
nuclear@0 565 else
nuclear@0 566 ThrowException( boost::str( boost::format( "Unknown semantic \"%s\" in <joints> data <input> element") % attrSemantic));
nuclear@0 567
nuclear@0 568 // skip inner data, if present
nuclear@0 569 if( !mReader->isEmptyElement())
nuclear@0 570 SkipElement();
nuclear@0 571 }
nuclear@0 572 else
nuclear@0 573 {
nuclear@0 574 // ignore the rest
nuclear@0 575 SkipElement();
nuclear@0 576 }
nuclear@0 577 }
nuclear@0 578 else if( mReader->getNodeType() == irr::io::EXN_ELEMENT_END)
nuclear@0 579 {
nuclear@0 580 if( strcmp( mReader->getNodeName(), "joints") != 0)
nuclear@0 581 ThrowException( "Expected end of <joints> element.");
nuclear@0 582
nuclear@0 583 break;
nuclear@0 584 }
nuclear@0 585 }
nuclear@0 586 }
nuclear@0 587
nuclear@0 588 // ------------------------------------------------------------------------------------------------
nuclear@0 589 // Reads the joint weights for the given controller
nuclear@0 590 void ColladaParser::ReadControllerWeights( Collada::Controller& pController)
nuclear@0 591 {
nuclear@0 592 // read vertex count from attributes and resize the array accordingly
nuclear@0 593 int indexCount = GetAttribute( "count");
nuclear@0 594 size_t vertexCount = (size_t) mReader->getAttributeValueAsInt( indexCount);
nuclear@0 595 pController.mWeightCounts.resize( vertexCount);
nuclear@0 596
nuclear@0 597 while( mReader->read())
nuclear@0 598 {
nuclear@0 599 if( mReader->getNodeType() == irr::io::EXN_ELEMENT)
nuclear@0 600 {
nuclear@0 601 // Input channels for weight data. Two possible semantics: "JOINT" and "WEIGHT"
nuclear@0 602 if( IsElement( "input") && vertexCount > 0 )
nuclear@0 603 {
nuclear@0 604 InputChannel channel;
nuclear@0 605
nuclear@0 606 int indexSemantic = GetAttribute( "semantic");
nuclear@0 607 const char* attrSemantic = mReader->getAttributeValue( indexSemantic);
nuclear@0 608 int indexSource = GetAttribute( "source");
nuclear@0 609 const char* attrSource = mReader->getAttributeValue( indexSource);
nuclear@0 610 int indexOffset = TestAttribute( "offset");
nuclear@0 611 if( indexOffset >= 0)
nuclear@0 612 channel.mOffset = mReader->getAttributeValueAsInt( indexOffset);
nuclear@0 613
nuclear@0 614 // local URLS always start with a '#'. We don't support global URLs
nuclear@0 615 if( attrSource[0] != '#')
nuclear@0 616 ThrowException( boost::str( boost::format( "Unsupported URL format in \"%s\" in source attribute of <vertex_weights> data <input> element") % attrSource));
nuclear@0 617 channel.mAccessor = attrSource + 1;
nuclear@0 618
nuclear@0 619 // parse source URL to corresponding source
nuclear@0 620 if( strcmp( attrSemantic, "JOINT") == 0)
nuclear@0 621 pController.mWeightInputJoints = channel;
nuclear@0 622 else if( strcmp( attrSemantic, "WEIGHT") == 0)
nuclear@0 623 pController.mWeightInputWeights = channel;
nuclear@0 624 else
nuclear@0 625 ThrowException( boost::str( boost::format( "Unknown semantic \"%s\" in <vertex_weights> data <input> element") % attrSemantic));
nuclear@0 626
nuclear@0 627 // skip inner data, if present
nuclear@0 628 if( !mReader->isEmptyElement())
nuclear@0 629 SkipElement();
nuclear@0 630 }
nuclear@0 631 else if( IsElement( "vcount") && vertexCount > 0 )
nuclear@0 632 {
nuclear@0 633 // read weight count per vertex
nuclear@0 634 const char* text = GetTextContent();
nuclear@0 635 size_t numWeights = 0;
nuclear@0 636 for( std::vector<size_t>::iterator it = pController.mWeightCounts.begin(); it != pController.mWeightCounts.end(); ++it)
nuclear@0 637 {
nuclear@0 638 if( *text == 0)
nuclear@0 639 ThrowException( "Out of data while reading <vcount>");
nuclear@0 640
nuclear@0 641 *it = strtoul10( text, &text);
nuclear@0 642 numWeights += *it;
nuclear@0 643 SkipSpacesAndLineEnd( &text);
nuclear@0 644 }
nuclear@0 645
nuclear@0 646 TestClosing( "vcount");
nuclear@0 647
nuclear@0 648 // reserve weight count
nuclear@0 649 pController.mWeights.resize( numWeights);
nuclear@0 650 }
nuclear@0 651 else if( IsElement( "v") && vertexCount > 0 )
nuclear@0 652 {
nuclear@0 653 // read JointIndex - WeightIndex pairs
nuclear@0 654 const char* text = GetTextContent();
nuclear@0 655
nuclear@0 656 for( std::vector< std::pair<size_t, size_t> >::iterator it = pController.mWeights.begin(); it != pController.mWeights.end(); ++it)
nuclear@0 657 {
nuclear@0 658 if( *text == 0)
nuclear@0 659 ThrowException( "Out of data while reading <vertex_weights>");
nuclear@0 660 it->first = strtoul10( text, &text);
nuclear@0 661 SkipSpacesAndLineEnd( &text);
nuclear@0 662 if( *text == 0)
nuclear@0 663 ThrowException( "Out of data while reading <vertex_weights>");
nuclear@0 664 it->second = strtoul10( text, &text);
nuclear@0 665 SkipSpacesAndLineEnd( &text);
nuclear@0 666 }
nuclear@0 667
nuclear@0 668 TestClosing( "v");
nuclear@0 669 }
nuclear@0 670 else
nuclear@0 671 {
nuclear@0 672 // ignore the rest
nuclear@0 673 SkipElement();
nuclear@0 674 }
nuclear@0 675 }
nuclear@0 676 else if( mReader->getNodeType() == irr::io::EXN_ELEMENT_END)
nuclear@0 677 {
nuclear@0 678 if( strcmp( mReader->getNodeName(), "vertex_weights") != 0)
nuclear@0 679 ThrowException( "Expected end of <vertex_weights> element.");
nuclear@0 680
nuclear@0 681 break;
nuclear@0 682 }
nuclear@0 683 }
nuclear@0 684 }
nuclear@0 685
nuclear@0 686 // ------------------------------------------------------------------------------------------------
nuclear@0 687 // Reads the image library contents
nuclear@0 688 void ColladaParser::ReadImageLibrary()
nuclear@0 689 {
nuclear@0 690 if( mReader->isEmptyElement())
nuclear@0 691 return;
nuclear@0 692
nuclear@0 693 while( mReader->read())
nuclear@0 694 {
nuclear@0 695 if( mReader->getNodeType() == irr::io::EXN_ELEMENT) {
nuclear@0 696 if( IsElement( "image"))
nuclear@0 697 {
nuclear@0 698 // read ID. Another entry which is "optional" by design but obligatory in reality
nuclear@0 699 int attrID = GetAttribute( "id");
nuclear@0 700 std::string id = mReader->getAttributeValue( attrID);
nuclear@0 701
nuclear@0 702 // create an entry and store it in the library under its ID
nuclear@0 703 mImageLibrary[id] = Image();
nuclear@0 704
nuclear@0 705 // read on from there
nuclear@0 706 ReadImage( mImageLibrary[id]);
nuclear@0 707 } else
nuclear@0 708 {
nuclear@0 709 // ignore the rest
nuclear@0 710 SkipElement();
nuclear@0 711 }
nuclear@0 712 }
nuclear@0 713 else if( mReader->getNodeType() == irr::io::EXN_ELEMENT_END) {
nuclear@0 714 if( strcmp( mReader->getNodeName(), "library_images") != 0)
nuclear@0 715 ThrowException( "Expected end of <library_images> element.");
nuclear@0 716
nuclear@0 717 break;
nuclear@0 718 }
nuclear@0 719 }
nuclear@0 720 }
nuclear@0 721
nuclear@0 722 // ------------------------------------------------------------------------------------------------
nuclear@0 723 // Reads an image entry into the given image
nuclear@0 724 void ColladaParser::ReadImage( Collada::Image& pImage)
nuclear@0 725 {
nuclear@0 726 while( mReader->read())
nuclear@0 727 {
nuclear@0 728 if( mReader->getNodeType() == irr::io::EXN_ELEMENT){
nuclear@0 729 // Need to run different code paths here, depending on the Collada XSD version
nuclear@0 730 if (IsElement("image")) {
nuclear@0 731 SkipElement();
nuclear@0 732 }
nuclear@0 733 else if( IsElement( "init_from"))
nuclear@0 734 {
nuclear@0 735 if (mFormat == FV_1_4_n)
nuclear@0 736 {
nuclear@0 737 // FIX: C4D exporter writes empty <init_from/> tags
nuclear@0 738 if (!mReader->isEmptyElement()) {
nuclear@0 739 // element content is filename - hopefully
nuclear@0 740 const char* sz = TestTextContent();
nuclear@0 741 if (sz)pImage.mFileName = sz;
nuclear@0 742 TestClosing( "init_from");
nuclear@0 743 }
nuclear@0 744 if (!pImage.mFileName.length()) {
nuclear@0 745 pImage.mFileName = "unknown_texture";
nuclear@0 746 }
nuclear@0 747 }
nuclear@0 748 else if (mFormat == FV_1_5_n)
nuclear@0 749 {
nuclear@0 750 // make sure we skip over mip and array initializations, which
nuclear@0 751 // we don't support, but which could confuse the loader if
nuclear@0 752 // they're not skipped.
nuclear@0 753 int attrib = TestAttribute("array_index");
nuclear@0 754 if (attrib != -1 && mReader->getAttributeValueAsInt(attrib) > 0) {
nuclear@0 755 DefaultLogger::get()->warn("Collada: Ignoring texture array index");
nuclear@0 756 continue;
nuclear@0 757 }
nuclear@0 758
nuclear@0 759 attrib = TestAttribute("mip_index");
nuclear@0 760 if (attrib != -1 && mReader->getAttributeValueAsInt(attrib) > 0) {
nuclear@0 761 DefaultLogger::get()->warn("Collada: Ignoring MIP map layer");
nuclear@0 762 continue;
nuclear@0 763 }
nuclear@0 764
nuclear@0 765 // TODO: correctly jump over cube and volume maps?
nuclear@0 766 }
nuclear@0 767 }
nuclear@0 768 else if (mFormat == FV_1_5_n)
nuclear@0 769 {
nuclear@0 770 if( IsElement( "ref"))
nuclear@0 771 {
nuclear@0 772 // element content is filename - hopefully
nuclear@0 773 const char* sz = TestTextContent();
nuclear@0 774 if (sz)pImage.mFileName = sz;
nuclear@0 775 TestClosing( "ref");
nuclear@0 776 }
nuclear@0 777 else if( IsElement( "hex") && !pImage.mFileName.length())
nuclear@0 778 {
nuclear@0 779 // embedded image. get format
nuclear@0 780 const int attrib = TestAttribute("format");
nuclear@0 781 if (-1 == attrib)
nuclear@0 782 DefaultLogger::get()->warn("Collada: Unknown image file format");
nuclear@0 783 else pImage.mEmbeddedFormat = mReader->getAttributeValue(attrib);
nuclear@0 784
nuclear@0 785 const char* data = GetTextContent();
nuclear@0 786
nuclear@0 787 // hexadecimal-encoded binary octets. First of all, find the
nuclear@0 788 // required buffer size to reserve enough storage.
nuclear@0 789 const char* cur = data;
nuclear@0 790 while (!IsSpaceOrNewLine(*cur)) cur++;
nuclear@0 791
nuclear@0 792 const unsigned int size = (unsigned int)(cur-data) * 2;
nuclear@0 793 pImage.mImageData.resize(size);
nuclear@0 794 for (unsigned int i = 0; i < size;++i)
nuclear@0 795 pImage.mImageData[i] = HexOctetToDecimal(data+(i<<1));
nuclear@0 796
nuclear@0 797 TestClosing( "hex");
nuclear@0 798 }
nuclear@0 799 }
nuclear@0 800 else
nuclear@0 801 {
nuclear@0 802 // ignore the rest
nuclear@0 803 SkipElement();
nuclear@0 804 }
nuclear@0 805 }
nuclear@0 806 else if( mReader->getNodeType() == irr::io::EXN_ELEMENT_END) {
nuclear@0 807 if( strcmp( mReader->getNodeName(), "image") == 0)
nuclear@0 808 break;
nuclear@0 809 }
nuclear@0 810 }
nuclear@0 811 }
nuclear@0 812
nuclear@0 813 // ------------------------------------------------------------------------------------------------
nuclear@0 814 // Reads the material library
nuclear@0 815 void ColladaParser::ReadMaterialLibrary()
nuclear@0 816 {
nuclear@0 817 if( mReader->isEmptyElement())
nuclear@0 818 return;
nuclear@0 819
nuclear@0 820 while( mReader->read())
nuclear@0 821 {
nuclear@0 822 if( mReader->getNodeType() == irr::io::EXN_ELEMENT)
nuclear@0 823 {
nuclear@0 824 if( IsElement( "material"))
nuclear@0 825 {
nuclear@0 826 // read ID. By now you propably know my opinion about this "specification"
nuclear@0 827 int attrID = GetAttribute( "id");
nuclear@0 828 std::string id = mReader->getAttributeValue( attrID);
nuclear@0 829
nuclear@0 830 // create an entry and store it in the library under its ID
nuclear@0 831 ReadMaterial(mMaterialLibrary[id] = Material());
nuclear@0 832 } else
nuclear@0 833 {
nuclear@0 834 // ignore the rest
nuclear@0 835 SkipElement();
nuclear@0 836 }
nuclear@0 837 }
nuclear@0 838 else if( mReader->getNodeType() == irr::io::EXN_ELEMENT_END)
nuclear@0 839 {
nuclear@0 840 if( strcmp( mReader->getNodeName(), "library_materials") != 0)
nuclear@0 841 ThrowException( "Expected end of <library_materials> element.");
nuclear@0 842
nuclear@0 843 break;
nuclear@0 844 }
nuclear@0 845 }
nuclear@0 846 }
nuclear@0 847
nuclear@0 848 // ------------------------------------------------------------------------------------------------
nuclear@0 849 // Reads the light library
nuclear@0 850 void ColladaParser::ReadLightLibrary()
nuclear@0 851 {
nuclear@0 852 if( mReader->isEmptyElement())
nuclear@0 853 return;
nuclear@0 854
nuclear@0 855 while( mReader->read())
nuclear@0 856 {
nuclear@0 857 if( mReader->getNodeType() == irr::io::EXN_ELEMENT) {
nuclear@0 858 if( IsElement( "light"))
nuclear@0 859 {
nuclear@0 860 // read ID. By now you propably know my opinion about this "specification"
nuclear@0 861 int attrID = GetAttribute( "id");
nuclear@0 862 std::string id = mReader->getAttributeValue( attrID);
nuclear@0 863
nuclear@0 864 // create an entry and store it in the library under its ID
nuclear@0 865 ReadLight(mLightLibrary[id] = Light());
nuclear@0 866
nuclear@0 867 } else
nuclear@0 868 {
nuclear@0 869 // ignore the rest
nuclear@0 870 SkipElement();
nuclear@0 871 }
nuclear@0 872 }
nuclear@0 873 else if( mReader->getNodeType() == irr::io::EXN_ELEMENT_END) {
nuclear@0 874 if( strcmp( mReader->getNodeName(), "library_lights") != 0)
nuclear@0 875 ThrowException( "Expected end of <library_lights> element.");
nuclear@0 876
nuclear@0 877 break;
nuclear@0 878 }
nuclear@0 879 }
nuclear@0 880 }
nuclear@0 881
nuclear@0 882 // ------------------------------------------------------------------------------------------------
nuclear@0 883 // Reads the camera library
nuclear@0 884 void ColladaParser::ReadCameraLibrary()
nuclear@0 885 {
nuclear@0 886 if( mReader->isEmptyElement())
nuclear@0 887 return;
nuclear@0 888
nuclear@0 889 while( mReader->read())
nuclear@0 890 {
nuclear@0 891 if( mReader->getNodeType() == irr::io::EXN_ELEMENT) {
nuclear@0 892 if( IsElement( "camera"))
nuclear@0 893 {
nuclear@0 894 // read ID. By now you propably know my opinion about this "specification"
nuclear@0 895 int attrID = GetAttribute( "id");
nuclear@0 896 std::string id = mReader->getAttributeValue( attrID);
nuclear@0 897
nuclear@0 898 // create an entry and store it in the library under its ID
nuclear@0 899 Camera& cam = mCameraLibrary[id];
nuclear@0 900 attrID = TestAttribute( "name");
nuclear@0 901 if (attrID != -1)
nuclear@0 902 cam.mName = mReader->getAttributeValue( attrID);
nuclear@0 903
nuclear@0 904 ReadCamera(cam);
nuclear@0 905
nuclear@0 906 } else
nuclear@0 907 {
nuclear@0 908 // ignore the rest
nuclear@0 909 SkipElement();
nuclear@0 910 }
nuclear@0 911 }
nuclear@0 912 else if( mReader->getNodeType() == irr::io::EXN_ELEMENT_END) {
nuclear@0 913 if( strcmp( mReader->getNodeName(), "library_cameras") != 0)
nuclear@0 914 ThrowException( "Expected end of <library_cameras> element.");
nuclear@0 915
nuclear@0 916 break;
nuclear@0 917 }
nuclear@0 918 }
nuclear@0 919 }
nuclear@0 920
nuclear@0 921 // ------------------------------------------------------------------------------------------------
nuclear@0 922 // Reads a material entry into the given material
nuclear@0 923 void ColladaParser::ReadMaterial( Collada::Material& pMaterial)
nuclear@0 924 {
nuclear@0 925 while( mReader->read())
nuclear@0 926 {
nuclear@0 927 if( mReader->getNodeType() == irr::io::EXN_ELEMENT) {
nuclear@0 928 if (IsElement("material")) {
nuclear@0 929 SkipElement();
nuclear@0 930 }
nuclear@0 931 else if( IsElement( "instance_effect"))
nuclear@0 932 {
nuclear@0 933 // referred effect by URL
nuclear@0 934 int attrUrl = GetAttribute( "url");
nuclear@0 935 const char* url = mReader->getAttributeValue( attrUrl);
nuclear@0 936 if( url[0] != '#')
nuclear@0 937 ThrowException( "Unknown reference format");
nuclear@0 938
nuclear@0 939 pMaterial.mEffect = url+1;
nuclear@0 940
nuclear@0 941 SkipElement();
nuclear@0 942 } else
nuclear@0 943 {
nuclear@0 944 // ignore the rest
nuclear@0 945 SkipElement();
nuclear@0 946 }
nuclear@0 947 }
nuclear@0 948 else if( mReader->getNodeType() == irr::io::EXN_ELEMENT_END) {
nuclear@0 949 if( strcmp( mReader->getNodeName(), "material") != 0)
nuclear@0 950 ThrowException( "Expected end of <material> element.");
nuclear@0 951
nuclear@0 952 break;
nuclear@0 953 }
nuclear@0 954 }
nuclear@0 955 }
nuclear@0 956
nuclear@0 957 // ------------------------------------------------------------------------------------------------
nuclear@0 958 // Reads a light entry into the given light
nuclear@0 959 void ColladaParser::ReadLight( Collada::Light& pLight)
nuclear@0 960 {
nuclear@0 961 while( mReader->read())
nuclear@0 962 {
nuclear@0 963 if( mReader->getNodeType() == irr::io::EXN_ELEMENT) {
nuclear@0 964 if (IsElement("light")) {
nuclear@0 965 SkipElement();
nuclear@0 966 }
nuclear@0 967 else if (IsElement("spot")) {
nuclear@0 968 pLight.mType = aiLightSource_SPOT;
nuclear@0 969 }
nuclear@0 970 else if (IsElement("ambient")) {
nuclear@0 971 pLight.mType = aiLightSource_AMBIENT;
nuclear@0 972 }
nuclear@0 973 else if (IsElement("directional")) {
nuclear@0 974 pLight.mType = aiLightSource_DIRECTIONAL;
nuclear@0 975 }
nuclear@0 976 else if (IsElement("point")) {
nuclear@0 977 pLight.mType = aiLightSource_POINT;
nuclear@0 978 }
nuclear@0 979 else if (IsElement("color")) {
nuclear@0 980 // text content contains 3 floats
nuclear@0 981 const char* content = GetTextContent();
nuclear@0 982
nuclear@0 983 content = fast_atoreal_move<float>( content, (float&)pLight.mColor.r);
nuclear@0 984 SkipSpacesAndLineEnd( &content);
nuclear@0 985
nuclear@0 986 content = fast_atoreal_move<float>( content, (float&)pLight.mColor.g);
nuclear@0 987 SkipSpacesAndLineEnd( &content);
nuclear@0 988
nuclear@0 989 content = fast_atoreal_move<float>( content, (float&)pLight.mColor.b);
nuclear@0 990 SkipSpacesAndLineEnd( &content);
nuclear@0 991
nuclear@0 992 TestClosing( "color");
nuclear@0 993 }
nuclear@0 994 else if (IsElement("constant_attenuation")) {
nuclear@0 995 pLight.mAttConstant = ReadFloatFromTextContent();
nuclear@0 996 TestClosing("constant_attenuation");
nuclear@0 997 }
nuclear@0 998 else if (IsElement("linear_attenuation")) {
nuclear@0 999 pLight.mAttLinear = ReadFloatFromTextContent();
nuclear@0 1000 TestClosing("linear_attenuation");
nuclear@0 1001 }
nuclear@0 1002 else if (IsElement("quadratic_attenuation")) {
nuclear@0 1003 pLight.mAttQuadratic = ReadFloatFromTextContent();
nuclear@0 1004 TestClosing("quadratic_attenuation");
nuclear@0 1005 }
nuclear@0 1006 else if (IsElement("falloff_angle")) {
nuclear@0 1007 pLight.mFalloffAngle = ReadFloatFromTextContent();
nuclear@0 1008 TestClosing("falloff_angle");
nuclear@0 1009 }
nuclear@0 1010 else if (IsElement("falloff_exponent")) {
nuclear@0 1011 pLight.mFalloffExponent = ReadFloatFromTextContent();
nuclear@0 1012 TestClosing("falloff_exponent");
nuclear@0 1013 }
nuclear@0 1014 // FCOLLADA extensions
nuclear@0 1015 // -------------------------------------------------------
nuclear@0 1016 else if (IsElement("outer_cone")) {
nuclear@0 1017 pLight.mOuterAngle = ReadFloatFromTextContent();
nuclear@0 1018 TestClosing("outer_cone");
nuclear@0 1019 }
nuclear@0 1020 // ... and this one is even deprecated
nuclear@0 1021 else if (IsElement("penumbra_angle")) {
nuclear@0 1022 pLight.mPenumbraAngle = ReadFloatFromTextContent();
nuclear@0 1023 TestClosing("penumbra_angle");
nuclear@0 1024 }
nuclear@0 1025 else if (IsElement("intensity")) {
nuclear@0 1026 pLight.mIntensity = ReadFloatFromTextContent();
nuclear@0 1027 TestClosing("intensity");
nuclear@0 1028 }
nuclear@0 1029 else if (IsElement("falloff")) {
nuclear@0 1030 pLight.mOuterAngle = ReadFloatFromTextContent();
nuclear@0 1031 TestClosing("falloff");
nuclear@0 1032 }
nuclear@0 1033 else if (IsElement("hotspot_beam")) {
nuclear@0 1034 pLight.mFalloffAngle = ReadFloatFromTextContent();
nuclear@0 1035 TestClosing("hotspot_beam");
nuclear@0 1036 }
nuclear@0 1037 }
nuclear@0 1038 else if( mReader->getNodeType() == irr::io::EXN_ELEMENT_END) {
nuclear@0 1039 if( strcmp( mReader->getNodeName(), "light") == 0)
nuclear@0 1040 break;
nuclear@0 1041 }
nuclear@0 1042 }
nuclear@0 1043 }
nuclear@0 1044
nuclear@0 1045 // ------------------------------------------------------------------------------------------------
nuclear@0 1046 // Reads a camera entry into the given light
nuclear@0 1047 void ColladaParser::ReadCamera( Collada::Camera& pCamera)
nuclear@0 1048 {
nuclear@0 1049 while( mReader->read())
nuclear@0 1050 {
nuclear@0 1051 if( mReader->getNodeType() == irr::io::EXN_ELEMENT) {
nuclear@0 1052 if (IsElement("camera")) {
nuclear@0 1053 SkipElement();
nuclear@0 1054 }
nuclear@0 1055 else if (IsElement("orthographic")) {
nuclear@0 1056 pCamera.mOrtho = true;
nuclear@0 1057 }
nuclear@0 1058 else if (IsElement("xfov") || IsElement("xmag")) {
nuclear@0 1059 pCamera.mHorFov = ReadFloatFromTextContent();
nuclear@0 1060 TestClosing((pCamera.mOrtho ? "xmag" : "xfov"));
nuclear@0 1061 }
nuclear@0 1062 else if (IsElement("yfov") || IsElement("ymag")) {
nuclear@0 1063 pCamera.mVerFov = ReadFloatFromTextContent();
nuclear@0 1064 TestClosing((pCamera.mOrtho ? "ymag" : "yfov"));
nuclear@0 1065 }
nuclear@0 1066 else if (IsElement("aspect_ratio")) {
nuclear@0 1067 pCamera.mAspect = ReadFloatFromTextContent();
nuclear@0 1068 TestClosing("aspect_ratio");
nuclear@0 1069 }
nuclear@0 1070 else if (IsElement("znear")) {
nuclear@0 1071 pCamera.mZNear = ReadFloatFromTextContent();
nuclear@0 1072 TestClosing("znear");
nuclear@0 1073 }
nuclear@0 1074 else if (IsElement("zfar")) {
nuclear@0 1075 pCamera.mZFar = ReadFloatFromTextContent();
nuclear@0 1076 TestClosing("zfar");
nuclear@0 1077 }
nuclear@0 1078 }
nuclear@0 1079 else if( mReader->getNodeType() == irr::io::EXN_ELEMENT_END) {
nuclear@0 1080 if( strcmp( mReader->getNodeName(), "camera") == 0)
nuclear@0 1081 break;
nuclear@0 1082 }
nuclear@0 1083 }
nuclear@0 1084 }
nuclear@0 1085
nuclear@0 1086 // ------------------------------------------------------------------------------------------------
nuclear@0 1087 // Reads the effect library
nuclear@0 1088 void ColladaParser::ReadEffectLibrary()
nuclear@0 1089 {
nuclear@0 1090 if (mReader->isEmptyElement()) {
nuclear@0 1091 return;
nuclear@0 1092 }
nuclear@0 1093
nuclear@0 1094 while( mReader->read())
nuclear@0 1095 {
nuclear@0 1096 if( mReader->getNodeType() == irr::io::EXN_ELEMENT) {
nuclear@0 1097 if( IsElement( "effect"))
nuclear@0 1098 {
nuclear@0 1099 // read ID. Do I have to repeat my ranting about "optional" attributes?
nuclear@0 1100 int attrID = GetAttribute( "id");
nuclear@0 1101 std::string id = mReader->getAttributeValue( attrID);
nuclear@0 1102
nuclear@0 1103 // create an entry and store it in the library under its ID
nuclear@0 1104 mEffectLibrary[id] = Effect();
nuclear@0 1105 // read on from there
nuclear@0 1106 ReadEffect( mEffectLibrary[id]);
nuclear@0 1107 } else
nuclear@0 1108 {
nuclear@0 1109 // ignore the rest
nuclear@0 1110 SkipElement();
nuclear@0 1111 }
nuclear@0 1112 }
nuclear@0 1113 else if( mReader->getNodeType() == irr::io::EXN_ELEMENT_END) {
nuclear@0 1114 if( strcmp( mReader->getNodeName(), "library_effects") != 0)
nuclear@0 1115 ThrowException( "Expected end of <library_effects> element.");
nuclear@0 1116
nuclear@0 1117 break;
nuclear@0 1118 }
nuclear@0 1119 }
nuclear@0 1120 }
nuclear@0 1121
nuclear@0 1122 // ------------------------------------------------------------------------------------------------
nuclear@0 1123 // Reads an effect entry into the given effect
nuclear@0 1124 void ColladaParser::ReadEffect( Collada::Effect& pEffect)
nuclear@0 1125 {
nuclear@0 1126 // for the moment we don't support any other type of effect.
nuclear@0 1127 while( mReader->read())
nuclear@0 1128 {
nuclear@0 1129 if( mReader->getNodeType() == irr::io::EXN_ELEMENT)
nuclear@0 1130 {
nuclear@0 1131 if( IsElement( "profile_COMMON"))
nuclear@0 1132 ReadEffectProfileCommon( pEffect);
nuclear@0 1133 else
nuclear@0 1134 SkipElement();
nuclear@0 1135 }
nuclear@0 1136 else if( mReader->getNodeType() == irr::io::EXN_ELEMENT_END)
nuclear@0 1137 {
nuclear@0 1138 if( strcmp( mReader->getNodeName(), "effect") != 0)
nuclear@0 1139 ThrowException( "Expected end of <effect> element.");
nuclear@0 1140
nuclear@0 1141 break;
nuclear@0 1142 }
nuclear@0 1143 }
nuclear@0 1144 }
nuclear@0 1145
nuclear@0 1146 // ------------------------------------------------------------------------------------------------
nuclear@0 1147 // Reads an COMMON effect profile
nuclear@0 1148 void ColladaParser::ReadEffectProfileCommon( Collada::Effect& pEffect)
nuclear@0 1149 {
nuclear@0 1150 while( mReader->read())
nuclear@0 1151 {
nuclear@0 1152 if( mReader->getNodeType() == irr::io::EXN_ELEMENT)
nuclear@0 1153 {
nuclear@0 1154 if( IsElement( "newparam")) {
nuclear@0 1155 // save ID
nuclear@0 1156 int attrSID = GetAttribute( "sid");
nuclear@0 1157 std::string sid = mReader->getAttributeValue( attrSID);
nuclear@0 1158 pEffect.mParams[sid] = EffectParam();
nuclear@0 1159 ReadEffectParam( pEffect.mParams[sid]);
nuclear@0 1160 }
nuclear@0 1161 else if( IsElement( "technique") || IsElement( "extra"))
nuclear@0 1162 {
nuclear@0 1163 // just syntactic sugar
nuclear@0 1164 }
nuclear@0 1165
nuclear@0 1166 /* Shading modes */
nuclear@0 1167 else if( IsElement( "phong"))
nuclear@0 1168 pEffect.mShadeType = Shade_Phong;
nuclear@0 1169 else if( IsElement( "constant"))
nuclear@0 1170 pEffect.mShadeType = Shade_Constant;
nuclear@0 1171 else if( IsElement( "lambert"))
nuclear@0 1172 pEffect.mShadeType = Shade_Lambert;
nuclear@0 1173 else if( IsElement( "blinn"))
nuclear@0 1174 pEffect.mShadeType = Shade_Blinn;
nuclear@0 1175
nuclear@0 1176 /* Color + texture properties */
nuclear@0 1177 else if( IsElement( "emission"))
nuclear@0 1178 ReadEffectColor( pEffect.mEmissive, pEffect.mTexEmissive);
nuclear@0 1179 else if( IsElement( "ambient"))
nuclear@0 1180 ReadEffectColor( pEffect.mAmbient, pEffect.mTexAmbient);
nuclear@0 1181 else if( IsElement( "diffuse"))
nuclear@0 1182 ReadEffectColor( pEffect.mDiffuse, pEffect.mTexDiffuse);
nuclear@0 1183 else if( IsElement( "specular"))
nuclear@0 1184 ReadEffectColor( pEffect.mSpecular, pEffect.mTexSpecular);
nuclear@0 1185 else if( IsElement( "reflective")) {
nuclear@0 1186 ReadEffectColor( pEffect.mReflective, pEffect.mTexReflective);
nuclear@0 1187 }
nuclear@0 1188 else if( IsElement( "transparent")) {
nuclear@0 1189 ReadEffectColor( pEffect.mTransparent,pEffect.mTexTransparent);
nuclear@0 1190 }
nuclear@0 1191 else if( IsElement( "shininess"))
nuclear@0 1192 ReadEffectFloat( pEffect.mShininess);
nuclear@0 1193 else if( IsElement( "reflectivity"))
nuclear@0 1194 ReadEffectFloat( pEffect.mReflectivity);
nuclear@0 1195
nuclear@0 1196 /* Single scalar properties */
nuclear@0 1197 else if( IsElement( "transparency"))
nuclear@0 1198 ReadEffectFloat( pEffect.mTransparency);
nuclear@0 1199 else if( IsElement( "index_of_refraction"))
nuclear@0 1200 ReadEffectFloat( pEffect.mRefractIndex);
nuclear@0 1201
nuclear@0 1202 // GOOGLEEARTH/OKINO extensions
nuclear@0 1203 // -------------------------------------------------------
nuclear@0 1204 else if( IsElement( "double_sided"))
nuclear@0 1205 pEffect.mDoubleSided = ReadBoolFromTextContent();
nuclear@0 1206
nuclear@0 1207 // FCOLLADA extensions
nuclear@0 1208 // -------------------------------------------------------
nuclear@0 1209 else if( IsElement( "bump")) {
nuclear@0 1210 aiColor4D dummy;
nuclear@0 1211 ReadEffectColor( dummy,pEffect.mTexBump);
nuclear@0 1212 }
nuclear@0 1213
nuclear@0 1214 // MAX3D extensions
nuclear@0 1215 // -------------------------------------------------------
nuclear@0 1216 else if( IsElement( "wireframe")) {
nuclear@0 1217 pEffect.mWireframe = ReadBoolFromTextContent();
nuclear@0 1218 TestClosing( "wireframe");
nuclear@0 1219 }
nuclear@0 1220 else if( IsElement( "faceted")) {
nuclear@0 1221 pEffect.mFaceted = ReadBoolFromTextContent();
nuclear@0 1222 TestClosing( "faceted");
nuclear@0 1223 }
nuclear@0 1224 else
nuclear@0 1225 {
nuclear@0 1226 // ignore the rest
nuclear@0 1227 SkipElement();
nuclear@0 1228 }
nuclear@0 1229 }
nuclear@0 1230 else if( mReader->getNodeType() == irr::io::EXN_ELEMENT_END) {
nuclear@0 1231 if( strcmp( mReader->getNodeName(), "profile_COMMON") == 0)
nuclear@0 1232 {
nuclear@0 1233 break;
nuclear@0 1234 }
nuclear@0 1235 }
nuclear@0 1236 }
nuclear@0 1237 }
nuclear@0 1238
nuclear@0 1239 // ------------------------------------------------------------------------------------------------
nuclear@0 1240 // Read texture wrapping + UV transform settings from a profile==Maya chunk
nuclear@0 1241 void ColladaParser::ReadSamplerProperties( Sampler& out )
nuclear@0 1242 {
nuclear@0 1243 if (mReader->isEmptyElement()) {
nuclear@0 1244 return;
nuclear@0 1245 }
nuclear@0 1246
nuclear@0 1247 while( mReader->read())
nuclear@0 1248 {
nuclear@0 1249 if( mReader->getNodeType() == irr::io::EXN_ELEMENT) {
nuclear@0 1250
nuclear@0 1251 // MAYA extensions
nuclear@0 1252 // -------------------------------------------------------
nuclear@0 1253 if( IsElement( "wrapU")) {
nuclear@0 1254 out.mWrapU = ReadBoolFromTextContent();
nuclear@0 1255 TestClosing( "wrapU");
nuclear@0 1256 }
nuclear@0 1257 else if( IsElement( "wrapV")) {
nuclear@0 1258 out.mWrapV = ReadBoolFromTextContent();
nuclear@0 1259 TestClosing( "wrapV");
nuclear@0 1260 }
nuclear@0 1261 else if( IsElement( "mirrorU")) {
nuclear@0 1262 out.mMirrorU = ReadBoolFromTextContent();
nuclear@0 1263 TestClosing( "mirrorU");
nuclear@0 1264 }
nuclear@0 1265 else if( IsElement( "mirrorV")) {
nuclear@0 1266 out.mMirrorV = ReadBoolFromTextContent();
nuclear@0 1267 TestClosing( "mirrorV");
nuclear@0 1268 }
nuclear@0 1269 else if( IsElement( "repeatU")) {
nuclear@0 1270 out.mTransform.mScaling.x = ReadFloatFromTextContent();
nuclear@0 1271 TestClosing( "repeatU");
nuclear@0 1272 }
nuclear@0 1273 else if( IsElement( "repeatV")) {
nuclear@0 1274 out.mTransform.mScaling.y = ReadFloatFromTextContent();
nuclear@0 1275 TestClosing( "repeatV");
nuclear@0 1276 }
nuclear@0 1277 else if( IsElement( "offsetU")) {
nuclear@0 1278 out.mTransform.mTranslation.x = ReadFloatFromTextContent();
nuclear@0 1279 TestClosing( "offsetU");
nuclear@0 1280 }
nuclear@0 1281 else if( IsElement( "offsetV")) {
nuclear@0 1282 out.mTransform.mTranslation.y = ReadFloatFromTextContent();
nuclear@0 1283 TestClosing( "offsetV");
nuclear@0 1284 }
nuclear@0 1285 else if( IsElement( "rotateUV")) {
nuclear@0 1286 out.mTransform.mRotation = ReadFloatFromTextContent();
nuclear@0 1287 TestClosing( "rotateUV");
nuclear@0 1288 }
nuclear@0 1289 else if( IsElement( "blend_mode")) {
nuclear@0 1290
nuclear@0 1291 const char* sz = GetTextContent();
nuclear@0 1292 // http://www.feelingsoftware.com/content/view/55/72/lang,en/
nuclear@0 1293 // NONE, OVER, IN, OUT, ADD, SUBTRACT, MULTIPLY, DIFFERENCE, LIGHTEN, DARKEN, SATURATE, DESATURATE and ILLUMINATE
nuclear@0 1294 if (0 == ASSIMP_strincmp(sz,"ADD",3))
nuclear@0 1295 out.mOp = aiTextureOp_Add;
nuclear@0 1296
nuclear@0 1297 else if (0 == ASSIMP_strincmp(sz,"SUBTRACT",8))
nuclear@0 1298 out.mOp = aiTextureOp_Subtract;
nuclear@0 1299
nuclear@0 1300 else if (0 == ASSIMP_strincmp(sz,"MULTIPLY",8))
nuclear@0 1301 out.mOp = aiTextureOp_Multiply;
nuclear@0 1302
nuclear@0 1303 else {
nuclear@0 1304 DefaultLogger::get()->warn("Collada: Unsupported MAYA texture blend mode");
nuclear@0 1305 }
nuclear@0 1306 TestClosing( "blend_mode");
nuclear@0 1307 }
nuclear@0 1308 // OKINO extensions
nuclear@0 1309 // -------------------------------------------------------
nuclear@0 1310 else if( IsElement( "weighting")) {
nuclear@0 1311 out.mWeighting = ReadFloatFromTextContent();
nuclear@0 1312 TestClosing( "weighting");
nuclear@0 1313 }
nuclear@0 1314 else if( IsElement( "mix_with_previous_layer")) {
nuclear@0 1315 out.mMixWithPrevious = ReadFloatFromTextContent();
nuclear@0 1316 TestClosing( "mix_with_previous_layer");
nuclear@0 1317 }
nuclear@0 1318 // MAX3D extensions
nuclear@0 1319 // -------------------------------------------------------
nuclear@0 1320 else if( IsElement( "amount")) {
nuclear@0 1321 out.mWeighting = ReadFloatFromTextContent();
nuclear@0 1322 TestClosing( "amount");
nuclear@0 1323 }
nuclear@0 1324 }
nuclear@0 1325 else if( mReader->getNodeType() == irr::io::EXN_ELEMENT_END) {
nuclear@0 1326 if( strcmp( mReader->getNodeName(), "technique") == 0)
nuclear@0 1327 break;
nuclear@0 1328 }
nuclear@0 1329 }
nuclear@0 1330 }
nuclear@0 1331
nuclear@0 1332 // ------------------------------------------------------------------------------------------------
nuclear@0 1333 // Reads an effect entry containing a color or a texture defining that color
nuclear@0 1334 void ColladaParser::ReadEffectColor( aiColor4D& pColor, Sampler& pSampler)
nuclear@0 1335 {
nuclear@0 1336 if (mReader->isEmptyElement())
nuclear@0 1337 return;
nuclear@0 1338
nuclear@0 1339 // Save current element name
nuclear@0 1340 const std::string curElem = mReader->getNodeName();
nuclear@0 1341
nuclear@0 1342 while( mReader->read())
nuclear@0 1343 {
nuclear@0 1344 if( mReader->getNodeType() == irr::io::EXN_ELEMENT) {
nuclear@0 1345 if( IsElement( "color"))
nuclear@0 1346 {
nuclear@0 1347 // text content contains 4 floats
nuclear@0 1348 const char* content = GetTextContent();
nuclear@0 1349
nuclear@0 1350 content = fast_atoreal_move<float>( content, (float&)pColor.r);
nuclear@0 1351 SkipSpacesAndLineEnd( &content);
nuclear@0 1352
nuclear@0 1353 content = fast_atoreal_move<float>( content, (float&)pColor.g);
nuclear@0 1354 SkipSpacesAndLineEnd( &content);
nuclear@0 1355
nuclear@0 1356 content = fast_atoreal_move<float>( content, (float&)pColor.b);
nuclear@0 1357 SkipSpacesAndLineEnd( &content);
nuclear@0 1358
nuclear@0 1359 content = fast_atoreal_move<float>( content, (float&)pColor.a);
nuclear@0 1360 SkipSpacesAndLineEnd( &content);
nuclear@0 1361 TestClosing( "color");
nuclear@0 1362 }
nuclear@0 1363 else if( IsElement( "texture"))
nuclear@0 1364 {
nuclear@0 1365 // get name of source textur/sampler
nuclear@0 1366 int attrTex = GetAttribute( "texture");
nuclear@0 1367 pSampler.mName = mReader->getAttributeValue( attrTex);
nuclear@0 1368
nuclear@0 1369 // get name of UV source channel. Specification demands it to be there, but some exporters
nuclear@0 1370 // don't write it. It will be the default UV channel in case it's missing.
nuclear@0 1371 attrTex = TestAttribute( "texcoord");
nuclear@0 1372 if( attrTex >= 0 )
nuclear@0 1373 pSampler.mUVChannel = mReader->getAttributeValue( attrTex);
nuclear@0 1374 //SkipElement();
nuclear@0 1375 }
nuclear@0 1376 else if( IsElement( "technique"))
nuclear@0 1377 {
nuclear@0 1378 const int _profile = GetAttribute( "profile");
nuclear@0 1379 const char* profile = mReader->getAttributeValue( _profile );
nuclear@0 1380
nuclear@0 1381 // Some extensions are quite useful ... ReadSamplerProperties processes
nuclear@0 1382 // several extensions in MAYA, OKINO and MAX3D profiles.
nuclear@0 1383 if (!::strcmp(profile,"MAYA") || !::strcmp(profile,"MAX3D") || !::strcmp(profile,"OKINO"))
nuclear@0 1384 {
nuclear@0 1385 // get more information on this sampler
nuclear@0 1386 ReadSamplerProperties(pSampler);
nuclear@0 1387 }
nuclear@0 1388 else SkipElement();
nuclear@0 1389 }
nuclear@0 1390 else if( !IsElement( "extra"))
nuclear@0 1391 {
nuclear@0 1392 // ignore the rest
nuclear@0 1393 SkipElement();
nuclear@0 1394 }
nuclear@0 1395 }
nuclear@0 1396 else if( mReader->getNodeType() == irr::io::EXN_ELEMENT_END){
nuclear@0 1397 if (mReader->getNodeName() == curElem)
nuclear@0 1398 break;
nuclear@0 1399 }
nuclear@0 1400 }
nuclear@0 1401 }
nuclear@0 1402
nuclear@0 1403 // ------------------------------------------------------------------------------------------------
nuclear@0 1404 // Reads an effect entry containing a float
nuclear@0 1405 void ColladaParser::ReadEffectFloat( float& pFloat)
nuclear@0 1406 {
nuclear@0 1407 while( mReader->read())
nuclear@0 1408 {
nuclear@0 1409 if( mReader->getNodeType() == irr::io::EXN_ELEMENT){
nuclear@0 1410 if( IsElement( "float"))
nuclear@0 1411 {
nuclear@0 1412 // text content contains a single floats
nuclear@0 1413 const char* content = GetTextContent();
nuclear@0 1414 content = fast_atoreal_move<float>( content, pFloat);
nuclear@0 1415 SkipSpacesAndLineEnd( &content);
nuclear@0 1416
nuclear@0 1417 TestClosing( "float");
nuclear@0 1418 } else
nuclear@0 1419 {
nuclear@0 1420 // ignore the rest
nuclear@0 1421 SkipElement();
nuclear@0 1422 }
nuclear@0 1423 }
nuclear@0 1424 else if( mReader->getNodeType() == irr::io::EXN_ELEMENT_END){
nuclear@0 1425 break;
nuclear@0 1426 }
nuclear@0 1427 }
nuclear@0 1428 }
nuclear@0 1429
nuclear@0 1430 // ------------------------------------------------------------------------------------------------
nuclear@0 1431 // Reads an effect parameter specification of any kind
nuclear@0 1432 void ColladaParser::ReadEffectParam( Collada::EffectParam& pParam)
nuclear@0 1433 {
nuclear@0 1434 while( mReader->read())
nuclear@0 1435 {
nuclear@0 1436 if( mReader->getNodeType() == irr::io::EXN_ELEMENT) {
nuclear@0 1437 if( IsElement( "surface"))
nuclear@0 1438 {
nuclear@0 1439 // image ID given inside <init_from> tags
nuclear@0 1440 TestOpening( "init_from");
nuclear@0 1441 const char* content = GetTextContent();
nuclear@0 1442 pParam.mType = Param_Surface;
nuclear@0 1443 pParam.mReference = content;
nuclear@0 1444 TestClosing( "init_from");
nuclear@0 1445
nuclear@0 1446 // don't care for remaining stuff
nuclear@0 1447 SkipElement( "surface");
nuclear@0 1448 }
nuclear@0 1449 else if( IsElement( "sampler2D"))
nuclear@0 1450 {
nuclear@0 1451 // surface ID is given inside <source> tags
nuclear@0 1452 TestOpening( "source");
nuclear@0 1453 const char* content = GetTextContent();
nuclear@0 1454 pParam.mType = Param_Sampler;
nuclear@0 1455 pParam.mReference = content;
nuclear@0 1456 TestClosing( "source");
nuclear@0 1457
nuclear@0 1458 // don't care for remaining stuff
nuclear@0 1459 SkipElement( "sampler2D");
nuclear@0 1460 } else
nuclear@0 1461 {
nuclear@0 1462 // ignore unknown element
nuclear@0 1463 SkipElement();
nuclear@0 1464 }
nuclear@0 1465 }
nuclear@0 1466 else if( mReader->getNodeType() == irr::io::EXN_ELEMENT_END) {
nuclear@0 1467 break;
nuclear@0 1468 }
nuclear@0 1469 }
nuclear@0 1470 }
nuclear@0 1471
nuclear@0 1472 // ------------------------------------------------------------------------------------------------
nuclear@0 1473 // Reads the geometry library contents
nuclear@0 1474 void ColladaParser::ReadGeometryLibrary()
nuclear@0 1475 {
nuclear@0 1476 if( mReader->isEmptyElement())
nuclear@0 1477 return;
nuclear@0 1478
nuclear@0 1479 while( mReader->read())
nuclear@0 1480 {
nuclear@0 1481 if( mReader->getNodeType() == irr::io::EXN_ELEMENT)
nuclear@0 1482 {
nuclear@0 1483 if( IsElement( "geometry"))
nuclear@0 1484 {
nuclear@0 1485 // read ID. Another entry which is "optional" by design but obligatory in reality
nuclear@0 1486 int indexID = GetAttribute( "id");
nuclear@0 1487 std::string id = mReader->getAttributeValue( indexID);
nuclear@0 1488
nuclear@0 1489 // TODO: (thom) support SIDs
nuclear@0 1490 // ai_assert( TestAttribute( "sid") == -1);
nuclear@0 1491
nuclear@0 1492 // create a mesh and store it in the library under its ID
nuclear@0 1493 Mesh* mesh = new Mesh;
nuclear@0 1494 mMeshLibrary[id] = mesh;
nuclear@0 1495
nuclear@0 1496 // read on from there
nuclear@0 1497 ReadGeometry( mesh);
nuclear@0 1498 } else
nuclear@0 1499 {
nuclear@0 1500 // ignore the rest
nuclear@0 1501 SkipElement();
nuclear@0 1502 }
nuclear@0 1503 }
nuclear@0 1504 else if( mReader->getNodeType() == irr::io::EXN_ELEMENT_END)
nuclear@0 1505 {
nuclear@0 1506 if( strcmp( mReader->getNodeName(), "library_geometries") != 0)
nuclear@0 1507 ThrowException( "Expected end of <library_geometries> element.");
nuclear@0 1508
nuclear@0 1509 break;
nuclear@0 1510 }
nuclear@0 1511 }
nuclear@0 1512 }
nuclear@0 1513
nuclear@0 1514 // ------------------------------------------------------------------------------------------------
nuclear@0 1515 // Reads a geometry from the geometry library.
nuclear@0 1516 void ColladaParser::ReadGeometry( Collada::Mesh* pMesh)
nuclear@0 1517 {
nuclear@0 1518 if( mReader->isEmptyElement())
nuclear@0 1519 return;
nuclear@0 1520
nuclear@0 1521 while( mReader->read())
nuclear@0 1522 {
nuclear@0 1523 if( mReader->getNodeType() == irr::io::EXN_ELEMENT)
nuclear@0 1524 {
nuclear@0 1525 if( IsElement( "mesh"))
nuclear@0 1526 {
nuclear@0 1527 // read on from there
nuclear@0 1528 ReadMesh( pMesh);
nuclear@0 1529 } else
nuclear@0 1530 {
nuclear@0 1531 // ignore the rest
nuclear@0 1532 SkipElement();
nuclear@0 1533 }
nuclear@0 1534 }
nuclear@0 1535 else if( mReader->getNodeType() == irr::io::EXN_ELEMENT_END)
nuclear@0 1536 {
nuclear@0 1537 if( strcmp( mReader->getNodeName(), "geometry") != 0)
nuclear@0 1538 ThrowException( "Expected end of <geometry> element.");
nuclear@0 1539
nuclear@0 1540 break;
nuclear@0 1541 }
nuclear@0 1542 }
nuclear@0 1543 }
nuclear@0 1544
nuclear@0 1545 // ------------------------------------------------------------------------------------------------
nuclear@0 1546 // Reads a mesh from the geometry library
nuclear@0 1547 void ColladaParser::ReadMesh( Mesh* pMesh)
nuclear@0 1548 {
nuclear@0 1549 if( mReader->isEmptyElement())
nuclear@0 1550 return;
nuclear@0 1551
nuclear@0 1552 while( mReader->read())
nuclear@0 1553 {
nuclear@0 1554 if( mReader->getNodeType() == irr::io::EXN_ELEMENT)
nuclear@0 1555 {
nuclear@0 1556 if( IsElement( "source"))
nuclear@0 1557 {
nuclear@0 1558 // we have professionals dealing with this
nuclear@0 1559 ReadSource();
nuclear@0 1560 }
nuclear@0 1561 else if( IsElement( "vertices"))
nuclear@0 1562 {
nuclear@0 1563 // read per-vertex mesh data
nuclear@0 1564 ReadVertexData( pMesh);
nuclear@0 1565 }
nuclear@0 1566 else if( IsElement( "triangles") || IsElement( "lines") || IsElement( "linestrips")
nuclear@0 1567 || IsElement( "polygons") || IsElement( "polylist") || IsElement( "trifans") || IsElement( "tristrips"))
nuclear@0 1568 {
nuclear@0 1569 // read per-index mesh data and faces setup
nuclear@0 1570 ReadIndexData( pMesh);
nuclear@0 1571 } else
nuclear@0 1572 {
nuclear@0 1573 // ignore the rest
nuclear@0 1574 SkipElement();
nuclear@0 1575 }
nuclear@0 1576 }
nuclear@0 1577 else if( mReader->getNodeType() == irr::io::EXN_ELEMENT_END)
nuclear@0 1578 {
nuclear@0 1579 if( strcmp( mReader->getNodeName(), "technique_common") == 0)
nuclear@0 1580 {
nuclear@0 1581 // end of another meaningless element - read over it
nuclear@0 1582 }
nuclear@0 1583 else if( strcmp( mReader->getNodeName(), "mesh") == 0)
nuclear@0 1584 {
nuclear@0 1585 // end of <mesh> element - we're done here
nuclear@0 1586 break;
nuclear@0 1587 } else
nuclear@0 1588 {
nuclear@0 1589 // everything else should be punished
nuclear@0 1590 ThrowException( "Expected end of <mesh> element.");
nuclear@0 1591 }
nuclear@0 1592 }
nuclear@0 1593 }
nuclear@0 1594 }
nuclear@0 1595
nuclear@0 1596 // ------------------------------------------------------------------------------------------------
nuclear@0 1597 // Reads a source element
nuclear@0 1598 void ColladaParser::ReadSource()
nuclear@0 1599 {
nuclear@0 1600 int indexID = GetAttribute( "id");
nuclear@0 1601 std::string sourceID = mReader->getAttributeValue( indexID);
nuclear@0 1602
nuclear@0 1603 while( mReader->read())
nuclear@0 1604 {
nuclear@0 1605 if( mReader->getNodeType() == irr::io::EXN_ELEMENT)
nuclear@0 1606 {
nuclear@0 1607 if( IsElement( "float_array") || IsElement( "IDREF_array") || IsElement( "Name_array"))
nuclear@0 1608 {
nuclear@0 1609 ReadDataArray();
nuclear@0 1610 }
nuclear@0 1611 else if( IsElement( "technique_common"))
nuclear@0 1612 {
nuclear@0 1613 // I don't care for your profiles
nuclear@0 1614 }
nuclear@0 1615 else if( IsElement( "accessor"))
nuclear@0 1616 {
nuclear@0 1617 ReadAccessor( sourceID);
nuclear@0 1618 } else
nuclear@0 1619 {
nuclear@0 1620 // ignore the rest
nuclear@0 1621 SkipElement();
nuclear@0 1622 }
nuclear@0 1623 }
nuclear@0 1624 else if( mReader->getNodeType() == irr::io::EXN_ELEMENT_END)
nuclear@0 1625 {
nuclear@0 1626 if( strcmp( mReader->getNodeName(), "source") == 0)
nuclear@0 1627 {
nuclear@0 1628 // end of <source> - we're done
nuclear@0 1629 break;
nuclear@0 1630 }
nuclear@0 1631 else if( strcmp( mReader->getNodeName(), "technique_common") == 0)
nuclear@0 1632 {
nuclear@0 1633 // end of another meaningless element - read over it
nuclear@0 1634 } else
nuclear@0 1635 {
nuclear@0 1636 // everything else should be punished
nuclear@0 1637 ThrowException( "Expected end of <source> element.");
nuclear@0 1638 }
nuclear@0 1639 }
nuclear@0 1640 }
nuclear@0 1641 }
nuclear@0 1642
nuclear@0 1643 // ------------------------------------------------------------------------------------------------
nuclear@0 1644 // Reads a data array holding a number of floats, and stores it in the global library
nuclear@0 1645 void ColladaParser::ReadDataArray()
nuclear@0 1646 {
nuclear@0 1647 std::string elmName = mReader->getNodeName();
nuclear@0 1648 bool isStringArray = (elmName == "IDREF_array" || elmName == "Name_array");
nuclear@0 1649 bool isEmptyElement = mReader->isEmptyElement();
nuclear@0 1650
nuclear@0 1651 // read attributes
nuclear@0 1652 int indexID = GetAttribute( "id");
nuclear@0 1653 std::string id = mReader->getAttributeValue( indexID);
nuclear@0 1654 int indexCount = GetAttribute( "count");
nuclear@0 1655 unsigned int count = (unsigned int) mReader->getAttributeValueAsInt( indexCount);
nuclear@0 1656 if (count == 0) { return; } // some exporters write empty data arrays with count="0"
nuclear@0 1657 const char* content = TestTextContent();
nuclear@0 1658
nuclear@0 1659 // read values and store inside an array in the data library
nuclear@0 1660 mDataLibrary[id] = Data();
nuclear@0 1661 Data& data = mDataLibrary[id];
nuclear@0 1662 data.mIsStringArray = isStringArray;
nuclear@0 1663
nuclear@0 1664 // some exporters write empty data arrays, but we need to conserve them anyways because others might reference them
nuclear@0 1665 if (content)
nuclear@0 1666 {
nuclear@0 1667 if( isStringArray)
nuclear@0 1668 {
nuclear@0 1669 data.mStrings.reserve( count);
nuclear@0 1670 std::string s;
nuclear@0 1671
nuclear@0 1672 for( unsigned int a = 0; a < count; a++)
nuclear@0 1673 {
nuclear@0 1674 if( *content == 0)
nuclear@0 1675 ThrowException( "Expected more values while reading IDREF_array contents.");
nuclear@0 1676
nuclear@0 1677 s.clear();
nuclear@0 1678 while( !IsSpaceOrNewLine( *content))
nuclear@0 1679 s += *content++;
nuclear@0 1680 data.mStrings.push_back( s);
nuclear@0 1681
nuclear@0 1682 SkipSpacesAndLineEnd( &content);
nuclear@0 1683 }
nuclear@0 1684 } else
nuclear@0 1685 {
nuclear@0 1686 data.mValues.reserve( count);
nuclear@0 1687
nuclear@0 1688 for( unsigned int a = 0; a < count; a++)
nuclear@0 1689 {
nuclear@0 1690 if( *content == 0)
nuclear@0 1691 ThrowException( "Expected more values while reading float_array contents.");
nuclear@0 1692
nuclear@0 1693 float value;
nuclear@0 1694 // read a number
nuclear@0 1695 content = fast_atoreal_move<float>( content, value);
nuclear@0 1696 data.mValues.push_back( value);
nuclear@0 1697 // skip whitespace after it
nuclear@0 1698 SkipSpacesAndLineEnd( &content);
nuclear@0 1699 }
nuclear@0 1700 }
nuclear@0 1701 }
nuclear@0 1702
nuclear@0 1703 // test for closing tag
nuclear@0 1704 if( !isEmptyElement )
nuclear@0 1705 TestClosing( elmName.c_str());
nuclear@0 1706 }
nuclear@0 1707
nuclear@0 1708 // ------------------------------------------------------------------------------------------------
nuclear@0 1709 // Reads an accessor and stores it in the global library
nuclear@0 1710 void ColladaParser::ReadAccessor( const std::string& pID)
nuclear@0 1711 {
nuclear@0 1712 // read accessor attributes
nuclear@0 1713 int attrSource = GetAttribute( "source");
nuclear@0 1714 const char* source = mReader->getAttributeValue( attrSource);
nuclear@0 1715 if( source[0] != '#')
nuclear@0 1716 ThrowException( boost::str( boost::format( "Unknown reference format in url \"%s\" in source attribute of <accessor> element.") % source));
nuclear@0 1717 int attrCount = GetAttribute( "count");
nuclear@0 1718 unsigned int count = (unsigned int) mReader->getAttributeValueAsInt( attrCount);
nuclear@0 1719 int attrOffset = TestAttribute( "offset");
nuclear@0 1720 unsigned int offset = 0;
nuclear@0 1721 if( attrOffset > -1)
nuclear@0 1722 offset = (unsigned int) mReader->getAttributeValueAsInt( attrOffset);
nuclear@0 1723 int attrStride = TestAttribute( "stride");
nuclear@0 1724 unsigned int stride = 1;
nuclear@0 1725 if( attrStride > -1)
nuclear@0 1726 stride = (unsigned int) mReader->getAttributeValueAsInt( attrStride);
nuclear@0 1727
nuclear@0 1728 // store in the library under the given ID
nuclear@0 1729 mAccessorLibrary[pID] = Accessor();
nuclear@0 1730 Accessor& acc = mAccessorLibrary[pID];
nuclear@0 1731 acc.mCount = count;
nuclear@0 1732 acc.mOffset = offset;
nuclear@0 1733 acc.mStride = stride;
nuclear@0 1734 acc.mSource = source+1; // ignore the leading '#'
nuclear@0 1735 acc.mSize = 0; // gets incremented with every param
nuclear@0 1736
nuclear@0 1737 // and read the components
nuclear@0 1738 while( mReader->read())
nuclear@0 1739 {
nuclear@0 1740 if( mReader->getNodeType() == irr::io::EXN_ELEMENT)
nuclear@0 1741 {
nuclear@0 1742 if( IsElement( "param"))
nuclear@0 1743 {
nuclear@0 1744 // read data param
nuclear@0 1745 int attrName = TestAttribute( "name");
nuclear@0 1746 std::string name;
nuclear@0 1747 if( attrName > -1)
nuclear@0 1748 {
nuclear@0 1749 name = mReader->getAttributeValue( attrName);
nuclear@0 1750
nuclear@0 1751 // analyse for common type components and store it's sub-offset in the corresponding field
nuclear@0 1752
nuclear@0 1753 /* Cartesian coordinates */
nuclear@0 1754 if( name == "X") acc.mSubOffset[0] = acc.mParams.size();
nuclear@0 1755 else if( name == "Y") acc.mSubOffset[1] = acc.mParams.size();
nuclear@0 1756 else if( name == "Z") acc.mSubOffset[2] = acc.mParams.size();
nuclear@0 1757
nuclear@0 1758 /* RGBA colors */
nuclear@0 1759 else if( name == "R") acc.mSubOffset[0] = acc.mParams.size();
nuclear@0 1760 else if( name == "G") acc.mSubOffset[1] = acc.mParams.size();
nuclear@0 1761 else if( name == "B") acc.mSubOffset[2] = acc.mParams.size();
nuclear@0 1762 else if( name == "A") acc.mSubOffset[3] = acc.mParams.size();
nuclear@0 1763
nuclear@0 1764 /* UVWQ (STPQ) texture coordinates */
nuclear@0 1765 else if( name == "S") acc.mSubOffset[0] = acc.mParams.size();
nuclear@0 1766 else if( name == "T") acc.mSubOffset[1] = acc.mParams.size();
nuclear@0 1767 else if( name == "P") acc.mSubOffset[2] = acc.mParams.size();
nuclear@0 1768 // else if( name == "Q") acc.mSubOffset[3] = acc.mParams.size();
nuclear@0 1769 /* 4D uv coordinates are not supported in Assimp */
nuclear@0 1770
nuclear@0 1771 /* Generic extra data, interpreted as UV data, too*/
nuclear@0 1772 else if( name == "U") acc.mSubOffset[0] = acc.mParams.size();
nuclear@0 1773 else if( name == "V") acc.mSubOffset[1] = acc.mParams.size();
nuclear@0 1774 //else
nuclear@0 1775 // DefaultLogger::get()->warn( boost::str( boost::format( "Unknown accessor parameter \"%s\". Ignoring data channel.") % name));
nuclear@0 1776 }
nuclear@0 1777
nuclear@0 1778 // read data type
nuclear@0 1779 int attrType = TestAttribute( "type");
nuclear@0 1780 if( attrType > -1)
nuclear@0 1781 {
nuclear@0 1782 // for the moment we only distinguish between a 4x4 matrix and anything else.
nuclear@0 1783 // TODO: (thom) I don't have a spec here at work. Check if there are other multi-value types
nuclear@0 1784 // which should be tested for here.
nuclear@0 1785 std::string type = mReader->getAttributeValue( attrType);
nuclear@0 1786 if( type == "float4x4")
nuclear@0 1787 acc.mSize += 16;
nuclear@0 1788 else
nuclear@0 1789 acc.mSize += 1;
nuclear@0 1790 }
nuclear@0 1791
nuclear@0 1792 acc.mParams.push_back( name);
nuclear@0 1793
nuclear@0 1794 // skip remaining stuff of this element, if any
nuclear@0 1795 SkipElement();
nuclear@0 1796 } else
nuclear@0 1797 {
nuclear@0 1798 ThrowException( boost::str( boost::format( "Unexpected sub element <%s> in tag <accessor>") % mReader->getNodeName()));
nuclear@0 1799 }
nuclear@0 1800 }
nuclear@0 1801 else if( mReader->getNodeType() == irr::io::EXN_ELEMENT_END)
nuclear@0 1802 {
nuclear@0 1803 if( strcmp( mReader->getNodeName(), "accessor") != 0)
nuclear@0 1804 ThrowException( "Expected end of <accessor> element.");
nuclear@0 1805 break;
nuclear@0 1806 }
nuclear@0 1807 }
nuclear@0 1808 }
nuclear@0 1809
nuclear@0 1810 // ------------------------------------------------------------------------------------------------
nuclear@0 1811 // Reads input declarations of per-vertex mesh data into the given mesh
nuclear@0 1812 void ColladaParser::ReadVertexData( Mesh* pMesh)
nuclear@0 1813 {
nuclear@0 1814 // extract the ID of the <vertices> element. Not that we care, but to catch strange referencing schemes we should warn about
nuclear@0 1815 int attrID= GetAttribute( "id");
nuclear@0 1816 pMesh->mVertexID = mReader->getAttributeValue( attrID);
nuclear@0 1817
nuclear@0 1818 // a number of <input> elements
nuclear@0 1819 while( mReader->read())
nuclear@0 1820 {
nuclear@0 1821 if( mReader->getNodeType() == irr::io::EXN_ELEMENT)
nuclear@0 1822 {
nuclear@0 1823 if( IsElement( "input"))
nuclear@0 1824 {
nuclear@0 1825 ReadInputChannel( pMesh->mPerVertexData);
nuclear@0 1826 } else
nuclear@0 1827 {
nuclear@0 1828 ThrowException( boost::str( boost::format( "Unexpected sub element <%s> in tag <vertices>") % mReader->getNodeName()));
nuclear@0 1829 }
nuclear@0 1830 }
nuclear@0 1831 else if( mReader->getNodeType() == irr::io::EXN_ELEMENT_END)
nuclear@0 1832 {
nuclear@0 1833 if( strcmp( mReader->getNodeName(), "vertices") != 0)
nuclear@0 1834 ThrowException( "Expected end of <vertices> element.");
nuclear@0 1835
nuclear@0 1836 break;
nuclear@0 1837 }
nuclear@0 1838 }
nuclear@0 1839 }
nuclear@0 1840
nuclear@0 1841 // ------------------------------------------------------------------------------------------------
nuclear@0 1842 // Reads input declarations of per-index mesh data into the given mesh
nuclear@0 1843 void ColladaParser::ReadIndexData( Mesh* pMesh)
nuclear@0 1844 {
nuclear@0 1845 std::vector<size_t> vcount;
nuclear@0 1846 std::vector<InputChannel> perIndexData;
nuclear@0 1847
nuclear@0 1848 // read primitive count from the attribute
nuclear@0 1849 int attrCount = GetAttribute( "count");
nuclear@0 1850 size_t numPrimitives = (size_t) mReader->getAttributeValueAsInt( attrCount);
nuclear@0 1851
nuclear@0 1852 // material subgroup
nuclear@0 1853 int attrMaterial = TestAttribute( "material");
nuclear@0 1854 SubMesh subgroup;
nuclear@0 1855 if( attrMaterial > -1)
nuclear@0 1856 subgroup.mMaterial = mReader->getAttributeValue( attrMaterial);
nuclear@0 1857 subgroup.mNumFaces = numPrimitives;
nuclear@0 1858 pMesh->mSubMeshes.push_back( subgroup);
nuclear@0 1859
nuclear@0 1860 // distinguish between polys and triangles
nuclear@0 1861 std::string elementName = mReader->getNodeName();
nuclear@0 1862 PrimitiveType primType = Prim_Invalid;
nuclear@0 1863 if( IsElement( "lines"))
nuclear@0 1864 primType = Prim_Lines;
nuclear@0 1865 else if( IsElement( "linestrips"))
nuclear@0 1866 primType = Prim_LineStrip;
nuclear@0 1867 else if( IsElement( "polygons"))
nuclear@0 1868 primType = Prim_Polygon;
nuclear@0 1869 else if( IsElement( "polylist"))
nuclear@0 1870 primType = Prim_Polylist;
nuclear@0 1871 else if( IsElement( "triangles"))
nuclear@0 1872 primType = Prim_Triangles;
nuclear@0 1873 else if( IsElement( "trifans"))
nuclear@0 1874 primType = Prim_TriFans;
nuclear@0 1875 else if( IsElement( "tristrips"))
nuclear@0 1876 primType = Prim_TriStrips;
nuclear@0 1877
nuclear@0 1878 ai_assert( primType != Prim_Invalid);
nuclear@0 1879
nuclear@0 1880 // also a number of <input> elements, but in addition a <p> primitive collection and propably index counts for all primitives
nuclear@0 1881 while( mReader->read())
nuclear@0 1882 {
nuclear@0 1883 if( mReader->getNodeType() == irr::io::EXN_ELEMENT)
nuclear@0 1884 {
nuclear@0 1885 if( IsElement( "input"))
nuclear@0 1886 {
nuclear@0 1887 ReadInputChannel( perIndexData);
nuclear@0 1888 }
nuclear@0 1889 else if( IsElement( "vcount"))
nuclear@0 1890 {
nuclear@0 1891 if( !mReader->isEmptyElement())
nuclear@0 1892 {
nuclear@0 1893 if (numPrimitives) // It is possible to define a mesh without any primitives
nuclear@0 1894 {
nuclear@0 1895 // case <polylist> - specifies the number of indices for each polygon
nuclear@0 1896 const char* content = GetTextContent();
nuclear@0 1897 vcount.reserve( numPrimitives);
nuclear@0 1898 for( unsigned int a = 0; a < numPrimitives; a++)
nuclear@0 1899 {
nuclear@0 1900 if( *content == 0)
nuclear@0 1901 ThrowException( "Expected more values while reading <vcount> contents.");
nuclear@0 1902 // read a number
nuclear@0 1903 vcount.push_back( (size_t) strtoul10( content, &content));
nuclear@0 1904 // skip whitespace after it
nuclear@0 1905 SkipSpacesAndLineEnd( &content);
nuclear@0 1906 }
nuclear@0 1907 }
nuclear@0 1908
nuclear@0 1909 TestClosing( "vcount");
nuclear@0 1910 }
nuclear@0 1911 }
nuclear@0 1912 else if( IsElement( "p"))
nuclear@0 1913 {
nuclear@0 1914 if( !mReader->isEmptyElement())
nuclear@0 1915 {
nuclear@0 1916 // now here the actual fun starts - these are the indices to construct the mesh data from
nuclear@0 1917 ReadPrimitives( pMesh, perIndexData, numPrimitives, vcount, primType);
nuclear@0 1918 }
nuclear@0 1919 } else
nuclear@0 1920 {
nuclear@0 1921 ThrowException( boost::str( boost::format( "Unexpected sub element <%s> in tag <%s>") % mReader->getNodeName() % elementName));
nuclear@0 1922 }
nuclear@0 1923 }
nuclear@0 1924 else if( mReader->getNodeType() == irr::io::EXN_ELEMENT_END)
nuclear@0 1925 {
nuclear@0 1926 if( mReader->getNodeName() != elementName)
nuclear@0 1927 ThrowException( boost::str( boost::format( "Expected end of <%s> element.") % elementName));
nuclear@0 1928
nuclear@0 1929 break;
nuclear@0 1930 }
nuclear@0 1931 }
nuclear@0 1932 }
nuclear@0 1933
nuclear@0 1934 // ------------------------------------------------------------------------------------------------
nuclear@0 1935 // Reads a single input channel element and stores it in the given array, if valid
nuclear@0 1936 void ColladaParser::ReadInputChannel( std::vector<InputChannel>& poChannels)
nuclear@0 1937 {
nuclear@0 1938 InputChannel channel;
nuclear@0 1939
nuclear@0 1940 // read semantic
nuclear@0 1941 int attrSemantic = GetAttribute( "semantic");
nuclear@0 1942 std::string semantic = mReader->getAttributeValue( attrSemantic);
nuclear@0 1943 channel.mType = GetTypeForSemantic( semantic);
nuclear@0 1944
nuclear@0 1945 // read source
nuclear@0 1946 int attrSource = GetAttribute( "source");
nuclear@0 1947 const char* source = mReader->getAttributeValue( attrSource);
nuclear@0 1948 if( source[0] != '#')
nuclear@0 1949 ThrowException( boost::str( boost::format( "Unknown reference format in url \"%s\" in source attribute of <input> element.") % source));
nuclear@0 1950 channel.mAccessor = source+1; // skipping the leading #, hopefully the remaining text is the accessor ID only
nuclear@0 1951
nuclear@0 1952 // read index offset, if per-index <input>
nuclear@0 1953 int attrOffset = TestAttribute( "offset");
nuclear@0 1954 if( attrOffset > -1)
nuclear@0 1955 channel.mOffset = mReader->getAttributeValueAsInt( attrOffset);
nuclear@0 1956
nuclear@0 1957 // read set if texture coordinates
nuclear@0 1958 if(channel.mType == IT_Texcoord || channel.mType == IT_Color){
nuclear@0 1959 int attrSet = TestAttribute("set");
nuclear@0 1960 if(attrSet > -1){
nuclear@0 1961 attrSet = mReader->getAttributeValueAsInt( attrSet);
nuclear@0 1962 if(attrSet < 0)
nuclear@0 1963 ThrowException( boost::str( boost::format( "Invalid index \"%i\" in set attribute of <input> element") % (attrSet)));
nuclear@0 1964
nuclear@0 1965 channel.mIndex = attrSet;
nuclear@0 1966 }
nuclear@0 1967 }
nuclear@0 1968
nuclear@0 1969 // store, if valid type
nuclear@0 1970 if( channel.mType != IT_Invalid)
nuclear@0 1971 poChannels.push_back( channel);
nuclear@0 1972
nuclear@0 1973 // skip remaining stuff of this element, if any
nuclear@0 1974 SkipElement();
nuclear@0 1975 }
nuclear@0 1976
nuclear@0 1977 // ------------------------------------------------------------------------------------------------
nuclear@0 1978 // Reads a <p> primitive index list and assembles the mesh data into the given mesh
nuclear@0 1979 void ColladaParser::ReadPrimitives( Mesh* pMesh, std::vector<InputChannel>& pPerIndexChannels,
nuclear@0 1980 size_t pNumPrimitives, const std::vector<size_t>& pVCount, PrimitiveType pPrimType)
nuclear@0 1981 {
nuclear@0 1982 // determine number of indices coming per vertex
nuclear@0 1983 // find the offset index for all per-vertex channels
nuclear@0 1984 size_t numOffsets = 1;
nuclear@0 1985 size_t perVertexOffset = SIZE_MAX; // invalid value
nuclear@0 1986 BOOST_FOREACH( const InputChannel& channel, pPerIndexChannels)
nuclear@0 1987 {
nuclear@0 1988 numOffsets = std::max( numOffsets, channel.mOffset+1);
nuclear@0 1989 if( channel.mType == IT_Vertex)
nuclear@0 1990 perVertexOffset = channel.mOffset;
nuclear@0 1991 }
nuclear@0 1992
nuclear@0 1993 // determine the expected number of indices
nuclear@0 1994 size_t expectedPointCount = 0;
nuclear@0 1995 switch( pPrimType)
nuclear@0 1996 {
nuclear@0 1997 case Prim_Polylist:
nuclear@0 1998 {
nuclear@0 1999 BOOST_FOREACH( size_t i, pVCount)
nuclear@0 2000 expectedPointCount += i;
nuclear@0 2001 break;
nuclear@0 2002 }
nuclear@0 2003 case Prim_Lines:
nuclear@0 2004 expectedPointCount = 2 * pNumPrimitives;
nuclear@0 2005 break;
nuclear@0 2006 case Prim_Triangles:
nuclear@0 2007 expectedPointCount = 3 * pNumPrimitives;
nuclear@0 2008 break;
nuclear@0 2009 default:
nuclear@0 2010 // other primitive types don't state the index count upfront... we need to guess
nuclear@0 2011 break;
nuclear@0 2012 }
nuclear@0 2013
nuclear@0 2014 // and read all indices into a temporary array
nuclear@0 2015 std::vector<size_t> indices;
nuclear@0 2016 if( expectedPointCount > 0)
nuclear@0 2017 indices.reserve( expectedPointCount * numOffsets);
nuclear@0 2018
nuclear@0 2019 if (pNumPrimitives > 0) // It is possible to not contain any indicies
nuclear@0 2020 {
nuclear@0 2021 const char* content = GetTextContent();
nuclear@0 2022 while( *content != 0)
nuclear@0 2023 {
nuclear@0 2024 // read a value.
nuclear@0 2025 // Hack: (thom) Some exporters put negative indices sometimes. We just try to carry on anyways.
nuclear@0 2026 int value = std::max( 0, strtol10( content, &content));
nuclear@0 2027 indices.push_back( size_t( value));
nuclear@0 2028 // skip whitespace after it
nuclear@0 2029 SkipSpacesAndLineEnd( &content);
nuclear@0 2030 }
nuclear@0 2031 }
nuclear@0 2032
nuclear@0 2033 // complain if the index count doesn't fit
nuclear@0 2034 if( expectedPointCount > 0 && indices.size() != expectedPointCount * numOffsets)
nuclear@0 2035 ThrowException( "Expected different index count in <p> element.");
nuclear@0 2036 else if( expectedPointCount == 0 && (indices.size() % numOffsets) != 0)
nuclear@0 2037 ThrowException( "Expected different index count in <p> element.");
nuclear@0 2038
nuclear@0 2039 // find the data for all sources
nuclear@0 2040 for( std::vector<InputChannel>::iterator it = pMesh->mPerVertexData.begin(); it != pMesh->mPerVertexData.end(); ++it)
nuclear@0 2041 {
nuclear@0 2042 InputChannel& input = *it;
nuclear@0 2043 if( input.mResolved)
nuclear@0 2044 continue;
nuclear@0 2045
nuclear@0 2046 // find accessor
nuclear@0 2047 input.mResolved = &ResolveLibraryReference( mAccessorLibrary, input.mAccessor);
nuclear@0 2048 // resolve accessor's data pointer as well, if neccessary
nuclear@0 2049 const Accessor* acc = input.mResolved;
nuclear@0 2050 if( !acc->mData)
nuclear@0 2051 acc->mData = &ResolveLibraryReference( mDataLibrary, acc->mSource);
nuclear@0 2052 }
nuclear@0 2053 // and the same for the per-index channels
nuclear@0 2054 for( std::vector<InputChannel>::iterator it = pPerIndexChannels.begin(); it != pPerIndexChannels.end(); ++it)
nuclear@0 2055 {
nuclear@0 2056 InputChannel& input = *it;
nuclear@0 2057 if( input.mResolved)
nuclear@0 2058 continue;
nuclear@0 2059
nuclear@0 2060 // ignore vertex pointer, it doesn't refer to an accessor
nuclear@0 2061 if( input.mType == IT_Vertex)
nuclear@0 2062 {
nuclear@0 2063 // warn if the vertex channel does not refer to the <vertices> element in the same mesh
nuclear@0 2064 if( input.mAccessor != pMesh->mVertexID)
nuclear@0 2065 ThrowException( "Unsupported vertex referencing scheme.");
nuclear@0 2066 continue;
nuclear@0 2067 }
nuclear@0 2068
nuclear@0 2069 // find accessor
nuclear@0 2070 input.mResolved = &ResolveLibraryReference( mAccessorLibrary, input.mAccessor);
nuclear@0 2071 // resolve accessor's data pointer as well, if neccessary
nuclear@0 2072 const Accessor* acc = input.mResolved;
nuclear@0 2073 if( !acc->mData)
nuclear@0 2074 acc->mData = &ResolveLibraryReference( mDataLibrary, acc->mSource);
nuclear@0 2075 }
nuclear@0 2076
nuclear@0 2077
nuclear@0 2078 // now assemble vertex data according to those indices
nuclear@0 2079 std::vector<size_t>::const_iterator idx = indices.begin();
nuclear@0 2080
nuclear@0 2081 // For continued primitives, the given count does not come all in one <p>, but only one primitive per <p>
nuclear@0 2082 size_t numPrimitives = pNumPrimitives;
nuclear@0 2083 if( pPrimType == Prim_TriFans || pPrimType == Prim_Polygon)
nuclear@0 2084 numPrimitives = 1;
nuclear@0 2085
nuclear@0 2086 pMesh->mFaceSize.reserve( numPrimitives);
nuclear@0 2087 pMesh->mFacePosIndices.reserve( indices.size() / numOffsets);
nuclear@0 2088
nuclear@0 2089 for( size_t a = 0; a < numPrimitives; a++)
nuclear@0 2090 {
nuclear@0 2091 // determine number of points for this primitive
nuclear@0 2092 size_t numPoints = 0;
nuclear@0 2093 switch( pPrimType)
nuclear@0 2094 {
nuclear@0 2095 case Prim_Lines:
nuclear@0 2096 numPoints = 2;
nuclear@0 2097 break;
nuclear@0 2098 case Prim_Triangles:
nuclear@0 2099 numPoints = 3;
nuclear@0 2100 break;
nuclear@0 2101 case Prim_Polylist:
nuclear@0 2102 numPoints = pVCount[a];
nuclear@0 2103 break;
nuclear@0 2104 case Prim_TriFans:
nuclear@0 2105 case Prim_Polygon:
nuclear@0 2106 numPoints = indices.size() / numOffsets;
nuclear@0 2107 break;
nuclear@0 2108 default:
nuclear@0 2109 // LineStrip and TriStrip not supported due to expected index unmangling
nuclear@0 2110 ThrowException( "Unsupported primitive type.");
nuclear@0 2111 break;
nuclear@0 2112 }
nuclear@0 2113
nuclear@0 2114 // store the face size to later reconstruct the face from
nuclear@0 2115 pMesh->mFaceSize.push_back( numPoints);
nuclear@0 2116
nuclear@0 2117 // gather that number of vertices
nuclear@0 2118 for( size_t b = 0; b < numPoints; b++)
nuclear@0 2119 {
nuclear@0 2120 // read all indices for this vertex. Yes, in a hacky local array
nuclear@0 2121 ai_assert( numOffsets < 20 && perVertexOffset < 20);
nuclear@0 2122 size_t vindex[20];
nuclear@0 2123 for( size_t offsets = 0; offsets < numOffsets; ++offsets)
nuclear@0 2124 vindex[offsets] = *idx++;
nuclear@0 2125
nuclear@0 2126 // extract per-vertex channels using the global per-vertex offset
nuclear@0 2127 for( std::vector<InputChannel>::iterator it = pMesh->mPerVertexData.begin(); it != pMesh->mPerVertexData.end(); ++it)
nuclear@0 2128 ExtractDataObjectFromChannel( *it, vindex[perVertexOffset], pMesh);
nuclear@0 2129 // and extract per-index channels using there specified offset
nuclear@0 2130 for( std::vector<InputChannel>::iterator it = pPerIndexChannels.begin(); it != pPerIndexChannels.end(); ++it)
nuclear@0 2131 ExtractDataObjectFromChannel( *it, vindex[it->mOffset], pMesh);
nuclear@0 2132
nuclear@0 2133 // store the vertex-data index for later assignment of bone vertex weights
nuclear@0 2134 pMesh->mFacePosIndices.push_back( vindex[perVertexOffset]);
nuclear@0 2135 }
nuclear@0 2136 }
nuclear@0 2137
nuclear@0 2138
nuclear@0 2139 // if I ever get my hands on that guy who invented this steaming pile of indirection...
nuclear@0 2140 TestClosing( "p");
nuclear@0 2141 }
nuclear@0 2142
nuclear@0 2143 // ------------------------------------------------------------------------------------------------
nuclear@0 2144 // Extracts a single object from an input channel and stores it in the appropriate mesh data array
nuclear@0 2145 void ColladaParser::ExtractDataObjectFromChannel( const InputChannel& pInput, size_t pLocalIndex, Mesh* pMesh)
nuclear@0 2146 {
nuclear@0 2147 // ignore vertex referrer - we handle them that separate
nuclear@0 2148 if( pInput.mType == IT_Vertex)
nuclear@0 2149 return;
nuclear@0 2150
nuclear@0 2151 const Accessor& acc = *pInput.mResolved;
nuclear@0 2152 if( pLocalIndex >= acc.mCount)
nuclear@0 2153 ThrowException( boost::str( boost::format( "Invalid data index (%d/%d) in primitive specification") % pLocalIndex % acc.mCount));
nuclear@0 2154
nuclear@0 2155 // get a pointer to the start of the data object referred to by the accessor and the local index
nuclear@0 2156 const float* dataObject = &(acc.mData->mValues[0]) + acc.mOffset + pLocalIndex* acc.mStride;
nuclear@0 2157
nuclear@0 2158 // assemble according to the accessors component sub-offset list. We don't care, yet,
nuclear@0 2159 // what kind of object exactly we're extracting here
nuclear@0 2160 float obj[4];
nuclear@0 2161 for( size_t c = 0; c < 4; ++c)
nuclear@0 2162 obj[c] = dataObject[acc.mSubOffset[c]];
nuclear@0 2163
nuclear@0 2164 // now we reinterpret it according to the type we're reading here
nuclear@0 2165 switch( pInput.mType)
nuclear@0 2166 {
nuclear@0 2167 case IT_Position: // ignore all position streams except 0 - there can be only one position
nuclear@0 2168 if( pInput.mIndex == 0)
nuclear@0 2169 pMesh->mPositions.push_back( aiVector3D( obj[0], obj[1], obj[2]));
nuclear@0 2170 else
nuclear@0 2171 DefaultLogger::get()->error("Collada: just one vertex position stream supported");
nuclear@0 2172 break;
nuclear@0 2173 case IT_Normal:
nuclear@0 2174 // pad to current vertex count if necessary
nuclear@0 2175 if( pMesh->mNormals.size() < pMesh->mPositions.size()-1)
nuclear@0 2176 pMesh->mNormals.insert( pMesh->mNormals.end(), pMesh->mPositions.size() - pMesh->mNormals.size() - 1, aiVector3D( 0, 1, 0));
nuclear@0 2177
nuclear@0 2178 // ignore all normal streams except 0 - there can be only one normal
nuclear@0 2179 if( pInput.mIndex == 0)
nuclear@0 2180 pMesh->mNormals.push_back( aiVector3D( obj[0], obj[1], obj[2]));
nuclear@0 2181 else
nuclear@0 2182 DefaultLogger::get()->error("Collada: just one vertex normal stream supported");
nuclear@0 2183 break;
nuclear@0 2184 case IT_Tangent:
nuclear@0 2185 // pad to current vertex count if necessary
nuclear@0 2186 if( pMesh->mTangents.size() < pMesh->mPositions.size()-1)
nuclear@0 2187 pMesh->mTangents.insert( pMesh->mTangents.end(), pMesh->mPositions.size() - pMesh->mTangents.size() - 1, aiVector3D( 1, 0, 0));
nuclear@0 2188
nuclear@0 2189 // ignore all tangent streams except 0 - there can be only one tangent
nuclear@0 2190 if( pInput.mIndex == 0)
nuclear@0 2191 pMesh->mTangents.push_back( aiVector3D( obj[0], obj[1], obj[2]));
nuclear@0 2192 else
nuclear@0 2193 DefaultLogger::get()->error("Collada: just one vertex tangent stream supported");
nuclear@0 2194 break;
nuclear@0 2195 case IT_Bitangent:
nuclear@0 2196 // pad to current vertex count if necessary
nuclear@0 2197 if( pMesh->mBitangents.size() < pMesh->mPositions.size()-1)
nuclear@0 2198 pMesh->mBitangents.insert( pMesh->mBitangents.end(), pMesh->mPositions.size() - pMesh->mBitangents.size() - 1, aiVector3D( 0, 0, 1));
nuclear@0 2199
nuclear@0 2200 // ignore all bitangent streams except 0 - there can be only one bitangent
nuclear@0 2201 if( pInput.mIndex == 0)
nuclear@0 2202 pMesh->mBitangents.push_back( aiVector3D( obj[0], obj[1], obj[2]));
nuclear@0 2203 else
nuclear@0 2204 DefaultLogger::get()->error("Collada: just one vertex bitangent stream supported");
nuclear@0 2205 break;
nuclear@0 2206 case IT_Texcoord:
nuclear@0 2207 // up to 4 texture coord sets are fine, ignore the others
nuclear@0 2208 if( pInput.mIndex < AI_MAX_NUMBER_OF_TEXTURECOORDS)
nuclear@0 2209 {
nuclear@0 2210 // pad to current vertex count if necessary
nuclear@0 2211 if( pMesh->mTexCoords[pInput.mIndex].size() < pMesh->mPositions.size()-1)
nuclear@0 2212 pMesh->mTexCoords[pInput.mIndex].insert( pMesh->mTexCoords[pInput.mIndex].end(),
nuclear@0 2213 pMesh->mPositions.size() - pMesh->mTexCoords[pInput.mIndex].size() - 1, aiVector3D( 0, 0, 0));
nuclear@0 2214
nuclear@0 2215 pMesh->mTexCoords[pInput.mIndex].push_back( aiVector3D( obj[0], obj[1], obj[2]));
nuclear@0 2216 if (0 != acc.mSubOffset[2] || 0 != acc.mSubOffset[3]) /* hack ... consider cleaner solution */
nuclear@0 2217 pMesh->mNumUVComponents[pInput.mIndex]=3;
nuclear@0 2218 } else
nuclear@0 2219 {
nuclear@0 2220 DefaultLogger::get()->error("Collada: too many texture coordinate sets. Skipping.");
nuclear@0 2221 }
nuclear@0 2222 break;
nuclear@0 2223 case IT_Color:
nuclear@0 2224 // up to 4 color sets are fine, ignore the others
nuclear@0 2225 if( pInput.mIndex < AI_MAX_NUMBER_OF_COLOR_SETS)
nuclear@0 2226 {
nuclear@0 2227 // pad to current vertex count if necessary
nuclear@0 2228 if( pMesh->mColors[pInput.mIndex].size() < pMesh->mPositions.size()-1)
nuclear@0 2229 pMesh->mColors[pInput.mIndex].insert( pMesh->mColors[pInput.mIndex].end(),
nuclear@0 2230 pMesh->mPositions.size() - pMesh->mColors[pInput.mIndex].size() - 1, aiColor4D( 0, 0, 0, 1));
nuclear@0 2231
nuclear@0 2232 aiColor4D result(0, 0, 0, 1);
nuclear@0 2233 for (size_t i = 0; i < pInput.mResolved->mSize; ++i)
nuclear@0 2234 {
nuclear@0 2235 result[i] = obj[pInput.mResolved->mSubOffset[i]];
nuclear@0 2236 }
nuclear@0 2237 pMesh->mColors[pInput.mIndex].push_back(result);
nuclear@0 2238 } else
nuclear@0 2239 {
nuclear@0 2240 DefaultLogger::get()->error("Collada: too many vertex color sets. Skipping.");
nuclear@0 2241 }
nuclear@0 2242
nuclear@0 2243 break;
nuclear@0 2244 default:
nuclear@0 2245 // IT_Invalid and IT_Vertex
nuclear@0 2246 ai_assert(false && "shouldn't ever get here");
nuclear@0 2247 }
nuclear@0 2248 }
nuclear@0 2249
nuclear@0 2250 // ------------------------------------------------------------------------------------------------
nuclear@0 2251 // Reads the library of node hierarchies and scene parts
nuclear@0 2252 void ColladaParser::ReadSceneLibrary()
nuclear@0 2253 {
nuclear@0 2254 if( mReader->isEmptyElement())
nuclear@0 2255 return;
nuclear@0 2256
nuclear@0 2257 while( mReader->read())
nuclear@0 2258 {
nuclear@0 2259 if( mReader->getNodeType() == irr::io::EXN_ELEMENT)
nuclear@0 2260 {
nuclear@0 2261 // a visual scene - generate root node under its ID and let ReadNode() do the recursive work
nuclear@0 2262 if( IsElement( "visual_scene"))
nuclear@0 2263 {
nuclear@0 2264 // read ID. Is optional according to the spec, but how on earth should a scene_instance refer to it then?
nuclear@0 2265 int indexID = GetAttribute( "id");
nuclear@0 2266 const char* attrID = mReader->getAttributeValue( indexID);
nuclear@0 2267
nuclear@0 2268 // read name if given.
nuclear@0 2269 int indexName = TestAttribute( "name");
nuclear@0 2270 const char* attrName = "unnamed";
nuclear@0 2271 if( indexName > -1)
nuclear@0 2272 attrName = mReader->getAttributeValue( indexName);
nuclear@0 2273
nuclear@0 2274 // create a node and store it in the library under its ID
nuclear@0 2275 Node* node = new Node;
nuclear@0 2276 node->mID = attrID;
nuclear@0 2277 node->mName = attrName;
nuclear@0 2278 mNodeLibrary[node->mID] = node;
nuclear@0 2279
nuclear@0 2280 ReadSceneNode( node);
nuclear@0 2281 } else
nuclear@0 2282 {
nuclear@0 2283 // ignore the rest
nuclear@0 2284 SkipElement();
nuclear@0 2285 }
nuclear@0 2286 }
nuclear@0 2287 else if( mReader->getNodeType() == irr::io::EXN_ELEMENT_END)
nuclear@0 2288 {
nuclear@0 2289 if( strcmp( mReader->getNodeName(), "library_visual_scenes") == 0)
nuclear@0 2290 //ThrowException( "Expected end of \"library_visual_scenes\" element.");
nuclear@0 2291
nuclear@0 2292 break;
nuclear@0 2293 }
nuclear@0 2294 }
nuclear@0 2295 }
nuclear@0 2296
nuclear@0 2297 // ------------------------------------------------------------------------------------------------
nuclear@0 2298 // Reads a scene node's contents including children and stores it in the given node
nuclear@0 2299 void ColladaParser::ReadSceneNode( Node* pNode)
nuclear@0 2300 {
nuclear@0 2301 // quit immediately on <bla/> elements
nuclear@0 2302 if( mReader->isEmptyElement())
nuclear@0 2303 return;
nuclear@0 2304
nuclear@0 2305 while( mReader->read())
nuclear@0 2306 {
nuclear@0 2307 if( mReader->getNodeType() == irr::io::EXN_ELEMENT)
nuclear@0 2308 {
nuclear@0 2309 if( IsElement( "node"))
nuclear@0 2310 {
nuclear@0 2311 Node* child = new Node;
nuclear@0 2312 int attrID = TestAttribute( "id");
nuclear@0 2313 if( attrID > -1)
nuclear@0 2314 child->mID = mReader->getAttributeValue( attrID);
nuclear@0 2315 int attrSID = TestAttribute( "sid");
nuclear@0 2316 if( attrSID > -1)
nuclear@0 2317 child->mSID = mReader->getAttributeValue( attrSID);
nuclear@0 2318
nuclear@0 2319 int attrName = TestAttribute( "name");
nuclear@0 2320 if( attrName > -1)
nuclear@0 2321 child->mName = mReader->getAttributeValue( attrName);
nuclear@0 2322
nuclear@0 2323 // TODO: (thom) support SIDs
nuclear@0 2324 // ai_assert( TestAttribute( "sid") == -1);
nuclear@0 2325
nuclear@0 2326 if (pNode)
nuclear@0 2327 {
nuclear@0 2328 pNode->mChildren.push_back( child);
nuclear@0 2329 child->mParent = pNode;
nuclear@0 2330 }
nuclear@0 2331 else
nuclear@0 2332 {
nuclear@0 2333 // no parent node given, probably called from <library_nodes> element.
nuclear@0 2334 // create new node in node library
nuclear@0 2335 mNodeLibrary[child->mID] = child;
nuclear@0 2336 }
nuclear@0 2337
nuclear@0 2338 // read on recursively from there
nuclear@0 2339 ReadSceneNode( child);
nuclear@0 2340 continue;
nuclear@0 2341 }
nuclear@0 2342 // For any further stuff we need a valid node to work on
nuclear@0 2343 else if (!pNode)
nuclear@0 2344 continue;
nuclear@0 2345
nuclear@0 2346 if( IsElement( "lookat"))
nuclear@0 2347 ReadNodeTransformation( pNode, TF_LOOKAT);
nuclear@0 2348 else if( IsElement( "matrix"))
nuclear@0 2349 ReadNodeTransformation( pNode, TF_MATRIX);
nuclear@0 2350 else if( IsElement( "rotate"))
nuclear@0 2351 ReadNodeTransformation( pNode, TF_ROTATE);
nuclear@0 2352 else if( IsElement( "scale"))
nuclear@0 2353 ReadNodeTransformation( pNode, TF_SCALE);
nuclear@0 2354 else if( IsElement( "skew"))
nuclear@0 2355 ReadNodeTransformation( pNode, TF_SKEW);
nuclear@0 2356 else if( IsElement( "translate"))
nuclear@0 2357 ReadNodeTransformation( pNode, TF_TRANSLATE);
nuclear@0 2358 else if( IsElement( "render") && pNode->mParent == NULL && 0 == pNode->mPrimaryCamera.length())
nuclear@0 2359 {
nuclear@0 2360 // ... scene evaluation or, in other words, postprocessing pipeline,
nuclear@0 2361 // or, again in other words, a turing-complete description how to
nuclear@0 2362 // render a Collada scene. The only thing that is interesting for
nuclear@0 2363 // us is the primary camera.
nuclear@0 2364 int attrId = TestAttribute("camera_node");
nuclear@0 2365 if (-1 != attrId)
nuclear@0 2366 {
nuclear@0 2367 const char* s = mReader->getAttributeValue(attrId);
nuclear@0 2368 if (s[0] != '#')
nuclear@0 2369 DefaultLogger::get()->error("Collada: Unresolved reference format of camera");
nuclear@0 2370 else
nuclear@0 2371 pNode->mPrimaryCamera = s+1;
nuclear@0 2372 }
nuclear@0 2373 }
nuclear@0 2374 else if( IsElement( "instance_node"))
nuclear@0 2375 {
nuclear@0 2376 // find the node in the library
nuclear@0 2377 int attrID = TestAttribute( "url");
nuclear@0 2378 if( attrID != -1)
nuclear@0 2379 {
nuclear@0 2380 const char* s = mReader->getAttributeValue(attrID);
nuclear@0 2381 if (s[0] != '#')
nuclear@0 2382 DefaultLogger::get()->error("Collada: Unresolved reference format of node");
nuclear@0 2383 else
nuclear@0 2384 {
nuclear@0 2385 pNode->mNodeInstances.push_back(NodeInstance());
nuclear@0 2386 pNode->mNodeInstances.back().mNode = s+1;
nuclear@0 2387 }
nuclear@0 2388 }
nuclear@0 2389 }
nuclear@0 2390 else if( IsElement( "instance_geometry") || IsElement( "instance_controller"))
nuclear@0 2391 {
nuclear@0 2392 // Reference to a mesh or controller, with possible material associations
nuclear@0 2393 ReadNodeGeometry( pNode);
nuclear@0 2394 }
nuclear@0 2395 else if( IsElement( "instance_light"))
nuclear@0 2396 {
nuclear@0 2397 // Reference to a light, name given in 'url' attribute
nuclear@0 2398 int attrID = TestAttribute("url");
nuclear@0 2399 if (-1 == attrID)
nuclear@0 2400 DefaultLogger::get()->warn("Collada: Expected url attribute in <instance_light> element");
nuclear@0 2401 else
nuclear@0 2402 {
nuclear@0 2403 const char* url = mReader->getAttributeValue( attrID);
nuclear@0 2404 if( url[0] != '#')
nuclear@0 2405 ThrowException( "Unknown reference format in <instance_light> element");
nuclear@0 2406
nuclear@0 2407 pNode->mLights.push_back(LightInstance());
nuclear@0 2408 pNode->mLights.back().mLight = url+1;
nuclear@0 2409 }
nuclear@0 2410 }
nuclear@0 2411 else if( IsElement( "instance_camera"))
nuclear@0 2412 {
nuclear@0 2413 // Reference to a camera, name given in 'url' attribute
nuclear@0 2414 int attrID = TestAttribute("url");
nuclear@0 2415 if (-1 == attrID)
nuclear@0 2416 DefaultLogger::get()->warn("Collada: Expected url attribute in <instance_camera> element");
nuclear@0 2417 else
nuclear@0 2418 {
nuclear@0 2419 const char* url = mReader->getAttributeValue( attrID);
nuclear@0 2420 if( url[0] != '#')
nuclear@0 2421 ThrowException( "Unknown reference format in <instance_camera> element");
nuclear@0 2422
nuclear@0 2423 pNode->mCameras.push_back(CameraInstance());
nuclear@0 2424 pNode->mCameras.back().mCamera = url+1;
nuclear@0 2425 }
nuclear@0 2426 }
nuclear@0 2427 else
nuclear@0 2428 {
nuclear@0 2429 // skip everything else for the moment
nuclear@0 2430 SkipElement();
nuclear@0 2431 }
nuclear@0 2432 }
nuclear@0 2433 else if( mReader->getNodeType() == irr::io::EXN_ELEMENT_END) {
nuclear@0 2434 break;
nuclear@0 2435 }
nuclear@0 2436 }
nuclear@0 2437 }
nuclear@0 2438
nuclear@0 2439 // ------------------------------------------------------------------------------------------------
nuclear@0 2440 // Reads a node transformation entry of the given type and adds it to the given node's transformation list.
nuclear@0 2441 void ColladaParser::ReadNodeTransformation( Node* pNode, TransformType pType)
nuclear@0 2442 {
nuclear@0 2443 if( mReader->isEmptyElement())
nuclear@0 2444 return;
nuclear@0 2445
nuclear@0 2446 std::string tagName = mReader->getNodeName();
nuclear@0 2447
nuclear@0 2448 Transform tf;
nuclear@0 2449 tf.mType = pType;
nuclear@0 2450
nuclear@0 2451 // read SID
nuclear@0 2452 int indexSID = TestAttribute( "sid");
nuclear@0 2453 if( indexSID >= 0)
nuclear@0 2454 tf.mID = mReader->getAttributeValue( indexSID);
nuclear@0 2455
nuclear@0 2456 // how many parameters to read per transformation type
nuclear@0 2457 static const unsigned int sNumParameters[] = { 9, 4, 3, 3, 7, 16 };
nuclear@0 2458 const char* content = GetTextContent();
nuclear@0 2459
nuclear@0 2460 // read as many parameters and store in the transformation
nuclear@0 2461 for( unsigned int a = 0; a < sNumParameters[pType]; a++)
nuclear@0 2462 {
nuclear@0 2463 // read a number
nuclear@0 2464 content = fast_atoreal_move<float>( content, tf.f[a]);
nuclear@0 2465 // skip whitespace after it
nuclear@0 2466 SkipSpacesAndLineEnd( &content);
nuclear@0 2467 }
nuclear@0 2468
nuclear@0 2469 // place the transformation at the queue of the node
nuclear@0 2470 pNode->mTransforms.push_back( tf);
nuclear@0 2471
nuclear@0 2472 // and consume the closing tag
nuclear@0 2473 TestClosing( tagName.c_str());
nuclear@0 2474 }
nuclear@0 2475
nuclear@0 2476 // ------------------------------------------------------------------------------------------------
nuclear@0 2477 // Processes bind_vertex_input and bind elements
nuclear@0 2478 void ColladaParser::ReadMaterialVertexInputBinding( Collada::SemanticMappingTable& tbl)
nuclear@0 2479 {
nuclear@0 2480 while( mReader->read())
nuclear@0 2481 {
nuclear@0 2482 if( mReader->getNodeType() == irr::io::EXN_ELEMENT) {
nuclear@0 2483 if( IsElement( "bind_vertex_input"))
nuclear@0 2484 {
nuclear@0 2485 Collada::InputSemanticMapEntry vn;
nuclear@0 2486
nuclear@0 2487 // effect semantic
nuclear@0 2488 int n = GetAttribute("semantic");
nuclear@0 2489 std::string s = mReader->getAttributeValue(n);
nuclear@0 2490
nuclear@0 2491 // input semantic
nuclear@0 2492 n = GetAttribute("input_semantic");
nuclear@0 2493 vn.mType = GetTypeForSemantic( mReader->getAttributeValue(n) );
nuclear@0 2494
nuclear@0 2495 // index of input set
nuclear@0 2496 n = TestAttribute("input_set");
nuclear@0 2497 if (-1 != n)
nuclear@0 2498 vn.mSet = mReader->getAttributeValueAsInt(n);
nuclear@0 2499
nuclear@0 2500 tbl.mMap[s] = vn;
nuclear@0 2501 }
nuclear@0 2502 else if( IsElement( "bind")) {
nuclear@0 2503 DefaultLogger::get()->warn("Collada: Found unsupported <bind> element");
nuclear@0 2504 }
nuclear@0 2505 }
nuclear@0 2506 else if( mReader->getNodeType() == irr::io::EXN_ELEMENT_END) {
nuclear@0 2507 if( strcmp( mReader->getNodeName(), "instance_material") == 0)
nuclear@0 2508 break;
nuclear@0 2509 }
nuclear@0 2510 }
nuclear@0 2511 }
nuclear@0 2512
nuclear@0 2513 // ------------------------------------------------------------------------------------------------
nuclear@0 2514 // Reads a mesh reference in a node and adds it to the node's mesh list
nuclear@0 2515 void ColladaParser::ReadNodeGeometry( Node* pNode)
nuclear@0 2516 {
nuclear@0 2517 // referred mesh is given as an attribute of the <instance_geometry> element
nuclear@0 2518 int attrUrl = GetAttribute( "url");
nuclear@0 2519 const char* url = mReader->getAttributeValue( attrUrl);
nuclear@0 2520 if( url[0] != '#')
nuclear@0 2521 ThrowException( "Unknown reference format");
nuclear@0 2522
nuclear@0 2523 Collada::MeshInstance instance;
nuclear@0 2524 instance.mMeshOrController = url+1; // skipping the leading #
nuclear@0 2525
nuclear@0 2526 if( !mReader->isEmptyElement())
nuclear@0 2527 {
nuclear@0 2528 // read material associations. Ignore additional elements inbetween
nuclear@0 2529 while( mReader->read())
nuclear@0 2530 {
nuclear@0 2531 if( mReader->getNodeType() == irr::io::EXN_ELEMENT)
nuclear@0 2532 {
nuclear@0 2533 if( IsElement( "instance_material"))
nuclear@0 2534 {
nuclear@0 2535 // read ID of the geometry subgroup and the target material
nuclear@0 2536 int attrGroup = GetAttribute( "symbol");
nuclear@0 2537 std::string group = mReader->getAttributeValue( attrGroup);
nuclear@0 2538 int attrMaterial = GetAttribute( "target");
nuclear@0 2539 const char* urlMat = mReader->getAttributeValue( attrMaterial);
nuclear@0 2540 Collada::SemanticMappingTable s;
nuclear@0 2541 if( urlMat[0] == '#')
nuclear@0 2542 urlMat++;
nuclear@0 2543
nuclear@0 2544 s.mMatName = urlMat;
nuclear@0 2545
nuclear@0 2546 // resolve further material details + THIS UGLY AND NASTY semantic mapping stuff
nuclear@0 2547 if( !mReader->isEmptyElement())
nuclear@0 2548 ReadMaterialVertexInputBinding(s);
nuclear@0 2549
nuclear@0 2550 // store the association
nuclear@0 2551 instance.mMaterials[group] = s;
nuclear@0 2552 }
nuclear@0 2553 }
nuclear@0 2554 else if( mReader->getNodeType() == irr::io::EXN_ELEMENT_END)
nuclear@0 2555 {
nuclear@0 2556 if( strcmp( mReader->getNodeName(), "instance_geometry") == 0
nuclear@0 2557 || strcmp( mReader->getNodeName(), "instance_controller") == 0)
nuclear@0 2558 break;
nuclear@0 2559 }
nuclear@0 2560 }
nuclear@0 2561 }
nuclear@0 2562
nuclear@0 2563 // store it
nuclear@0 2564 pNode->mMeshes.push_back( instance);
nuclear@0 2565 }
nuclear@0 2566
nuclear@0 2567 // ------------------------------------------------------------------------------------------------
nuclear@0 2568 // Reads the collada scene
nuclear@0 2569 void ColladaParser::ReadScene()
nuclear@0 2570 {
nuclear@0 2571 if( mReader->isEmptyElement())
nuclear@0 2572 return;
nuclear@0 2573
nuclear@0 2574 while( mReader->read())
nuclear@0 2575 {
nuclear@0 2576 if( mReader->getNodeType() == irr::io::EXN_ELEMENT) {
nuclear@0 2577 if( IsElement( "instance_visual_scene"))
nuclear@0 2578 {
nuclear@0 2579 // should be the first and only occurence
nuclear@0 2580 if( mRootNode)
nuclear@0 2581 ThrowException( "Invalid scene containing multiple root nodes in <instance_visual_scene> element");
nuclear@0 2582
nuclear@0 2583 // read the url of the scene to instance. Should be of format "#some_name"
nuclear@0 2584 int urlIndex = GetAttribute( "url");
nuclear@0 2585 const char* url = mReader->getAttributeValue( urlIndex);
nuclear@0 2586 if( url[0] != '#')
nuclear@0 2587 ThrowException( "Unknown reference format in <instance_visual_scene> element");
nuclear@0 2588
nuclear@0 2589 // find the referred scene, skip the leading #
nuclear@0 2590 NodeLibrary::const_iterator sit = mNodeLibrary.find( url+1);
nuclear@0 2591 if( sit == mNodeLibrary.end())
nuclear@0 2592 ThrowException( "Unable to resolve visual_scene reference \"" + std::string(url) + "\" in <instance_visual_scene> element.");
nuclear@0 2593 mRootNode = sit->second;
nuclear@0 2594 } else {
nuclear@0 2595 SkipElement();
nuclear@0 2596 }
nuclear@0 2597 }
nuclear@0 2598 else if( mReader->getNodeType() == irr::io::EXN_ELEMENT_END){
nuclear@0 2599 break;
nuclear@0 2600 }
nuclear@0 2601 }
nuclear@0 2602 }
nuclear@0 2603
nuclear@0 2604 // ------------------------------------------------------------------------------------------------
nuclear@0 2605 // Aborts the file reading with an exception
nuclear@0 2606 void ColladaParser::ThrowException( const std::string& pError) const
nuclear@0 2607 {
nuclear@0 2608 throw DeadlyImportError( boost::str( boost::format( "Collada: %s - %s") % mFileName % pError));
nuclear@0 2609 }
nuclear@0 2610
nuclear@0 2611 // ------------------------------------------------------------------------------------------------
nuclear@0 2612 // Skips all data until the end node of the current element
nuclear@0 2613 void ColladaParser::SkipElement()
nuclear@0 2614 {
nuclear@0 2615 // nothing to skip if it's an <element />
nuclear@0 2616 if( mReader->isEmptyElement())
nuclear@0 2617 return;
nuclear@0 2618
nuclear@0 2619 // reroute
nuclear@0 2620 SkipElement( mReader->getNodeName());
nuclear@0 2621 }
nuclear@0 2622
nuclear@0 2623 // ------------------------------------------------------------------------------------------------
nuclear@0 2624 // Skips all data until the end node of the given element
nuclear@0 2625 void ColladaParser::SkipElement( const char* pElement)
nuclear@0 2626 {
nuclear@0 2627 // copy the current node's name because it'a pointer to the reader's internal buffer,
nuclear@0 2628 // which is going to change with the upcoming parsing
nuclear@0 2629 std::string element = pElement;
nuclear@0 2630 while( mReader->read())
nuclear@0 2631 {
nuclear@0 2632 if( mReader->getNodeType() == irr::io::EXN_ELEMENT_END)
nuclear@0 2633 if( mReader->getNodeName() == element)
nuclear@0 2634 break;
nuclear@0 2635 }
nuclear@0 2636 }
nuclear@0 2637
nuclear@0 2638 // ------------------------------------------------------------------------------------------------
nuclear@0 2639 // Tests for an opening element of the given name, throws an exception if not found
nuclear@0 2640 void ColladaParser::TestOpening( const char* pName)
nuclear@0 2641 {
nuclear@0 2642 // read element start
nuclear@0 2643 if( !mReader->read())
nuclear@0 2644 ThrowException( boost::str( boost::format( "Unexpected end of file while beginning of <%s> element.") % pName));
nuclear@0 2645 // whitespace in front is ok, just read again if found
nuclear@0 2646 if( mReader->getNodeType() == irr::io::EXN_TEXT)
nuclear@0 2647 if( !mReader->read())
nuclear@0 2648 ThrowException( boost::str( boost::format( "Unexpected end of file while reading beginning of <%s> element.") % pName));
nuclear@0 2649
nuclear@0 2650 if( mReader->getNodeType() != irr::io::EXN_ELEMENT || strcmp( mReader->getNodeName(), pName) != 0)
nuclear@0 2651 ThrowException( boost::str( boost::format( "Expected start of <%s> element.") % pName));
nuclear@0 2652 }
nuclear@0 2653
nuclear@0 2654 // ------------------------------------------------------------------------------------------------
nuclear@0 2655 // Tests for the closing tag of the given element, throws an exception if not found
nuclear@0 2656 void ColladaParser::TestClosing( const char* pName)
nuclear@0 2657 {
nuclear@0 2658 // check if we're already on the closing tag and return right away
nuclear@0 2659 if( mReader->getNodeType() == irr::io::EXN_ELEMENT_END && strcmp( mReader->getNodeName(), pName) == 0)
nuclear@0 2660 return;
nuclear@0 2661
nuclear@0 2662 // if not, read some more
nuclear@0 2663 if( !mReader->read())
nuclear@0 2664 ThrowException( boost::str( boost::format( "Unexpected end of file while reading end of <%s> element.") % pName));
nuclear@0 2665 // whitespace in front is ok, just read again if found
nuclear@0 2666 if( mReader->getNodeType() == irr::io::EXN_TEXT)
nuclear@0 2667 if( !mReader->read())
nuclear@0 2668 ThrowException( boost::str( boost::format( "Unexpected end of file while reading end of <%s> element.") % pName));
nuclear@0 2669
nuclear@0 2670 // but this has the be the closing tag, or we're lost
nuclear@0 2671 if( mReader->getNodeType() != irr::io::EXN_ELEMENT_END || strcmp( mReader->getNodeName(), pName) != 0)
nuclear@0 2672 ThrowException( boost::str( boost::format( "Expected end of <%s> element.") % pName));
nuclear@0 2673 }
nuclear@0 2674
nuclear@0 2675 // ------------------------------------------------------------------------------------------------
nuclear@0 2676 // Returns the index of the named attribute or -1 if not found. Does not throw, therefore useful for optional attributes
nuclear@0 2677 int ColladaParser::GetAttribute( const char* pAttr) const
nuclear@0 2678 {
nuclear@0 2679 int index = TestAttribute( pAttr);
nuclear@0 2680 if( index != -1)
nuclear@0 2681 return index;
nuclear@0 2682
nuclear@0 2683 // attribute not found -> throw an exception
nuclear@0 2684 ThrowException( boost::str( boost::format( "Expected attribute \"%s\" for element <%s>.") % pAttr % mReader->getNodeName()));
nuclear@0 2685 return -1;
nuclear@0 2686 }
nuclear@0 2687
nuclear@0 2688 // ------------------------------------------------------------------------------------------------
nuclear@0 2689 // Tests the present element for the presence of one attribute, returns its index or throws an exception if not found
nuclear@0 2690 int ColladaParser::TestAttribute( const char* pAttr) const
nuclear@0 2691 {
nuclear@0 2692 for( int a = 0; a < mReader->getAttributeCount(); a++)
nuclear@0 2693 if( strcmp( mReader->getAttributeName( a), pAttr) == 0)
nuclear@0 2694 return a;
nuclear@0 2695
nuclear@0 2696 return -1;
nuclear@0 2697 }
nuclear@0 2698
nuclear@0 2699 // ------------------------------------------------------------------------------------------------
nuclear@0 2700 // Reads the text contents of an element, throws an exception if not given. Skips leading whitespace.
nuclear@0 2701 const char* ColladaParser::GetTextContent()
nuclear@0 2702 {
nuclear@0 2703 const char* sz = TestTextContent();
nuclear@0 2704 if(!sz) {
nuclear@0 2705 ThrowException( "Invalid contents in element \"n\".");
nuclear@0 2706 }
nuclear@0 2707 return sz;
nuclear@0 2708 }
nuclear@0 2709
nuclear@0 2710 // ------------------------------------------------------------------------------------------------
nuclear@0 2711 // Reads the text contents of an element, returns NULL if not given. Skips leading whitespace.
nuclear@0 2712 const char* ColladaParser::TestTextContent()
nuclear@0 2713 {
nuclear@0 2714 // present node should be the beginning of an element
nuclear@0 2715 if( mReader->getNodeType() != irr::io::EXN_ELEMENT || mReader->isEmptyElement())
nuclear@0 2716 return NULL;
nuclear@0 2717
nuclear@0 2718 // read contents of the element
nuclear@0 2719 if( !mReader->read() )
nuclear@0 2720 return NULL;
nuclear@0 2721 if( mReader->getNodeType() != irr::io::EXN_TEXT)
nuclear@0 2722 return NULL;
nuclear@0 2723
nuclear@0 2724 // skip leading whitespace
nuclear@0 2725 const char* text = mReader->getNodeData();
nuclear@0 2726 SkipSpacesAndLineEnd( &text);
nuclear@0 2727
nuclear@0 2728 return text;
nuclear@0 2729 }
nuclear@0 2730
nuclear@0 2731 // ------------------------------------------------------------------------------------------------
nuclear@0 2732 // Calculates the resulting transformation fromm all the given transform steps
nuclear@0 2733 aiMatrix4x4 ColladaParser::CalculateResultTransform( const std::vector<Transform>& pTransforms) const
nuclear@0 2734 {
nuclear@0 2735 aiMatrix4x4 res;
nuclear@0 2736
nuclear@0 2737 for( std::vector<Transform>::const_iterator it = pTransforms.begin(); it != pTransforms.end(); ++it)
nuclear@0 2738 {
nuclear@0 2739 const Transform& tf = *it;
nuclear@0 2740 switch( tf.mType)
nuclear@0 2741 {
nuclear@0 2742 case TF_LOOKAT:
nuclear@0 2743 {
nuclear@0 2744 aiVector3D pos( tf.f[0], tf.f[1], tf.f[2]);
nuclear@0 2745 aiVector3D dstPos( tf.f[3], tf.f[4], tf.f[5]);
nuclear@0 2746 aiVector3D up = aiVector3D( tf.f[6], tf.f[7], tf.f[8]).Normalize();
nuclear@0 2747 aiVector3D dir = aiVector3D( dstPos - pos).Normalize();
nuclear@0 2748 aiVector3D right = (dir ^ up).Normalize();
nuclear@0 2749
nuclear@0 2750 res *= aiMatrix4x4(
nuclear@0 2751 right.x, up.x, -dir.x, pos.x,
nuclear@0 2752 right.y, up.y, -dir.y, pos.y,
nuclear@0 2753 right.z, up.z, -dir.z, pos.z,
nuclear@0 2754 0, 0, 0, 1);
nuclear@0 2755 break;
nuclear@0 2756 }
nuclear@0 2757 case TF_ROTATE:
nuclear@0 2758 {
nuclear@0 2759 aiMatrix4x4 rot;
nuclear@0 2760 float angle = tf.f[3] * float( AI_MATH_PI) / 180.0f;
nuclear@0 2761 aiVector3D axis( tf.f[0], tf.f[1], tf.f[2]);
nuclear@0 2762 aiMatrix4x4::Rotation( angle, axis, rot);
nuclear@0 2763 res *= rot;
nuclear@0 2764 break;
nuclear@0 2765 }
nuclear@0 2766 case TF_TRANSLATE:
nuclear@0 2767 {
nuclear@0 2768 aiMatrix4x4 trans;
nuclear@0 2769 aiMatrix4x4::Translation( aiVector3D( tf.f[0], tf.f[1], tf.f[2]), trans);
nuclear@0 2770 res *= trans;
nuclear@0 2771 break;
nuclear@0 2772 }
nuclear@0 2773 case TF_SCALE:
nuclear@0 2774 {
nuclear@0 2775 aiMatrix4x4 scale( tf.f[0], 0.0f, 0.0f, 0.0f, 0.0f, tf.f[1], 0.0f, 0.0f, 0.0f, 0.0f, tf.f[2], 0.0f,
nuclear@0 2776 0.0f, 0.0f, 0.0f, 1.0f);
nuclear@0 2777 res *= scale;
nuclear@0 2778 break;
nuclear@0 2779 }
nuclear@0 2780 case TF_SKEW:
nuclear@0 2781 // TODO: (thom)
nuclear@0 2782 ai_assert( false);
nuclear@0 2783 break;
nuclear@0 2784 case TF_MATRIX:
nuclear@0 2785 {
nuclear@0 2786 aiMatrix4x4 mat( tf.f[0], tf.f[1], tf.f[2], tf.f[3], tf.f[4], tf.f[5], tf.f[6], tf.f[7],
nuclear@0 2787 tf.f[8], tf.f[9], tf.f[10], tf.f[11], tf.f[12], tf.f[13], tf.f[14], tf.f[15]);
nuclear@0 2788 res *= mat;
nuclear@0 2789 break;
nuclear@0 2790 }
nuclear@0 2791 default:
nuclear@0 2792 ai_assert( false);
nuclear@0 2793 break;
nuclear@0 2794 }
nuclear@0 2795 }
nuclear@0 2796
nuclear@0 2797 return res;
nuclear@0 2798 }
nuclear@0 2799
nuclear@0 2800 // ------------------------------------------------------------------------------------------------
nuclear@0 2801 // Determines the input data type for the given semantic string
nuclear@0 2802 Collada::InputType ColladaParser::GetTypeForSemantic( const std::string& pSemantic)
nuclear@0 2803 {
nuclear@0 2804 if( pSemantic == "POSITION")
nuclear@0 2805 return IT_Position;
nuclear@0 2806 else if( pSemantic == "TEXCOORD")
nuclear@0 2807 return IT_Texcoord;
nuclear@0 2808 else if( pSemantic == "NORMAL")
nuclear@0 2809 return IT_Normal;
nuclear@0 2810 else if( pSemantic == "COLOR")
nuclear@0 2811 return IT_Color;
nuclear@0 2812 else if( pSemantic == "VERTEX")
nuclear@0 2813 return IT_Vertex;
nuclear@0 2814 else if( pSemantic == "BINORMAL" || pSemantic == "TEXBINORMAL")
nuclear@0 2815 return IT_Bitangent;
nuclear@0 2816 else if( pSemantic == "TANGENT" || pSemantic == "TEXTANGENT")
nuclear@0 2817 return IT_Tangent;
nuclear@0 2818
nuclear@0 2819 DefaultLogger::get()->warn( boost::str( boost::format( "Unknown vertex input type \"%s\". Ignoring.") % pSemantic));
nuclear@0 2820 return IT_Invalid;
nuclear@0 2821 }
nuclear@0 2822
nuclear@0 2823 #endif // !! ASSIMP_BUILD_NO_DAE_IMPORTER