示例#1
0
void StdMeshUpdate::Update(StdMeshInstance* instance, const StdMesh& new_mesh) const
{
	assert(&instance->GetMesh() == OldMesh);

	// Update instance to represent new mesh
	instance->Mesh = &new_mesh;
	instance->BoneTransforms = std::vector<StdMeshMatrix>(new_mesh.GetSkeleton().GetNumBones(), StdMeshMatrix::Identity());
	instance->BoneTransformsDirty = true;

	for (unsigned int i = 0; i < instance->SubMeshInstances.size(); ++i)
		delete instance->SubMeshInstances[i];
	instance->SubMeshInstances.resize(new_mesh.GetNumSubMeshes());
	for (unsigned int i = 0; i < instance->SubMeshInstances.size(); ++i)
	{
		instance->SubMeshInstances[i] = new StdSubMeshInstance(*instance, new_mesh.GetSubMesh(i), instance->GetCompletion());

		// Submeshes are reset to their default material, so the submesh order is unaltered
		instance->SubMeshInstancesOrdered = instance->SubMeshInstances;

		// TODO: We might try to store the previous mesh material here
	}

	// Update child bone of attach parent. If the bone does not exist anymore
	// in the updated mesh, then detach the mesh from its parent
	if(instance->AttachParent)
	{
		if(!instance->AttachParent->SetChildBone(BoneNamesByIndex[instance->AttachParent->ChildBone]))
		{
			bool OwnChild = instance->AttachParent->OwnChild;
			instance->AttachParent->Parent->DetachMesh(instance->AttachParent->Number);
			
			// If the attachment owned the child instance then detach procedure
			// deleted the child instance. In that case we do not want to proceed
			// with the mesh update procedure.
			if(OwnChild) return;
		}
	}

	// Update parent bones of attach children. If a bone does not exist in the
	// updated mesh then detach the mesh from its parent.
	std::vector<unsigned int> Removal;
	for(StdMeshInstance::AttachedMeshIter iter = instance->AttachedMeshesBegin(); iter != instance->AttachedMeshesEnd(); ++iter)
	{
		if(!(*iter)->SetParentBone(BoneNamesByIndex[(*iter)->ParentBone]))
		{
			// Do not detach the mesh right here so we can finish iterating over
			// all attached meshes first.
			Removal.push_back((*iter)->Number);
		}
	}

	for(unsigned int i = 0; i < Removal.size(); ++i)
		instance->DetachMesh(Removal[i]);

	// Update the animation tree. Leaf nodes which refer to an animation that
	// does not exist anymore are removed.
	for (unsigned int i = instance->AnimationStack.size(); i > 0; --i)
		if(!UpdateAnimationNode(instance, new_mesh, instance->AnimationStack[i-1]))
			instance->StopAnimation(instance->AnimationStack[i-1]);
}
示例#2
0
bool StdMeshUpdate::UpdateAnimationNode(StdMeshInstance* instance, const StdMesh& new_mesh, StdMeshInstance::AnimationNode* node) const
{
	switch (node->GetType())
	{
	case StdMeshInstance::AnimationNode::LeafNode:
		{
			// Find dead animation
			std::map<const StdMeshAnimation*, StdCopyStrBuf>::const_iterator iter = AnimationNames.find(node->Leaf.Animation);
			assert(iter != AnimationNames.end());

			// Update to new animation
			node->Leaf.Animation = new_mesh.GetSkeleton().GetAnimationByName(iter->second);
			if(!node->Leaf.Animation) return false;

			// Clamp provider value
			StdMeshInstance::ValueProvider* provider = node->GetPositionProvider();
			C4Real min = Fix0;
			C4Real max = ftofix(node->GetAnimation()->Length);
			provider->Value = BoundBy(provider->Value, min, max);
			return true;
		}
	case StdMeshInstance::AnimationNode::CustomNode:
		{
			// Update bone index by bone name
			StdCopyStrBuf bone_name = BoneNamesByIndex[node->Custom.BoneIndex];
			const StdMeshBone* bone = new_mesh.GetSkeleton().GetBoneByName(bone_name);
			if(!bone) return false;
			node->Custom.BoneIndex = bone->Index;
			return true;
		}
	case StdMeshInstance::AnimationNode::LinearInterpolationNode:
		{
			const bool left_result = UpdateAnimationNode(instance, new_mesh, node->GetLeftChild());
			const bool right_result = UpdateAnimationNode(instance, new_mesh, node->GetRightChild());

			// Remove this node completely
			if (!left_result && !right_result)
				return false;

			// Note that either of this also removes this node (and replaces by
			// the other child in the tree).
			if (!left_result)
				instance->StopAnimation(node->GetLeftChild());
			if (!right_result)
				instance->StopAnimation(node->GetRightChild());

			return true;
		}
	default:
		assert(false);
		return false;
	}
}
示例#3
0
void StdMeshLoader::StdMeshXML::LoadBoneAssignments(StdMesh& mesh, std::vector<StdSubMesh::Vertex>& vertices, TiXmlElement* boneassignments_elem)
{
	for (TiXmlElement* vertexboneassignment_elem = boneassignments_elem->FirstChildElement("vertexboneassignment"); vertexboneassignment_elem != NULL; vertexboneassignment_elem = vertexboneassignment_elem->NextSiblingElement("vertexboneassignment"))
	{
		int BoneID = RequireIntAttribute(vertexboneassignment_elem, "boneindex");
		int VertexIndex = RequireIntAttribute(vertexboneassignment_elem, "vertexindex");
		float weight = RequireFloatAttribute(vertexboneassignment_elem, "weight");

		if (VertexIndex < 0 || static_cast<unsigned int>(VertexIndex) >= vertices.size())
			Error(FormatString("Vertex index in bone assignment (%d) is out of range", VertexIndex), vertexboneassignment_elem);

		// maybe not needed, see comment below
		const StdMeshBone* bone = NULL;
		for (unsigned int i = 0; !bone && i < mesh.GetSkeleton().GetNumBones(); ++i)
			if (mesh.GetSkeleton().GetBone(i).ID == BoneID)
				bone = &mesh.GetSkeleton().GetBone(i);

		if (!bone) Error(FormatString("There is no such bone with ID %d", BoneID), vertexboneassignment_elem);

		// Find first bone assignment with a zero weight (i.e. is unused)
		StdSubMesh::Vertex& vertex = vertices[VertexIndex];
		// Check quickly if all weight slots are used
		if (vertex.bone_weight[StdMeshVertex::MaxBoneWeightCount - 1] != 0)
		{
			Error(FormatString("Vertex %d is influenced by more than %d bones", VertexIndex, static_cast<int>(StdMeshVertex::MaxBoneWeightCount)), vertexboneassignment_elem);
		}
		for (size_t weight_index = 0; weight_index < StdMeshVertex::MaxBoneWeightCount; ++weight_index)
		{
			if (vertex.bone_weight[weight_index] == 0)
			{
				vertex.bone_weight[weight_index] = weight;
				vertex.bone_index[weight_index] = bone->Index;
				break;
			}
		}
	}

	// Normalize vertex bone assignment weights (this is not guaranteed in the
	// Ogre file format).
	for (unsigned int i = 0; i < vertices.size(); ++i)
	{
		StdSubMesh::Vertex& vertex = vertices[i];
		float sum = 0.0;
		for (float weight : vertex.bone_weight)
			sum += weight;
		if (sum != 0)
			for (float &weight : vertex.bone_weight)
				weight /= sum;
		else
			vertex.bone_weight[0] = 1.0f;
	}
}