Browse Source

- fbx: refactor animation code.

Alexander Gessler 13 years ago
parent
commit
80e7e18e28
1 changed files with 175 additions and 160 deletions
  1. 175 160
      code/FBXConverter.cpp

+ 175 - 160
code/FBXConverter.cpp

@@ -1400,196 +1400,211 @@ private:
 		double max_time = -1e10;
 		double max_time = -1e10;
 
 
 		try {
 		try {
-
-			NodeMap node_property_map;
 			BOOST_FOREACH(const NodeMap::value_type& kv, node_map) {
 			BOOST_FOREACH(const NodeMap::value_type& kv, node_map) {
-				node_property_map.clear();
+				GenerateNodeAnimations(node_anims, 
+					kv.first, 
+					kv.second, 
+					layer_map, 
+					min_time, 
+					max_time);
+			}
+		}
+		catch(std::exception&) {
+			std::for_each(node_anims.begin(), node_anims.end(), Util::delete_fun<aiNodeAnim>());
+			throw;
+		}
 
 
-				ai_assert(kv.second.size());
+		if(node_anims.size()) {
+			anim->mChannels = new aiNodeAnim*[node_anims.size()]();
+			anim->mNumChannels = static_cast<unsigned int>(node_anims.size());
 
 
-				const AnimationCurveNode* curve_node;
-				BOOST_FOREACH(const AnimationCurveNode* node, kv.second) {
-					ai_assert(node);
+			std::swap_ranges(node_anims.begin(),node_anims.end(),anim->mChannels);
+		}
+		else {
+			// empty animations would fail validation, so drop them
+			delete anim;
+			animations.pop_back();
+			FBXImporter::LogInfo("ignoring empty AnimationStack: " + name);
+			return;
+		}
 
 
-					if (node->TargetProperty().empty()) {
-						FBXImporter::LogWarn("target property for animation curve not set");
-						continue;
-					}
+		// for some mysterious reason, mDuration is simply the maximum key -- the
+		// validator always assumes animations to start at zero.
+		anim->mDuration = max_time /*- min_time */;
+		anim->mTicksPerSecond = 1000.0;
+	}
 
 
-					curve_node = node;
-					if (node->Curves().empty()) {
-						FBXImporter::LogWarn("no animation curves assigned to AnimationCurveNode");
-						continue;
-					}
 
 
-					node_property_map[node->TargetProperty()].push_back(node);
-				}
+	// ------------------------------------------------------------------------------------------------
+	void GenerateNodeAnimations(std::vector<aiNodeAnim*>& node_anims, 
+		const std::string& fixed_name, 
+		const std::vector<const AnimationCurveNode*>& curves, 
+		const LayerMap& layer_map, 
+		double& max_time,
+		double& min_time)
+	{
 
 
-				ai_assert(curve_node);
+		NodeMap node_property_map;
+		ai_assert(curves.size());
 
 
-				// check for all possible transformation components
-				NodeMap::const_iterator chain[TransformationComp_MAXIMUM];
+		const AnimationCurveNode* curve_node;
+		BOOST_FOREACH(const AnimationCurveNode* node, curves) {
+			ai_assert(node);
 
 
-				bool has_any = false;
-				bool has_complex = false;
+			if (node->TargetProperty().empty()) {
+				FBXImporter::LogWarn("target property for animation curve not set");
+				continue;
+			}
 
 
-				for (size_t i = 0; i < TransformationComp_MAXIMUM; ++i) {
-					const TransformationComp comp = static_cast<TransformationComp>(i);
+			curve_node = node;
+			if (node->Curves().empty()) {
+				FBXImporter::LogWarn("no animation curves assigned to AnimationCurveNode");
+				continue;
+			}
 
 
-					// inverse pivots don't exist in the input, we just generate them
-					if (comp == TransformationComp_RotationPivotInverse || comp == TransformationComp_ScalingPivotInverse) {
-						chain[i] = node_property_map.end();
-						continue;
-					}
+			node_property_map[node->TargetProperty()].push_back(node);
+		}
 
 
-					chain[i] = node_property_map.find(NameTransformationCompProperty(comp));
-					if (chain[i] != node_property_map.end()) {
-						has_any = true;
+		ai_assert(curve_node);
 
 
-						if (comp != TransformationComp_Rotation && comp != TransformationComp_Scaling &&
-							comp != TransformationComp_Translation) {
+		// check for all possible transformation components
+		NodeMap::const_iterator chain[TransformationComp_MAXIMUM];
 
 
-							has_complex = true;
-						}
-					}
-				}
+		bool has_any = false;
+		bool has_complex = false;
 
 
-				if (!has_any) {
-					FBXImporter::LogWarn("ignoring node animation, did not find any transformation key frames");
-					continue;
-				}
+		for (size_t i = 0; i < TransformationComp_MAXIMUM; ++i) {
+			const TransformationComp comp = static_cast<TransformationComp>(i);
 
 
-				ai_assert(curve_node->TargetAsModel());
+			// inverse pivots don't exist in the input, we just generate them
+			if (comp == TransformationComp_RotationPivotInverse || comp == TransformationComp_ScalingPivotInverse) {
+				chain[i] = node_property_map.end();
+				continue;
+			}
 
 
-				// this needs to play nicely with GenerateTransformationNodeChain() which will
-				// be invoked _later_ (animations come first). If this node has only rotation,
-				// scaling and translation _and_ there are no animated other components either,
-				// we can use a single node and also a single node animation channel.
-				const Model& target = *curve_node->TargetAsModel();
-				if (!has_complex && !NeedsComplexTransformationChain(target)) {
+			chain[i] = node_property_map.find(NameTransformationCompProperty(comp));
+			if (chain[i] != node_property_map.end()) {
+				has_any = true;
 
 
-					aiNodeAnim* const nd = GenerateSimpleNodeAnim(kv.first, target, chain, 
-						node_property_map.end(), 
-						layer_map,
-						max_time,
-						min_time
-					);
+				if (comp != TransformationComp_Rotation && comp != TransformationComp_Scaling &&
+					comp != TransformationComp_Translation) {
 
 
-					ai_assert(nd);
-					node_anims.push_back(nd);
-					continue;
+						has_complex = true;
 				}
 				}
+			}
+		}
 
 
-				// otherwise, things get gruesome and we need separate animation channels
-				// for each part of the transformation chain.
-				for (size_t i = 0; i < TransformationComp_MAXIMUM; ++i) {
-					const TransformationComp comp = static_cast<TransformationComp>(i);
-
-					if (chain[i] != node_property_map.end()) {
-
-						const std::string& chain_name = NameTransformationChainNode(kv.first, comp);
-
-						aiNodeAnim* na;
-						switch(comp) 
-						{
-						case TransformationComp_Rotation:
-						case TransformationComp_PreRotation:
-						case TransformationComp_PostRotation:
-							na = GenerateRotationNodeAnim(chain_name, 
-								target, 
-								(*chain[i]).second,
-								layer_map,
-								max_time,
-								min_time
-							);
-							break;
+		if (!has_any) {
+			FBXImporter::LogWarn("ignoring node animation, did not find any transformation key frames");
+			return;
+		}
 
 
-						case TransformationComp_RotationOffset:
-						case TransformationComp_RotationPivot:
-						case TransformationComp_ScalingOffset:
-						case TransformationComp_ScalingPivot:
-						case TransformationComp_Translation:
-							na = GenerateTranslationNodeAnim(chain_name, 
-								target, 
-								(*chain[i]).second,
-								layer_map,
-								max_time,
-								min_time);
-
-							// pivoting requires us to generate an inverse channel to undo the pivot translation
-							if (comp == TransformationComp_RotationPivot) {
-								const std::string& invName = NameTransformationChainNode(kv.first, TransformationComp_RotationPivotInverse);
-								aiNodeAnim* const inv = GenerateTranslationNodeAnim(invName, 
-									target, 
-									(*chain[i]).second,
-									layer_map,
-									max_time,
-									min_time,
-									true);
-
-								ai_assert(inv);
-								node_anims.push_back(inv);
-							}
-							else if (comp == TransformationComp_ScalingPivot) {
-								const std::string& invName = NameTransformationChainNode(kv.first, TransformationComp_ScalingPivotInverse);
-								aiNodeAnim* const inv = GenerateTranslationNodeAnim(invName, 
-									target, 
-									(*chain[i]).second,
-									layer_map,
-									max_time,
-									min_time,
-									true);
-
-								ai_assert(inv);
-								node_anims.push_back(inv);
-							}
+		ai_assert(curve_node->TargetAsModel());
 
 
-							break;
+		// this needs to play nicely with GenerateTransformationNodeChain() which will
+		// be invoked _later_ (animations come first). If this node has only rotation,
+		// scaling and translation _and_ there are no animated other components either,
+		// we can use a single node and also a single node animation channel.
+		const Model& target = *curve_node->TargetAsModel();
+		if (!has_complex && !NeedsComplexTransformationChain(target)) {
 
 
-						case TransformationComp_Scaling:
-							na = GenerateScalingNodeAnim(chain_name, 
-								target, 
-								(*chain[i]).second,
-								layer_map,
-								max_time,
-								min_time
-							);
-							break;
+			aiNodeAnim* const nd = GenerateSimpleNodeAnim(fixed_name, target, chain, 
+				node_property_map.end(), 
+				layer_map,
+				max_time,
+				min_time
+				);
 
 
-						default:
-							ai_assert(false);
-						}
+			ai_assert(nd);
+			node_anims.push_back(nd);
+			return;
+		}
 
 
-						ai_assert(na);
-						node_anims.push_back(na);
-						continue;
+		// otherwise, things get gruesome and we need separate animation channels
+		// for each part of the transformation chain.
+		for (size_t i = 0; i < TransformationComp_MAXIMUM; ++i) {
+			const TransformationComp comp = static_cast<TransformationComp>(i);
+
+			if (chain[i] != node_property_map.end()) {
+
+				const std::string& chain_name = NameTransformationChainNode(fixed_name, comp);
+
+				aiNodeAnim* na;
+				switch(comp) 
+				{
+				case TransformationComp_Rotation:
+				case TransformationComp_PreRotation:
+				case TransformationComp_PostRotation:
+					na = GenerateRotationNodeAnim(chain_name, 
+						target, 
+						(*chain[i]).second,
+						layer_map,
+						max_time,
+						min_time
+						);
+					break;
+
+				case TransformationComp_RotationOffset:
+				case TransformationComp_RotationPivot:
+				case TransformationComp_ScalingOffset:
+				case TransformationComp_ScalingPivot:
+				case TransformationComp_Translation:
+					na = GenerateTranslationNodeAnim(chain_name, 
+						target, 
+						(*chain[i]).second,
+						layer_map,
+						max_time,
+						min_time);
+
+					// pivoting requires us to generate an inverse channel to undo the pivot translation
+					if (comp == TransformationComp_RotationPivot) {
+						const std::string& invName = NameTransformationChainNode(fixed_name, TransformationComp_RotationPivotInverse);
+						aiNodeAnim* const inv = GenerateTranslationNodeAnim(invName, 
+							target, 
+							(*chain[i]).second,
+							layer_map,
+							max_time,
+							min_time,
+							true);
+
+						ai_assert(inv);
+						node_anims.push_back(inv);
+					}
+					else if (comp == TransformationComp_ScalingPivot) {
+						const std::string& invName = NameTransformationChainNode(fixed_name, TransformationComp_ScalingPivotInverse);
+						aiNodeAnim* const inv = GenerateTranslationNodeAnim(invName, 
+							target, 
+							(*chain[i]).second,
+							layer_map,
+							max_time,
+							min_time,
+							true);
+
+						ai_assert(inv);
+						node_anims.push_back(inv);
 					}
 					}
-				}
-			}
-		}
-		catch(std::exception&) {
-			std::for_each(node_anims.begin(), node_anims.end(), Util::delete_fun<aiNodeAnim>());
-			throw;
-		}
 
 
-		if(node_anims.size()) {
-			anim->mChannels = new aiNodeAnim*[node_anims.size()]();
-			anim->mNumChannels = static_cast<unsigned int>(node_anims.size());
+					break;
 
 
-			std::swap_ranges(node_anims.begin(),node_anims.end(),anim->mChannels);
-		}
-		else {
-			// empty animations would fail validation, so drop them
-			delete anim;
-			animations.pop_back();
-			FBXImporter::LogInfo("ignoring empty AnimationStack: " + name);
-			return;
-		}
+				case TransformationComp_Scaling:
+					na = GenerateScalingNodeAnim(chain_name, 
+						target, 
+						(*chain[i]).second,
+						layer_map,
+						max_time,
+						min_time
+						);
+					break;
 
 
-		// for some mysterious reason, mDuration is simply the maximum key -- the
-		// validator always assumes animations to start at zero.
-		anim->mDuration = max_time /*- min_time */;
-		anim->mTicksPerSecond = 1000.0;
+				default:
+					ai_assert(false);
+				}
+
+				ai_assert(na);
+				node_anims.push_back(na);
+				continue;
+			}
+		}
 	}
 	}