Browse Source

Exporters

Panagiotis Christopoulos Charitos 12 years ago
parent
commit
a67e5bae30
5 changed files with 154 additions and 186 deletions
  1. 15 86
      include/anki/resource/Skeleton.h
  2. 1 1
      src/core/App.cpp
  3. 40 96
      src/resource/Skeleton.cpp
  4. 6 0
      src/scene/SkinNode.cpp
  5. 92 3
      tools/2anki/Main.cpp

+ 15 - 86
include/anki/resource/Skeleton.h

@@ -3,24 +3,13 @@
 
 #include "anki/Math.h"
 #include "anki/util/Vector.h"
-#include <array>
-
 
 namespace anki {
 
-
 /// Skeleton bone
-///
-/// @note The rotation and translation that transform the bone from bone space
-/// to armature space. Meaning that if MA = TRS(rotSkelSpace, tslSkelSpace)
-/// then head = MA * Vec3(0.0, length, 0.0) and tail = MA * Vec3(0.0, 0.0, 0.0).
-/// We need the MA because the animation rotations and translations are in bone
-/// space. We also keep the inverted ones for fast calculations.
-/// rotSkelSpaceInv = MA.Inverted().getRotationPart() and NOT
-/// rotSkelSpaceInv = rotSkelSpace.getInverted()
 struct Bone
 {
-	friend class Skeleton; /// For loading
+	friend class Skeleton; ///< For loading
 
 public:
 	/// @name Accessors
@@ -30,100 +19,40 @@ public:
 		return name;
 	}
 
-	const Vec3& getHead() const
-	{
-		return head;
-	}
-
-	const Vec3& getTail() const
-	{
-		return tail;
-	}
-
-	uint getId() const
-	{
-		return id;
-	}
-
-	const Bone* getParent() const
-	{
-		return parent;
-	}
-
-	const Bone& getChild(uint i) const
-	{
-		return *childs[i];
-	}
-
-	size_t getChildsNum() const
-	{
-		return childsNum;
-	}
-
-	const Mat3& getRotationSkeletonSpace() const
-	{
-		return rotSkelSpace;
-	}
-
-	const Vec3& getTranslationSkeletonSpace() const
-	{
-		return tslSkelSpace;
-	}
-
-	const Mat3& getRotationSkeletonSpaceInverted() const
-	{
-		return rotSkelSpaceInv;
-	}
-
-	const Vec3& getTranslationSkeletonSpaceInverted() const
+	const Mat4& getTransform() const
 	{
-		return tslSkelSpaceInv;
+		return transform;
 	}
 	/// @}
 
 private:
 	std::string name; ///< The name of the bone
-	Vec3 head; ///< Starting point of the bone
-	Vec3 tail; ///< End point of the bone
-	uint id; ///< Pos inside the @ref Skeleton::bones vector
 	static const uint MAX_CHILDS_PER_BONE = 4; ///< Please dont change this
-	Bone* parent;
-	std::array<Bone*, MAX_CHILDS_PER_BONE> childs;
-	ushort childsNum;
 
 	// see the class notes
-	Mat3 rotSkelSpace;
-	Vec3 tslSkelSpace;
-	Mat3 rotSkelSpaceInv;
-	Vec3 tslSkelSpaceInv;
+	Mat4 transform;
 };
 
 
 /// It contains the bones with their position and hierarchy
 ///
-/// Binary file format:
+/// XML file format:
 ///
 /// @code
-/// magic: ANKISKEL
-/// uint: bones num
-/// n * bone: bones
-/// 
-/// bone:
-/// string: name
-/// 3 * floats: head
-/// 3 * floats: tail
-/// 16 * floats: armature space matrix
-/// uint: parent id, if it has no parent then its 0xFFFFFFFF
-/// uint: children number
-/// n * child: children
-/// 
-/// child:
-/// uint: bone id
+/// <skeleton>
+/// 	<bones>
+/// 		<bone>
+/// 			<name>X</name>
+/// 			<transform></transform>
+/// 		<bone>
+///         ...
+/// 	</bones>
+/// </skeleton>
 /// @endcode
 class Skeleton
 {
 public:
-	/// Implements Resource::load
+	/// Load file
 	void load(const char* filename);
 
 	/// @name Accessors

+ 1 - 1
src/core/App.cpp

@@ -15,7 +15,7 @@ namespace anki {
 
 //==============================================================================
 /// Segfault signal handler
-void handler(int sig)
+static void handler(int sig)
 {
 	void *array[10];
 	size_t size;

+ 40 - 96
src/resource/Skeleton.cpp

@@ -1,116 +1,60 @@
-#include <cstring>
-#include <fstream>
 #include "anki/resource/Skeleton.h"
-#include "anki/util/BinaryStream.h"
-
+#include "anki/misc/Xml.h"
+#include "anki/util/StringList.h"
 
 namespace anki {
 
-
-//==============================================================================
-// load                                                                        =
 //==============================================================================
 void Skeleton::load(const char* filename)
 {
-	std::ifstream fs;
-	fs.open(filename);
-	if(!fs.is_open())
-	{
-		throw ANKI_EXCEPTION("Cannot open \"" + filename + "\"");
-	}
-
-	try
-	{
-		BinaryStream bs(fs.rdbuf());
-
-		// Magic word
-		char magic[8];
-		bs.read(magic, 8);
-		if(bs.fail() || memcmp(magic, "ANKISKEL", 8))
-		{
-			throw ANKI_EXCEPTION("Incorrect magic word");
-		}
-
-		// Bones num
-		uint bonesNum = bs.readUint();
-		bones.resize(bonesNum);
-
-		// For all bones
-		for(uint i=0; i<bones.size(); i++)
-		{
-			Bone& bone = bones[i];
-			bone.id = i;
-
-			bone.name = bs.readString();
-
-			for(uint j=0; j<3; j++)
-			{
-				bone.head[j] = bs.readFloat();
-			}
+	XmlDocument doc;
+	doc.loadFile(filename);
 
-			for(uint j=0; j<3; j++)
-			{
-				bone.tail[j] = bs.readFloat();
-			}
+	XmlElement rootEl = doc.getChildElement("skeleton");
+	XmlElement bonesEl = rootEl.getChildElement("bones");
 
-			// Matrix
-			Mat4 m4;
-			for(uint j=0; j<16; j++)
-			{
-				m4[j] = bs.readFloat();
-			}
+	// count the bones count
+	U bonesCount = 0;
 
-			// Matrix for real
-			bone.rotSkelSpace = m4.getRotationPart();
-			bone.tslSkelSpace = m4.getTranslationPart();
-			Mat4 MAi(m4.getInverse());
-			bone.rotSkelSpaceInv = MAi.getRotationPart();
-			bone.tslSkelSpaceInv = MAi.getTranslationPart();
+	XmlElement boneEl = bonesEl.getChildElement("bone");
 
-			// Parent
-			uint parentId = bs.readUint();
-			if(parentId == 0xFFFFFFFF)
-			{
-				bone.parent = NULL;
-			}
-			else if(parentId >= bonesNum)
-			{
-				throw ANKI_EXCEPTION("Incorrect parent id");
-			}
-			else
-			{
-				bone.parent = &bones[parentId];
-			}
+	do
+	{
+		++bonesCount;
+		boneEl = boneEl.getNextSiblingElement("bone");
+	} while(boneEl);
 
-			// Children
-			uint childsNum = bs.readUint();
+	// Alloc the vector
+	bones.resize(bonesCount);
 
-			if(childsNum > Bone::MAX_CHILDS_PER_BONE)
-			{
-				throw ANKI_EXCEPTION("Children for bone \"" + bone.getName() +
-					"\" exceed the max");
-			}
+	// Load every bone
+	boneEl = bonesEl.getChildElement("bone");
+	bonesCount = 0;
+	do
+	{
+		Bone& bone = bones[bonesCount++];
 
-			bone.childsNum = childsNum;
+		// <name>
+		XmlElement nameEl = boneEl.getChildElement("name");
+		bone.name = nameEl.getText();
 
-			for(uint j=0; j<bone.childsNum; j++)
-			{
-				uint id = bs.readUint();
+		// <transform>
+		XmlElement trfEl = boneEl.getChildElement("transform");
+		StringList list = StringList::splitString(trfEl.getText(), ' ');
 
-				if(id >= bonesNum)
-				{
-					throw ANKI_EXCEPTION("Incorrect child id");
-				}
+		if(list.size() != 16)
+		{
+			throw ANKI_EXCEPTION("Expecting 16 floats for <transform>");
+		}
 
-				bone.childs[j] = &bones[id];
-			}
+		for(U i = 0; i < 16; i++)
+		{
+			bone.transform[i] = std::stof(list[i]);
 		}
-	}
-	catch(std::exception& e)
-	{
-		throw ANKI_EXCEPTION("Skeleton \"" + filename + "\"") << e;
-	}
-}
 
+		// Advance 
+		boneEl = boneEl.getNextSiblingElement("bone");
+	} while(boneEl);
+}
 
-} // end namespace
+} // end namespace anki

+ 6 - 0
src/scene/SkinNode.cpp

@@ -229,6 +229,7 @@ void SkinNode::frameUpdate(float prevUpdateTime, float crntTime, int f)
 void SkinNode::interpolate(const SkelAnim& animation, float frame,
 	SceneVector<Vec3>& boneTranslations, SceneVector<Mat3>& boneRotations)
 {
+#if 0
 	ANKI_ASSERT(frame < animation.getFramesNum());
 
 	// calculate the t (used in slerp and lerp) using the keyframs and the
@@ -288,12 +289,14 @@ void SkinNode::interpolate(const SkelAnim& animation, float frame,
 			localTransl = Vec3(0.0, 0.0, 0.0);
 		}
 	}
+#endif
 }
 
 //==============================================================================
 void SkinNode::updateBoneTransforms(const Skeleton& skeleton,
 	SceneVector<Vec3>& boneTranslations, SceneVector<Mat3>& boneRotations)
 {
+#if 0
 	std::array<uint, 128> queue;
 	uint head = 0, tail = 0;
 
@@ -346,6 +349,7 @@ void SkinNode::updateBoneTransforms(const Skeleton& skeleton,
 			queue[tail++] = boned.getChild(i).getId();
 		}
 	}
+#endif
 }
 
 //==============================================================================
@@ -354,6 +358,7 @@ void SkinNode::deformHeadsTails(const Skeleton& skeleton,
     const SceneVector<Mat3>& boneRotations,
 	SceneVector<Vec3>& heads, SceneVector<Vec3>& tails)
 {
+#if 0
 	for(uint i = 0; i < skeleton.getBones().size(); i++)
 	{
 		const Mat3& rot = boneRotations[i];
@@ -362,6 +367,7 @@ void SkinNode::deformHeadsTails(const Skeleton& skeleton,
 		heads[i] = skeleton.getBones()[i].getHead().getTransformed(transl, rot);
 		tails[i] = skeleton.getBones()[i].getTail().getTransformed(transl, rot);
 	}
+#endif
 }
 
 } // end namespace

+ 92 - 3
tools/2anki/Main.cpp

@@ -63,9 +63,9 @@ void parseConfig(int argc, char** argv, Config& config)
 {
 	static const char* usage = R"(Usage: 2anki in_file out_dir [options]
 Options:
--texpath <string>: Append a string to the paths of textures
--rpath <string>:   Append a string to the meshes and materials
--flipyz:           Flip y with z
+-texpath <string> : Append a string to the paths of textures
+-rpath <string>   : Append a string to the meshes and materials
+-flipyz           : Flip y with z (For blender exports)
 )";
 
 	// Parse config
@@ -308,6 +308,8 @@ void exportSkeleton(const aiMesh& mesh, const Config& config)
 	file << "<skeleton>\n";
 	file << "\t<bones>\n";
 
+	bool rootBoneFound = false;
+
 	for(uint32_t i = 0; i < mesh.mNumBones; i++)
 	{
 		const aiBone& bone = *mesh.mBones[i];
@@ -317,6 +319,11 @@ void exportSkeleton(const aiMesh& mesh, const Config& config)
 		// <name>
 		file << "\t\t\t<name>" << bone.mName.C_Str() << "</name>\n";
 
+		if(strcmp(bone.mName.C_Str(), "root") == 0)
+		{
+			rootBoneFound = true;
+		}
+
 		// <transform>
 		file << "\t\t\t<transform>";
 		for(uint32_t j = 0; j < 16; j++)
@@ -328,6 +335,11 @@ void exportSkeleton(const aiMesh& mesh, const Config& config)
 		file << "\t\t</bone>\n";
 	}
 
+	if(!rootBoneFound)
+	{
+		ERROR("There should be one bone named \"root\"\n");
+	}
+
 	file << "\t</bones>\n";
 	file << "</skeleton>\n";
 }
@@ -522,6 +534,77 @@ void exportModel(const aiScene& scene, const aiNode& node, const Config& config)
 	file << "</model>\n";
 }
 
+//==============================================================================
+void exportAnimation(const aiAnimation& anim, uint32_t index, 
+	const aiScene& scene, const Config& config)
+{
+	// Get name
+	std::string name = anim.mName.C_Str();
+	if(name.size() == 0)
+	{
+		name = std::string("animation_") + std::to_string(index);
+	}
+
+	// Find if it's skeleton animation
+	/*bool isSkeletalAnimation = false;
+	for(uint32_t i = 0; i < scene.mNumMeshes; i++)
+	{
+		const aiMesh& mesh = *scene.mMeshes[i];
+		if(mesh.HasBones())
+		{
+
+		}
+	}*/
+
+	std::fstream file;
+	LOGI("Exporting animation %s\n", name.c_str());
+
+	file.open(config.outDir + name + ".anim", std::ios::out);
+
+	file << xmlHeader << "\n";
+	file << "<animation>\n";
+
+	file << "\t<duration>" << anim.mDuration << "</duration>\n";
+
+	file << "\t<channels>\n";
+
+	for(uint32_t i = 0; i < anim.mNumChannels; i++)
+	{
+		const aiNodeAnim& nAnim = *anim.mChannels[i];
+
+		file << "\t\t<channel>\n";
+		
+		// Name
+		file << "\t\t\t<name>" << nAnim.mNodeName.C_Str() << "</name>\n";
+
+		// Positions
+		file << "\t\t\t<positionKeys>";
+		for(uint32_t j = 0; j < nAnim.mNumPositionKeys; j++)
+		{
+			const aiVectorKey& key = nAnim.mPositionKeys[j];
+			file << key.mTime << " " << key.mValue[0] << " " 
+				<< key.mValue[1] << " " << key.mValue[2] << " ";
+		}
+		file << "</positionKeys>\n";
+
+		// Rotations
+		file << "\t\t\t<rotationKeys>";
+		for(uint32_t j = 0; j < nAnim.mNumRotationKeys; j++)
+		{
+			const aiQuatKey& key = nAnim.mRotationKeys[j];
+			file << key.mTime << " " << key.mValue.x << " " 
+				<< key.mValue.y << " " << key.mValue.z << " "
+				<< key.mValue.w << " ";
+		}
+		file << "</rotationKeys>\n";
+
+		file << "\t\t</channel>\n";
+	}
+
+	file << "\t</channels>\n";
+	file << "</animation>\n";
+}
+
 //==============================================================================
 void exportNode(const aiScene& scene, const aiNode* node, const Config& config)
 {
@@ -565,6 +648,12 @@ void exportScene(const aiScene& scene, const Config& config)
 	// The nodes
 	exportNode(scene, scene.mRootNode, config);
 
+	// The animations
+	for(uint32_t i = 0; i < scene.mNumAnimations; i++)
+	{
+		exportAnimation(*scene.mAnimations[i], i, scene, config);	
+	}
+
 	LOGI("Done exporting scene!\n");
 }