[Bf-blender-cvs] SVN commit: /data/svn/bf-blender [21778] branches/soc-2009-chingachgook/ source/blender/collada/DocumentExporter.cpp: Basic object transform animation export:

Arystanbek Dyussenov arystan.d at gmail.com
Tue Jul 21 21:08:36 CEST 2009


Revision: 21778
          http://projects.blender.org/plugins/scmsvn/viewcvs.php?view=rev&root=bf-blender&revision=21778
Author:   kazanbas
Date:     2009-07-21 21:08:36 +0200 (Tue, 21 Jul 2009)

Log Message:
-----------
Basic object transform animation export:
- just writes all curves from action linked to an object
- linear interpolation

Modified Paths:
--------------
    branches/soc-2009-chingachgook/source/blender/collada/DocumentExporter.cpp

Modified: branches/soc-2009-chingachgook/source/blender/collada/DocumentExporter.cpp
===================================================================
--- branches/soc-2009-chingachgook/source/blender/collada/DocumentExporter.cpp	2009-07-21 18:49:16 UTC (rev 21777)
+++ branches/soc-2009-chingachgook/source/blender/collada/DocumentExporter.cpp	2009-07-21 19:08:36 UTC (rev 21778)
@@ -1,3 +1,7 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <math.h>
+
 #include "DNA_scene_types.h"
 #include "DNA_object_types.h"
 #include "DNA_meshdata_types.h"
@@ -21,6 +25,7 @@
 #include "BKE_material.h"
 
 #include "BLI_arithb.h"
+#include "BLI_string.h"
 
 #include "DocumentExporter.h"
 
@@ -57,7 +62,6 @@
 
 #include <vector>
 #include <algorithm> // std::find
-#include <math.h>
 
 // TODO: this can handy in BLI_arith.b
 // This function assumes that quat is normalized.
@@ -130,15 +134,14 @@
 }
 
 template<class Functor>
-void forEachObjectWithAnimationInScene(Scene *sce, Functor &f)
+void forEachObjectInScene(Scene *sce, Functor &f)
 {
 	Base *base= (Base*) sce->base.first;
 	while(base) {
 		Object *ob = base->object;
 			
-		if (ob->adt && ob->data) {
-			f(ob);
-		}
+		f(ob);
+
 		base= base->next;
 	}
 }
@@ -573,23 +576,32 @@
 	void writeNodes(Object *ob, Scene *sce) {
 		
 		COLLADASW::Node node(mSW);
+		node.setNodeId(ob->id.name);
+		node.setType(COLLADASW::Node::NODE);
+
 		std::string ob_name(id_name(ob));
+
 		node.start();
+		node.addTranslate("location", ob->loc[0], ob->loc[1], ob->loc[2]);
 		
-		node.addTranslate(ob->loc[0], ob->loc[1], ob->loc[2]);
+		// this code used to create a single <rotate> representing object rotation
+		// float quat[4];
+		// float axis[3];
+		// float angle;
+		// double angle_deg;
+		// EulToQuat(ob->rot, quat);
+		// NormalQuat(quat);
+		// QuatToAxisAngle(quat, axis, &angle);
+		// angle_deg = angle * 180.0f / M_PI;
+		// node.addRotate(axis[0], axis[1], axis[2], angle_deg);
+
+		float *rot = ob->rot;
+		node.addRotateX("rotationX", COLLADABU::Math::Utils::radToDegF(rot[0]));
+		node.addRotateY("rotationY", COLLADABU::Math::Utils::radToDegF(rot[1]));
+		node.addRotateZ("rotationZ", COLLADABU::Math::Utils::radToDegF(rot[2]));
+
+		node.addScale("scale", ob->size[0], ob->size[1], ob->size[2]);
 		
-		// when animation time comes, replace a single <rotate> with 3, one for each axis
-		float quat[4];
-		float axis[3];
-		float angle;
-		double angle_deg;
-		EulToQuat(ob->rot, quat);
-		NormalQuat(quat);
-		QuatToAxisAngle(quat, axis, &angle);
-		angle_deg = angle * 180.0f / M_PI;
-		node.addRotate(axis[0], axis[1], axis[2], angle_deg);
-		node.addScale(ob->size[0], ob->size[1], ob->size[2]);
-		
 		// <instance_geometry>
 		if (ob->type == OB_MESH) {
 			COLLADASW::InstanceGeometry instGeom(mSW);
@@ -1020,43 +1032,226 @@
 	}
 };
 
-class AnimationsExporter: COLLADASW::LibraryAnimations
+// TODO: it would be better to instantiate animations rather than create a new one per object
+// COLLADA allows this through multiple <channel>s in <animation>.
+// For this to work, we need to know objects that use a certain action.
+class AnimationExporter: COLLADASW::LibraryAnimations
 {
+	Scene *scene;
 public:
-	AnimationsExporter(COLLADASW::StreamWriter *sw): COLLADASW::LibraryAnimations(sw) {}
-	void exportAnimation(Scene *sce)
+	AnimationExporter(COLLADASW::StreamWriter *sw): COLLADASW::LibraryAnimations(sw) {}
+
+	void exportAnimations(Scene *sce)
 	{
+		this->scene = sce;
+
 		openLibrary();
 		
-		forEachObjectWithAnimationInScene(sce, *this);
+		forEachObjectInScene(sce, *this);
 		
 		closeLibrary();
 	}
-	void operator() (Object *ob) 
+
+	// create <animation> for each transform axis
+
+	float convert_time(float frame) {
+		return FRA2TIME(frame);
+	}
+
+	float convert_angle(float angle) {
+		return COLLADABU::Math::Utils::radToDegF(angle);
+	}
+
+	std::string get_semantic_suffix(Sampler::Semantic semantic) {
+		switch(semantic) {
+		case Sampler::INPUT:
+			return INPUT_SOURCE_ID_SUFFIX;
+		case Sampler::OUTPUT:
+			return OUTPUT_SOURCE_ID_SUFFIX;
+		case Sampler::INTERPOLATION:
+			return INTERPOLATION_SOURCE_ID_SUFFIX;
+		case Sampler::IN_TANGENT:
+			return INTANGENT_SOURCE_ID_SUFFIX;
+		case Sampler::OUT_TANGENT:
+			return OUTTANGENT_SOURCE_ID_SUFFIX;
+		}
+		return "";
+	}
+
+	void add_source_parameters(COLLADASW::SourceBase::ParameterNameList& param,
+							   Sampler::Semantic semantic, bool rotation, char *axis) {
+		switch(semantic) {
+		case Sampler::INPUT:
+			param.push_back("TIME");
+			break;
+		case Sampler::OUTPUT:
+			if (rotation) {
+				param.push_back("ANGLE");
+			}
+			else {
+				param.push_back(axis);
+			}
+			break;
+		case Sampler::IN_TANGENT:
+		case Sampler::OUT_TANGENT:
+			param.push_back("X");
+			param.push_back("Y");
+			break;
+		}
+	}
+
+	void get_source_values(BezTriple *bezt, Sampler::Semantic semantic, bool rotation, float *values, int *length)
 	{
+		switch (semantic) {
+		case Sampler::INPUT:
+			*length = 1;
+			values[0] = convert_time(bezt->vec[1][0]);
+			break;
+		case Sampler::OUTPUT:
+			*length = 1;
+			if (rotation) {
+				values[0] = convert_angle(bezt->vec[1][1]);
+			}
+			else {
+				values[0] = bezt->vec[1][1];
+			}
+			break;
+		case Sampler::IN_TANGENT:
+		case Sampler::OUT_TANGENT:
+			// XXX
+			*length = 2;
+			break;
+		}
+	}
+
+	std::string create_source(Sampler::Semantic semantic, FCurve *fcu, std::string& anim_id, char *axis_name)
+	{
+		std::string source_id = anim_id + get_semantic_suffix(semantic);
+
+		bool is_rotation = !strcmp(fcu->rna_path, "rotation");
+
+		COLLADASW::FloatSourceF source(mSW);
+		source.setId(source_id);
+		source.setArrayId(source_id + ARRAY_ID_SUFFIX);
+		source.setAccessorCount(fcu->totvert);
+		source.setAccessorStride(1);
 		
-		AnimData *adt = ob->adt;
-		NlaTrack *nlt;
-		NlaStrip *strip;
-		FCurve *fcu;		
+		COLLADASW::SourceBase::ParameterNameList &param = source.getParameterNameList();
+		add_source_parameters(param, semantic, is_rotation, axis_name);
+
+		source.prepareToAppendValues();
+
+		for (int i = 0; i < fcu->totvert; i++) {
+			float values[3]; // be careful!
+			int length;
+
+			get_source_values(&fcu->bezt[i], semantic, is_rotation, values, &length);
+			for (int j = 0; j < length; j++)
+				source.appendValues(values[j]);
+		}
+
+		source.finish();
+
+		return source_id;
+	}
+
+	std::string create_interpolation_source(FCurve *fcu, std::string& anim_id, char *axis_name)
+	{
+		std::string source_id = anim_id + get_semantic_suffix(Sampler::INTERPOLATION);
+
+		bool is_rotation = !strcmp(fcu->rna_path, "rotation");
+
+		COLLADASW::NameSource source(mSW);
+		source.setId(source_id);
+		source.setArrayId(source_id + ARRAY_ID_SUFFIX);
+		source.setAccessorCount(fcu->totvert);
+		source.setAccessorStride(1);
 		
-		// iterate over all nla tracks
-		for (nlt = (NlaTrack*)adt->nla_tracks.first; nlt; nlt = nlt->next) {
-			
-			// iterate over all nla strips of current nla track
-			for (strip = (NlaStrip*)nlt->strips.first; strip; strip = strip->next) {
-				bAction *act = strip->act;
-				// iterate over all fcurves of current nla strip's action
-				for (fcu = (FCurve*)act->curves.first; fcu; fcu = fcu->next) {
-					// write <animation> for each fcurve
-					// each fcurve represents one axis of loc/rot/scale
-					// through fcurve I can take intangents and outtangents
-					// but how do I get objects loc/rot/scale data at specific time
-					
-				}
+		COLLADASW::SourceBase::ParameterNameList &param = source.getParameterNameList();
+		param.push_back("INTERPOLATION");
+
+		source.prepareToAppendValues();
+
+		for (int i = 0; i < fcu->totvert; i++) {
+			// XXX
+			source.appendValues(LINEAR_NAME);
+		}
+
+		source.finish();
+
+		return source_id;
+	}
+
+	std::string get_transform_sid(char *rna_path, char *axis_name)
+	{
+		if (!strcmp(rna_path, "rotation"))
+			return std::string(rna_path) + axis_name;
+
+		return std::string(rna_path) + "." + axis_name;
+	}
+
+	void add_animation(FCurve *fcu, const char *ob_name)
+	{
+		static char *axis_names[] = {"X", "Y", "Z"};
+		char *axis_name = NULL;
+		char c_anim_id[100]; // careful!
+
+		if (fcu->array_index < 3)
+			axis_name = axis_names[fcu->array_index];
+
+		BLI_snprintf(c_anim_id, sizeof(c_anim_id), "%s.%s.%s", ob_name, fcu->rna_path, axis_names[fcu->array_index]);
+		std::string anim_id(c_anim_id);
+
+		// check rna_path is one of: rotation, scale, location
+
+		openAnimation(anim_id);
+
+		// create input source
+		std::string input_id = create_source(Sampler::INPUT, fcu, anim_id, axis_name);
+
+		// create output source
+		std::string output_id = create_source(Sampler::OUTPUT, fcu, anim_id, axis_name);
+
+		// create interpolations source
+		std::string interpolation_id = create_interpolation_source(fcu, anim_id, axis_name);
+
+		std::string sampler_id = anim_id + SAMPLER_ID_SUFFIX;
+		COLLADASW::LibraryAnimations::Sampler sampler(sampler_id);
+		std::string empty;
+		sampler.addInput(Sampler::INPUT, COLLADABU::URI(empty, input_id));
+		sampler.addInput(Sampler::OUTPUT, COLLADABU::URI(empty, output_id));
+
+		// this input is required
+		sampler.addInput(Sampler::INTERPOLATION, COLLADABU::URI(empty, interpolation_id));
+
+		addSampler(sampler);
+
+		std::string target = std::string(ob_name) + "/" + get_transform_sid(fcu->rna_path, axis_name);
+		addChannel(COLLADABU::URI(empty, sampler_id), target);
+
+		closeAnimation();
+	}
+
+	// called for each exported object
+	void operator() (Object *ob) 
+	{
+		if (!ob->adt || !ob->adt->action) return;
+
+		// XXX this needs to be handled differently?
+		if (ob->type == OB_ARMATURE) return;
+
+		FCurve *fcu = (FCurve*)ob->adt->action->curves.first;
+		while (fcu) {
+
+			if (!strcmp(fcu->rna_path, "location") ||
+				!strcmp(fcu->rna_path, "scale") ||
+				!strcmp(fcu->rna_path, "rotation")) {
+
+				add_animation(fcu, ob->id.name);
 			}
+
+			fcu = fcu->next;
 		}
-		
 	}
 };
 
@@ -1099,6 +1294,10 @@
 	// <library_geometries>
 	GeometryExporter ge(&sw);
 	ge.exportGeom(sce);
+
+	// <library_animations>
+	AnimationExporter ae(&sw);
+	ae.exportAnimations(sce);
 	
 	// <library_visual_scenes>
 	SceneExporter se(&sw);





More information about the Bf-blender-cvs mailing list