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