OpenClonk
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/StdMeshUpdate.h"
18 
19 #include "lib/StdMesh.h"
20 #include "lib/StdMeshMaterial.h"
21 #include "lib/StdMeshLoader.h"
22 
24  MaterialManager(manager)
25 {
26 }
27 
29 {
30  for(auto & SubMesh : mesh->SubMeshes)
31  {
32  auto mat_iter = Materials.find(SubMesh.Material);
33  if(mat_iter != Materials.end())
34  {
35  const StdMeshMaterial* new_material = MaterialManager.GetMaterial(mat_iter->second.Name.getData());
36 
37  if(new_material)
38  {
39  SubMesh.Material = new_material;
40  }
41  else
42  {
43  // If no replacement material is available, then re-insert the previous
44  // material into the material map. This is mainly just to keep things
45  // going - next time the scenario will be started the mesh will fail
46  // to load because the material cannot be found.
47  MaterialManager.Materials[mat_iter->second.Name] = mat_iter->second; // TODO: could be moved
48  SubMesh.Material = MaterialManager.GetMaterial(mat_iter->second.Name.getData());
49  }
50  }
51  }
52 }
53 
55 {
56  for(unsigned int i = 0; i < instance->SubMeshInstances.size(); ++i)
57  {
58  StdSubMeshInstance* sub_instance = instance->SubMeshInstances[i];
59  std::map<const StdMeshMaterial*, StdMeshMaterial>::const_iterator mat_iter = Materials.find(sub_instance->Material);
60  if(mat_iter != Materials.end())
61  {
62  // Material needs to be updated
63  const StdMeshMaterial* new_material = MaterialManager.GetMaterial(mat_iter->second.Name.getData());
64  // If new material is not available, fall back to StdMesh (definition) material
65  if(!new_material) new_material = instance->GetMesh().GetSubMesh(i).Material;
66  sub_instance->SetMaterial(*new_material);
67  }
68  }
69 }
70 
72 {
73  // Reset all materials in manager
74  for(const auto & Material : Materials)
75  MaterialManager.Materials[Material.second.Name] = Material.second; // TODO: could be moved
76 }
77 
78 void StdMeshMaterialUpdate::Add(const StdMeshMaterial* material)
79 {
80  assert(Materials.find(material) == Materials.end());
81  Materials[material] = *material; // TODO: could be moved
82 }
83 
85  OldMesh(&old_mesh), BoneNamesByIndex(OldMesh->GetSkeleton().GetNumBones())
86 {
87  for (unsigned int i = 0; i < OldMesh->GetSkeleton().GetNumBones(); ++i)
88  BoneNamesByIndex[i] = OldMesh->GetSkeleton().GetBone(i).Name;
89 }
90 
91 void StdMeshUpdate::Update(StdMeshInstance* instance, const StdMesh& new_mesh) const
92 {
93  assert(&instance->GetMesh() == OldMesh);
94 
95  // Update instance to represent new mesh
96  instance->Mesh = &new_mesh;
97  instance->BoneTransforms = std::vector<StdMeshMatrix>(new_mesh.GetSkeleton().GetNumBones(), StdMeshMatrix::Identity());
98  instance->BoneTransformsDirty = true;
99 
100  for (auto & SubMeshInstance : instance->SubMeshInstances)
101  delete SubMeshInstance;
102  instance->SubMeshInstances.resize(new_mesh.GetNumSubMeshes());
103  for (unsigned int i = 0; i < instance->SubMeshInstances.size(); ++i)
104  {
105  instance->SubMeshInstances[i] = new StdSubMeshInstance(*instance, new_mesh.GetSubMesh(i), instance->GetCompletion());
106 
107  // Submeshes are reset to their default material,
108  // so the submesh order is unaltered
109  instance->SubMeshInstancesOrdered = instance->SubMeshInstances;
110 
111  // TODO: We might try to restore the previous mesh material here, using global material manager, maybe iff the number of submesh instances is unchanged.
112  }
113 
114  // Update child bone of attach parent. If the bone does not exist anymore
115  // in the updated mesh, then detach the mesh from its parent
116  if(instance->AttachParent)
117  {
118  if(!instance->AttachParent->SetChildBone(BoneNamesByIndex[instance->AttachParent->ChildBone]))
119  {
120  bool OwnChild = instance->AttachParent->OwnChild;
121  instance->AttachParent->Parent->DetachMesh(instance->AttachParent->Number);
122 
123  // If the attachment owned the child instance then detach procedure
124  // deleted the child instance. In that case we do not want to proceed
125  // with the mesh update procedure.
126  if(OwnChild) return;
127  }
128  }
129 
130  // Update parent bones of attach children. If a bone does not exist in the
131  // updated mesh then detach the mesh from its parent.
132  std::vector<unsigned int> Removal;
133  for(StdMeshInstance::AttachedMeshIter iter = instance->AttachedMeshesBegin(); iter != instance->AttachedMeshesEnd(); ++iter)
134  {
135  if(!(*iter)->SetParentBone(BoneNamesByIndex[(*iter)->ParentBone]))
136  {
137  // Do not detach the mesh right here so we can finish iterating over
138  // all attached meshes first.
139  Removal.push_back((*iter)->Number);
140  }
141  }
142 
143  for(unsigned int i : Removal)
144  instance->DetachMesh(i);
145 
146  // Update custom nodes in the animation tree. Leaf nodes which refer to an animation that
147  // does not exist anymore are removed.
148  for (unsigned int i = instance->AnimationStack.size(); i > 0; --i)
149  if(!UpdateAnimationNode(instance, instance->AnimationStack[i-1]))
150  instance->StopAnimation(instance->AnimationStack[i-1]);
151 }
152 
153 bool StdMeshUpdate::UpdateAnimationNode(StdMeshInstance* instance, StdMeshInstance::AnimationNode* node) const
154 {
155  const StdMesh& new_mesh = *instance->Mesh;
156  switch (node->GetType())
157  {
159  // Animation pointer is updated by StdMeshAnimationUpdate
160  return true;
162  {
163  // Update bone index by bone name
164  StdCopyStrBuf bone_name = BoneNamesByIndex[node->Custom.BoneIndex];
165  const StdMeshBone* bone = new_mesh.GetSkeleton().GetBoneByName(bone_name);
166  if(!bone) return false;
167  node->Custom.BoneIndex = bone->Index;
168  return true;
169  }
171  {
172  const bool left_result = UpdateAnimationNode(instance, node->GetLeftChild());
173  const bool right_result = UpdateAnimationNode(instance, node->GetRightChild());
174 
175  // Remove this node completely
176  if (!left_result && !right_result)
177  return false;
178 
179  // Note that either of this also removes this node (and replaces by
180  // the other child in the tree).
181  if (!left_result)
182  instance->StopAnimation(node->GetLeftChild());
183  if (!right_result)
184  instance->StopAnimation(node->GetRightChild());
185 
186  return true;
187  }
188  default:
189  assert(false);
190  return false;
191  }
192 }
193 
195 {
196  // Store all animation names of all skeletons by pointer, we need those when
197  // updating the animation state of mesh instances after the update.
198  for(StdMeshSkeletonLoader::skeleton_iterator iter = skeleton_loader.skeletons_begin(); iter != skeleton_loader.skeletons_end(); ++iter)
199  {
200  const StdMeshSkeleton& skeleton = *iter->second;
201  for (const auto & Animation : skeleton.Animations)
202  {
203  AnimationNames[&Animation.second] = Animation.first;
204  }
205  }
206 }
207 
209 {
210  // Update the animation tree. Leaf nodes which refer to an animation that
211  // does not exist anymore are removed.
212  for (unsigned int i = instance->AnimationStack.size(); i > 0; --i)
213  if(!UpdateAnimationNode(instance, instance->AnimationStack[i-1]))
214  instance->StopAnimation(instance->AnimationStack[i-1]);
215 }
216 
217 bool StdMeshAnimationUpdate::UpdateAnimationNode(StdMeshInstance* instance, StdMeshInstance::AnimationNode* node) const
218 {
219  const StdMesh& new_mesh = *instance->Mesh;
220  switch (node->GetType())
221  {
223  {
224  // Find dead animation
225  std::map<const StdMeshAnimation*, StdCopyStrBuf>::const_iterator iter = AnimationNames.find(node->Leaf.Animation);
226 
227  // If this assertion fires, it typically means that UpdateAnimations() was called twice for the same mesh instance
228  assert(iter != AnimationNames.end());
229 
230  // Update to new animation
231  node->Leaf.Animation = new_mesh.GetSkeleton().GetAnimationByName(iter->second);
232  if(!node->Leaf.Animation) return false;
233 
234  // Clamp provider value
236  C4Real min = Fix0;
237  C4Real max = ftofix(node->GetAnimation()->Length);
238  provider->Value = Clamp(provider->Value, min, max);
239  return true;
240  }
242  // Nothing to do here; bone index is updated in StdMeshUpdate
243  return true;
245  {
246  const bool left_result = UpdateAnimationNode(instance, node->GetLeftChild());
247  const bool right_result = UpdateAnimationNode(instance, node->GetRightChild());
248 
249  // Remove this node completely
250  if (!left_result && !right_result)
251  return false;
252 
253  // Note that either of this also removes this node (and replaces by
254  // the other child in the tree).
255  if (!left_result)
256  instance->StopAnimation(node->GetLeftChild());
257  if (!right_result)
258  instance->StopAnimation(node->GetRightChild());
259 
260  return true;
261  }
262  default:
263  assert(false);
264  return false;
265  }
266 }
C4Fixed ftofix(float x)
Definition: C4Real.h:258
const C4Real Fix0
Definition: C4Real.h:312
T Clamp(T bval, T lbound, T rbound)
Definition: Standard.h:44
Definition: C4Real.h:59
float Length
Definition: StdMesh.h:98
StdMeshAnimationUpdate(const StdMeshSkeletonLoader &skeleton_loader)
void Update(StdMeshInstance *instance) const
unsigned int Index
Definition: StdMesh.h:32
StdCopyStrBuf Name
Definition: StdMesh.h:34
const StdSubMesh & GetSubMesh(size_t i) const
Definition: StdMesh.h:198
size_t GetNumSubMeshes() const
Definition: StdMesh.h:199
const StdMeshSkeleton & GetSkeleton() const
Definition: StdMesh.h:203
bool SetChildBone(const StdStrBuf &bone)
Definition: StdMesh.cpp:1001
StdMeshInstance * Parent
Definition: StdMesh.h:510
NodeType GetType() const
Definition: StdMesh.h:347
AnimationNode * GetLeftChild()
Definition: StdMesh.h:354
ValueProvider * GetPositionProvider()
Definition: StdMesh.h:351
const StdMeshAnimation * GetAnimation() const
Definition: StdMesh.h:350
AnimationNode * GetRightChild()
Definition: StdMesh.h:355
float GetCompletion() const
Definition: StdMesh.h:554
std::vector< StdSubMeshInstance * > SubMeshInstances
Definition: StdMesh.h:655
std::vector< StdSubMeshInstance * > SubMeshInstancesOrdered
Definition: StdMesh.h:656
AnimationNodeList AnimationStack
Definition: StdMesh.h:652
bool DetachMesh(unsigned int number)
Definition: StdMesh.cpp:1395
AttachedMeshIter AttachedMeshesBegin() const
Definition: StdMesh.h:584
void StopAnimation(AnimationNode *node)
Definition: StdMesh.cpp:1190
const StdMesh & GetMesh() const
Definition: StdMesh.h:622
std::vector< StdMeshMatrix > BoneTransforms
Definition: StdMesh.h:653
AttachedMeshIter AttachedMeshesEnd() const
Definition: StdMesh.h:585
bool BoneTransformsDirty
Definition: StdMesh.h:663
AttachedMesh * AttachParent
Definition: StdMesh.h:661
AttachedMeshList::const_iterator AttachedMeshIter
Definition: StdMesh.h:544
const StdMesh * Mesh
Definition: StdMesh.h:647
const StdMeshMaterial * GetMaterial(const char *material_name) const
StdMeshMaterialUpdate(StdMeshMatManager &manager)
void Update(StdMesh *mesh) const
static StdMeshMatrix Identity()
const StdMeshBone * GetBoneByName(const StdStrBuf &name) const
Definition: StdMesh.cpp:388
const StdMeshBone & GetBone(size_t i) const
Definition: StdMesh.h:116
const StdMeshAnimation * GetAnimationByName(const StdStrBuf &name) const
Definition: StdMesh.cpp:398
size_t GetNumBones() const
Definition: StdMesh.h:117
skeleton_iterator skeletons_end() const
Definition: StdMeshLoader.h:86
skeleton_iterator skeletons_begin() const
Definition: StdMeshLoader.h:85
SkeletonMap::const_iterator skeleton_iterator
Definition: StdMeshLoader.h:83
void Update(StdMeshInstance *instance, const StdMesh &new_mesh) const
StdMeshUpdate(const StdMesh &old_mesh)
void SetMaterial(const StdMeshMaterial &material)
Definition: StdMesh.cpp:698
const StdMeshMaterial * Material
Definition: StdMesh.h:282