OpenClonk
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros
StdMeshUpdate.cpp
Go to the documentation of this file.
1 /*
2  * OpenClonk, http://www.openclonk.org
3  *
4  * Copyright (c) 2009-2016, The OpenClonk Team and contributors
5  *
6  * Distributed under the terms of the ISC license; see accompanying file
7  * "COPYING" for details.
8  *
9  * "Clonk" is a registered trademark of Matthes Bender, used with permission.
10  * See accompanying file "TRADEMARK" for details.
11  *
12  * To redistribute this file separately, substitute the full license texts
13  * for the above references.
14  */
15 
16 #include "C4Include.h"
17 #include "lib/StdMesh.h"
18 #include "lib/StdMeshMaterial.h"
19 #include "lib/StdMeshUpdate.h"
20 #include "lib/StdMeshLoader.h"
21 
23  MaterialManager(manager)
24 {
25 }
26 
28 {
29  for(std::vector<StdSubMesh>::iterator iter = mesh->SubMeshes.begin(); iter != mesh->SubMeshes.end(); ++iter)
30  {
31  std::map<const StdMeshMaterial*, StdMeshMaterial>::const_iterator mat_iter = Materials.find(iter->Material);
32  if(mat_iter != Materials.end())
33  {
34  const StdMeshMaterial* new_material = MaterialManager.GetMaterial(mat_iter->second.Name.getData());
35 
36  if(new_material)
37  {
38  iter->Material = new_material;
39  }
40  else
41  {
42  // If no replacement material is available, then re-insert the previous
43  // material into the material map. This is mainly just to keep things
44  // going - next time the scenario will be started the mesh will fail
45  // to load because the material cannot be found.
46  MaterialManager.Materials[mat_iter->second.Name] = mat_iter->second; // TODO: could be moved
47  iter->Material = MaterialManager.GetMaterial(mat_iter->second.Name.getData());
48  }
49  }
50  }
51 }
52 
54 {
55  for(unsigned int i = 0; i < instance->SubMeshInstances.size(); ++i)
56  {
57  StdSubMeshInstance* sub_instance = instance->SubMeshInstances[i];
58  std::map<const StdMeshMaterial*, StdMeshMaterial>::const_iterator mat_iter = Materials.find(sub_instance->Material);
59  if(mat_iter != Materials.end())
60  {
61  // Material needs to be updated
62  const StdMeshMaterial* new_material = MaterialManager.GetMaterial(mat_iter->second.Name.getData());
63  // If new material is not available, fall back to StdMesh (definition) material
64  if(!new_material) new_material = instance->GetMesh().GetSubMesh(i).Material;
65  sub_instance->SetMaterial(*new_material);
66  }
67  }
68 }
69 
71 {
72  // Reset all materials in manager
73  for(std::map<const StdMeshMaterial*, StdMeshMaterial>::const_iterator iter = Materials.begin(); iter != Materials.end(); ++iter)
74  MaterialManager.Materials[iter->second.Name] = iter->second; // TODO: could be moved
75 }
76 
77 void StdMeshMaterialUpdate::Add(const StdMeshMaterial* material)
78 {
79  assert(Materials.find(material) == Materials.end());
80  Materials[material] = *material; // TODO: could be moved
81 }
82 
84  OldMesh(&old_mesh), BoneNamesByIndex(OldMesh->GetSkeleton().GetNumBones())
85 {
86  for (unsigned int i = 0; i < OldMesh->GetSkeleton().GetNumBones(); ++i)
87  BoneNamesByIndex[i] = OldMesh->GetSkeleton().GetBone(i).Name;
88 }
89 
90 void StdMeshUpdate::Update(StdMeshInstance* instance, const StdMesh& new_mesh) const
91 {
92  assert(&instance->GetMesh() == OldMesh);
93 
94  // Update instance to represent new mesh
95  instance->Mesh = &new_mesh;
96  instance->BoneTransforms = std::vector<StdMeshMatrix>(new_mesh.GetSkeleton().GetNumBones(), StdMeshMatrix::Identity());
97  instance->BoneTransformsDirty = true;
98 
99  for (unsigned int i = 0; i < instance->SubMeshInstances.size(); ++i)
100  delete instance->SubMeshInstances[i];
101  instance->SubMeshInstances.resize(new_mesh.GetNumSubMeshes());
102  for (unsigned int i = 0; i < instance->SubMeshInstances.size(); ++i)
103  {
104  instance->SubMeshInstances[i] = new StdSubMeshInstance(*instance, new_mesh.GetSubMesh(i), instance->GetCompletion());
105 
106  // Submeshes are reset to their default material,
107  // so the submesh order is unaltered
108  instance->SubMeshInstancesOrdered = instance->SubMeshInstances;
109 
110  // TODO: We might try to restore the previous mesh material here, using global material manager, maybe iff the number of submesh instances is unchanged.
111  }
112 
113  // Update child bone of attach parent. If the bone does not exist anymore
114  // in the updated mesh, then detach the mesh from its parent
115  if(instance->AttachParent)
116  {
117  if(!instance->AttachParent->SetChildBone(BoneNamesByIndex[instance->AttachParent->ChildBone]))
118  {
119  bool OwnChild = instance->AttachParent->OwnChild;
120  instance->AttachParent->Parent->DetachMesh(instance->AttachParent->Number);
121 
122  // If the attachment owned the child instance then detach procedure
123  // deleted the child instance. In that case we do not want to proceed
124  // with the mesh update procedure.
125  if(OwnChild) return;
126  }
127  }
128 
129  // Update parent bones of attach children. If a bone does not exist in the
130  // updated mesh then detach the mesh from its parent.
131  std::vector<unsigned int> Removal;
132  for(StdMeshInstance::AttachedMeshIter iter = instance->AttachedMeshesBegin(); iter != instance->AttachedMeshesEnd(); ++iter)
133  {
134  if(!(*iter)->SetParentBone(BoneNamesByIndex[(*iter)->ParentBone]))
135  {
136  // Do not detach the mesh right here so we can finish iterating over
137  // all attached meshes first.
138  Removal.push_back((*iter)->Number);
139  }
140  }
141 
142  for(unsigned int i = 0; i < Removal.size(); ++i)
143  instance->DetachMesh(Removal[i]);
144 
145  // Update custom nodes in the animation tree. Leaf nodes which refer to an animation that
146  // does not exist anymore are removed.
147  for (unsigned int i = instance->AnimationStack.size(); i > 0; --i)
148  if(!UpdateAnimationNode(instance, instance->AnimationStack[i-1]))
149  instance->StopAnimation(instance->AnimationStack[i-1]);
150 }
151 
152 bool StdMeshUpdate::UpdateAnimationNode(StdMeshInstance* instance, StdMeshInstance::AnimationNode* node) const
153 {
154  const StdMesh& new_mesh = *instance->Mesh;
155  switch (node->GetType())
156  {
158  // Animation pointer is updated by StdMeshAnimationUpdate
159  return true;
161  {
162  // Update bone index by bone name
163  StdCopyStrBuf bone_name = BoneNamesByIndex[node->Custom.BoneIndex];
164  const StdMeshBone* bone = new_mesh.GetSkeleton().GetBoneByName(bone_name);
165  if(!bone) return false;
166  node->Custom.BoneIndex = bone->Index;
167  return true;
168  }
170  {
171  const bool left_result = UpdateAnimationNode(instance, node->GetLeftChild());
172  const bool right_result = UpdateAnimationNode(instance, node->GetRightChild());
173 
174  // Remove this node completely
175  if (!left_result && !right_result)
176  return false;
177 
178  // Note that either of this also removes this node (and replaces by
179  // the other child in the tree).
180  if (!left_result)
181  instance->StopAnimation(node->GetLeftChild());
182  if (!right_result)
183  instance->StopAnimation(node->GetRightChild());
184 
185  return true;
186  }
187  default:
188  assert(false);
189  return false;
190  }
191 }
192 
194 {
195  // Store all animation names of all skeletons by pointer, we need those when
196  // updating the animation state of mesh instances after the update.
197  for(StdMeshSkeletonLoader::skeleton_iterator iter = skeleton_loader.skeletons_begin(); iter != skeleton_loader.skeletons_end(); ++iter)
198  {
199  const StdMeshSkeleton& skeleton = *iter->second;
200  for (std::map<StdCopyStrBuf, StdMeshAnimation>::const_iterator iter = skeleton.Animations.begin(); iter != skeleton.Animations.end(); ++iter)
201  {
202  AnimationNames[&iter->second] = iter->first;
203  }
204  }
205 }
206 
208 {
209  // Update the animation tree. Leaf nodes which refer to an animation that
210  // does not exist anymore are removed.
211  for (unsigned int i = instance->AnimationStack.size(); i > 0; --i)
212  if(!UpdateAnimationNode(instance, instance->AnimationStack[i-1]))
213  instance->StopAnimation(instance->AnimationStack[i-1]);
214 }
215 
216 bool StdMeshAnimationUpdate::UpdateAnimationNode(StdMeshInstance* instance, StdMeshInstance::AnimationNode* node) const
217 {
218  const StdMesh& new_mesh = *instance->Mesh;
219  switch (node->GetType())
220  {
222  {
223  // Find dead animation
224  std::map<const StdMeshAnimation*, StdCopyStrBuf>::const_iterator iter = AnimationNames.find(node->Leaf.Animation);
225 
226  // If this assertion fires, it typically means that UpdateAnimations() was called twice for the same mesh instance
227  assert(iter != AnimationNames.end());
228 
229  // Update to new animation
230  node->Leaf.Animation = new_mesh.GetSkeleton().GetAnimationByName(iter->second);
231  if(!node->Leaf.Animation) return false;
232 
233  // Clamp provider value
235  C4Real min = Fix0;
236  C4Real max = ftofix(node->GetAnimation()->Length);
237  provider->Value = Clamp(provider->Value, min, max);
238  return true;
239  }
241  // Nothing to do here; bone index is updated in StdMeshUpdate
242  return true;
244  {
245  const bool left_result = UpdateAnimationNode(instance, node->GetLeftChild());
246  const bool right_result = UpdateAnimationNode(instance, node->GetRightChild());
247 
248  // Remove this node completely
249  if (!left_result && !right_result)
250  return false;
251 
252  // Note that either of this also removes this node (and replaces by
253  // the other child in the tree).
254  if (!left_result)
255  instance->StopAnimation(node->GetLeftChild());
256  if (!right_result)
257  instance->StopAnimation(node->GetRightChild());
258 
259  return true;
260  }
261  default:
262  assert(false);
263  return false;
264  }
265 }
std::vector< StdSubMeshInstance * > SubMeshInstancesOrdered
Definition: StdMesh.h:658
AnimationNodeList AnimationStack
Definition: StdMesh.h:654
bool BoneTransformsDirty
Definition: StdMesh.h:665
const StdMeshMaterial * Material
Definition: StdMesh.h:284
NodeType GetType() const
Definition: StdMesh.h:349
SkeletonMap::const_iterator skeleton_iterator
Definition: StdMeshLoader.h:84
void Update(StdMesh *mesh) const
const StdMeshSkeleton & GetSkeleton() const
Definition: StdMesh.h:205
bool SetChildBone(const StdStrBuf &bone)
Definition: StdMesh.cpp:1014
size_t GetNumSubMeshes() const
Definition: StdMesh.h:201
Definition: C4Real.h:58
T Clamp(T bval, T lbound, T rbound)
Definition: Standard.h:46
StdMeshUpdate(const StdMesh &old_mesh)
AttachedMeshIter AttachedMeshesBegin() const
Definition: StdMesh.h:586
const StdMeshBone & GetBone(size_t i) const
Definition: StdMesh.h:118
StdMeshMaterialUpdate(StdMeshMatManager &manager)
void StopAnimation(AnimationNode *node)
Definition: StdMesh.cpp:1203
ValueProvider * GetPositionProvider()
Definition: StdMesh.h:353
AnimationNode * GetRightChild()
Definition: StdMesh.h:357
void Update(StdMeshInstance *instance, const StdMesh &new_mesh) const
StdMeshAnimationUpdate(const StdMeshSkeletonLoader &skeleton_loader)
skeleton_iterator skeletons_begin() const
Definition: StdMeshLoader.h:86
const StdMeshAnimation * GetAnimationByName(const StdStrBuf &name) const
Definition: StdMesh.cpp:398
const StdSubMesh & GetSubMesh(size_t i) const
Definition: StdMesh.h:200
const StdMesh * Mesh
Definition: StdMesh.h:649
C4Fixed ftofix(float x)
Definition: C4Real.h:258
AttachedMeshList::const_iterator AttachedMeshIter
Definition: StdMesh.h:546
bool DetachMesh(unsigned int number)
Definition: StdMesh.cpp:1408
const StdMeshBone * GetBoneByName(const StdStrBuf &name) const
Definition: StdMesh.cpp:388
float GetCompletion() const
Definition: StdMesh.h:556
void SetMaterial(const StdMeshMaterial &material)
Definition: StdMesh.cpp:706
StdCopyStrBuf Name
Definition: StdMesh.h:36
AttachedMesh * AttachParent
Definition: StdMesh.h:663
skeleton_iterator skeletons_end() const
Definition: StdMeshLoader.h:87
unsigned int Index
Definition: StdMesh.h:34
std::vector< StdMeshMatrix > BoneTransforms
Definition: StdMesh.h:655
const StdMeshAnimation * GetAnimation() const
Definition: StdMesh.h:352
AnimationNode * GetLeftChild()
Definition: StdMesh.h:356
const StdMeshMaterial * GetMaterial(const char *material_name) const
const StdMesh & GetMesh() const
Definition: StdMesh.h:624
size_t GetNumBones() const
Definition: StdMesh.h:119
StdMeshInstance * Parent
Definition: StdMesh.h:512
const C4Real Fix0
Definition: C4Real.h:312
std::vector< StdSubMeshInstance * > SubMeshInstances
Definition: StdMesh.h:657
AttachedMeshIter AttachedMeshesEnd() const
Definition: StdMesh.h:587
void Update(StdMeshInstance *instance) const