vrshoot
diff 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 |
line diff
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/libs/assimp/ColladaParser.cpp Sat Feb 01 19:58:19 2014 +0200 1.3 @@ -0,0 +1,2823 @@ 1.4 +/* 1.5 +--------------------------------------------------------------------------- 1.6 +Open Asset Import Library (assimp) 1.7 +--------------------------------------------------------------------------- 1.8 + 1.9 +Copyright (c) 2006-2012, assimp team 1.10 + 1.11 +All rights reserved. 1.12 + 1.13 +Redistribution and use of this software in source and binary forms, 1.14 +with or without modification, are permitted provided that the following 1.15 +conditions are met: 1.16 + 1.17 +* Redistributions of source code must retain the above 1.18 +copyright notice, this list of conditions and the 1.19 +following disclaimer. 1.20 + 1.21 +* Redistributions in binary form must reproduce the above 1.22 +copyright notice, this list of conditions and the 1.23 +following disclaimer in the documentation and/or other 1.24 +materials provided with the distribution. 1.25 + 1.26 +* Neither the name of the assimp team, nor the names of its 1.27 +contributors may be used to endorse or promote products 1.28 +derived from this software without specific prior 1.29 +written permission of the assimp team. 1.30 + 1.31 +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 1.32 +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 1.33 +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 1.34 +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 1.35 +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 1.36 +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 1.37 +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 1.38 +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 1.39 +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 1.40 +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 1.41 +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 1.42 +--------------------------------------------------------------------------- 1.43 +*/ 1.44 + 1.45 +/** @file ColladaParser.cpp 1.46 + * @brief Implementation of the Collada parser helper 1.47 + */ 1.48 + 1.49 +#include "AssimpPCH.h" 1.50 +#ifndef ASSIMP_BUILD_NO_COLLADA_IMPORTER 1.51 + 1.52 +#include "ColladaParser.h" 1.53 +#include "fast_atof.h" 1.54 +#include "ParsingUtils.h" 1.55 + 1.56 +using namespace Assimp; 1.57 +using namespace Assimp::Collada; 1.58 + 1.59 +// ------------------------------------------------------------------------------------------------ 1.60 +// Constructor to be privately used by Importer 1.61 +ColladaParser::ColladaParser( IOSystem* pIOHandler, const std::string& pFile) 1.62 + : mFileName( pFile) 1.63 +{ 1.64 + mRootNode = NULL; 1.65 + mUnitSize = 1.0f; 1.66 + mUpDirection = UP_Z; 1.67 + 1.68 + // We assume the newest file format by default 1.69 + mFormat = FV_1_5_n; 1.70 + 1.71 + // open the file 1.72 + boost::scoped_ptr<IOStream> file( pIOHandler->Open( pFile)); 1.73 + if( file.get() == NULL) 1.74 + throw DeadlyImportError( "Failed to open file " + pFile + "."); 1.75 + 1.76 + // generate a XML reader for it 1.77 + boost::scoped_ptr<CIrrXML_IOStreamReader> mIOWrapper( new CIrrXML_IOStreamReader( file.get())); 1.78 + mReader = irr::io::createIrrXMLReader( mIOWrapper.get()); 1.79 + if( !mReader) 1.80 + ThrowException( "Collada: Unable to open file."); 1.81 + 1.82 + // start reading 1.83 + ReadContents(); 1.84 +} 1.85 + 1.86 +// ------------------------------------------------------------------------------------------------ 1.87 +// Destructor, private as well 1.88 +ColladaParser::~ColladaParser() 1.89 +{ 1.90 + delete mReader; 1.91 + for( NodeLibrary::iterator it = mNodeLibrary.begin(); it != mNodeLibrary.end(); ++it) 1.92 + delete it->second; 1.93 + for( MeshLibrary::iterator it = mMeshLibrary.begin(); it != mMeshLibrary.end(); ++it) 1.94 + delete it->second; 1.95 +} 1.96 + 1.97 +// ------------------------------------------------------------------------------------------------ 1.98 +// Read bool from text contents of current element 1.99 +bool ColladaParser::ReadBoolFromTextContent() 1.100 +{ 1.101 + const char* cur = GetTextContent(); 1.102 + return (!ASSIMP_strincmp(cur,"true",4) || '0' != *cur); 1.103 +} 1.104 + 1.105 +// ------------------------------------------------------------------------------------------------ 1.106 +// Read float from text contents of current element 1.107 +float ColladaParser::ReadFloatFromTextContent() 1.108 +{ 1.109 + const char* cur = GetTextContent(); 1.110 + return fast_atof(cur); 1.111 +} 1.112 + 1.113 +// ------------------------------------------------------------------------------------------------ 1.114 +// Reads the contents of the file 1.115 +void ColladaParser::ReadContents() 1.116 +{ 1.117 + while( mReader->read()) 1.118 + { 1.119 + // handle the root element "COLLADA" 1.120 + if( mReader->getNodeType() == irr::io::EXN_ELEMENT) 1.121 + { 1.122 + if( IsElement( "COLLADA")) 1.123 + { 1.124 + // check for 'version' attribute 1.125 + const int attrib = TestAttribute("version"); 1.126 + if (attrib != -1) { 1.127 + const char* version = mReader->getAttributeValue(attrib); 1.128 + 1.129 + if (!::strncmp(version,"1.5",3)) { 1.130 + mFormat = FV_1_5_n; 1.131 + DefaultLogger::get()->debug("Collada schema version is 1.5.n"); 1.132 + } 1.133 + else if (!::strncmp(version,"1.4",3)) { 1.134 + mFormat = FV_1_4_n; 1.135 + DefaultLogger::get()->debug("Collada schema version is 1.4.n"); 1.136 + } 1.137 + else if (!::strncmp(version,"1.3",3)) { 1.138 + mFormat = FV_1_3_n; 1.139 + DefaultLogger::get()->debug("Collada schema version is 1.3.n"); 1.140 + } 1.141 + } 1.142 + 1.143 + ReadStructure(); 1.144 + } else 1.145 + { 1.146 + DefaultLogger::get()->debug( boost::str( boost::format( "Ignoring global element <%s>.") % mReader->getNodeName())); 1.147 + SkipElement(); 1.148 + } 1.149 + } else 1.150 + { 1.151 + // skip everything else silently 1.152 + } 1.153 + } 1.154 +} 1.155 + 1.156 +// ------------------------------------------------------------------------------------------------ 1.157 +// Reads the structure of the file 1.158 +void ColladaParser::ReadStructure() 1.159 +{ 1.160 + while( mReader->read()) 1.161 + { 1.162 + // beginning of elements 1.163 + if( mReader->getNodeType() == irr::io::EXN_ELEMENT) 1.164 + { 1.165 + if( IsElement( "asset")) 1.166 + ReadAssetInfo(); 1.167 + else if( IsElement( "library_animations")) 1.168 + ReadAnimationLibrary(); 1.169 + else if( IsElement( "library_controllers")) 1.170 + ReadControllerLibrary(); 1.171 + else if( IsElement( "library_images")) 1.172 + ReadImageLibrary(); 1.173 + else if( IsElement( "library_materials")) 1.174 + ReadMaterialLibrary(); 1.175 + else if( IsElement( "library_effects")) 1.176 + ReadEffectLibrary(); 1.177 + else if( IsElement( "library_geometries")) 1.178 + ReadGeometryLibrary(); 1.179 + else if( IsElement( "library_visual_scenes")) 1.180 + ReadSceneLibrary(); 1.181 + else if( IsElement( "library_lights")) 1.182 + ReadLightLibrary(); 1.183 + else if( IsElement( "library_cameras")) 1.184 + ReadCameraLibrary(); 1.185 + else if( IsElement( "library_nodes")) 1.186 + ReadSceneNode(NULL); /* some hacking to reuse this piece of code */ 1.187 + else if( IsElement( "scene")) 1.188 + ReadScene(); 1.189 + else 1.190 + SkipElement(); 1.191 + } 1.192 + else if( mReader->getNodeType() == irr::io::EXN_ELEMENT_END) 1.193 + { 1.194 + break; 1.195 + } 1.196 + } 1.197 +} 1.198 + 1.199 +// ------------------------------------------------------------------------------------------------ 1.200 +// Reads asset informations such as coordinate system informations and legal blah 1.201 +void ColladaParser::ReadAssetInfo() 1.202 +{ 1.203 + if( mReader->isEmptyElement()) 1.204 + return; 1.205 + 1.206 + while( mReader->read()) 1.207 + { 1.208 + if( mReader->getNodeType() == irr::io::EXN_ELEMENT) 1.209 + { 1.210 + if( IsElement( "unit")) 1.211 + { 1.212 + // read unit data from the element's attributes 1.213 + const int attrIndex = TestAttribute( "meter"); 1.214 + if (attrIndex == -1) { 1.215 + mUnitSize = 1.f; 1.216 + } 1.217 + else { 1.218 + mUnitSize = mReader->getAttributeValueAsFloat( attrIndex); 1.219 + } 1.220 + 1.221 + // consume the trailing stuff 1.222 + if( !mReader->isEmptyElement()) 1.223 + SkipElement(); 1.224 + } 1.225 + else if( IsElement( "up_axis")) 1.226 + { 1.227 + // read content, strip whitespace, compare 1.228 + const char* content = GetTextContent(); 1.229 + if( strncmp( content, "X_UP", 4) == 0) 1.230 + mUpDirection = UP_X; 1.231 + else if( strncmp( content, "Y_UP", 4) == 0) 1.232 + mUpDirection = UP_Y; 1.233 + else 1.234 + mUpDirection = UP_Z; 1.235 + 1.236 + // check element end 1.237 + TestClosing( "up_axis"); 1.238 + } else 1.239 + { 1.240 + SkipElement(); 1.241 + } 1.242 + } 1.243 + else if( mReader->getNodeType() == irr::io::EXN_ELEMENT_END) 1.244 + { 1.245 + if( strcmp( mReader->getNodeName(), "asset") != 0) 1.246 + ThrowException( "Expected end of <asset> element."); 1.247 + 1.248 + break; 1.249 + } 1.250 + } 1.251 +} 1.252 + 1.253 +// ------------------------------------------------------------------------------------------------ 1.254 +// Reads the animation library 1.255 +void ColladaParser::ReadAnimationLibrary() 1.256 +{ 1.257 + if (mReader->isEmptyElement()) 1.258 + return; 1.259 + 1.260 + while( mReader->read()) 1.261 + { 1.262 + if( mReader->getNodeType() == irr::io::EXN_ELEMENT) 1.263 + { 1.264 + if( IsElement( "animation")) 1.265 + { 1.266 + // delegate the reading. Depending on the inner elements it will be a container or a anim channel 1.267 + ReadAnimation( &mAnims); 1.268 + } else 1.269 + { 1.270 + // ignore the rest 1.271 + SkipElement(); 1.272 + } 1.273 + } 1.274 + else if( mReader->getNodeType() == irr::io::EXN_ELEMENT_END) 1.275 + { 1.276 + if( strcmp( mReader->getNodeName(), "library_animations") != 0) 1.277 + ThrowException( "Expected end of <library_animations> element."); 1.278 + 1.279 + break; 1.280 + } 1.281 + } 1.282 +} 1.283 + 1.284 +// ------------------------------------------------------------------------------------------------ 1.285 +// Reads an animation into the given parent structure 1.286 +void ColladaParser::ReadAnimation( Collada::Animation* pParent) 1.287 +{ 1.288 + if( mReader->isEmptyElement()) 1.289 + return; 1.290 + 1.291 + // an <animation> element may be a container for grouping sub-elements or an animation channel 1.292 + // this is the channel collection by ID, in case it has channels 1.293 + typedef std::map<std::string, AnimationChannel> ChannelMap; 1.294 + ChannelMap channels; 1.295 + // this is the anim container in case we're a container 1.296 + Animation* anim = NULL; 1.297 + 1.298 + // optional name given as an attribute 1.299 + std::string animName; 1.300 + int indexName = TestAttribute( "name"); 1.301 + int indexID = TestAttribute( "id"); 1.302 + if( indexName >= 0) 1.303 + animName = mReader->getAttributeValue( indexName); 1.304 + else if( indexID >= 0) 1.305 + animName = mReader->getAttributeValue( indexID); 1.306 + else 1.307 + animName = "animation"; 1.308 + 1.309 + while( mReader->read()) 1.310 + { 1.311 + if( mReader->getNodeType() == irr::io::EXN_ELEMENT) 1.312 + { 1.313 + // we have subanimations 1.314 + if( IsElement( "animation")) 1.315 + { 1.316 + // create container from our element 1.317 + if( !anim) 1.318 + { 1.319 + anim = new Animation; 1.320 + anim->mName = animName; 1.321 + pParent->mSubAnims.push_back( anim); 1.322 + } 1.323 + 1.324 + // recurse into the subelement 1.325 + ReadAnimation( anim); 1.326 + } 1.327 + else if( IsElement( "source")) 1.328 + { 1.329 + // possible animation data - we'll never know. Better store it 1.330 + ReadSource(); 1.331 + } 1.332 + else if( IsElement( "sampler")) 1.333 + { 1.334 + // read the ID to assign the corresponding collada channel afterwards. 1.335 + int indexID = GetAttribute( "id"); 1.336 + std::string id = mReader->getAttributeValue( indexID); 1.337 + ChannelMap::iterator newChannel = channels.insert( std::make_pair( id, AnimationChannel())).first; 1.338 + 1.339 + // have it read into a channel 1.340 + ReadAnimationSampler( newChannel->second); 1.341 + } 1.342 + else if( IsElement( "channel")) 1.343 + { 1.344 + // the binding element whose whole purpose is to provide the target to animate 1.345 + // Thanks, Collada! A directly posted information would have been too simple, I guess. 1.346 + // Better add another indirection to that! Can't have enough of those. 1.347 + int indexTarget = GetAttribute( "target"); 1.348 + int indexSource = GetAttribute( "source"); 1.349 + const char* sourceId = mReader->getAttributeValue( indexSource); 1.350 + if( sourceId[0] == '#') 1.351 + sourceId++; 1.352 + ChannelMap::iterator cit = channels.find( sourceId); 1.353 + if( cit != channels.end()) 1.354 + cit->second.mTarget = mReader->getAttributeValue( indexTarget); 1.355 + 1.356 + if( !mReader->isEmptyElement()) 1.357 + SkipElement(); 1.358 + } 1.359 + else 1.360 + { 1.361 + // ignore the rest 1.362 + SkipElement(); 1.363 + } 1.364 + } 1.365 + else if( mReader->getNodeType() == irr::io::EXN_ELEMENT_END) 1.366 + { 1.367 + if( strcmp( mReader->getNodeName(), "animation") != 0) 1.368 + ThrowException( "Expected end of <animation> element."); 1.369 + 1.370 + break; 1.371 + } 1.372 + } 1.373 + 1.374 + // it turned out to have channels - add them 1.375 + if( !channels.empty()) 1.376 + { 1.377 + // special filtering for stupid exporters packing each channel into a separate animation 1.378 + if( channels.size() == 1) 1.379 + { 1.380 + pParent->mChannels.push_back( channels.begin()->second); 1.381 + } else 1.382 + { 1.383 + // else create the animation, if not done yet, and store the channels 1.384 + if( !anim) 1.385 + { 1.386 + anim = new Animation; 1.387 + anim->mName = animName; 1.388 + pParent->mSubAnims.push_back( anim); 1.389 + } 1.390 + for( ChannelMap::const_iterator it = channels.begin(); it != channels.end(); ++it) 1.391 + anim->mChannels.push_back( it->second); 1.392 + } 1.393 + } 1.394 +} 1.395 + 1.396 +// ------------------------------------------------------------------------------------------------ 1.397 +// Reads an animation sampler into the given anim channel 1.398 +void ColladaParser::ReadAnimationSampler( Collada::AnimationChannel& pChannel) 1.399 +{ 1.400 + while( mReader->read()) 1.401 + { 1.402 + if( mReader->getNodeType() == irr::io::EXN_ELEMENT) 1.403 + { 1.404 + if( IsElement( "input")) 1.405 + { 1.406 + int indexSemantic = GetAttribute( "semantic"); 1.407 + const char* semantic = mReader->getAttributeValue( indexSemantic); 1.408 + int indexSource = GetAttribute( "source"); 1.409 + const char* source = mReader->getAttributeValue( indexSource); 1.410 + if( source[0] != '#') 1.411 + ThrowException( "Unsupported URL format"); 1.412 + source++; 1.413 + 1.414 + if( strcmp( semantic, "INPUT") == 0) 1.415 + pChannel.mSourceTimes = source; 1.416 + else if( strcmp( semantic, "OUTPUT") == 0) 1.417 + pChannel.mSourceValues = source; 1.418 + 1.419 + if( !mReader->isEmptyElement()) 1.420 + SkipElement(); 1.421 + } 1.422 + else 1.423 + { 1.424 + // ignore the rest 1.425 + SkipElement(); 1.426 + } 1.427 + } 1.428 + else if( mReader->getNodeType() == irr::io::EXN_ELEMENT_END) 1.429 + { 1.430 + if( strcmp( mReader->getNodeName(), "sampler") != 0) 1.431 + ThrowException( "Expected end of <sampler> element."); 1.432 + 1.433 + break; 1.434 + } 1.435 + } 1.436 +} 1.437 + 1.438 +// ------------------------------------------------------------------------------------------------ 1.439 +// Reads the skeleton controller library 1.440 +void ColladaParser::ReadControllerLibrary() 1.441 +{ 1.442 + if (mReader->isEmptyElement()) 1.443 + return; 1.444 + 1.445 + while( mReader->read()) 1.446 + { 1.447 + if( mReader->getNodeType() == irr::io::EXN_ELEMENT) 1.448 + { 1.449 + if( IsElement( "controller")) 1.450 + { 1.451 + // read ID. Ask the spec if it's neccessary or optional... you might be surprised. 1.452 + int attrID = GetAttribute( "id"); 1.453 + std::string id = mReader->getAttributeValue( attrID); 1.454 + 1.455 + // create an entry and store it in the library under its ID 1.456 + mControllerLibrary[id] = Controller(); 1.457 + 1.458 + // read on from there 1.459 + ReadController( mControllerLibrary[id]); 1.460 + } else 1.461 + { 1.462 + // ignore the rest 1.463 + SkipElement(); 1.464 + } 1.465 + } 1.466 + else if( mReader->getNodeType() == irr::io::EXN_ELEMENT_END) 1.467 + { 1.468 + if( strcmp( mReader->getNodeName(), "library_controllers") != 0) 1.469 + ThrowException( "Expected end of <library_controllers> element."); 1.470 + 1.471 + break; 1.472 + } 1.473 + } 1.474 +} 1.475 + 1.476 +// ------------------------------------------------------------------------------------------------ 1.477 +// Reads a controller into the given mesh structure 1.478 +void ColladaParser::ReadController( Collada::Controller& pController) 1.479 +{ 1.480 + while( mReader->read()) 1.481 + { 1.482 + if( mReader->getNodeType() == irr::io::EXN_ELEMENT) 1.483 + { 1.484 + // two types of controllers: "skin" and "morph". Only the first one is relevant, we skip the other 1.485 + if( IsElement( "morph")) 1.486 + { 1.487 + // should skip everything inside, so there's no danger of catching elements inbetween 1.488 + SkipElement(); 1.489 + } 1.490 + else if( IsElement( "skin")) 1.491 + { 1.492 + // read the mesh it refers to. According to the spec this could also be another 1.493 + // controller, but I refuse to implement every single idea they've come up with 1.494 + int sourceIndex = GetAttribute( "source"); 1.495 + pController.mMeshId = mReader->getAttributeValue( sourceIndex) + 1; 1.496 + } 1.497 + else if( IsElement( "bind_shape_matrix")) 1.498 + { 1.499 + // content is 16 floats to define a matrix... it seems to be important for some models 1.500 + const char* content = GetTextContent(); 1.501 + 1.502 + // read the 16 floats 1.503 + for( unsigned int a = 0; a < 16; a++) 1.504 + { 1.505 + // read a number 1.506 + content = fast_atoreal_move<float>( content, pController.mBindShapeMatrix[a]); 1.507 + // skip whitespace after it 1.508 + SkipSpacesAndLineEnd( &content); 1.509 + } 1.510 + 1.511 + TestClosing( "bind_shape_matrix"); 1.512 + } 1.513 + else if( IsElement( "source")) 1.514 + { 1.515 + // data array - we have specialists to handle this 1.516 + ReadSource(); 1.517 + } 1.518 + else if( IsElement( "joints")) 1.519 + { 1.520 + ReadControllerJoints( pController); 1.521 + } 1.522 + else if( IsElement( "vertex_weights")) 1.523 + { 1.524 + ReadControllerWeights( pController); 1.525 + } 1.526 + else 1.527 + { 1.528 + // ignore the rest 1.529 + SkipElement(); 1.530 + } 1.531 + } 1.532 + else if( mReader->getNodeType() == irr::io::EXN_ELEMENT_END) 1.533 + { 1.534 + if( strcmp( mReader->getNodeName(), "controller") == 0) 1.535 + break; 1.536 + else if( strcmp( mReader->getNodeName(), "skin") != 0) 1.537 + ThrowException( "Expected end of <controller> element."); 1.538 + } 1.539 + } 1.540 +} 1.541 + 1.542 +// ------------------------------------------------------------------------------------------------ 1.543 +// Reads the joint definitions for the given controller 1.544 +void ColladaParser::ReadControllerJoints( Collada::Controller& pController) 1.545 +{ 1.546 + while( mReader->read()) 1.547 + { 1.548 + if( mReader->getNodeType() == irr::io::EXN_ELEMENT) 1.549 + { 1.550 + // Input channels for joint data. Two possible semantics: "JOINT" and "INV_BIND_MATRIX" 1.551 + if( IsElement( "input")) 1.552 + { 1.553 + int indexSemantic = GetAttribute( "semantic"); 1.554 + const char* attrSemantic = mReader->getAttributeValue( indexSemantic); 1.555 + int indexSource = GetAttribute( "source"); 1.556 + const char* attrSource = mReader->getAttributeValue( indexSource); 1.557 + 1.558 + // local URLS always start with a '#'. We don't support global URLs 1.559 + if( attrSource[0] != '#') 1.560 + ThrowException( boost::str( boost::format( "Unsupported URL format in \"%s\" in source attribute of <joints> data <input> element") % attrSource)); 1.561 + attrSource++; 1.562 + 1.563 + // parse source URL to corresponding source 1.564 + if( strcmp( attrSemantic, "JOINT") == 0) 1.565 + pController.mJointNameSource = attrSource; 1.566 + else if( strcmp( attrSemantic, "INV_BIND_MATRIX") == 0) 1.567 + pController.mJointOffsetMatrixSource = attrSource; 1.568 + else 1.569 + ThrowException( boost::str( boost::format( "Unknown semantic \"%s\" in <joints> data <input> element") % attrSemantic)); 1.570 + 1.571 + // skip inner data, if present 1.572 + if( !mReader->isEmptyElement()) 1.573 + SkipElement(); 1.574 + } 1.575 + else 1.576 + { 1.577 + // ignore the rest 1.578 + SkipElement(); 1.579 + } 1.580 + } 1.581 + else if( mReader->getNodeType() == irr::io::EXN_ELEMENT_END) 1.582 + { 1.583 + if( strcmp( mReader->getNodeName(), "joints") != 0) 1.584 + ThrowException( "Expected end of <joints> element."); 1.585 + 1.586 + break; 1.587 + } 1.588 + } 1.589 +} 1.590 + 1.591 +// ------------------------------------------------------------------------------------------------ 1.592 +// Reads the joint weights for the given controller 1.593 +void ColladaParser::ReadControllerWeights( Collada::Controller& pController) 1.594 +{ 1.595 + // read vertex count from attributes and resize the array accordingly 1.596 + int indexCount = GetAttribute( "count"); 1.597 + size_t vertexCount = (size_t) mReader->getAttributeValueAsInt( indexCount); 1.598 + pController.mWeightCounts.resize( vertexCount); 1.599 + 1.600 + while( mReader->read()) 1.601 + { 1.602 + if( mReader->getNodeType() == irr::io::EXN_ELEMENT) 1.603 + { 1.604 + // Input channels for weight data. Two possible semantics: "JOINT" and "WEIGHT" 1.605 + if( IsElement( "input") && vertexCount > 0 ) 1.606 + { 1.607 + InputChannel channel; 1.608 + 1.609 + int indexSemantic = GetAttribute( "semantic"); 1.610 + const char* attrSemantic = mReader->getAttributeValue( indexSemantic); 1.611 + int indexSource = GetAttribute( "source"); 1.612 + const char* attrSource = mReader->getAttributeValue( indexSource); 1.613 + int indexOffset = TestAttribute( "offset"); 1.614 + if( indexOffset >= 0) 1.615 + channel.mOffset = mReader->getAttributeValueAsInt( indexOffset); 1.616 + 1.617 + // local URLS always start with a '#'. We don't support global URLs 1.618 + if( attrSource[0] != '#') 1.619 + ThrowException( boost::str( boost::format( "Unsupported URL format in \"%s\" in source attribute of <vertex_weights> data <input> element") % attrSource)); 1.620 + channel.mAccessor = attrSource + 1; 1.621 + 1.622 + // parse source URL to corresponding source 1.623 + if( strcmp( attrSemantic, "JOINT") == 0) 1.624 + pController.mWeightInputJoints = channel; 1.625 + else if( strcmp( attrSemantic, "WEIGHT") == 0) 1.626 + pController.mWeightInputWeights = channel; 1.627 + else 1.628 + ThrowException( boost::str( boost::format( "Unknown semantic \"%s\" in <vertex_weights> data <input> element") % attrSemantic)); 1.629 + 1.630 + // skip inner data, if present 1.631 + if( !mReader->isEmptyElement()) 1.632 + SkipElement(); 1.633 + } 1.634 + else if( IsElement( "vcount") && vertexCount > 0 ) 1.635 + { 1.636 + // read weight count per vertex 1.637 + const char* text = GetTextContent(); 1.638 + size_t numWeights = 0; 1.639 + for( std::vector<size_t>::iterator it = pController.mWeightCounts.begin(); it != pController.mWeightCounts.end(); ++it) 1.640 + { 1.641 + if( *text == 0) 1.642 + ThrowException( "Out of data while reading <vcount>"); 1.643 + 1.644 + *it = strtoul10( text, &text); 1.645 + numWeights += *it; 1.646 + SkipSpacesAndLineEnd( &text); 1.647 + } 1.648 + 1.649 + TestClosing( "vcount"); 1.650 + 1.651 + // reserve weight count 1.652 + pController.mWeights.resize( numWeights); 1.653 + } 1.654 + else if( IsElement( "v") && vertexCount > 0 ) 1.655 + { 1.656 + // read JointIndex - WeightIndex pairs 1.657 + const char* text = GetTextContent(); 1.658 + 1.659 + for( std::vector< std::pair<size_t, size_t> >::iterator it = pController.mWeights.begin(); it != pController.mWeights.end(); ++it) 1.660 + { 1.661 + if( *text == 0) 1.662 + ThrowException( "Out of data while reading <vertex_weights>"); 1.663 + it->first = strtoul10( text, &text); 1.664 + SkipSpacesAndLineEnd( &text); 1.665 + if( *text == 0) 1.666 + ThrowException( "Out of data while reading <vertex_weights>"); 1.667 + it->second = strtoul10( text, &text); 1.668 + SkipSpacesAndLineEnd( &text); 1.669 + } 1.670 + 1.671 + TestClosing( "v"); 1.672 + } 1.673 + else 1.674 + { 1.675 + // ignore the rest 1.676 + SkipElement(); 1.677 + } 1.678 + } 1.679 + else if( mReader->getNodeType() == irr::io::EXN_ELEMENT_END) 1.680 + { 1.681 + if( strcmp( mReader->getNodeName(), "vertex_weights") != 0) 1.682 + ThrowException( "Expected end of <vertex_weights> element."); 1.683 + 1.684 + break; 1.685 + } 1.686 + } 1.687 +} 1.688 + 1.689 +// ------------------------------------------------------------------------------------------------ 1.690 +// Reads the image library contents 1.691 +void ColladaParser::ReadImageLibrary() 1.692 +{ 1.693 + if( mReader->isEmptyElement()) 1.694 + return; 1.695 + 1.696 + while( mReader->read()) 1.697 + { 1.698 + if( mReader->getNodeType() == irr::io::EXN_ELEMENT) { 1.699 + if( IsElement( "image")) 1.700 + { 1.701 + // read ID. Another entry which is "optional" by design but obligatory in reality 1.702 + int attrID = GetAttribute( "id"); 1.703 + std::string id = mReader->getAttributeValue( attrID); 1.704 + 1.705 + // create an entry and store it in the library under its ID 1.706 + mImageLibrary[id] = Image(); 1.707 + 1.708 + // read on from there 1.709 + ReadImage( mImageLibrary[id]); 1.710 + } else 1.711 + { 1.712 + // ignore the rest 1.713 + SkipElement(); 1.714 + } 1.715 + } 1.716 + else if( mReader->getNodeType() == irr::io::EXN_ELEMENT_END) { 1.717 + if( strcmp( mReader->getNodeName(), "library_images") != 0) 1.718 + ThrowException( "Expected end of <library_images> element."); 1.719 + 1.720 + break; 1.721 + } 1.722 + } 1.723 +} 1.724 + 1.725 +// ------------------------------------------------------------------------------------------------ 1.726 +// Reads an image entry into the given image 1.727 +void ColladaParser::ReadImage( Collada::Image& pImage) 1.728 +{ 1.729 + while( mReader->read()) 1.730 + { 1.731 + if( mReader->getNodeType() == irr::io::EXN_ELEMENT){ 1.732 + // Need to run different code paths here, depending on the Collada XSD version 1.733 + if (IsElement("image")) { 1.734 + SkipElement(); 1.735 + } 1.736 + else if( IsElement( "init_from")) 1.737 + { 1.738 + if (mFormat == FV_1_4_n) 1.739 + { 1.740 + // FIX: C4D exporter writes empty <init_from/> tags 1.741 + if (!mReader->isEmptyElement()) { 1.742 + // element content is filename - hopefully 1.743 + const char* sz = TestTextContent(); 1.744 + if (sz)pImage.mFileName = sz; 1.745 + TestClosing( "init_from"); 1.746 + } 1.747 + if (!pImage.mFileName.length()) { 1.748 + pImage.mFileName = "unknown_texture"; 1.749 + } 1.750 + } 1.751 + else if (mFormat == FV_1_5_n) 1.752 + { 1.753 + // make sure we skip over mip and array initializations, which 1.754 + // we don't support, but which could confuse the loader if 1.755 + // they're not skipped. 1.756 + int attrib = TestAttribute("array_index"); 1.757 + if (attrib != -1 && mReader->getAttributeValueAsInt(attrib) > 0) { 1.758 + DefaultLogger::get()->warn("Collada: Ignoring texture array index"); 1.759 + continue; 1.760 + } 1.761 + 1.762 + attrib = TestAttribute("mip_index"); 1.763 + if (attrib != -1 && mReader->getAttributeValueAsInt(attrib) > 0) { 1.764 + DefaultLogger::get()->warn("Collada: Ignoring MIP map layer"); 1.765 + continue; 1.766 + } 1.767 + 1.768 + // TODO: correctly jump over cube and volume maps? 1.769 + } 1.770 + } 1.771 + else if (mFormat == FV_1_5_n) 1.772 + { 1.773 + if( IsElement( "ref")) 1.774 + { 1.775 + // element content is filename - hopefully 1.776 + const char* sz = TestTextContent(); 1.777 + if (sz)pImage.mFileName = sz; 1.778 + TestClosing( "ref"); 1.779 + } 1.780 + else if( IsElement( "hex") && !pImage.mFileName.length()) 1.781 + { 1.782 + // embedded image. get format 1.783 + const int attrib = TestAttribute("format"); 1.784 + if (-1 == attrib) 1.785 + DefaultLogger::get()->warn("Collada: Unknown image file format"); 1.786 + else pImage.mEmbeddedFormat = mReader->getAttributeValue(attrib); 1.787 + 1.788 + const char* data = GetTextContent(); 1.789 + 1.790 + // hexadecimal-encoded binary octets. First of all, find the 1.791 + // required buffer size to reserve enough storage. 1.792 + const char* cur = data; 1.793 + while (!IsSpaceOrNewLine(*cur)) cur++; 1.794 + 1.795 + const unsigned int size = (unsigned int)(cur-data) * 2; 1.796 + pImage.mImageData.resize(size); 1.797 + for (unsigned int i = 0; i < size;++i) 1.798 + pImage.mImageData[i] = HexOctetToDecimal(data+(i<<1)); 1.799 + 1.800 + TestClosing( "hex"); 1.801 + } 1.802 + } 1.803 + else 1.804 + { 1.805 + // ignore the rest 1.806 + SkipElement(); 1.807 + } 1.808 + } 1.809 + else if( mReader->getNodeType() == irr::io::EXN_ELEMENT_END) { 1.810 + if( strcmp( mReader->getNodeName(), "image") == 0) 1.811 + break; 1.812 + } 1.813 + } 1.814 +} 1.815 + 1.816 +// ------------------------------------------------------------------------------------------------ 1.817 +// Reads the material library 1.818 +void ColladaParser::ReadMaterialLibrary() 1.819 +{ 1.820 + if( mReader->isEmptyElement()) 1.821 + return; 1.822 + 1.823 + while( mReader->read()) 1.824 + { 1.825 + if( mReader->getNodeType() == irr::io::EXN_ELEMENT) 1.826 + { 1.827 + if( IsElement( "material")) 1.828 + { 1.829 + // read ID. By now you propably know my opinion about this "specification" 1.830 + int attrID = GetAttribute( "id"); 1.831 + std::string id = mReader->getAttributeValue( attrID); 1.832 + 1.833 + // create an entry and store it in the library under its ID 1.834 + ReadMaterial(mMaterialLibrary[id] = Material()); 1.835 + } else 1.836 + { 1.837 + // ignore the rest 1.838 + SkipElement(); 1.839 + } 1.840 + } 1.841 + else if( mReader->getNodeType() == irr::io::EXN_ELEMENT_END) 1.842 + { 1.843 + if( strcmp( mReader->getNodeName(), "library_materials") != 0) 1.844 + ThrowException( "Expected end of <library_materials> element."); 1.845 + 1.846 + break; 1.847 + } 1.848 + } 1.849 +} 1.850 + 1.851 +// ------------------------------------------------------------------------------------------------ 1.852 +// Reads the light library 1.853 +void ColladaParser::ReadLightLibrary() 1.854 +{ 1.855 + if( mReader->isEmptyElement()) 1.856 + return; 1.857 + 1.858 + while( mReader->read()) 1.859 + { 1.860 + if( mReader->getNodeType() == irr::io::EXN_ELEMENT) { 1.861 + if( IsElement( "light")) 1.862 + { 1.863 + // read ID. By now you propably know my opinion about this "specification" 1.864 + int attrID = GetAttribute( "id"); 1.865 + std::string id = mReader->getAttributeValue( attrID); 1.866 + 1.867 + // create an entry and store it in the library under its ID 1.868 + ReadLight(mLightLibrary[id] = Light()); 1.869 + 1.870 + } else 1.871 + { 1.872 + // ignore the rest 1.873 + SkipElement(); 1.874 + } 1.875 + } 1.876 + else if( mReader->getNodeType() == irr::io::EXN_ELEMENT_END) { 1.877 + if( strcmp( mReader->getNodeName(), "library_lights") != 0) 1.878 + ThrowException( "Expected end of <library_lights> element."); 1.879 + 1.880 + break; 1.881 + } 1.882 + } 1.883 +} 1.884 + 1.885 +// ------------------------------------------------------------------------------------------------ 1.886 +// Reads the camera library 1.887 +void ColladaParser::ReadCameraLibrary() 1.888 +{ 1.889 + if( mReader->isEmptyElement()) 1.890 + return; 1.891 + 1.892 + while( mReader->read()) 1.893 + { 1.894 + if( mReader->getNodeType() == irr::io::EXN_ELEMENT) { 1.895 + if( IsElement( "camera")) 1.896 + { 1.897 + // read ID. By now you propably know my opinion about this "specification" 1.898 + int attrID = GetAttribute( "id"); 1.899 + std::string id = mReader->getAttributeValue( attrID); 1.900 + 1.901 + // create an entry and store it in the library under its ID 1.902 + Camera& cam = mCameraLibrary[id]; 1.903 + attrID = TestAttribute( "name"); 1.904 + if (attrID != -1) 1.905 + cam.mName = mReader->getAttributeValue( attrID); 1.906 + 1.907 + ReadCamera(cam); 1.908 + 1.909 + } else 1.910 + { 1.911 + // ignore the rest 1.912 + SkipElement(); 1.913 + } 1.914 + } 1.915 + else if( mReader->getNodeType() == irr::io::EXN_ELEMENT_END) { 1.916 + if( strcmp( mReader->getNodeName(), "library_cameras") != 0) 1.917 + ThrowException( "Expected end of <library_cameras> element."); 1.918 + 1.919 + break; 1.920 + } 1.921 + } 1.922 +} 1.923 + 1.924 +// ------------------------------------------------------------------------------------------------ 1.925 +// Reads a material entry into the given material 1.926 +void ColladaParser::ReadMaterial( Collada::Material& pMaterial) 1.927 +{ 1.928 + while( mReader->read()) 1.929 + { 1.930 + if( mReader->getNodeType() == irr::io::EXN_ELEMENT) { 1.931 + if (IsElement("material")) { 1.932 + SkipElement(); 1.933 + } 1.934 + else if( IsElement( "instance_effect")) 1.935 + { 1.936 + // referred effect by URL 1.937 + int attrUrl = GetAttribute( "url"); 1.938 + const char* url = mReader->getAttributeValue( attrUrl); 1.939 + if( url[0] != '#') 1.940 + ThrowException( "Unknown reference format"); 1.941 + 1.942 + pMaterial.mEffect = url+1; 1.943 + 1.944 + SkipElement(); 1.945 + } else 1.946 + { 1.947 + // ignore the rest 1.948 + SkipElement(); 1.949 + } 1.950 + } 1.951 + else if( mReader->getNodeType() == irr::io::EXN_ELEMENT_END) { 1.952 + if( strcmp( mReader->getNodeName(), "material") != 0) 1.953 + ThrowException( "Expected end of <material> element."); 1.954 + 1.955 + break; 1.956 + } 1.957 + } 1.958 +} 1.959 + 1.960 +// ------------------------------------------------------------------------------------------------ 1.961 +// Reads a light entry into the given light 1.962 +void ColladaParser::ReadLight( Collada::Light& pLight) 1.963 +{ 1.964 + while( mReader->read()) 1.965 + { 1.966 + if( mReader->getNodeType() == irr::io::EXN_ELEMENT) { 1.967 + if (IsElement("light")) { 1.968 + SkipElement(); 1.969 + } 1.970 + else if (IsElement("spot")) { 1.971 + pLight.mType = aiLightSource_SPOT; 1.972 + } 1.973 + else if (IsElement("ambient")) { 1.974 + pLight.mType = aiLightSource_AMBIENT; 1.975 + } 1.976 + else if (IsElement("directional")) { 1.977 + pLight.mType = aiLightSource_DIRECTIONAL; 1.978 + } 1.979 + else if (IsElement("point")) { 1.980 + pLight.mType = aiLightSource_POINT; 1.981 + } 1.982 + else if (IsElement("color")) { 1.983 + // text content contains 3 floats 1.984 + const char* content = GetTextContent(); 1.985 + 1.986 + content = fast_atoreal_move<float>( content, (float&)pLight.mColor.r); 1.987 + SkipSpacesAndLineEnd( &content); 1.988 + 1.989 + content = fast_atoreal_move<float>( content, (float&)pLight.mColor.g); 1.990 + SkipSpacesAndLineEnd( &content); 1.991 + 1.992 + content = fast_atoreal_move<float>( content, (float&)pLight.mColor.b); 1.993 + SkipSpacesAndLineEnd( &content); 1.994 + 1.995 + TestClosing( "color"); 1.996 + } 1.997 + else if (IsElement("constant_attenuation")) { 1.998 + pLight.mAttConstant = ReadFloatFromTextContent(); 1.999 + TestClosing("constant_attenuation"); 1.1000 + } 1.1001 + else if (IsElement("linear_attenuation")) { 1.1002 + pLight.mAttLinear = ReadFloatFromTextContent(); 1.1003 + TestClosing("linear_attenuation"); 1.1004 + } 1.1005 + else if (IsElement("quadratic_attenuation")) { 1.1006 + pLight.mAttQuadratic = ReadFloatFromTextContent(); 1.1007 + TestClosing("quadratic_attenuation"); 1.1008 + } 1.1009 + else if (IsElement("falloff_angle")) { 1.1010 + pLight.mFalloffAngle = ReadFloatFromTextContent(); 1.1011 + TestClosing("falloff_angle"); 1.1012 + } 1.1013 + else if (IsElement("falloff_exponent")) { 1.1014 + pLight.mFalloffExponent = ReadFloatFromTextContent(); 1.1015 + TestClosing("falloff_exponent"); 1.1016 + } 1.1017 + // FCOLLADA extensions 1.1018 + // ------------------------------------------------------- 1.1019 + else if (IsElement("outer_cone")) { 1.1020 + pLight.mOuterAngle = ReadFloatFromTextContent(); 1.1021 + TestClosing("outer_cone"); 1.1022 + } 1.1023 + // ... and this one is even deprecated 1.1024 + else if (IsElement("penumbra_angle")) { 1.1025 + pLight.mPenumbraAngle = ReadFloatFromTextContent(); 1.1026 + TestClosing("penumbra_angle"); 1.1027 + } 1.1028 + else if (IsElement("intensity")) { 1.1029 + pLight.mIntensity = ReadFloatFromTextContent(); 1.1030 + TestClosing("intensity"); 1.1031 + } 1.1032 + else if (IsElement("falloff")) { 1.1033 + pLight.mOuterAngle = ReadFloatFromTextContent(); 1.1034 + TestClosing("falloff"); 1.1035 + } 1.1036 + else if (IsElement("hotspot_beam")) { 1.1037 + pLight.mFalloffAngle = ReadFloatFromTextContent(); 1.1038 + TestClosing("hotspot_beam"); 1.1039 + } 1.1040 + } 1.1041 + else if( mReader->getNodeType() == irr::io::EXN_ELEMENT_END) { 1.1042 + if( strcmp( mReader->getNodeName(), "light") == 0) 1.1043 + break; 1.1044 + } 1.1045 + } 1.1046 +} 1.1047 + 1.1048 +// ------------------------------------------------------------------------------------------------ 1.1049 +// Reads a camera entry into the given light 1.1050 +void ColladaParser::ReadCamera( Collada::Camera& pCamera) 1.1051 +{ 1.1052 + while( mReader->read()) 1.1053 + { 1.1054 + if( mReader->getNodeType() == irr::io::EXN_ELEMENT) { 1.1055 + if (IsElement("camera")) { 1.1056 + SkipElement(); 1.1057 + } 1.1058 + else if (IsElement("orthographic")) { 1.1059 + pCamera.mOrtho = true; 1.1060 + } 1.1061 + else if (IsElement("xfov") || IsElement("xmag")) { 1.1062 + pCamera.mHorFov = ReadFloatFromTextContent(); 1.1063 + TestClosing((pCamera.mOrtho ? "xmag" : "xfov")); 1.1064 + } 1.1065 + else if (IsElement("yfov") || IsElement("ymag")) { 1.1066 + pCamera.mVerFov = ReadFloatFromTextContent(); 1.1067 + TestClosing((pCamera.mOrtho ? "ymag" : "yfov")); 1.1068 + } 1.1069 + else if (IsElement("aspect_ratio")) { 1.1070 + pCamera.mAspect = ReadFloatFromTextContent(); 1.1071 + TestClosing("aspect_ratio"); 1.1072 + } 1.1073 + else if (IsElement("znear")) { 1.1074 + pCamera.mZNear = ReadFloatFromTextContent(); 1.1075 + TestClosing("znear"); 1.1076 + } 1.1077 + else if (IsElement("zfar")) { 1.1078 + pCamera.mZFar = ReadFloatFromTextContent(); 1.1079 + TestClosing("zfar"); 1.1080 + } 1.1081 + } 1.1082 + else if( mReader->getNodeType() == irr::io::EXN_ELEMENT_END) { 1.1083 + if( strcmp( mReader->getNodeName(), "camera") == 0) 1.1084 + break; 1.1085 + } 1.1086 + } 1.1087 +} 1.1088 + 1.1089 +// ------------------------------------------------------------------------------------------------ 1.1090 +// Reads the effect library 1.1091 +void ColladaParser::ReadEffectLibrary() 1.1092 +{ 1.1093 + if (mReader->isEmptyElement()) { 1.1094 + return; 1.1095 + } 1.1096 + 1.1097 + while( mReader->read()) 1.1098 + { 1.1099 + if( mReader->getNodeType() == irr::io::EXN_ELEMENT) { 1.1100 + if( IsElement( "effect")) 1.1101 + { 1.1102 + // read ID. Do I have to repeat my ranting about "optional" attributes? 1.1103 + int attrID = GetAttribute( "id"); 1.1104 + std::string id = mReader->getAttributeValue( attrID); 1.1105 + 1.1106 + // create an entry and store it in the library under its ID 1.1107 + mEffectLibrary[id] = Effect(); 1.1108 + // read on from there 1.1109 + ReadEffect( mEffectLibrary[id]); 1.1110 + } else 1.1111 + { 1.1112 + // ignore the rest 1.1113 + SkipElement(); 1.1114 + } 1.1115 + } 1.1116 + else if( mReader->getNodeType() == irr::io::EXN_ELEMENT_END) { 1.1117 + if( strcmp( mReader->getNodeName(), "library_effects") != 0) 1.1118 + ThrowException( "Expected end of <library_effects> element."); 1.1119 + 1.1120 + break; 1.1121 + } 1.1122 + } 1.1123 +} 1.1124 + 1.1125 +// ------------------------------------------------------------------------------------------------ 1.1126 +// Reads an effect entry into the given effect 1.1127 +void ColladaParser::ReadEffect( Collada::Effect& pEffect) 1.1128 +{ 1.1129 + // for the moment we don't support any other type of effect. 1.1130 + while( mReader->read()) 1.1131 + { 1.1132 + if( mReader->getNodeType() == irr::io::EXN_ELEMENT) 1.1133 + { 1.1134 + if( IsElement( "profile_COMMON")) 1.1135 + ReadEffectProfileCommon( pEffect); 1.1136 + else 1.1137 + SkipElement(); 1.1138 + } 1.1139 + else if( mReader->getNodeType() == irr::io::EXN_ELEMENT_END) 1.1140 + { 1.1141 + if( strcmp( mReader->getNodeName(), "effect") != 0) 1.1142 + ThrowException( "Expected end of <effect> element."); 1.1143 + 1.1144 + break; 1.1145 + } 1.1146 + } 1.1147 +} 1.1148 + 1.1149 +// ------------------------------------------------------------------------------------------------ 1.1150 +// Reads an COMMON effect profile 1.1151 +void ColladaParser::ReadEffectProfileCommon( Collada::Effect& pEffect) 1.1152 +{ 1.1153 + while( mReader->read()) 1.1154 + { 1.1155 + if( mReader->getNodeType() == irr::io::EXN_ELEMENT) 1.1156 + { 1.1157 + if( IsElement( "newparam")) { 1.1158 + // save ID 1.1159 + int attrSID = GetAttribute( "sid"); 1.1160 + std::string sid = mReader->getAttributeValue( attrSID); 1.1161 + pEffect.mParams[sid] = EffectParam(); 1.1162 + ReadEffectParam( pEffect.mParams[sid]); 1.1163 + } 1.1164 + else if( IsElement( "technique") || IsElement( "extra")) 1.1165 + { 1.1166 + // just syntactic sugar 1.1167 + } 1.1168 + 1.1169 + /* Shading modes */ 1.1170 + else if( IsElement( "phong")) 1.1171 + pEffect.mShadeType = Shade_Phong; 1.1172 + else if( IsElement( "constant")) 1.1173 + pEffect.mShadeType = Shade_Constant; 1.1174 + else if( IsElement( "lambert")) 1.1175 + pEffect.mShadeType = Shade_Lambert; 1.1176 + else if( IsElement( "blinn")) 1.1177 + pEffect.mShadeType = Shade_Blinn; 1.1178 + 1.1179 + /* Color + texture properties */ 1.1180 + else if( IsElement( "emission")) 1.1181 + ReadEffectColor( pEffect.mEmissive, pEffect.mTexEmissive); 1.1182 + else if( IsElement( "ambient")) 1.1183 + ReadEffectColor( pEffect.mAmbient, pEffect.mTexAmbient); 1.1184 + else if( IsElement( "diffuse")) 1.1185 + ReadEffectColor( pEffect.mDiffuse, pEffect.mTexDiffuse); 1.1186 + else if( IsElement( "specular")) 1.1187 + ReadEffectColor( pEffect.mSpecular, pEffect.mTexSpecular); 1.1188 + else if( IsElement( "reflective")) { 1.1189 + ReadEffectColor( pEffect.mReflective, pEffect.mTexReflective); 1.1190 + } 1.1191 + else if( IsElement( "transparent")) { 1.1192 + ReadEffectColor( pEffect.mTransparent,pEffect.mTexTransparent); 1.1193 + } 1.1194 + else if( IsElement( "shininess")) 1.1195 + ReadEffectFloat( pEffect.mShininess); 1.1196 + else if( IsElement( "reflectivity")) 1.1197 + ReadEffectFloat( pEffect.mReflectivity); 1.1198 + 1.1199 + /* Single scalar properties */ 1.1200 + else if( IsElement( "transparency")) 1.1201 + ReadEffectFloat( pEffect.mTransparency); 1.1202 + else if( IsElement( "index_of_refraction")) 1.1203 + ReadEffectFloat( pEffect.mRefractIndex); 1.1204 + 1.1205 + // GOOGLEEARTH/OKINO extensions 1.1206 + // ------------------------------------------------------- 1.1207 + else if( IsElement( "double_sided")) 1.1208 + pEffect.mDoubleSided = ReadBoolFromTextContent(); 1.1209 + 1.1210 + // FCOLLADA extensions 1.1211 + // ------------------------------------------------------- 1.1212 + else if( IsElement( "bump")) { 1.1213 + aiColor4D dummy; 1.1214 + ReadEffectColor( dummy,pEffect.mTexBump); 1.1215 + } 1.1216 + 1.1217 + // MAX3D extensions 1.1218 + // ------------------------------------------------------- 1.1219 + else if( IsElement( "wireframe")) { 1.1220 + pEffect.mWireframe = ReadBoolFromTextContent(); 1.1221 + TestClosing( "wireframe"); 1.1222 + } 1.1223 + else if( IsElement( "faceted")) { 1.1224 + pEffect.mFaceted = ReadBoolFromTextContent(); 1.1225 + TestClosing( "faceted"); 1.1226 + } 1.1227 + else 1.1228 + { 1.1229 + // ignore the rest 1.1230 + SkipElement(); 1.1231 + } 1.1232 + } 1.1233 + else if( mReader->getNodeType() == irr::io::EXN_ELEMENT_END) { 1.1234 + if( strcmp( mReader->getNodeName(), "profile_COMMON") == 0) 1.1235 + { 1.1236 + break; 1.1237 + } 1.1238 + } 1.1239 + } 1.1240 +} 1.1241 + 1.1242 +// ------------------------------------------------------------------------------------------------ 1.1243 +// Read texture wrapping + UV transform settings from a profile==Maya chunk 1.1244 +void ColladaParser::ReadSamplerProperties( Sampler& out ) 1.1245 +{ 1.1246 + if (mReader->isEmptyElement()) { 1.1247 + return; 1.1248 + } 1.1249 + 1.1250 + while( mReader->read()) 1.1251 + { 1.1252 + if( mReader->getNodeType() == irr::io::EXN_ELEMENT) { 1.1253 + 1.1254 + // MAYA extensions 1.1255 + // ------------------------------------------------------- 1.1256 + if( IsElement( "wrapU")) { 1.1257 + out.mWrapU = ReadBoolFromTextContent(); 1.1258 + TestClosing( "wrapU"); 1.1259 + } 1.1260 + else if( IsElement( "wrapV")) { 1.1261 + out.mWrapV = ReadBoolFromTextContent(); 1.1262 + TestClosing( "wrapV"); 1.1263 + } 1.1264 + else if( IsElement( "mirrorU")) { 1.1265 + out.mMirrorU = ReadBoolFromTextContent(); 1.1266 + TestClosing( "mirrorU"); 1.1267 + } 1.1268 + else if( IsElement( "mirrorV")) { 1.1269 + out.mMirrorV = ReadBoolFromTextContent(); 1.1270 + TestClosing( "mirrorV"); 1.1271 + } 1.1272 + else if( IsElement( "repeatU")) { 1.1273 + out.mTransform.mScaling.x = ReadFloatFromTextContent(); 1.1274 + TestClosing( "repeatU"); 1.1275 + } 1.1276 + else if( IsElement( "repeatV")) { 1.1277 + out.mTransform.mScaling.y = ReadFloatFromTextContent(); 1.1278 + TestClosing( "repeatV"); 1.1279 + } 1.1280 + else if( IsElement( "offsetU")) { 1.1281 + out.mTransform.mTranslation.x = ReadFloatFromTextContent(); 1.1282 + TestClosing( "offsetU"); 1.1283 + } 1.1284 + else if( IsElement( "offsetV")) { 1.1285 + out.mTransform.mTranslation.y = ReadFloatFromTextContent(); 1.1286 + TestClosing( "offsetV"); 1.1287 + } 1.1288 + else if( IsElement( "rotateUV")) { 1.1289 + out.mTransform.mRotation = ReadFloatFromTextContent(); 1.1290 + TestClosing( "rotateUV"); 1.1291 + } 1.1292 + else if( IsElement( "blend_mode")) { 1.1293 + 1.1294 + const char* sz = GetTextContent(); 1.1295 + // http://www.feelingsoftware.com/content/view/55/72/lang,en/ 1.1296 + // NONE, OVER, IN, OUT, ADD, SUBTRACT, MULTIPLY, DIFFERENCE, LIGHTEN, DARKEN, SATURATE, DESATURATE and ILLUMINATE 1.1297 + if (0 == ASSIMP_strincmp(sz,"ADD",3)) 1.1298 + out.mOp = aiTextureOp_Add; 1.1299 + 1.1300 + else if (0 == ASSIMP_strincmp(sz,"SUBTRACT",8)) 1.1301 + out.mOp = aiTextureOp_Subtract; 1.1302 + 1.1303 + else if (0 == ASSIMP_strincmp(sz,"MULTIPLY",8)) 1.1304 + out.mOp = aiTextureOp_Multiply; 1.1305 + 1.1306 + else { 1.1307 + DefaultLogger::get()->warn("Collada: Unsupported MAYA texture blend mode"); 1.1308 + } 1.1309 + TestClosing( "blend_mode"); 1.1310 + } 1.1311 + // OKINO extensions 1.1312 + // ------------------------------------------------------- 1.1313 + else if( IsElement( "weighting")) { 1.1314 + out.mWeighting = ReadFloatFromTextContent(); 1.1315 + TestClosing( "weighting"); 1.1316 + } 1.1317 + else if( IsElement( "mix_with_previous_layer")) { 1.1318 + out.mMixWithPrevious = ReadFloatFromTextContent(); 1.1319 + TestClosing( "mix_with_previous_layer"); 1.1320 + } 1.1321 + // MAX3D extensions 1.1322 + // ------------------------------------------------------- 1.1323 + else if( IsElement( "amount")) { 1.1324 + out.mWeighting = ReadFloatFromTextContent(); 1.1325 + TestClosing( "amount"); 1.1326 + } 1.1327 + } 1.1328 + else if( mReader->getNodeType() == irr::io::EXN_ELEMENT_END) { 1.1329 + if( strcmp( mReader->getNodeName(), "technique") == 0) 1.1330 + break; 1.1331 + } 1.1332 + } 1.1333 +} 1.1334 + 1.1335 +// ------------------------------------------------------------------------------------------------ 1.1336 +// Reads an effect entry containing a color or a texture defining that color 1.1337 +void ColladaParser::ReadEffectColor( aiColor4D& pColor, Sampler& pSampler) 1.1338 +{ 1.1339 + if (mReader->isEmptyElement()) 1.1340 + return; 1.1341 + 1.1342 + // Save current element name 1.1343 + const std::string curElem = mReader->getNodeName(); 1.1344 + 1.1345 + while( mReader->read()) 1.1346 + { 1.1347 + if( mReader->getNodeType() == irr::io::EXN_ELEMENT) { 1.1348 + if( IsElement( "color")) 1.1349 + { 1.1350 + // text content contains 4 floats 1.1351 + const char* content = GetTextContent(); 1.1352 + 1.1353 + content = fast_atoreal_move<float>( content, (float&)pColor.r); 1.1354 + SkipSpacesAndLineEnd( &content); 1.1355 + 1.1356 + content = fast_atoreal_move<float>( content, (float&)pColor.g); 1.1357 + SkipSpacesAndLineEnd( &content); 1.1358 + 1.1359 + content = fast_atoreal_move<float>( content, (float&)pColor.b); 1.1360 + SkipSpacesAndLineEnd( &content); 1.1361 + 1.1362 + content = fast_atoreal_move<float>( content, (float&)pColor.a); 1.1363 + SkipSpacesAndLineEnd( &content); 1.1364 + TestClosing( "color"); 1.1365 + } 1.1366 + else if( IsElement( "texture")) 1.1367 + { 1.1368 + // get name of source textur/sampler 1.1369 + int attrTex = GetAttribute( "texture"); 1.1370 + pSampler.mName = mReader->getAttributeValue( attrTex); 1.1371 + 1.1372 + // get name of UV source channel. Specification demands it to be there, but some exporters 1.1373 + // don't write it. It will be the default UV channel in case it's missing. 1.1374 + attrTex = TestAttribute( "texcoord"); 1.1375 + if( attrTex >= 0 ) 1.1376 + pSampler.mUVChannel = mReader->getAttributeValue( attrTex); 1.1377 + //SkipElement(); 1.1378 + } 1.1379 + else if( IsElement( "technique")) 1.1380 + { 1.1381 + const int _profile = GetAttribute( "profile"); 1.1382 + const char* profile = mReader->getAttributeValue( _profile ); 1.1383 + 1.1384 + // Some extensions are quite useful ... ReadSamplerProperties processes 1.1385 + // several extensions in MAYA, OKINO and MAX3D profiles. 1.1386 + if (!::strcmp(profile,"MAYA") || !::strcmp(profile,"MAX3D") || !::strcmp(profile,"OKINO")) 1.1387 + { 1.1388 + // get more information on this sampler 1.1389 + ReadSamplerProperties(pSampler); 1.1390 + } 1.1391 + else SkipElement(); 1.1392 + } 1.1393 + else if( !IsElement( "extra")) 1.1394 + { 1.1395 + // ignore the rest 1.1396 + SkipElement(); 1.1397 + } 1.1398 + } 1.1399 + else if( mReader->getNodeType() == irr::io::EXN_ELEMENT_END){ 1.1400 + if (mReader->getNodeName() == curElem) 1.1401 + break; 1.1402 + } 1.1403 + } 1.1404 +} 1.1405 + 1.1406 +// ------------------------------------------------------------------------------------------------ 1.1407 +// Reads an effect entry containing a float 1.1408 +void ColladaParser::ReadEffectFloat( float& pFloat) 1.1409 +{ 1.1410 + while( mReader->read()) 1.1411 + { 1.1412 + if( mReader->getNodeType() == irr::io::EXN_ELEMENT){ 1.1413 + if( IsElement( "float")) 1.1414 + { 1.1415 + // text content contains a single floats 1.1416 + const char* content = GetTextContent(); 1.1417 + content = fast_atoreal_move<float>( content, pFloat); 1.1418 + SkipSpacesAndLineEnd( &content); 1.1419 + 1.1420 + TestClosing( "float"); 1.1421 + } else 1.1422 + { 1.1423 + // ignore the rest 1.1424 + SkipElement(); 1.1425 + } 1.1426 + } 1.1427 + else if( mReader->getNodeType() == irr::io::EXN_ELEMENT_END){ 1.1428 + break; 1.1429 + } 1.1430 + } 1.1431 +} 1.1432 + 1.1433 +// ------------------------------------------------------------------------------------------------ 1.1434 +// Reads an effect parameter specification of any kind 1.1435 +void ColladaParser::ReadEffectParam( Collada::EffectParam& pParam) 1.1436 +{ 1.1437 + while( mReader->read()) 1.1438 + { 1.1439 + if( mReader->getNodeType() == irr::io::EXN_ELEMENT) { 1.1440 + if( IsElement( "surface")) 1.1441 + { 1.1442 + // image ID given inside <init_from> tags 1.1443 + TestOpening( "init_from"); 1.1444 + const char* content = GetTextContent(); 1.1445 + pParam.mType = Param_Surface; 1.1446 + pParam.mReference = content; 1.1447 + TestClosing( "init_from"); 1.1448 + 1.1449 + // don't care for remaining stuff 1.1450 + SkipElement( "surface"); 1.1451 + } 1.1452 + else if( IsElement( "sampler2D")) 1.1453 + { 1.1454 + // surface ID is given inside <source> tags 1.1455 + TestOpening( "source"); 1.1456 + const char* content = GetTextContent(); 1.1457 + pParam.mType = Param_Sampler; 1.1458 + pParam.mReference = content; 1.1459 + TestClosing( "source"); 1.1460 + 1.1461 + // don't care for remaining stuff 1.1462 + SkipElement( "sampler2D"); 1.1463 + } else 1.1464 + { 1.1465 + // ignore unknown element 1.1466 + SkipElement(); 1.1467 + } 1.1468 + } 1.1469 + else if( mReader->getNodeType() == irr::io::EXN_ELEMENT_END) { 1.1470 + break; 1.1471 + } 1.1472 + } 1.1473 +} 1.1474 + 1.1475 +// ------------------------------------------------------------------------------------------------ 1.1476 +// Reads the geometry library contents 1.1477 +void ColladaParser::ReadGeometryLibrary() 1.1478 +{ 1.1479 + if( mReader->isEmptyElement()) 1.1480 + return; 1.1481 + 1.1482 + while( mReader->read()) 1.1483 + { 1.1484 + if( mReader->getNodeType() == irr::io::EXN_ELEMENT) 1.1485 + { 1.1486 + if( IsElement( "geometry")) 1.1487 + { 1.1488 + // read ID. Another entry which is "optional" by design but obligatory in reality 1.1489 + int indexID = GetAttribute( "id"); 1.1490 + std::string id = mReader->getAttributeValue( indexID); 1.1491 + 1.1492 + // TODO: (thom) support SIDs 1.1493 + // ai_assert( TestAttribute( "sid") == -1); 1.1494 + 1.1495 + // create a mesh and store it in the library under its ID 1.1496 + Mesh* mesh = new Mesh; 1.1497 + mMeshLibrary[id] = mesh; 1.1498 + 1.1499 + // read on from there 1.1500 + ReadGeometry( mesh); 1.1501 + } else 1.1502 + { 1.1503 + // ignore the rest 1.1504 + SkipElement(); 1.1505 + } 1.1506 + } 1.1507 + else if( mReader->getNodeType() == irr::io::EXN_ELEMENT_END) 1.1508 + { 1.1509 + if( strcmp( mReader->getNodeName(), "library_geometries") != 0) 1.1510 + ThrowException( "Expected end of <library_geometries> element."); 1.1511 + 1.1512 + break; 1.1513 + } 1.1514 + } 1.1515 +} 1.1516 + 1.1517 +// ------------------------------------------------------------------------------------------------ 1.1518 +// Reads a geometry from the geometry library. 1.1519 +void ColladaParser::ReadGeometry( Collada::Mesh* pMesh) 1.1520 +{ 1.1521 + if( mReader->isEmptyElement()) 1.1522 + return; 1.1523 + 1.1524 + while( mReader->read()) 1.1525 + { 1.1526 + if( mReader->getNodeType() == irr::io::EXN_ELEMENT) 1.1527 + { 1.1528 + if( IsElement( "mesh")) 1.1529 + { 1.1530 + // read on from there 1.1531 + ReadMesh( pMesh); 1.1532 + } else 1.1533 + { 1.1534 + // ignore the rest 1.1535 + SkipElement(); 1.1536 + } 1.1537 + } 1.1538 + else if( mReader->getNodeType() == irr::io::EXN_ELEMENT_END) 1.1539 + { 1.1540 + if( strcmp( mReader->getNodeName(), "geometry") != 0) 1.1541 + ThrowException( "Expected end of <geometry> element."); 1.1542 + 1.1543 + break; 1.1544 + } 1.1545 + } 1.1546 +} 1.1547 + 1.1548 +// ------------------------------------------------------------------------------------------------ 1.1549 +// Reads a mesh from the geometry library 1.1550 +void ColladaParser::ReadMesh( Mesh* pMesh) 1.1551 +{ 1.1552 + if( mReader->isEmptyElement()) 1.1553 + return; 1.1554 + 1.1555 + while( mReader->read()) 1.1556 + { 1.1557 + if( mReader->getNodeType() == irr::io::EXN_ELEMENT) 1.1558 + { 1.1559 + if( IsElement( "source")) 1.1560 + { 1.1561 + // we have professionals dealing with this 1.1562 + ReadSource(); 1.1563 + } 1.1564 + else if( IsElement( "vertices")) 1.1565 + { 1.1566 + // read per-vertex mesh data 1.1567 + ReadVertexData( pMesh); 1.1568 + } 1.1569 + else if( IsElement( "triangles") || IsElement( "lines") || IsElement( "linestrips") 1.1570 + || IsElement( "polygons") || IsElement( "polylist") || IsElement( "trifans") || IsElement( "tristrips")) 1.1571 + { 1.1572 + // read per-index mesh data and faces setup 1.1573 + ReadIndexData( pMesh); 1.1574 + } else 1.1575 + { 1.1576 + // ignore the rest 1.1577 + SkipElement(); 1.1578 + } 1.1579 + } 1.1580 + else if( mReader->getNodeType() == irr::io::EXN_ELEMENT_END) 1.1581 + { 1.1582 + if( strcmp( mReader->getNodeName(), "technique_common") == 0) 1.1583 + { 1.1584 + // end of another meaningless element - read over it 1.1585 + } 1.1586 + else if( strcmp( mReader->getNodeName(), "mesh") == 0) 1.1587 + { 1.1588 + // end of <mesh> element - we're done here 1.1589 + break; 1.1590 + } else 1.1591 + { 1.1592 + // everything else should be punished 1.1593 + ThrowException( "Expected end of <mesh> element."); 1.1594 + } 1.1595 + } 1.1596 + } 1.1597 +} 1.1598 + 1.1599 +// ------------------------------------------------------------------------------------------------ 1.1600 +// Reads a source element 1.1601 +void ColladaParser::ReadSource() 1.1602 +{ 1.1603 + int indexID = GetAttribute( "id"); 1.1604 + std::string sourceID = mReader->getAttributeValue( indexID); 1.1605 + 1.1606 + while( mReader->read()) 1.1607 + { 1.1608 + if( mReader->getNodeType() == irr::io::EXN_ELEMENT) 1.1609 + { 1.1610 + if( IsElement( "float_array") || IsElement( "IDREF_array") || IsElement( "Name_array")) 1.1611 + { 1.1612 + ReadDataArray(); 1.1613 + } 1.1614 + else if( IsElement( "technique_common")) 1.1615 + { 1.1616 + // I don't care for your profiles 1.1617 + } 1.1618 + else if( IsElement( "accessor")) 1.1619 + { 1.1620 + ReadAccessor( sourceID); 1.1621 + } else 1.1622 + { 1.1623 + // ignore the rest 1.1624 + SkipElement(); 1.1625 + } 1.1626 + } 1.1627 + else if( mReader->getNodeType() == irr::io::EXN_ELEMENT_END) 1.1628 + { 1.1629 + if( strcmp( mReader->getNodeName(), "source") == 0) 1.1630 + { 1.1631 + // end of <source> - we're done 1.1632 + break; 1.1633 + } 1.1634 + else if( strcmp( mReader->getNodeName(), "technique_common") == 0) 1.1635 + { 1.1636 + // end of another meaningless element - read over it 1.1637 + } else 1.1638 + { 1.1639 + // everything else should be punished 1.1640 + ThrowException( "Expected end of <source> element."); 1.1641 + } 1.1642 + } 1.1643 + } 1.1644 +} 1.1645 + 1.1646 +// ------------------------------------------------------------------------------------------------ 1.1647 +// Reads a data array holding a number of floats, and stores it in the global library 1.1648 +void ColladaParser::ReadDataArray() 1.1649 +{ 1.1650 + std::string elmName = mReader->getNodeName(); 1.1651 + bool isStringArray = (elmName == "IDREF_array" || elmName == "Name_array"); 1.1652 + bool isEmptyElement = mReader->isEmptyElement(); 1.1653 + 1.1654 + // read attributes 1.1655 + int indexID = GetAttribute( "id"); 1.1656 + std::string id = mReader->getAttributeValue( indexID); 1.1657 + int indexCount = GetAttribute( "count"); 1.1658 + unsigned int count = (unsigned int) mReader->getAttributeValueAsInt( indexCount); 1.1659 + if (count == 0) { return; } // some exporters write empty data arrays with count="0" 1.1660 + const char* content = TestTextContent(); 1.1661 + 1.1662 + // read values and store inside an array in the data library 1.1663 + mDataLibrary[id] = Data(); 1.1664 + Data& data = mDataLibrary[id]; 1.1665 + data.mIsStringArray = isStringArray; 1.1666 + 1.1667 + // some exporters write empty data arrays, but we need to conserve them anyways because others might reference them 1.1668 + if (content) 1.1669 + { 1.1670 + if( isStringArray) 1.1671 + { 1.1672 + data.mStrings.reserve( count); 1.1673 + std::string s; 1.1674 + 1.1675 + for( unsigned int a = 0; a < count; a++) 1.1676 + { 1.1677 + if( *content == 0) 1.1678 + ThrowException( "Expected more values while reading IDREF_array contents."); 1.1679 + 1.1680 + s.clear(); 1.1681 + while( !IsSpaceOrNewLine( *content)) 1.1682 + s += *content++; 1.1683 + data.mStrings.push_back( s); 1.1684 + 1.1685 + SkipSpacesAndLineEnd( &content); 1.1686 + } 1.1687 + } else 1.1688 + { 1.1689 + data.mValues.reserve( count); 1.1690 + 1.1691 + for( unsigned int a = 0; a < count; a++) 1.1692 + { 1.1693 + if( *content == 0) 1.1694 + ThrowException( "Expected more values while reading float_array contents."); 1.1695 + 1.1696 + float value; 1.1697 + // read a number 1.1698 + content = fast_atoreal_move<float>( content, value); 1.1699 + data.mValues.push_back( value); 1.1700 + // skip whitespace after it 1.1701 + SkipSpacesAndLineEnd( &content); 1.1702 + } 1.1703 + } 1.1704 + } 1.1705 + 1.1706 + // test for closing tag 1.1707 + if( !isEmptyElement ) 1.1708 + TestClosing( elmName.c_str()); 1.1709 +} 1.1710 + 1.1711 +// ------------------------------------------------------------------------------------------------ 1.1712 +// Reads an accessor and stores it in the global library 1.1713 +void ColladaParser::ReadAccessor( const std::string& pID) 1.1714 +{ 1.1715 + // read accessor attributes 1.1716 + int attrSource = GetAttribute( "source"); 1.1717 + const char* source = mReader->getAttributeValue( attrSource); 1.1718 + if( source[0] != '#') 1.1719 + ThrowException( boost::str( boost::format( "Unknown reference format in url \"%s\" in source attribute of <accessor> element.") % source)); 1.1720 + int attrCount = GetAttribute( "count"); 1.1721 + unsigned int count = (unsigned int) mReader->getAttributeValueAsInt( attrCount); 1.1722 + int attrOffset = TestAttribute( "offset"); 1.1723 + unsigned int offset = 0; 1.1724 + if( attrOffset > -1) 1.1725 + offset = (unsigned int) mReader->getAttributeValueAsInt( attrOffset); 1.1726 + int attrStride = TestAttribute( "stride"); 1.1727 + unsigned int stride = 1; 1.1728 + if( attrStride > -1) 1.1729 + stride = (unsigned int) mReader->getAttributeValueAsInt( attrStride); 1.1730 + 1.1731 + // store in the library under the given ID 1.1732 + mAccessorLibrary[pID] = Accessor(); 1.1733 + Accessor& acc = mAccessorLibrary[pID]; 1.1734 + acc.mCount = count; 1.1735 + acc.mOffset = offset; 1.1736 + acc.mStride = stride; 1.1737 + acc.mSource = source+1; // ignore the leading '#' 1.1738 + acc.mSize = 0; // gets incremented with every param 1.1739 + 1.1740 + // and read the components 1.1741 + while( mReader->read()) 1.1742 + { 1.1743 + if( mReader->getNodeType() == irr::io::EXN_ELEMENT) 1.1744 + { 1.1745 + if( IsElement( "param")) 1.1746 + { 1.1747 + // read data param 1.1748 + int attrName = TestAttribute( "name"); 1.1749 + std::string name; 1.1750 + if( attrName > -1) 1.1751 + { 1.1752 + name = mReader->getAttributeValue( attrName); 1.1753 + 1.1754 + // analyse for common type components and store it's sub-offset in the corresponding field 1.1755 + 1.1756 + /* Cartesian coordinates */ 1.1757 + if( name == "X") acc.mSubOffset[0] = acc.mParams.size(); 1.1758 + else if( name == "Y") acc.mSubOffset[1] = acc.mParams.size(); 1.1759 + else if( name == "Z") acc.mSubOffset[2] = acc.mParams.size(); 1.1760 + 1.1761 + /* RGBA colors */ 1.1762 + else if( name == "R") acc.mSubOffset[0] = acc.mParams.size(); 1.1763 + else if( name == "G") acc.mSubOffset[1] = acc.mParams.size(); 1.1764 + else if( name == "B") acc.mSubOffset[2] = acc.mParams.size(); 1.1765 + else if( name == "A") acc.mSubOffset[3] = acc.mParams.size(); 1.1766 + 1.1767 + /* UVWQ (STPQ) texture coordinates */ 1.1768 + else if( name == "S") acc.mSubOffset[0] = acc.mParams.size(); 1.1769 + else if( name == "T") acc.mSubOffset[1] = acc.mParams.size(); 1.1770 + else if( name == "P") acc.mSubOffset[2] = acc.mParams.size(); 1.1771 + // else if( name == "Q") acc.mSubOffset[3] = acc.mParams.size(); 1.1772 + /* 4D uv coordinates are not supported in Assimp */ 1.1773 + 1.1774 + /* Generic extra data, interpreted as UV data, too*/ 1.1775 + else if( name == "U") acc.mSubOffset[0] = acc.mParams.size(); 1.1776 + else if( name == "V") acc.mSubOffset[1] = acc.mParams.size(); 1.1777 + //else 1.1778 + // DefaultLogger::get()->warn( boost::str( boost::format( "Unknown accessor parameter \"%s\". Ignoring data channel.") % name)); 1.1779 + } 1.1780 + 1.1781 + // read data type 1.1782 + int attrType = TestAttribute( "type"); 1.1783 + if( attrType > -1) 1.1784 + { 1.1785 + // for the moment we only distinguish between a 4x4 matrix and anything else. 1.1786 + // TODO: (thom) I don't have a spec here at work. Check if there are other multi-value types 1.1787 + // which should be tested for here. 1.1788 + std::string type = mReader->getAttributeValue( attrType); 1.1789 + if( type == "float4x4") 1.1790 + acc.mSize += 16; 1.1791 + else 1.1792 + acc.mSize += 1; 1.1793 + } 1.1794 + 1.1795 + acc.mParams.push_back( name); 1.1796 + 1.1797 + // skip remaining stuff of this element, if any 1.1798 + SkipElement(); 1.1799 + } else 1.1800 + { 1.1801 + ThrowException( boost::str( boost::format( "Unexpected sub element <%s> in tag <accessor>") % mReader->getNodeName())); 1.1802 + } 1.1803 + } 1.1804 + else if( mReader->getNodeType() == irr::io::EXN_ELEMENT_END) 1.1805 + { 1.1806 + if( strcmp( mReader->getNodeName(), "accessor") != 0) 1.1807 + ThrowException( "Expected end of <accessor> element."); 1.1808 + break; 1.1809 + } 1.1810 + } 1.1811 +} 1.1812 + 1.1813 +// ------------------------------------------------------------------------------------------------ 1.1814 +// Reads input declarations of per-vertex mesh data into the given mesh 1.1815 +void ColladaParser::ReadVertexData( Mesh* pMesh) 1.1816 +{ 1.1817 + // extract the ID of the <vertices> element. Not that we care, but to catch strange referencing schemes we should warn about 1.1818 + int attrID= GetAttribute( "id"); 1.1819 + pMesh->mVertexID = mReader->getAttributeValue( attrID); 1.1820 + 1.1821 + // a number of <input> elements 1.1822 + while( mReader->read()) 1.1823 + { 1.1824 + if( mReader->getNodeType() == irr::io::EXN_ELEMENT) 1.1825 + { 1.1826 + if( IsElement( "input")) 1.1827 + { 1.1828 + ReadInputChannel( pMesh->mPerVertexData); 1.1829 + } else 1.1830 + { 1.1831 + ThrowException( boost::str( boost::format( "Unexpected sub element <%s> in tag <vertices>") % mReader->getNodeName())); 1.1832 + } 1.1833 + } 1.1834 + else if( mReader->getNodeType() == irr::io::EXN_ELEMENT_END) 1.1835 + { 1.1836 + if( strcmp( mReader->getNodeName(), "vertices") != 0) 1.1837 + ThrowException( "Expected end of <vertices> element."); 1.1838 + 1.1839 + break; 1.1840 + } 1.1841 + } 1.1842 +} 1.1843 + 1.1844 +// ------------------------------------------------------------------------------------------------ 1.1845 +// Reads input declarations of per-index mesh data into the given mesh 1.1846 +void ColladaParser::ReadIndexData( Mesh* pMesh) 1.1847 +{ 1.1848 + std::vector<size_t> vcount; 1.1849 + std::vector<InputChannel> perIndexData; 1.1850 + 1.1851 + // read primitive count from the attribute 1.1852 + int attrCount = GetAttribute( "count"); 1.1853 + size_t numPrimitives = (size_t) mReader->getAttributeValueAsInt( attrCount); 1.1854 + 1.1855 + // material subgroup 1.1856 + int attrMaterial = TestAttribute( "material"); 1.1857 + SubMesh subgroup; 1.1858 + if( attrMaterial > -1) 1.1859 + subgroup.mMaterial = mReader->getAttributeValue( attrMaterial); 1.1860 + subgroup.mNumFaces = numPrimitives; 1.1861 + pMesh->mSubMeshes.push_back( subgroup); 1.1862 + 1.1863 + // distinguish between polys and triangles 1.1864 + std::string elementName = mReader->getNodeName(); 1.1865 + PrimitiveType primType = Prim_Invalid; 1.1866 + if( IsElement( "lines")) 1.1867 + primType = Prim_Lines; 1.1868 + else if( IsElement( "linestrips")) 1.1869 + primType = Prim_LineStrip; 1.1870 + else if( IsElement( "polygons")) 1.1871 + primType = Prim_Polygon; 1.1872 + else if( IsElement( "polylist")) 1.1873 + primType = Prim_Polylist; 1.1874 + else if( IsElement( "triangles")) 1.1875 + primType = Prim_Triangles; 1.1876 + else if( IsElement( "trifans")) 1.1877 + primType = Prim_TriFans; 1.1878 + else if( IsElement( "tristrips")) 1.1879 + primType = Prim_TriStrips; 1.1880 + 1.1881 + ai_assert( primType != Prim_Invalid); 1.1882 + 1.1883 + // also a number of <input> elements, but in addition a <p> primitive collection and propably index counts for all primitives 1.1884 + while( mReader->read()) 1.1885 + { 1.1886 + if( mReader->getNodeType() == irr::io::EXN_ELEMENT) 1.1887 + { 1.1888 + if( IsElement( "input")) 1.1889 + { 1.1890 + ReadInputChannel( perIndexData); 1.1891 + } 1.1892 + else if( IsElement( "vcount")) 1.1893 + { 1.1894 + if( !mReader->isEmptyElement()) 1.1895 + { 1.1896 + if (numPrimitives) // It is possible to define a mesh without any primitives 1.1897 + { 1.1898 + // case <polylist> - specifies the number of indices for each polygon 1.1899 + const char* content = GetTextContent(); 1.1900 + vcount.reserve( numPrimitives); 1.1901 + for( unsigned int a = 0; a < numPrimitives; a++) 1.1902 + { 1.1903 + if( *content == 0) 1.1904 + ThrowException( "Expected more values while reading <vcount> contents."); 1.1905 + // read a number 1.1906 + vcount.push_back( (size_t) strtoul10( content, &content)); 1.1907 + // skip whitespace after it 1.1908 + SkipSpacesAndLineEnd( &content); 1.1909 + } 1.1910 + } 1.1911 + 1.1912 + TestClosing( "vcount"); 1.1913 + } 1.1914 + } 1.1915 + else if( IsElement( "p")) 1.1916 + { 1.1917 + if( !mReader->isEmptyElement()) 1.1918 + { 1.1919 + // now here the actual fun starts - these are the indices to construct the mesh data from 1.1920 + ReadPrimitives( pMesh, perIndexData, numPrimitives, vcount, primType); 1.1921 + } 1.1922 + } else 1.1923 + { 1.1924 + ThrowException( boost::str( boost::format( "Unexpected sub element <%s> in tag <%s>") % mReader->getNodeName() % elementName)); 1.1925 + } 1.1926 + } 1.1927 + else if( mReader->getNodeType() == irr::io::EXN_ELEMENT_END) 1.1928 + { 1.1929 + if( mReader->getNodeName() != elementName) 1.1930 + ThrowException( boost::str( boost::format( "Expected end of <%s> element.") % elementName)); 1.1931 + 1.1932 + break; 1.1933 + } 1.1934 + } 1.1935 +} 1.1936 + 1.1937 +// ------------------------------------------------------------------------------------------------ 1.1938 +// Reads a single input channel element and stores it in the given array, if valid 1.1939 +void ColladaParser::ReadInputChannel( std::vector<InputChannel>& poChannels) 1.1940 +{ 1.1941 + InputChannel channel; 1.1942 + 1.1943 + // read semantic 1.1944 + int attrSemantic = GetAttribute( "semantic"); 1.1945 + std::string semantic = mReader->getAttributeValue( attrSemantic); 1.1946 + channel.mType = GetTypeForSemantic( semantic); 1.1947 + 1.1948 + // read source 1.1949 + int attrSource = GetAttribute( "source"); 1.1950 + const char* source = mReader->getAttributeValue( attrSource); 1.1951 + if( source[0] != '#') 1.1952 + ThrowException( boost::str( boost::format( "Unknown reference format in url \"%s\" in source attribute of <input> element.") % source)); 1.1953 + channel.mAccessor = source+1; // skipping the leading #, hopefully the remaining text is the accessor ID only 1.1954 + 1.1955 + // read index offset, if per-index <input> 1.1956 + int attrOffset = TestAttribute( "offset"); 1.1957 + if( attrOffset > -1) 1.1958 + channel.mOffset = mReader->getAttributeValueAsInt( attrOffset); 1.1959 + 1.1960 + // read set if texture coordinates 1.1961 + if(channel.mType == IT_Texcoord || channel.mType == IT_Color){ 1.1962 + int attrSet = TestAttribute("set"); 1.1963 + if(attrSet > -1){ 1.1964 + attrSet = mReader->getAttributeValueAsInt( attrSet); 1.1965 + if(attrSet < 0) 1.1966 + ThrowException( boost::str( boost::format( "Invalid index \"%i\" in set attribute of <input> element") % (attrSet))); 1.1967 + 1.1968 + channel.mIndex = attrSet; 1.1969 + } 1.1970 + } 1.1971 + 1.1972 + // store, if valid type 1.1973 + if( channel.mType != IT_Invalid) 1.1974 + poChannels.push_back( channel); 1.1975 + 1.1976 + // skip remaining stuff of this element, if any 1.1977 + SkipElement(); 1.1978 +} 1.1979 + 1.1980 +// ------------------------------------------------------------------------------------------------ 1.1981 +// Reads a <p> primitive index list and assembles the mesh data into the given mesh 1.1982 +void ColladaParser::ReadPrimitives( Mesh* pMesh, std::vector<InputChannel>& pPerIndexChannels, 1.1983 + size_t pNumPrimitives, const std::vector<size_t>& pVCount, PrimitiveType pPrimType) 1.1984 +{ 1.1985 + // determine number of indices coming per vertex 1.1986 + // find the offset index for all per-vertex channels 1.1987 + size_t numOffsets = 1; 1.1988 + size_t perVertexOffset = SIZE_MAX; // invalid value 1.1989 + BOOST_FOREACH( const InputChannel& channel, pPerIndexChannels) 1.1990 + { 1.1991 + numOffsets = std::max( numOffsets, channel.mOffset+1); 1.1992 + if( channel.mType == IT_Vertex) 1.1993 + perVertexOffset = channel.mOffset; 1.1994 + } 1.1995 + 1.1996 + // determine the expected number of indices 1.1997 + size_t expectedPointCount = 0; 1.1998 + switch( pPrimType) 1.1999 + { 1.2000 + case Prim_Polylist: 1.2001 + { 1.2002 + BOOST_FOREACH( size_t i, pVCount) 1.2003 + expectedPointCount += i; 1.2004 + break; 1.2005 + } 1.2006 + case Prim_Lines: 1.2007 + expectedPointCount = 2 * pNumPrimitives; 1.2008 + break; 1.2009 + case Prim_Triangles: 1.2010 + expectedPointCount = 3 * pNumPrimitives; 1.2011 + break; 1.2012 + default: 1.2013 + // other primitive types don't state the index count upfront... we need to guess 1.2014 + break; 1.2015 + } 1.2016 + 1.2017 + // and read all indices into a temporary array 1.2018 + std::vector<size_t> indices; 1.2019 + if( expectedPointCount > 0) 1.2020 + indices.reserve( expectedPointCount * numOffsets); 1.2021 + 1.2022 + if (pNumPrimitives > 0) // It is possible to not contain any indicies 1.2023 + { 1.2024 + const char* content = GetTextContent(); 1.2025 + while( *content != 0) 1.2026 + { 1.2027 + // read a value. 1.2028 + // Hack: (thom) Some exporters put negative indices sometimes. We just try to carry on anyways. 1.2029 + int value = std::max( 0, strtol10( content, &content)); 1.2030 + indices.push_back( size_t( value)); 1.2031 + // skip whitespace after it 1.2032 + SkipSpacesAndLineEnd( &content); 1.2033 + } 1.2034 + } 1.2035 + 1.2036 + // complain if the index count doesn't fit 1.2037 + if( expectedPointCount > 0 && indices.size() != expectedPointCount * numOffsets) 1.2038 + ThrowException( "Expected different index count in <p> element."); 1.2039 + else if( expectedPointCount == 0 && (indices.size() % numOffsets) != 0) 1.2040 + ThrowException( "Expected different index count in <p> element."); 1.2041 + 1.2042 + // find the data for all sources 1.2043 + for( std::vector<InputChannel>::iterator it = pMesh->mPerVertexData.begin(); it != pMesh->mPerVertexData.end(); ++it) 1.2044 + { 1.2045 + InputChannel& input = *it; 1.2046 + if( input.mResolved) 1.2047 + continue; 1.2048 + 1.2049 + // find accessor 1.2050 + input.mResolved = &ResolveLibraryReference( mAccessorLibrary, input.mAccessor); 1.2051 + // resolve accessor's data pointer as well, if neccessary 1.2052 + const Accessor* acc = input.mResolved; 1.2053 + if( !acc->mData) 1.2054 + acc->mData = &ResolveLibraryReference( mDataLibrary, acc->mSource); 1.2055 + } 1.2056 + // and the same for the per-index channels 1.2057 + for( std::vector<InputChannel>::iterator it = pPerIndexChannels.begin(); it != pPerIndexChannels.end(); ++it) 1.2058 + { 1.2059 + InputChannel& input = *it; 1.2060 + if( input.mResolved) 1.2061 + continue; 1.2062 + 1.2063 + // ignore vertex pointer, it doesn't refer to an accessor 1.2064 + if( input.mType == IT_Vertex) 1.2065 + { 1.2066 + // warn if the vertex channel does not refer to the <vertices> element in the same mesh 1.2067 + if( input.mAccessor != pMesh->mVertexID) 1.2068 + ThrowException( "Unsupported vertex referencing scheme."); 1.2069 + continue; 1.2070 + } 1.2071 + 1.2072 + // find accessor 1.2073 + input.mResolved = &ResolveLibraryReference( mAccessorLibrary, input.mAccessor); 1.2074 + // resolve accessor's data pointer as well, if neccessary 1.2075 + const Accessor* acc = input.mResolved; 1.2076 + if( !acc->mData) 1.2077 + acc->mData = &ResolveLibraryReference( mDataLibrary, acc->mSource); 1.2078 + } 1.2079 + 1.2080 + 1.2081 + // now assemble vertex data according to those indices 1.2082 + std::vector<size_t>::const_iterator idx = indices.begin(); 1.2083 + 1.2084 + // For continued primitives, the given count does not come all in one <p>, but only one primitive per <p> 1.2085 + size_t numPrimitives = pNumPrimitives; 1.2086 + if( pPrimType == Prim_TriFans || pPrimType == Prim_Polygon) 1.2087 + numPrimitives = 1; 1.2088 + 1.2089 + pMesh->mFaceSize.reserve( numPrimitives); 1.2090 + pMesh->mFacePosIndices.reserve( indices.size() / numOffsets); 1.2091 + 1.2092 + for( size_t a = 0; a < numPrimitives; a++) 1.2093 + { 1.2094 + // determine number of points for this primitive 1.2095 + size_t numPoints = 0; 1.2096 + switch( pPrimType) 1.2097 + { 1.2098 + case Prim_Lines: 1.2099 + numPoints = 2; 1.2100 + break; 1.2101 + case Prim_Triangles: 1.2102 + numPoints = 3; 1.2103 + break; 1.2104 + case Prim_Polylist: 1.2105 + numPoints = pVCount[a]; 1.2106 + break; 1.2107 + case Prim_TriFans: 1.2108 + case Prim_Polygon: 1.2109 + numPoints = indices.size() / numOffsets; 1.2110 + break; 1.2111 + default: 1.2112 + // LineStrip and TriStrip not supported due to expected index unmangling 1.2113 + ThrowException( "Unsupported primitive type."); 1.2114 + break; 1.2115 + } 1.2116 + 1.2117 + // store the face size to later reconstruct the face from 1.2118 + pMesh->mFaceSize.push_back( numPoints); 1.2119 + 1.2120 + // gather that number of vertices 1.2121 + for( size_t b = 0; b < numPoints; b++) 1.2122 + { 1.2123 + // read all indices for this vertex. Yes, in a hacky local array 1.2124 + ai_assert( numOffsets < 20 && perVertexOffset < 20); 1.2125 + size_t vindex[20]; 1.2126 + for( size_t offsets = 0; offsets < numOffsets; ++offsets) 1.2127 + vindex[offsets] = *idx++; 1.2128 + 1.2129 + // extract per-vertex channels using the global per-vertex offset 1.2130 + for( std::vector<InputChannel>::iterator it = pMesh->mPerVertexData.begin(); it != pMesh->mPerVertexData.end(); ++it) 1.2131 + ExtractDataObjectFromChannel( *it, vindex[perVertexOffset], pMesh); 1.2132 + // and extract per-index channels using there specified offset 1.2133 + for( std::vector<InputChannel>::iterator it = pPerIndexChannels.begin(); it != pPerIndexChannels.end(); ++it) 1.2134 + ExtractDataObjectFromChannel( *it, vindex[it->mOffset], pMesh); 1.2135 + 1.2136 + // store the vertex-data index for later assignment of bone vertex weights 1.2137 + pMesh->mFacePosIndices.push_back( vindex[perVertexOffset]); 1.2138 + } 1.2139 + } 1.2140 + 1.2141 + 1.2142 + // if I ever get my hands on that guy who invented this steaming pile of indirection... 1.2143 + TestClosing( "p"); 1.2144 +} 1.2145 + 1.2146 +// ------------------------------------------------------------------------------------------------ 1.2147 +// Extracts a single object from an input channel and stores it in the appropriate mesh data array 1.2148 +void ColladaParser::ExtractDataObjectFromChannel( const InputChannel& pInput, size_t pLocalIndex, Mesh* pMesh) 1.2149 +{ 1.2150 + // ignore vertex referrer - we handle them that separate 1.2151 + if( pInput.mType == IT_Vertex) 1.2152 + return; 1.2153 + 1.2154 + const Accessor& acc = *pInput.mResolved; 1.2155 + if( pLocalIndex >= acc.mCount) 1.2156 + ThrowException( boost::str( boost::format( "Invalid data index (%d/%d) in primitive specification") % pLocalIndex % acc.mCount)); 1.2157 + 1.2158 + // get a pointer to the start of the data object referred to by the accessor and the local index 1.2159 + const float* dataObject = &(acc.mData->mValues[0]) + acc.mOffset + pLocalIndex* acc.mStride; 1.2160 + 1.2161 + // assemble according to the accessors component sub-offset list. We don't care, yet, 1.2162 + // what kind of object exactly we're extracting here 1.2163 + float obj[4]; 1.2164 + for( size_t c = 0; c < 4; ++c) 1.2165 + obj[c] = dataObject[acc.mSubOffset[c]]; 1.2166 + 1.2167 + // now we reinterpret it according to the type we're reading here 1.2168 + switch( pInput.mType) 1.2169 + { 1.2170 + case IT_Position: // ignore all position streams except 0 - there can be only one position 1.2171 + if( pInput.mIndex == 0) 1.2172 + pMesh->mPositions.push_back( aiVector3D( obj[0], obj[1], obj[2])); 1.2173 + else 1.2174 + DefaultLogger::get()->error("Collada: just one vertex position stream supported"); 1.2175 + break; 1.2176 + case IT_Normal: 1.2177 + // pad to current vertex count if necessary 1.2178 + if( pMesh->mNormals.size() < pMesh->mPositions.size()-1) 1.2179 + pMesh->mNormals.insert( pMesh->mNormals.end(), pMesh->mPositions.size() - pMesh->mNormals.size() - 1, aiVector3D( 0, 1, 0)); 1.2180 + 1.2181 + // ignore all normal streams except 0 - there can be only one normal 1.2182 + if( pInput.mIndex == 0) 1.2183 + pMesh->mNormals.push_back( aiVector3D( obj[0], obj[1], obj[2])); 1.2184 + else 1.2185 + DefaultLogger::get()->error("Collada: just one vertex normal stream supported"); 1.2186 + break; 1.2187 + case IT_Tangent: 1.2188 + // pad to current vertex count if necessary 1.2189 + if( pMesh->mTangents.size() < pMesh->mPositions.size()-1) 1.2190 + pMesh->mTangents.insert( pMesh->mTangents.end(), pMesh->mPositions.size() - pMesh->mTangents.size() - 1, aiVector3D( 1, 0, 0)); 1.2191 + 1.2192 + // ignore all tangent streams except 0 - there can be only one tangent 1.2193 + if( pInput.mIndex == 0) 1.2194 + pMesh->mTangents.push_back( aiVector3D( obj[0], obj[1], obj[2])); 1.2195 + else 1.2196 + DefaultLogger::get()->error("Collada: just one vertex tangent stream supported"); 1.2197 + break; 1.2198 + case IT_Bitangent: 1.2199 + // pad to current vertex count if necessary 1.2200 + if( pMesh->mBitangents.size() < pMesh->mPositions.size()-1) 1.2201 + pMesh->mBitangents.insert( pMesh->mBitangents.end(), pMesh->mPositions.size() - pMesh->mBitangents.size() - 1, aiVector3D( 0, 0, 1)); 1.2202 + 1.2203 + // ignore all bitangent streams except 0 - there can be only one bitangent 1.2204 + if( pInput.mIndex == 0) 1.2205 + pMesh->mBitangents.push_back( aiVector3D( obj[0], obj[1], obj[2])); 1.2206 + else 1.2207 + DefaultLogger::get()->error("Collada: just one vertex bitangent stream supported"); 1.2208 + break; 1.2209 + case IT_Texcoord: 1.2210 + // up to 4 texture coord sets are fine, ignore the others 1.2211 + if( pInput.mIndex < AI_MAX_NUMBER_OF_TEXTURECOORDS) 1.2212 + { 1.2213 + // pad to current vertex count if necessary 1.2214 + if( pMesh->mTexCoords[pInput.mIndex].size() < pMesh->mPositions.size()-1) 1.2215 + pMesh->mTexCoords[pInput.mIndex].insert( pMesh->mTexCoords[pInput.mIndex].end(), 1.2216 + pMesh->mPositions.size() - pMesh->mTexCoords[pInput.mIndex].size() - 1, aiVector3D( 0, 0, 0)); 1.2217 + 1.2218 + pMesh->mTexCoords[pInput.mIndex].push_back( aiVector3D( obj[0], obj[1], obj[2])); 1.2219 + if (0 != acc.mSubOffset[2] || 0 != acc.mSubOffset[3]) /* hack ... consider cleaner solution */ 1.2220 + pMesh->mNumUVComponents[pInput.mIndex]=3; 1.2221 + } else 1.2222 + { 1.2223 + DefaultLogger::get()->error("Collada: too many texture coordinate sets. Skipping."); 1.2224 + } 1.2225 + break; 1.2226 + case IT_Color: 1.2227 + // up to 4 color sets are fine, ignore the others 1.2228 + if( pInput.mIndex < AI_MAX_NUMBER_OF_COLOR_SETS) 1.2229 + { 1.2230 + // pad to current vertex count if necessary 1.2231 + if( pMesh->mColors[pInput.mIndex].size() < pMesh->mPositions.size()-1) 1.2232 + pMesh->mColors[pInput.mIndex].insert( pMesh->mColors[pInput.mIndex].end(), 1.2233 + pMesh->mPositions.size() - pMesh->mColors[pInput.mIndex].size() - 1, aiColor4D( 0, 0, 0, 1)); 1.2234 + 1.2235 + aiColor4D result(0, 0, 0, 1); 1.2236 + for (size_t i = 0; i < pInput.mResolved->mSize; ++i) 1.2237 + { 1.2238 + result[i] = obj[pInput.mResolved->mSubOffset[i]]; 1.2239 + } 1.2240 + pMesh->mColors[pInput.mIndex].push_back(result); 1.2241 + } else 1.2242 + { 1.2243 + DefaultLogger::get()->error("Collada: too many vertex color sets. Skipping."); 1.2244 + } 1.2245 + 1.2246 + break; 1.2247 + default: 1.2248 + // IT_Invalid and IT_Vertex 1.2249 + ai_assert(false && "shouldn't ever get here"); 1.2250 + } 1.2251 +} 1.2252 + 1.2253 +// ------------------------------------------------------------------------------------------------ 1.2254 +// Reads the library of node hierarchies and scene parts 1.2255 +void ColladaParser::ReadSceneLibrary() 1.2256 +{ 1.2257 + if( mReader->isEmptyElement()) 1.2258 + return; 1.2259 + 1.2260 + while( mReader->read()) 1.2261 + { 1.2262 + if( mReader->getNodeType() == irr::io::EXN_ELEMENT) 1.2263 + { 1.2264 + // a visual scene - generate root node under its ID and let ReadNode() do the recursive work 1.2265 + if( IsElement( "visual_scene")) 1.2266 + { 1.2267 + // read ID. Is optional according to the spec, but how on earth should a scene_instance refer to it then? 1.2268 + int indexID = GetAttribute( "id"); 1.2269 + const char* attrID = mReader->getAttributeValue( indexID); 1.2270 + 1.2271 + // read name if given. 1.2272 + int indexName = TestAttribute( "name"); 1.2273 + const char* attrName = "unnamed"; 1.2274 + if( indexName > -1) 1.2275 + attrName = mReader->getAttributeValue( indexName); 1.2276 + 1.2277 + // create a node and store it in the library under its ID 1.2278 + Node* node = new Node; 1.2279 + node->mID = attrID; 1.2280 + node->mName = attrName; 1.2281 + mNodeLibrary[node->mID] = node; 1.2282 + 1.2283 + ReadSceneNode( node); 1.2284 + } else 1.2285 + { 1.2286 + // ignore the rest 1.2287 + SkipElement(); 1.2288 + } 1.2289 + } 1.2290 + else if( mReader->getNodeType() == irr::io::EXN_ELEMENT_END) 1.2291 + { 1.2292 + if( strcmp( mReader->getNodeName(), "library_visual_scenes") == 0) 1.2293 + //ThrowException( "Expected end of \"library_visual_scenes\" element."); 1.2294 + 1.2295 + break; 1.2296 + } 1.2297 + } 1.2298 +} 1.2299 + 1.2300 +// ------------------------------------------------------------------------------------------------ 1.2301 +// Reads a scene node's contents including children and stores it in the given node 1.2302 +void ColladaParser::ReadSceneNode( Node* pNode) 1.2303 +{ 1.2304 + // quit immediately on <bla/> elements 1.2305 + if( mReader->isEmptyElement()) 1.2306 + return; 1.2307 + 1.2308 + while( mReader->read()) 1.2309 + { 1.2310 + if( mReader->getNodeType() == irr::io::EXN_ELEMENT) 1.2311 + { 1.2312 + if( IsElement( "node")) 1.2313 + { 1.2314 + Node* child = new Node; 1.2315 + int attrID = TestAttribute( "id"); 1.2316 + if( attrID > -1) 1.2317 + child->mID = mReader->getAttributeValue( attrID); 1.2318 + int attrSID = TestAttribute( "sid"); 1.2319 + if( attrSID > -1) 1.2320 + child->mSID = mReader->getAttributeValue( attrSID); 1.2321 + 1.2322 + int attrName = TestAttribute( "name"); 1.2323 + if( attrName > -1) 1.2324 + child->mName = mReader->getAttributeValue( attrName); 1.2325 + 1.2326 + // TODO: (thom) support SIDs 1.2327 + // ai_assert( TestAttribute( "sid") == -1); 1.2328 + 1.2329 + if (pNode) 1.2330 + { 1.2331 + pNode->mChildren.push_back( child); 1.2332 + child->mParent = pNode; 1.2333 + } 1.2334 + else 1.2335 + { 1.2336 + // no parent node given, probably called from <library_nodes> element. 1.2337 + // create new node in node library 1.2338 + mNodeLibrary[child->mID] = child; 1.2339 + } 1.2340 + 1.2341 + // read on recursively from there 1.2342 + ReadSceneNode( child); 1.2343 + continue; 1.2344 + } 1.2345 + // For any further stuff we need a valid node to work on 1.2346 + else if (!pNode) 1.2347 + continue; 1.2348 + 1.2349 + if( IsElement( "lookat")) 1.2350 + ReadNodeTransformation( pNode, TF_LOOKAT); 1.2351 + else if( IsElement( "matrix")) 1.2352 + ReadNodeTransformation( pNode, TF_MATRIX); 1.2353 + else if( IsElement( "rotate")) 1.2354 + ReadNodeTransformation( pNode, TF_ROTATE); 1.2355 + else if( IsElement( "scale")) 1.2356 + ReadNodeTransformation( pNode, TF_SCALE); 1.2357 + else if( IsElement( "skew")) 1.2358 + ReadNodeTransformation( pNode, TF_SKEW); 1.2359 + else if( IsElement( "translate")) 1.2360 + ReadNodeTransformation( pNode, TF_TRANSLATE); 1.2361 + else if( IsElement( "render") && pNode->mParent == NULL && 0 == pNode->mPrimaryCamera.length()) 1.2362 + { 1.2363 + // ... scene evaluation or, in other words, postprocessing pipeline, 1.2364 + // or, again in other words, a turing-complete description how to 1.2365 + // render a Collada scene. The only thing that is interesting for 1.2366 + // us is the primary camera. 1.2367 + int attrId = TestAttribute("camera_node"); 1.2368 + if (-1 != attrId) 1.2369 + { 1.2370 + const char* s = mReader->getAttributeValue(attrId); 1.2371 + if (s[0] != '#') 1.2372 + DefaultLogger::get()->error("Collada: Unresolved reference format of camera"); 1.2373 + else 1.2374 + pNode->mPrimaryCamera = s+1; 1.2375 + } 1.2376 + } 1.2377 + else if( IsElement( "instance_node")) 1.2378 + { 1.2379 + // find the node in the library 1.2380 + int attrID = TestAttribute( "url"); 1.2381 + if( attrID != -1) 1.2382 + { 1.2383 + const char* s = mReader->getAttributeValue(attrID); 1.2384 + if (s[0] != '#') 1.2385 + DefaultLogger::get()->error("Collada: Unresolved reference format of node"); 1.2386 + else 1.2387 + { 1.2388 + pNode->mNodeInstances.push_back(NodeInstance()); 1.2389 + pNode->mNodeInstances.back().mNode = s+1; 1.2390 + } 1.2391 + } 1.2392 + } 1.2393 + else if( IsElement( "instance_geometry") || IsElement( "instance_controller")) 1.2394 + { 1.2395 + // Reference to a mesh or controller, with possible material associations 1.2396 + ReadNodeGeometry( pNode); 1.2397 + } 1.2398 + else if( IsElement( "instance_light")) 1.2399 + { 1.2400 + // Reference to a light, name given in 'url' attribute 1.2401 + int attrID = TestAttribute("url"); 1.2402 + if (-1 == attrID) 1.2403 + DefaultLogger::get()->warn("Collada: Expected url attribute in <instance_light> element"); 1.2404 + else 1.2405 + { 1.2406 + const char* url = mReader->getAttributeValue( attrID); 1.2407 + if( url[0] != '#') 1.2408 + ThrowException( "Unknown reference format in <instance_light> element"); 1.2409 + 1.2410 + pNode->mLights.push_back(LightInstance()); 1.2411 + pNode->mLights.back().mLight = url+1; 1.2412 + } 1.2413 + } 1.2414 + else if( IsElement( "instance_camera")) 1.2415 + { 1.2416 + // Reference to a camera, name given in 'url' attribute 1.2417 + int attrID = TestAttribute("url"); 1.2418 + if (-1 == attrID) 1.2419 + DefaultLogger::get()->warn("Collada: Expected url attribute in <instance_camera> element"); 1.2420 + else 1.2421 + { 1.2422 + const char* url = mReader->getAttributeValue( attrID); 1.2423 + if( url[0] != '#') 1.2424 + ThrowException( "Unknown reference format in <instance_camera> element"); 1.2425 + 1.2426 + pNode->mCameras.push_back(CameraInstance()); 1.2427 + pNode->mCameras.back().mCamera = url+1; 1.2428 + } 1.2429 + } 1.2430 + else 1.2431 + { 1.2432 + // skip everything else for the moment 1.2433 + SkipElement(); 1.2434 + } 1.2435 + } 1.2436 + else if( mReader->getNodeType() == irr::io::EXN_ELEMENT_END) { 1.2437 + break; 1.2438 + } 1.2439 + } 1.2440 +} 1.2441 + 1.2442 +// ------------------------------------------------------------------------------------------------ 1.2443 +// Reads a node transformation entry of the given type and adds it to the given node's transformation list. 1.2444 +void ColladaParser::ReadNodeTransformation( Node* pNode, TransformType pType) 1.2445 +{ 1.2446 + if( mReader->isEmptyElement()) 1.2447 + return; 1.2448 + 1.2449 + std::string tagName = mReader->getNodeName(); 1.2450 + 1.2451 + Transform tf; 1.2452 + tf.mType = pType; 1.2453 + 1.2454 + // read SID 1.2455 + int indexSID = TestAttribute( "sid"); 1.2456 + if( indexSID >= 0) 1.2457 + tf.mID = mReader->getAttributeValue( indexSID); 1.2458 + 1.2459 + // how many parameters to read per transformation type 1.2460 + static const unsigned int sNumParameters[] = { 9, 4, 3, 3, 7, 16 }; 1.2461 + const char* content = GetTextContent(); 1.2462 + 1.2463 + // read as many parameters and store in the transformation 1.2464 + for( unsigned int a = 0; a < sNumParameters[pType]; a++) 1.2465 + { 1.2466 + // read a number 1.2467 + content = fast_atoreal_move<float>( content, tf.f[a]); 1.2468 + // skip whitespace after it 1.2469 + SkipSpacesAndLineEnd( &content); 1.2470 + } 1.2471 + 1.2472 + // place the transformation at the queue of the node 1.2473 + pNode->mTransforms.push_back( tf); 1.2474 + 1.2475 + // and consume the closing tag 1.2476 + TestClosing( tagName.c_str()); 1.2477 +} 1.2478 + 1.2479 +// ------------------------------------------------------------------------------------------------ 1.2480 +// Processes bind_vertex_input and bind elements 1.2481 +void ColladaParser::ReadMaterialVertexInputBinding( Collada::SemanticMappingTable& tbl) 1.2482 +{ 1.2483 + while( mReader->read()) 1.2484 + { 1.2485 + if( mReader->getNodeType() == irr::io::EXN_ELEMENT) { 1.2486 + if( IsElement( "bind_vertex_input")) 1.2487 + { 1.2488 + Collada::InputSemanticMapEntry vn; 1.2489 + 1.2490 + // effect semantic 1.2491 + int n = GetAttribute("semantic"); 1.2492 + std::string s = mReader->getAttributeValue(n); 1.2493 + 1.2494 + // input semantic 1.2495 + n = GetAttribute("input_semantic"); 1.2496 + vn.mType = GetTypeForSemantic( mReader->getAttributeValue(n) ); 1.2497 + 1.2498 + // index of input set 1.2499 + n = TestAttribute("input_set"); 1.2500 + if (-1 != n) 1.2501 + vn.mSet = mReader->getAttributeValueAsInt(n); 1.2502 + 1.2503 + tbl.mMap[s] = vn; 1.2504 + } 1.2505 + else if( IsElement( "bind")) { 1.2506 + DefaultLogger::get()->warn("Collada: Found unsupported <bind> element"); 1.2507 + } 1.2508 + } 1.2509 + else if( mReader->getNodeType() == irr::io::EXN_ELEMENT_END) { 1.2510 + if( strcmp( mReader->getNodeName(), "instance_material") == 0) 1.2511 + break; 1.2512 + } 1.2513 + } 1.2514 +} 1.2515 + 1.2516 +// ------------------------------------------------------------------------------------------------ 1.2517 +// Reads a mesh reference in a node and adds it to the node's mesh list 1.2518 +void ColladaParser::ReadNodeGeometry( Node* pNode) 1.2519 +{ 1.2520 + // referred mesh is given as an attribute of the <instance_geometry> element 1.2521 + int attrUrl = GetAttribute( "url"); 1.2522 + const char* url = mReader->getAttributeValue( attrUrl); 1.2523 + if( url[0] != '#') 1.2524 + ThrowException( "Unknown reference format"); 1.2525 + 1.2526 + Collada::MeshInstance instance; 1.2527 + instance.mMeshOrController = url+1; // skipping the leading # 1.2528 + 1.2529 + if( !mReader->isEmptyElement()) 1.2530 + { 1.2531 + // read material associations. Ignore additional elements inbetween 1.2532 + while( mReader->read()) 1.2533 + { 1.2534 + if( mReader->getNodeType() == irr::io::EXN_ELEMENT) 1.2535 + { 1.2536 + if( IsElement( "instance_material")) 1.2537 + { 1.2538 + // read ID of the geometry subgroup and the target material 1.2539 + int attrGroup = GetAttribute( "symbol"); 1.2540 + std::string group = mReader->getAttributeValue( attrGroup); 1.2541 + int attrMaterial = GetAttribute( "target"); 1.2542 + const char* urlMat = mReader->getAttributeValue( attrMaterial); 1.2543 + Collada::SemanticMappingTable s; 1.2544 + if( urlMat[0] == '#') 1.2545 + urlMat++; 1.2546 + 1.2547 + s.mMatName = urlMat; 1.2548 + 1.2549 + // resolve further material details + THIS UGLY AND NASTY semantic mapping stuff 1.2550 + if( !mReader->isEmptyElement()) 1.2551 + ReadMaterialVertexInputBinding(s); 1.2552 + 1.2553 + // store the association 1.2554 + instance.mMaterials[group] = s; 1.2555 + } 1.2556 + } 1.2557 + else if( mReader->getNodeType() == irr::io::EXN_ELEMENT_END) 1.2558 + { 1.2559 + if( strcmp( mReader->getNodeName(), "instance_geometry") == 0 1.2560 + || strcmp( mReader->getNodeName(), "instance_controller") == 0) 1.2561 + break; 1.2562 + } 1.2563 + } 1.2564 + } 1.2565 + 1.2566 + // store it 1.2567 + pNode->mMeshes.push_back( instance); 1.2568 +} 1.2569 + 1.2570 +// ------------------------------------------------------------------------------------------------ 1.2571 +// Reads the collada scene 1.2572 +void ColladaParser::ReadScene() 1.2573 +{ 1.2574 + if( mReader->isEmptyElement()) 1.2575 + return; 1.2576 + 1.2577 + while( mReader->read()) 1.2578 + { 1.2579 + if( mReader->getNodeType() == irr::io::EXN_ELEMENT) { 1.2580 + if( IsElement( "instance_visual_scene")) 1.2581 + { 1.2582 + // should be the first and only occurence 1.2583 + if( mRootNode) 1.2584 + ThrowException( "Invalid scene containing multiple root nodes in <instance_visual_scene> element"); 1.2585 + 1.2586 + // read the url of the scene to instance. Should be of format "#some_name" 1.2587 + int urlIndex = GetAttribute( "url"); 1.2588 + const char* url = mReader->getAttributeValue( urlIndex); 1.2589 + if( url[0] != '#') 1.2590 + ThrowException( "Unknown reference format in <instance_visual_scene> element"); 1.2591 + 1.2592 + // find the referred scene, skip the leading # 1.2593 + NodeLibrary::const_iterator sit = mNodeLibrary.find( url+1); 1.2594 + if( sit == mNodeLibrary.end()) 1.2595 + ThrowException( "Unable to resolve visual_scene reference \"" + std::string(url) + "\" in <instance_visual_scene> element."); 1.2596 + mRootNode = sit->second; 1.2597 + } else { 1.2598 + SkipElement(); 1.2599 + } 1.2600 + } 1.2601 + else if( mReader->getNodeType() == irr::io::EXN_ELEMENT_END){ 1.2602 + break; 1.2603 + } 1.2604 + } 1.2605 +} 1.2606 + 1.2607 +// ------------------------------------------------------------------------------------------------ 1.2608 +// Aborts the file reading with an exception 1.2609 +void ColladaParser::ThrowException( const std::string& pError) const 1.2610 +{ 1.2611 + throw DeadlyImportError( boost::str( boost::format( "Collada: %s - %s") % mFileName % pError)); 1.2612 +} 1.2613 + 1.2614 +// ------------------------------------------------------------------------------------------------ 1.2615 +// Skips all data until the end node of the current element 1.2616 +void ColladaParser::SkipElement() 1.2617 +{ 1.2618 + // nothing to skip if it's an <element /> 1.2619 + if( mReader->isEmptyElement()) 1.2620 + return; 1.2621 + 1.2622 + // reroute 1.2623 + SkipElement( mReader->getNodeName()); 1.2624 +} 1.2625 + 1.2626 +// ------------------------------------------------------------------------------------------------ 1.2627 +// Skips all data until the end node of the given element 1.2628 +void ColladaParser::SkipElement( const char* pElement) 1.2629 +{ 1.2630 + // copy the current node's name because it'a pointer to the reader's internal buffer, 1.2631 + // which is going to change with the upcoming parsing 1.2632 + std::string element = pElement; 1.2633 + while( mReader->read()) 1.2634 + { 1.2635 + if( mReader->getNodeType() == irr::io::EXN_ELEMENT_END) 1.2636 + if( mReader->getNodeName() == element) 1.2637 + break; 1.2638 + } 1.2639 +} 1.2640 + 1.2641 +// ------------------------------------------------------------------------------------------------ 1.2642 +// Tests for an opening element of the given name, throws an exception if not found 1.2643 +void ColladaParser::TestOpening( const char* pName) 1.2644 +{ 1.2645 + // read element start 1.2646 + if( !mReader->read()) 1.2647 + ThrowException( boost::str( boost::format( "Unexpected end of file while beginning of <%s> element.") % pName)); 1.2648 + // whitespace in front is ok, just read again if found 1.2649 + if( mReader->getNodeType() == irr::io::EXN_TEXT) 1.2650 + if( !mReader->read()) 1.2651 + ThrowException( boost::str( boost::format( "Unexpected end of file while reading beginning of <%s> element.") % pName)); 1.2652 + 1.2653 + if( mReader->getNodeType() != irr::io::EXN_ELEMENT || strcmp( mReader->getNodeName(), pName) != 0) 1.2654 + ThrowException( boost::str( boost::format( "Expected start of <%s> element.") % pName)); 1.2655 +} 1.2656 + 1.2657 +// ------------------------------------------------------------------------------------------------ 1.2658 +// Tests for the closing tag of the given element, throws an exception if not found 1.2659 +void ColladaParser::TestClosing( const char* pName) 1.2660 +{ 1.2661 + // check if we're already on the closing tag and return right away 1.2662 + if( mReader->getNodeType() == irr::io::EXN_ELEMENT_END && strcmp( mReader->getNodeName(), pName) == 0) 1.2663 + return; 1.2664 + 1.2665 + // if not, read some more 1.2666 + if( !mReader->read()) 1.2667 + ThrowException( boost::str( boost::format( "Unexpected end of file while reading end of <%s> element.") % pName)); 1.2668 + // whitespace in front is ok, just read again if found 1.2669 + if( mReader->getNodeType() == irr::io::EXN_TEXT) 1.2670 + if( !mReader->read()) 1.2671 + ThrowException( boost::str( boost::format( "Unexpected end of file while reading end of <%s> element.") % pName)); 1.2672 + 1.2673 + // but this has the be the closing tag, or we're lost 1.2674 + if( mReader->getNodeType() != irr::io::EXN_ELEMENT_END || strcmp( mReader->getNodeName(), pName) != 0) 1.2675 + ThrowException( boost::str( boost::format( "Expected end of <%s> element.") % pName)); 1.2676 +} 1.2677 + 1.2678 +// ------------------------------------------------------------------------------------------------ 1.2679 +// Returns the index of the named attribute or -1 if not found. Does not throw, therefore useful for optional attributes 1.2680 +int ColladaParser::GetAttribute( const char* pAttr) const 1.2681 +{ 1.2682 + int index = TestAttribute( pAttr); 1.2683 + if( index != -1) 1.2684 + return index; 1.2685 + 1.2686 + // attribute not found -> throw an exception 1.2687 + ThrowException( boost::str( boost::format( "Expected attribute \"%s\" for element <%s>.") % pAttr % mReader->getNodeName())); 1.2688 + return -1; 1.2689 +} 1.2690 + 1.2691 +// ------------------------------------------------------------------------------------------------ 1.2692 +// Tests the present element for the presence of one attribute, returns its index or throws an exception if not found 1.2693 +int ColladaParser::TestAttribute( const char* pAttr) const 1.2694 +{ 1.2695 + for( int a = 0; a < mReader->getAttributeCount(); a++) 1.2696 + if( strcmp( mReader->getAttributeName( a), pAttr) == 0) 1.2697 + return a; 1.2698 + 1.2699 + return -1; 1.2700 +} 1.2701 + 1.2702 +// ------------------------------------------------------------------------------------------------ 1.2703 +// Reads the text contents of an element, throws an exception if not given. Skips leading whitespace. 1.2704 +const char* ColladaParser::GetTextContent() 1.2705 +{ 1.2706 + const char* sz = TestTextContent(); 1.2707 + if(!sz) { 1.2708 + ThrowException( "Invalid contents in element \"n\"."); 1.2709 + } 1.2710 + return sz; 1.2711 +} 1.2712 + 1.2713 +// ------------------------------------------------------------------------------------------------ 1.2714 +// Reads the text contents of an element, returns NULL if not given. Skips leading whitespace. 1.2715 +const char* ColladaParser::TestTextContent() 1.2716 +{ 1.2717 + // present node should be the beginning of an element 1.2718 + if( mReader->getNodeType() != irr::io::EXN_ELEMENT || mReader->isEmptyElement()) 1.2719 + return NULL; 1.2720 + 1.2721 + // read contents of the element 1.2722 + if( !mReader->read() ) 1.2723 + return NULL; 1.2724 + if( mReader->getNodeType() != irr::io::EXN_TEXT) 1.2725 + return NULL; 1.2726 + 1.2727 + // skip leading whitespace 1.2728 + const char* text = mReader->getNodeData(); 1.2729 + SkipSpacesAndLineEnd( &text); 1.2730 + 1.2731 + return text; 1.2732 +} 1.2733 + 1.2734 +// ------------------------------------------------------------------------------------------------ 1.2735 +// Calculates the resulting transformation fromm all the given transform steps 1.2736 +aiMatrix4x4 ColladaParser::CalculateResultTransform( const std::vector<Transform>& pTransforms) const 1.2737 +{ 1.2738 + aiMatrix4x4 res; 1.2739 + 1.2740 + for( std::vector<Transform>::const_iterator it = pTransforms.begin(); it != pTransforms.end(); ++it) 1.2741 + { 1.2742 + const Transform& tf = *it; 1.2743 + switch( tf.mType) 1.2744 + { 1.2745 + case TF_LOOKAT: 1.2746 + { 1.2747 + aiVector3D pos( tf.f[0], tf.f[1], tf.f[2]); 1.2748 + aiVector3D dstPos( tf.f[3], tf.f[4], tf.f[5]); 1.2749 + aiVector3D up = aiVector3D( tf.f[6], tf.f[7], tf.f[8]).Normalize(); 1.2750 + aiVector3D dir = aiVector3D( dstPos - pos).Normalize(); 1.2751 + aiVector3D right = (dir ^ up).Normalize(); 1.2752 + 1.2753 + res *= aiMatrix4x4( 1.2754 + right.x, up.x, -dir.x, pos.x, 1.2755 + right.y, up.y, -dir.y, pos.y, 1.2756 + right.z, up.z, -dir.z, pos.z, 1.2757 + 0, 0, 0, 1); 1.2758 + break; 1.2759 + } 1.2760 + case TF_ROTATE: 1.2761 + { 1.2762 + aiMatrix4x4 rot; 1.2763 + float angle = tf.f[3] * float( AI_MATH_PI) / 180.0f; 1.2764 + aiVector3D axis( tf.f[0], tf.f[1], tf.f[2]); 1.2765 + aiMatrix4x4::Rotation( angle, axis, rot); 1.2766 + res *= rot; 1.2767 + break; 1.2768 + } 1.2769 + case TF_TRANSLATE: 1.2770 + { 1.2771 + aiMatrix4x4 trans; 1.2772 + aiMatrix4x4::Translation( aiVector3D( tf.f[0], tf.f[1], tf.f[2]), trans); 1.2773 + res *= trans; 1.2774 + break; 1.2775 + } 1.2776 + case TF_SCALE: 1.2777 + { 1.2778 + 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, 1.2779 + 0.0f, 0.0f, 0.0f, 1.0f); 1.2780 + res *= scale; 1.2781 + break; 1.2782 + } 1.2783 + case TF_SKEW: 1.2784 + // TODO: (thom) 1.2785 + ai_assert( false); 1.2786 + break; 1.2787 + case TF_MATRIX: 1.2788 + { 1.2789 + 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], 1.2790 + tf.f[8], tf.f[9], tf.f[10], tf.f[11], tf.f[12], tf.f[13], tf.f[14], tf.f[15]); 1.2791 + res *= mat; 1.2792 + break; 1.2793 + } 1.2794 + default: 1.2795 + ai_assert( false); 1.2796 + break; 1.2797 + } 1.2798 + } 1.2799 + 1.2800 + return res; 1.2801 +} 1.2802 + 1.2803 +// ------------------------------------------------------------------------------------------------ 1.2804 +// Determines the input data type for the given semantic string 1.2805 +Collada::InputType ColladaParser::GetTypeForSemantic( const std::string& pSemantic) 1.2806 +{ 1.2807 + if( pSemantic == "POSITION") 1.2808 + return IT_Position; 1.2809 + else if( pSemantic == "TEXCOORD") 1.2810 + return IT_Texcoord; 1.2811 + else if( pSemantic == "NORMAL") 1.2812 + return IT_Normal; 1.2813 + else if( pSemantic == "COLOR") 1.2814 + return IT_Color; 1.2815 + else if( pSemantic == "VERTEX") 1.2816 + return IT_Vertex; 1.2817 + else if( pSemantic == "BINORMAL" || pSemantic == "TEXBINORMAL") 1.2818 + return IT_Bitangent; 1.2819 + else if( pSemantic == "TANGENT" || pSemantic == "TEXTANGENT") 1.2820 + return IT_Tangent; 1.2821 + 1.2822 + DefaultLogger::get()->warn( boost::str( boost::format( "Unknown vertex input type \"%s\". Ignoring.") % pSemantic)); 1.2823 + return IT_Invalid; 1.2824 +} 1.2825 + 1.2826 +#endif // !! ASSIMP_BUILD_NO_DAE_IMPORTER