1 /*
2     Copyright (c) 2008-2009 NetAllied Systems GmbH
3 
4     This file is part of COLLADASaxFrameworkLoader.
5 
6     Licensed under the MIT Open Source License,
7     for details please see LICENSE file or the website
8     http://www.opensource.org/licenses/mit-license.php
9 */
10 
11 #include "COLLADASaxFWLStableHeaders.h"
12 #include "COLLADASaxFWLLibraryAnimationsLoader.h"
13 #include "COLLADASaxFWLSidAddress.h"
14 #include "COLLADASaxFWLSidTreeNode.h"
15 #include "COLLADASaxFWLInterpolationTypeSource.h"
16 #include "COLLADASaxFWLLoader.h"
17 
18 #include "COLLADAFWValidate.h"
19 #include "COLLADAFWAnimationCurve.h"
20 #include "COLLADAFWAnimationList.h"
21 #include "COLLADAFWIWriter.h"
22 #include "COLLADAFWTypes.h"
23 
24 
25 namespace COLLADASaxFWL
26 {
27 
28 	enum SamplerInputSemantics
29 	{
30 		SEMANTIC_UNKNOWN,
31 		SEMANTIC_INPUT,
32 		SEMANTIC_OUTPUT,
33 		SEMANTIC_INTERPOLATION,
34 		SEMANTIC_IN_TANGENT,
35 		SEMANTIC_OUT_TANGENT
36 	};
37 
38 	const String INTERPOLATIONTYPE_LINEAR("LINEAR");
39 	const String INTERPOLATIONTYPE_BEZIER("BEZIER");
40 	const String INTERPOLATIONTYPE_CARDINAL("CARDINAL");
41 	const String INTERPOLATIONTYPE_HERMITE("HERMITE");
42 	const String INTERPOLATIONTYPE_BSPLINE("BSPLINE");
43 	const String INTERPOLATIONTYPE_STEP("STEP");
44 	const String INTERPOLATIONTYPE_MIXED("MIXED");
45 
46 
47 	//------------------------------
operator ==(const ParserString & parserString,const String & stlSring)48 	bool operator==( const ParserString& parserString, const String& stlSring )
49 	{
50 		if ( parserString.length != stlSring.length() )
51 			return false;
52 
53 		size_t pos = 0;
54 		const char* str = stlSring.c_str();
55 		while ( (pos < parserString.length) )
56 		{
57 			if ( parserString.str[pos] != str[pos] )
58 				return false;
59 			++pos;
60 		}
61 		return true;
62 	}
63 
64 	struct AccessorAnimationClassPair
65 	{
AccessorAnimationClassPairCOLLADASaxFWL::AccessorAnimationClassPair66 		AccessorAnimationClassPair( const SourceBase::AccessorParameter* _parameters,
67 									size_t _parameterCount,
68 			                        COLLADAFW::AnimationList::AnimationClass _animationClass)
69 									: parameters(_parameters)
70 									, parameterCount(_parameterCount/sizeof(SourceBase::AccessorParameter))
71 									, animationClass(_animationClass)
72 		{}
73 		const SourceBase::AccessorParameter* parameters;
74 		size_t parameterCount;
75 		COLLADAFW::AnimationList::AnimationClass animationClass;
76 	};
77 
78 	struct AccessorDimensionsPair
79 	{
AccessorDimensionsPairCOLLADASaxFWL::AccessorDimensionsPair80 		AccessorDimensionsPair( const SourceBase::AccessorParameter& _parameter,
81 								COLLADAFW::PhysicalDimension _physicalDimension,
82 								size_t _dimension)
83 			: parameter(_parameter)
84 			, physicalDimension(_physicalDimension)
85 			, dimension(_dimension)
86 		{}
87 		const SourceBase::AccessorParameter& parameter;
88 		COLLADAFW::PhysicalDimension physicalDimension;
89 		size_t dimension;
90 	};
91 
92 	SourceBase::AccessorParameter parameterTime = {"TIME", "float"};
93 	SourceBase::AccessorParameter parameterFloat = {"", "float"};
94 	SourceBase::AccessorParameter parameterX = {"X", "float"};
95 	SourceBase::AccessorParameter parameterY = {"Y", "float"};
96 	SourceBase::AccessorParameter parameterZ = {"Z", "float"};
97 	SourceBase::AccessorParameter parameterR = {"R", "float"};
98 	SourceBase::AccessorParameter parameterG = {"G", "float"};
99 	SourceBase::AccessorParameter parameterB = {"B", "float"};
100 	SourceBase::AccessorParameter parameterA = {"A", "float"};
101 	SourceBase::AccessorParameter parameterAngle = {"ANGLE", "float"};
102 	SourceBase::AccessorParameter parameterTransform = {"TRANSFORM", "float4x4"};
103 
104 	SourceBase::AccessorParameter accessorTime[] = {parameterTime};
105 	SourceBase::AccessorParameter accessorFloat[] = {parameterFloat};
106 	SourceBase::AccessorParameter accessorX[] = {parameterX};
107 	SourceBase::AccessorParameter accessorY[] = {parameterY};
108 	SourceBase::AccessorParameter accessorZ[] = {parameterZ};
109 	SourceBase::AccessorParameter accessorR[] = {parameterR};
110 	SourceBase::AccessorParameter accessorG[] = {parameterG};
111 	SourceBase::AccessorParameter accessorB[] = {parameterB};
112 	SourceBase::AccessorParameter accessorA[] = {parameterA};
113 	SourceBase::AccessorParameter accessorAngle[] = {parameterAngle};
114 	SourceBase::AccessorParameter accessorTransform[] = {parameterTransform};
115 
116 	SourceBase::AccessorParameter accessorXYZ[] = {parameterX, parameterY, parameterZ};
117 	SourceBase::AccessorParameter accessorRGB[] = {parameterR, parameterG, parameterB};
118 	SourceBase::AccessorParameter accessorRGBA[] = {parameterR, parameterG, parameterB, parameterA};
119 	SourceBase::AccessorParameter accessorAxisAngle[] = {parameterX, parameterY, parameterZ, parameterAngle};
120 
121 	AccessorAnimationClassPair animationClassMap[] =
122 	{
123 		  AccessorAnimationClassPair( accessorTime, sizeof(accessorTime), COLLADAFW::AnimationList::TIME)
124 		, AccessorAnimationClassPair( accessorFloat, sizeof(accessorFloat), COLLADAFW::AnimationList::FLOAT)
125 		, AccessorAnimationClassPair( accessorX, sizeof(accessorX), COLLADAFW::AnimationList::POSITION_X)
126 		, AccessorAnimationClassPair( accessorY, sizeof(accessorY), COLLADAFW::AnimationList::POSITION_Y)
127 		, AccessorAnimationClassPair( accessorZ, sizeof(accessorZ), COLLADAFW::AnimationList::POSITION_Z)
128 		, AccessorAnimationClassPair( accessorR, sizeof(accessorR), COLLADAFW::AnimationList::COLOR_R)
129 		, AccessorAnimationClassPair( accessorG, sizeof(accessorG), COLLADAFW::AnimationList::COLOR_G)
130 		, AccessorAnimationClassPair( accessorB, sizeof(accessorB), COLLADAFW::AnimationList::COLOR_B)
131 		, AccessorAnimationClassPair( accessorA, sizeof(accessorA), COLLADAFW::AnimationList::COLOR_A)
132 		, AccessorAnimationClassPair( accessorAngle, sizeof(accessorAngle), COLLADAFW::AnimationList::ANGLE)
133 		, AccessorAnimationClassPair( accessorXYZ, sizeof(accessorXYZ), COLLADAFW::AnimationList::POSITION_XYZ)
134 		, AccessorAnimationClassPair( accessorRGB, sizeof(accessorRGB), COLLADAFW::AnimationList::COLOR_RGB)
135 		, AccessorAnimationClassPair( accessorRGBA, sizeof(accessorRGBA), COLLADAFW::AnimationList::COLOR_RGBA)
136 		, AccessorAnimationClassPair( accessorAxisAngle, sizeof(accessorAxisAngle), COLLADAFW::AnimationList::AXISANGLE)
137 		, AccessorAnimationClassPair( accessorTransform, sizeof(accessorTransform), COLLADAFW::AnimationList::MATRIX4X4)
138 	};
139 
140 #if 0
141 	AccessorDimensionsPair animationDimensionMap[] =
142 	{
143 	      AccessorDimensionsPair( parameterFloat, PHYSICAL_DIMENSION_UNKNOWN, 1)
144     	, AccessorDimensionsPair( parameterX, PHYSICAL_DIMENSION_LENGTH, 1)
145 		, AccessorDimensionsPair( parameterY, PHYSICAL_DIMENSION_LENGTH, 1)
146 		, AccessorDimensionsPair( parameterZ, PHYSICAL_DIMENSION_LENGTH, 1)
147 		, AccessorDimensionsPair( parameterAngle, PHYSICAL_DIMENSION_ANGLE, 1)
148 		, AccessorDimensionsPair( parameterTransform, PHYSICAL_DIMENSION_TRANSFORMATIONMATRIX4X4, 16)
149 	};
150 #endif
151 
152 
153 	/** Determines the animation class from the accessor.*/
154 	//------------------------------
determineAnimationClass(const SourceBase::Accessor & accessor)155 	COLLADAFW::AnimationList::AnimationClass determineAnimationClass( const SourceBase::Accessor& accessor )
156 	{
157 		static const size_t mapSize = sizeof(animationClassMap)/sizeof(AccessorAnimationClassPair);
158 		for ( size_t i = 0; i < mapSize; ++i)
159 		{
160 			const AccessorAnimationClassPair& animationClassPair = animationClassMap[i];
161 
162 			if ( accessor.size() != animationClassPair.parameterCount )
163 			{
164 				// two accessor must have equal number of parameters to be equal
165 				continue;
166 			}
167 
168 			bool equal = true;
169 			for ( size_t j = 0; j < animationClassPair.parameterCount; ++j)
170 			{
171 				const SourceBase::AccessorParameter& parameter = animationClassPair.parameters[j];
172 				const SourceBase::AccessorParameter& accessorParameter = accessor[j];
173 				if ( parameter !=  accessorParameter )
174 				{
175 					equal = false;
176 					break;
177 				}
178 			}
179 
180 			if ( equal )
181 			{
182 				// if we reach this point, the parameters in accessor are equal to those in animationClassPair
183 				return animationClassPair.animationClass;
184 			}
185 		}
186 
187 		return COLLADAFW::AnimationList::UNKNOWN_CLASS;
188 	}
189 
190 #if 0
191 	/** Determines the physical dimension and the dimension of @a parameter.
192 	@param parameters the accessor parameter to determine the dimensions from
193 	@param physicalDimension Will be set to the physical dimension
194 	@param dimension Will be set to the dimension of the parameter, e.g. 1 for float, 16 for float4x4
195 	@return True if parameter was found, false otherwise.*/
196 	//------------------------------
197 	bool determineParameterDimensions( const SourceBase::AccessorParameter& parameter,
198 									   COLLADAFW::PhysicalDimension& physicalDimension,
199 									   size_t& dimension)
200 	{
201 		static const size_t mapSize = sizeof(animationDimensionMap)/sizeof(AccessorDimensionsPair);
202 		for ( size_t i = 0; i < mapSize; ++i)
203 		{
204 			const AccessorDimensionsPair& animationDimensionPair = animationDimensionMap[i];
205 
206 			if ( parameter ==  animationDimensionPair.parameter )
207 			{
208 				physicalDimension = animationDimensionPair.physicalDimension;
209 				dimension = animationDimensionPair.dimension;
210 				return true;
211 			}
212 		}
213 
214 		return false;
215 	}
216 #endif
217 
218 	//------------------------------
getInterpolationTypeByString(const ParserString & string)219 	COLLADAFW::AnimationCurve::InterpolationType LibraryAnimationsLoader::getInterpolationTypeByString( const ParserString& string )
220 	{
221 		if ( string == INTERPOLATIONTYPE_LINEAR )
222 		{
223 			return COLLADAFW::AnimationCurve::INTERPOLATION_LINEAR;
224 		}
225 		else if ( string == INTERPOLATIONTYPE_BEZIER )
226 		{
227 			return COLLADAFW::AnimationCurve::INTERPOLATION_BEZIER;
228 		}
229 		else if ( string == INTERPOLATIONTYPE_CARDINAL )
230 		{
231 			return COLLADAFW::AnimationCurve::INTERPOLATION_CARDINAL;
232 		}
233 		else if ( string == INTERPOLATIONTYPE_HERMITE )
234 		{
235 			return COLLADAFW::AnimationCurve::INTERPOLATION_HERMITE;
236 		}
237 		else if ( string == INTERPOLATIONTYPE_BSPLINE )
238 		{
239 			return COLLADAFW::AnimationCurve::INTERPOLATION_BSPLINE;
240 		}
241 		else if ( string == INTERPOLATIONTYPE_STEP )
242 		{
243 			return COLLADAFW::AnimationCurve::INTERPOLATION_STEP;
244 		}
245 		else if ( string == INTERPOLATIONTYPE_MIXED )
246 		{
247 			return COLLADAFW::AnimationCurve::INTERPOLATION_MIXED;
248 		}
249 
250 		return COLLADAFW::AnimationCurve::INTERPOLATION_UNKNOWN;
251 	}
252 
253 	//------------------------------
getSemanticBySemanticStr(const char * semanticStr)254 	SamplerInputSemantics getSemanticBySemanticStr( const char * semanticStr)
255 	{
256 		if ( strcmp(semanticStr, "INPUT" ) == 0 )
257 		{
258 			return SEMANTIC_INPUT;
259 		}
260 		else if ( strcmp(semanticStr, "OUTPUT" ) == 0 )
261 		{
262 			return SEMANTIC_OUTPUT;
263 		}
264 		else if ( strcmp(semanticStr, "INTERPOLATION" ) == 0 )
265 		{
266 			return SEMANTIC_INTERPOLATION;
267 		}
268 		else if ( strcmp(semanticStr, "IN_TANGENT" ) == 0 )
269 		{
270 			return SEMANTIC_IN_TANGENT;
271 		}
272 		else if ( strcmp(semanticStr, "OUT_TANGENT" ) == 0 )
273 		{
274 			return SEMANTIC_OUT_TANGENT;
275 		}
276 		return SEMANTIC_UNKNOWN;
277 	}
278 
279 	//------------------------------
LibraryAnimationsLoader(IFilePartLoader * callingFilePartLoader)280 	LibraryAnimationsLoader::LibraryAnimationsLoader( IFilePartLoader* callingFilePartLoader )
281 		: SourceArrayLoader(callingFilePartLoader)
282 		, mCurrentAnimationCurve(0)
283 		, mCurrentlyParsingInterpolationArray(false)
284 		, mCurrentAnimationInfo( 0 )
285 		, mCurrentAnimationCurveRequiresTangents(true)
286 		, mVerboseValidate(true)
287         , mProcessedCount(0)
288 	{}
289 
290     //------------------------------
~LibraryAnimationsLoader()291 	LibraryAnimationsLoader::~LibraryAnimationsLoader()
292 	{
293 	}
294 
295     //------------------------------
getUniqueId()296     const COLLADAFW::UniqueId& LibraryAnimationsLoader::getUniqueId ()
297     {
298         if ( mCurrentAnimationCurve )
299             return mCurrentAnimationCurve->getUniqueId ();
300 
301         // TODO One curve for every sampler in an collada animation. Returns always an invalid id!
302         return COLLADAFW::UniqueId::INVALID;
303     }
304 
305 	//------------------------------
getAnimationInfoBySamplerId(const String & samplerId)306 	AnimationInfo* LibraryAnimationsLoader::getAnimationInfoBySamplerId( const String& samplerId )
307 	{
308 		StringAnimationInfoMap::iterator it = mSamplerIdAnimationInfoMap.find( samplerId );
309 		if ( it == mSamplerIdAnimationInfoMap.end() )
310 		{
311 			return 0;
312 		}
313 		else
314 		{
315 			return &(it->second);
316 		}
317 	}
318 
319 	//------------------------------
end__library_animations()320 	bool LibraryAnimationsLoader::end__library_animations()
321 	{
322 		moveUpInSidTree();
323 		finish();
324 		return true;
325 	}
326 
327 	//------------------------------
begin__source(const source__AttributeData & attributes)328 	bool LibraryAnimationsLoader::begin__source( const source__AttributeData& attributes )
329 	{
330 		return beginSource(attributes);
331 	}
332 
333 	//------------------------------
end__source()334 	bool LibraryAnimationsLoader::end__source(  )
335 	{
336 		return endSource();
337 	}
338 
339 	//------------------------------
begin__animation(const animation__AttributeData & attributeData)340 	bool LibraryAnimationsLoader::begin__animation( const animation__AttributeData& attributeData )
341 	{
342         if ( attributeData.name )
343             mName = (const char*)attributeData.name;
344         else if ( attributeData.id)
345             mName = (const char*)attributeData.id;
346 
347         if ( attributeData.id )
348             mOriginalId = (const char*)attributeData.id;
349         else {
350             //FR: we create an id, so that clients can figure out - for an incoming animation - which animation it originally belongs to.
351             //Thus, it can be able to respect the same layout of animation than the input COLLADA file.
352             std::ostringstream o;
353             o << "animation_"  << this->mProcessedCount++;
354             mOriginalId = o.str();
355         }
356 
357 		return true;
358 	}
359 
360 	//------------------------------
end__animation()361 	bool LibraryAnimationsLoader::end__animation()
362 	{
363         mOriginalId = COLLADABU::Utils::EMPTY_STRING;
364 
365 		return true;
366 	}
367 
368 	//------------------------------
begin__sampler(const sampler__AttributeData & attributeData)369 	bool LibraryAnimationsLoader::begin__sampler( const sampler__AttributeData& attributeData )
370 	{
371 		mCurrentAnimationCurve = FW_NEW COLLADAFW::AnimationCurve(createUniqueIdFromId(attributeData.id, COLLADAFW::Animation::ID()));
372 
373 		mCurrentAnimationCurve->setName ( mName );
374         mCurrentAnimationCurve->setOriginalId ( mOriginalId );
375 
376 		if ( attributeData.id && *attributeData.id )
377 		{
378 			AnimationInfo animationInfo;
379 			animationInfo.uniqueId = mCurrentAnimationCurve->getUniqueId();
380 			animationInfo.animationClass = COLLADAFW::AnimationList::UNKNOWN_CLASS;
381 			mCurrentAnimationInfo = &(mSamplerIdAnimationInfoMap.insert(std::make_pair(attributeData.id, animationInfo)).first->second);
382 		}
383 		return true;
384 	}
385 
386 	//------------------------------
end__sampler()387 	bool LibraryAnimationsLoader::end__sampler()
388 	{
389 		bool success = true;
390 		if ( !mCurrentAnimationCurveRequiresTangents )
391 		{
392 			mCurrentAnimationCurve->getInTangentValues().clear();
393 			mCurrentAnimationCurve->getOutTangentValues().clear();
394 		}
395 		if ( (getObjectFlags() & Loader::ANIMATION_FLAG) != 0 )
396 		{
397 			//assume linear interpolation if no interpolation is set
398 			if ( mCurrentAnimationCurve->getInterpolationType() == COLLADAFW::AnimationCurve::INTERPOLATION_UNKNOWN )
399 			{
400 				mCurrentAnimationCurve->setInterpolationType(COLLADAFW::AnimationCurve::INTERPOLATION_LINEAR );
401 			}
402 
403 			if ( COLLADAFW::validate( mCurrentAnimationCurve, mVerboseValidate ) == 0)
404 			{
405 				success = writer()->writeAnimation(mCurrentAnimationCurve);
406 				FW_DELETE mCurrentAnimationCurve;
407 			}
408 			else
409 			{
410                 handleFWLError ( SaxFWLError::ERROR_DATA_NOT_VALID, "Animation curve \"" + mCurrentAnimationCurve->getName () + "\" not valid!" );
411 			}
412 		}
413 		mCurrentAnimationCurve = 0;
414 		mCurrentAnimationInfo = 0;
415 		mCurrentAnimationCurveRequiresTangents = true;
416 		return success;
417 	}
418 
419 	//------------------------------
begin__channel(const channel__AttributeData & attributeData)420 	bool LibraryAnimationsLoader::begin__channel( const channel__AttributeData& attributeData )
421 	{
422 		String samplerId = getIdFromURIFragmentType(attributeData.source);
423 
424 		AnimationInfo* animationInfo = getAnimationInfoBySamplerId( samplerId );
425 
426 		if ( !animationInfo )
427 			return true;
428 
429 		SidAddress sidAddress( String(attributeData.target) );
430 #if 0
431 		const SidTreeNode* sidTreeNode = resolveSid( sidAddress );
432 
433 		if ( sidTreeNode )
434 		{
435 			if ( sidTreeNode->getTargetType() == SidTreeNode::TARGETTYPE_ANIMATABLE )
436 			{
437 				COLLADAFW::Animatable* animatable = sidTreeNode->getAnimatableTarget();
438 				COLLADAFW::UniqueId animationListUniqueId = animatable->getAnimationList();
439 				if ( !animationListUniqueId.isValid() )
440 				{
441 					animationListUniqueId = getUniqueId( COLLADAFW::AnimationList::ID() );
442 					animatable->setAnimationList( animationListUniqueId );
443 				}
444 				COLLADAFW::AnimationList*& animationList = getAnimationListByUniqueId(animationListUniqueId);
445 
446 				if ( !animationList )
447 				{
448 					animationList = new COLLADAFW::AnimationList( animationListUniqueId.getObjectId() );
449 				}
450 
451 				// TODO handle this for arrays
452 				COLLADAFW::AnimationList::AnimationBinding animationBinding;
453 				animationBinding.animation = animationInfo->uniqueId;
454 				animationBinding.animationClass = animationInfo->animationClass;
455 				if ( animationBinding.animationClass == COLLADAFW::AnimationList::MATRIX4X4_ELEMENT )
456 				{
457 					animationBinding.firstIndex = sidAddress.getFirstIndex();
458 					animationBinding.secondIndex = sidAddress.getSecondIndex();
459 				}
460 				else
461 				{
462 					animationBinding.firstIndex = 0;
463 					animationBinding.secondIndex = 0;
464 				}
465 				animationList->getAnimationBindings().append( animationBinding );
466 			}
467 		}
468 		else
469 #endif
470 		{
471 			// the references element has not been parsed. Store the connection. Will be processed by FileLoader
472 			// at the end of the collada file.
473 			addToAnimationSidAddressBindings( *animationInfo, sidAddress );
474 		}
475 
476 		return true;
477 	}
478 
479 	//------------------------------
end__channel()480 	bool LibraryAnimationsLoader::end__channel()
481 	{
482 		return true;
483 	}
484 
485 
486 	//------------------------------
begin__input____InputLocal(const input____InputLocal__AttributeData & attributeData)487 	bool LibraryAnimationsLoader::begin__input____InputLocal( const input____InputLocal__AttributeData& attributeData )
488 	{
489 		// we ignore inputs that don't have semantics or source
490 		if ( !attributeData.semantic || !attributeData.source  )
491 		{
492 			return true;
493 		}
494 
495 		SamplerInputSemantics semantic = getSemanticBySemanticStr( attributeData.semantic );
496 		if ( semantic == SEMANTIC_UNKNOWN )
497 		{
498 			return true;
499 		}
500 
501 		String sourceId = getIdFromURIFragmentType(attributeData.source);
502 		const SourceBase* sourceBase = getSourceById ( sourceId );
503 		// TODO handle case where source could not be found
504 		if ( !sourceBase )
505 			return true;
506 		SourceBase::DataType sourceDataType =  sourceBase->getDataType();
507 
508 
509 		switch ( semantic )
510 		{
511 		case SEMANTIC_INPUT:
512 			{
513 				if ( sourceDataType != SourceBase::DATA_TYPE_REAL )
514 				{
515 					// The source array has wrong type. Only reals are allowed for semantic INPUT
516 					break;
517 				}
518 
519 				COLLADAFW::AnimationList::AnimationClass animationClass = determineAnimationClass( sourceBase->getAccessor() );
520 
521 				if ( animationClass == COLLADAFW::AnimationList::TIME )
522 				{
523 					mCurrentAnimationCurve->setInPhysicalDimension( COLLADAFW::PHYSICAL_DIMENSION_TIME );
524 				}
525 				else
526 				{
527 					mCurrentAnimationCurve->setInPhysicalDimension( COLLADAFW::PHYSICAL_DIMENSION_UNKNOWN );
528 				}
529 
530 				setRealValues( mCurrentAnimationCurve->getInputValues(), (const RealSource*)sourceBase);
531 			}
532 			break;
533 		case SEMANTIC_OUTPUT:
534 			{
535 				if ( sourceDataType != SourceBase::DATA_TYPE_REAL )
536 				{
537 					// The source array has wrong type. Only reals are allowed for semantic OUTPUT
538 					break;
539 				}
540 
541 				COLLADABU_ASSERT( mCurrentAnimationInfo );
542 				COLLADAFW::PhysicalDimensionArray& physicalDimensions = mCurrentAnimationCurve->getOutPhysicalDimensions();
543 
544 				if ( mCurrentAnimationInfo )
545 				{
546 					COLLADAFW::AnimationList::AnimationClass animationClass = determineAnimationClass( sourceBase->getAccessor() );
547 					mCurrentAnimationInfo->animationClass = animationClass;
548 
549 					switch ( animationClass )
550 					{
551 					case COLLADAFW::AnimationList::POSITION_X:
552 					case COLLADAFW::AnimationList::POSITION_Y:
553 					case COLLADAFW::AnimationList::POSITION_Z:
554 						physicalDimensions.append(COLLADAFW::PHYSICAL_DIMENSION_LENGTH);
555 						break;
556 					case COLLADAFW::AnimationList::POSITION_XYZ:
557 						physicalDimensions.append(COLLADAFW::PHYSICAL_DIMENSION_LENGTH);
558 						physicalDimensions.append(COLLADAFW::PHYSICAL_DIMENSION_LENGTH);
559 						physicalDimensions.append(COLLADAFW::PHYSICAL_DIMENSION_LENGTH);
560 						break;
561 					case COLLADAFW::AnimationList::ANGLE:
562 						physicalDimensions.append(COLLADAFW::PHYSICAL_DIMENSION_ANGLE);
563 						break;
564 					case COLLADAFW::AnimationList::AXISANGLE:
565 						physicalDimensions.append(COLLADAFW::PHYSICAL_DIMENSION_NUMBER);
566 						physicalDimensions.append(COLLADAFW::PHYSICAL_DIMENSION_NUMBER);
567 						physicalDimensions.append(COLLADAFW::PHYSICAL_DIMENSION_NUMBER);
568 						physicalDimensions.append(COLLADAFW::PHYSICAL_DIMENSION_ANGLE);
569 						break;
570 					case COLLADAFW::AnimationList::MATRIX4X4:
571 						physicalDimensions.append(COLLADAFW::PHYSICAL_DIMENSION_NUMBER);
572 						physicalDimensions.append(COLLADAFW::PHYSICAL_DIMENSION_NUMBER);
573 						physicalDimensions.append(COLLADAFW::PHYSICAL_DIMENSION_NUMBER);
574 						physicalDimensions.append(COLLADAFW::PHYSICAL_DIMENSION_LENGTH);
575 						physicalDimensions.append(COLLADAFW::PHYSICAL_DIMENSION_NUMBER);
576 						physicalDimensions.append(COLLADAFW::PHYSICAL_DIMENSION_NUMBER);
577 						physicalDimensions.append(COLLADAFW::PHYSICAL_DIMENSION_NUMBER);
578 						physicalDimensions.append(COLLADAFW::PHYSICAL_DIMENSION_LENGTH);
579 						physicalDimensions.append(COLLADAFW::PHYSICAL_DIMENSION_NUMBER);
580 						physicalDimensions.append(COLLADAFW::PHYSICAL_DIMENSION_NUMBER);
581 						physicalDimensions.append(COLLADAFW::PHYSICAL_DIMENSION_NUMBER);
582 						physicalDimensions.append(COLLADAFW::PHYSICAL_DIMENSION_LENGTH);
583 						physicalDimensions.append(COLLADAFW::PHYSICAL_DIMENSION_NUMBER);
584 						physicalDimensions.append(COLLADAFW::PHYSICAL_DIMENSION_NUMBER);
585 						physicalDimensions.append(COLLADAFW::PHYSICAL_DIMENSION_NUMBER);
586 						physicalDimensions.append(COLLADAFW::PHYSICAL_DIMENSION_NUMBER);
587 						break;
588 					case COLLADAFW::AnimationList::COLOR_R:
589 					case COLLADAFW::AnimationList::COLOR_G:
590 					case COLLADAFW::AnimationList::COLOR_B:
591 					case COLLADAFW::AnimationList::COLOR_A:
592 						physicalDimensions.append(COLLADAFW::PHYSICAL_DIMENSION_COLOR);
593 						break;
594 					case COLLADAFW::AnimationList::COLOR_RGB:
595 						physicalDimensions.append(COLLADAFW::PHYSICAL_DIMENSION_COLOR);
596 						physicalDimensions.append(COLLADAFW::PHYSICAL_DIMENSION_COLOR);
597 						physicalDimensions.append(COLLADAFW::PHYSICAL_DIMENSION_COLOR);
598 						break;
599 					case COLLADAFW::AnimationList::COLOR_RGBA:
600 						physicalDimensions.append(COLLADAFW::PHYSICAL_DIMENSION_COLOR);
601 						physicalDimensions.append(COLLADAFW::PHYSICAL_DIMENSION_COLOR);
602 						physicalDimensions.append(COLLADAFW::PHYSICAL_DIMENSION_COLOR);
603 						physicalDimensions.append(COLLADAFW::PHYSICAL_DIMENSION_COLOR);
604 						break;
605                     case COLLADAFW::AnimationList::FLOAT:
606                         physicalDimensions.append(COLLADAFW::PHYSICAL_DIMENSION_NUMBER);
607                         break;
608                     case COLLADAFW::AnimationList::ARRAY_ELEMENT_1D:
609                     case COLLADAFW::AnimationList::ARRAY_ELEMENT_2D:
610                             //https://github.com/KhronosGroup/OpenCOLLADA/issues/245
611                             //FR: is this an issue to have nothing processed here, or is it processed somewhere else ?
612                         break;
613                     case COLLADAFW::AnimationList::UNKNOWN_CLASS:
614                     case COLLADAFW::AnimationList::TIME:
615                         break;
616 					}
617 				}
618 
619 				const RealSource* realSource = (const RealSource*)sourceBase;
620 				setRealValues( mCurrentAnimationCurve->getOutputValues(), realSource);
621 
622 				size_t stride = (size_t)realSource->getStride();
623 				size_t physicalDimensionsCount = physicalDimensions.getCount();
624 				// if stride is larger that physicalDimensionsCount, we need to append dimensions to physicalDimensions
625 				for ( size_t i =  physicalDimensionsCount; i < stride; ++i)
626 				{
627 					physicalDimensions.append(COLLADAFW::PHYSICAL_DIMENSION_UNKNOWN);
628 				}
629 				mCurrentAnimationCurve->setOutDimension(stride);
630 			}
631 			break;
632 		case SEMANTIC_OUT_TANGENT:
633 			{
634 				if ( sourceDataType != SourceBase::DATA_TYPE_REAL )
635 				{
636 					// The source array has wrong type. Only reals are allowed for semantic OUTPUT
637 					break;
638 				}
639 
640 				if ( !mCurrentAnimationCurveRequiresTangents )
641 				{
642 					// This animation does not require tangents
643 					break;
644 				}
645 				setRealValues( mCurrentAnimationCurve->getOutTangentValues(), (const RealSource*)sourceBase);
646 			}
647 			break;
648 		case SEMANTIC_IN_TANGENT:
649 			{
650 				if ( sourceDataType != SourceBase::DATA_TYPE_REAL )
651 				{
652 					// The source array has wrong type. Only reals are allowed for semantic OUTPUT
653 					break;
654 				}
655 				if ( !mCurrentAnimationCurveRequiresTangents )
656 				{
657 					// This animation does not require tangents
658 					break;
659 				}
660 				setRealValues( mCurrentAnimationCurve->getInTangentValues(), (const RealSource*)sourceBase);
661 			}
662 			break;
663 		case SEMANTIC_INTERPOLATION:
664 			{
665 				if ( sourceDataType != SourceBase::DATA_TYPE_INTERPOLATIONTYPE )
666 				{
667 					// The source array has wrong type. Only reals are allowed for semantic INTERPOLATION
668 					break;
669 				}
670 
671 				COLLADAFW::AnimationCurve::InterpolationType currentAnimationCurveInterpolationType = mCurrentAnimationCurve->getInterpolationType();
672 
673 				if ( currentAnimationCurveInterpolationType != COLLADAFW::AnimationCurve::INTERPOLATION_UNKNOWN )
674 				{
675 					// There already must have been an input with semantic INTERPOLATION. We ignore all following.
676 					break;
677 				}
678 
679 				const InterpolationTypeSource* interpolationTypeSource = (const InterpolationTypeSource*)sourceBase;
680 				COLLADAFW::AnimationCurve::InterpolationType interpolationType = interpolationTypeSource->getInterpolationType();
681 				mCurrentAnimationCurveRequiresTangents = interpolationTypeSource->getRequiresTangents();
682 
683 				mCurrentAnimationCurve->setInterpolationType(interpolationType);
684 
685 				if ( interpolationType == COLLADAFW::AnimationCurve::INTERPOLATION_MIXED )
686 				{
687 					COLLADAFW::AnimationCurve::InterpolationTypeArray& interpolationTypes = mCurrentAnimationCurve->getInterpolationTypes();
688 					interpolationTypes.appendValues(interpolationTypeSource->getArrayElement().getValues());
689 				}
690 			}
691 			break;
692         default:
693             break;
694 		}
695 
696 		return true;
697 	}
698 
699 	//------------------------------
begin__Name_array(const Name_array__AttributeData & attributeData)700 	bool LibraryAnimationsLoader::begin__Name_array( const Name_array__AttributeData& attributeData )
701 	{
702 		return beginArray<InterpolationTypeSource>( attributeData.count, attributeData.id ) != 0;
703 		return true;
704 	}
705 
706 	//------------------------------
end__Name_array()707 	bool LibraryAnimationsLoader::end__Name_array()
708 	{
709 		return true;
710 	}
711 
712 	//------------------------------
data__Name_array(const ParserString * data,size_t length)713 	bool LibraryAnimationsLoader::data__Name_array( const ParserString* data, size_t length )
714 	{
715 		InterpolationTypeSource* interpolationTypeSource = (InterpolationTypeSource*)mCurrentSoure;
716 		for ( size_t i = 0; i < length;  ++i)
717 		{
718 			const ParserString& interpolationTypeString = data[i];
719 			COLLADAFW::AnimationCurve::InterpolationType interpolationType = getInterpolationTypeByString( interpolationTypeString );
720 			COLLADAFW::AnimationCurve::InterpolationTypeArray& array  = interpolationTypeSource->getArrayElement().getValues();
721 			array.append( interpolationType );
722 
723 			COLLADAFW::AnimationCurve::InterpolationType interpolationTypeSourceInterpolationType = interpolationTypeSource->getInterpolationType();
724 			if ( (interpolationType == COLLADAFW::AnimationCurve::INTERPOLATION_BEZIER) ||
725 				 (interpolationType == COLLADAFW::AnimationCurve::INTERPOLATION_HERMITE) )
726 			{
727 				interpolationTypeSource->setRequiresTangents( true );
728 			}
729 			if ( interpolationTypeSourceInterpolationType == COLLADAFW::AnimationCurve::INTERPOLATION_UNKNOWN )
730 			{
731 				interpolationTypeSource->setInterpolationType( interpolationType );
732 			}
733 			else if ( interpolationTypeSourceInterpolationType != interpolationType )
734 			{
735 				interpolationTypeSource->setInterpolationType( COLLADAFW::AnimationCurve::INTERPOLATION_MIXED);
736 			}
737 		}
738 		return true;
739 	}
740 
741 } // namespace COLLADASaxFWL
742