Пример #1
0
Json::Value FileSaver::StoreFrame(KeyFrame* frame, const std::string& dir, 
								  bool single)
{
	Json::Value value;

	value["id"] = frame->GetID();

	value["time"] = frame->GetTime();

	value["tween"] = frame->HasClassicTween();
	value["lerp"] = libanim::FileSaver::StoreLerps(frame->GetLerps());

	for (size_t i = 0, n = frame->Size(); i < n; ++i)
		value["actor"][i] = StoreActor(frame->GetSprite(i), dir, single);

	value["skeleton"] = StoreSkeleton(frame->GetSkeletonData());

	return value;
}
Пример #2
0
void StdMeshSkeletonLoader::LoadSkeletonXml(const char* groupname, const char* filename, const char *sourcefile, size_t size)
{
	if (sourcefile == NULL)
	{
		throw Ogre::InsufficientData(FormatString("Failed to load '%s/%s'", groupname, filename).getData());
	}

	std::shared_ptr<StdMeshLoader::StdMeshXML> skeleton(new StdMeshLoader::StdMeshXML(filename, sourcefile));

	TiXmlElement* skeleton_elem = skeleton->RequireFirstChild(NULL, "skeleton");
	TiXmlElement* bones_elem = skeleton->RequireFirstChild(skeleton_elem, "bones");

	// Read bones. Don't insert into Master bone table yet, as the master bone
	// table is sorted hierarchically, and we will read the hierarchy only
	// afterwards.
	std::vector<StdMeshBone*> bones;
	for (TiXmlElement* bone_elem = bones_elem->FirstChildElement("bone"); bone_elem != NULL; bone_elem = bone_elem->NextSiblingElement("bone"))
	{
		StdMeshBone* bone = new StdMeshBone;
		bones.push_back(bone);

		bone->ID = skeleton->RequireIntAttribute(bone_elem, "id");
		bone->Name = skeleton->RequireStrAttribute(bone_elem, "name");
		// TODO: Make sure ID and name are unique

		bone->Parent = NULL;
		// Index of bone will be set when building Master Bone Table later

		TiXmlElement* position_elem = skeleton->RequireFirstChild(bone_elem, "position");
		TiXmlElement* rotation_elem = skeleton->RequireFirstChild(bone_elem, "rotation");
		TiXmlElement* axis_elem = skeleton->RequireFirstChild(rotation_elem, "axis");

		StdMeshVector d, r;
		d.x = skeleton->RequireFloatAttribute(position_elem, "x");
		d.y = skeleton->RequireFloatAttribute(position_elem, "y");
		d.z = skeleton->RequireFloatAttribute(position_elem, "z");
		float angle = skeleton->RequireFloatAttribute(rotation_elem, "angle");
		r.x = skeleton->RequireFloatAttribute(axis_elem, "x");
		r.y = skeleton->RequireFloatAttribute(axis_elem, "y");
		r.z = skeleton->RequireFloatAttribute(axis_elem, "z");

		bone->Transformation.scale = StdMeshVector::UnitScale();
		bone->Transformation.rotate = StdMeshQuaternion::AngleAxis(angle, r);
		bone->Transformation.translate = d;

		// We need this later for applying animations, and attaching meshes, therefore cache it here
		bone->InverseTransformation = StdMeshTransformation::Inverse(bone->Transformation);
	}

	// Bone hierarchy
	TiXmlElement* bonehierarchy_elem = skeleton->RequireFirstChild(skeleton_elem, "bonehierarchy");
	for (TiXmlElement* boneparent_elem = bonehierarchy_elem->FirstChildElement("boneparent"); boneparent_elem != NULL; boneparent_elem = boneparent_elem->NextSiblingElement("boneparent"))
	{
		const char* child_name = skeleton->RequireStrAttribute(boneparent_elem, "bone");
		const char* parent_name = skeleton->RequireStrAttribute(boneparent_elem, "parent");

		// Lookup the two bones
		StdMeshBone* child = NULL;
		StdMeshBone* parent = NULL;
		for (unsigned int i = 0; i < bones.size() && (!child || !parent); ++i)
		{
			if (!child && bones[i]->Name == child_name)
				child = bones[i];
			if (!parent && bones[i]->Name == parent_name)
				parent = bones[i];
		}

		if (!child) skeleton->Error(FormatString("There is no such bone with name '%s'", child_name), boneparent_elem);
		if (!parent) skeleton->Error(FormatString("There is no such bone with name '%s'", parent_name), boneparent_elem);

		child->Parent = parent;
		parent->Children.push_back(child);
	}

	std::shared_ptr<StdMeshSkeleton> Skeleton(new StdMeshSkeleton);

	// Fill master bone table in hierarchical order:
	for (unsigned int i = 0; i < bones.size(); ++i)
		if (bones[i]->Parent == NULL)
			Skeleton->AddMasterBone(bones[i]);

	// Load Animations
	TiXmlElement* animations_elem = skeleton_elem->FirstChildElement("animations");
	if (animations_elem)
	{
		for (TiXmlElement* animation_elem = animations_elem->FirstChildElement("animation"); animation_elem != NULL; animation_elem = animation_elem->NextSiblingElement("animation"))
		{
			StdCopyStrBuf name(skeleton->RequireStrAttribute(animation_elem, "name"));
			if (Skeleton->Animations.find(name) != Skeleton->Animations.end())
				skeleton->Error(FormatString("There is already an animation with name '%s'", name.getData()), animation_elem);

			StdMeshAnimation& animation = Skeleton->Animations.insert(std::make_pair(name, StdMeshAnimation())).first->second;
			animation.Name = name;
			animation.Length = skeleton->RequireFloatAttribute(animation_elem, "length");
			animation.Tracks.resize(Skeleton->GetNumBones());
			animation.OriginSkeleton = &(*Skeleton);

			TiXmlElement* tracks_elem = skeleton->RequireFirstChild(animation_elem, "tracks");
			for (TiXmlElement* track_elem = tracks_elem->FirstChildElement("track"); track_elem != NULL; track_elem = track_elem->NextSiblingElement("track"))
			{
				const char* bone_name = skeleton->RequireStrAttribute(track_elem, "bone");
				StdMeshBone* bone = NULL;
				for (unsigned int i = 0; !bone && i < Skeleton->GetNumBones(); ++i)
					if (Skeleton->Bones[i]->Name == bone_name)
						bone = Skeleton->Bones[i];
				if (!bone) skeleton->Error(FormatString("There is no such bone with name '%s'", bone_name), track_elem);

				if (animation.Tracks[bone->Index] != NULL) skeleton->Error(FormatString("There is already a track for bone '%s' in animation '%s'", bone_name, animation.Name.getData()), track_elem);

				StdMeshTrack* track = new StdMeshTrack;
				animation.Tracks[bone->Index] = track;

				TiXmlElement* keyframes_elem = skeleton->RequireFirstChild(track_elem, "keyframes");
				for (TiXmlElement* keyframe_elem = keyframes_elem->FirstChildElement("keyframe"); keyframe_elem != NULL; keyframe_elem = keyframe_elem->NextSiblingElement("keyframe"))
				{
					float time = skeleton->RequireFloatAttribute(keyframe_elem, "time");
					StdMeshKeyFrame& frame = track->Frames[time];

					TiXmlElement* translate_elem = keyframe_elem->FirstChildElement("translate");
					TiXmlElement* rotate_elem = keyframe_elem->FirstChildElement("rotate");
					TiXmlElement* scale_elem = keyframe_elem->FirstChildElement("scale");

					StdMeshVector d, s, r;
					d.x = d.y = d.z = 0.0f;
					s = StdMeshVector::UnitScale();
					r.x = r.y = 0.0f; r.z = 1.0f;
					float angle = 0.0f;

					if (translate_elem)
					{
						d.x = skeleton->RequireFloatAttribute(translate_elem, "x");
						d.y = skeleton->RequireFloatAttribute(translate_elem, "y");
						d.z = skeleton->RequireFloatAttribute(translate_elem, "z");
					}

					if (rotate_elem)
					{
						TiXmlElement* axis_elem = skeleton->RequireFirstChild(rotate_elem, "axis");
						angle = skeleton->RequireFloatAttribute(rotate_elem, "angle");
						r.x = skeleton->RequireFloatAttribute(axis_elem, "x");
						r.y = skeleton->RequireFloatAttribute(axis_elem, "y");
						r.z = skeleton->RequireFloatAttribute(axis_elem, "z");
					}

					if (scale_elem)
					{
						s.x = skeleton->RequireFloatAttribute(scale_elem, "x");
						s.y = skeleton->RequireFloatAttribute(scale_elem, "y");
						s.z = skeleton->RequireFloatAttribute(scale_elem, "z");
					}

					frame.Transformation.scale = s;
					frame.Transformation.rotate = StdMeshQuaternion::AngleAxis(angle, r);
					frame.Transformation.translate = bone->InverseTransformation.rotate * (bone->InverseTransformation.scale * d);
					frame.Transformation = OgreToClonk::TransformTransformation(frame.Transformation);
				}
			}
		}
	}

	// is there even any xml file that we load from?
	// it looks like this could never work: if the mesh has no skeleton, then the code below will fail because of a null pointer...

	// Apply parent transformation to each bone transformation. We need to
	// do this late since animation keyframe computation needs the bone
	// transformations, not bone+parent.
	for (unsigned int i = 0; i < Skeleton->GetNumBones(); ++i)
	{
		// Apply parent transformation
		if (Skeleton->Bones[i]->Parent)
			Skeleton->Bones[i]->Transformation = Skeleton->Bones[i]->Parent->Transformation * OgreToClonk::TransformTransformation(Skeleton->Bones[i]->Transformation);
		else
			Skeleton->Bones[i]->Transformation = OgreToClonk::TransformTransformation(Skeleton->Bones[i]->Transformation);

		// Update inverse
		Skeleton->Bones[i]->InverseTransformation = StdMeshTransformation::Inverse(Skeleton->Bones[i]->Transformation);
	}

	StoreSkeleton(groupname, filename, Skeleton);
}