OpenClonk
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros
StdMesh.cpp
Go to the documentation of this file.
1 /*
2  * OpenClonk, http://www.openclonk.org
3  *
4  * Copyright (c) 2001-2009, RedWolf Design GmbH, http://www.clonk.de/
5  * Copyright (c) 2009-2016, The OpenClonk Team and contributors
6  *
7  * Distributed under the terms of the ISC license; see accompanying file
8  * "COPYING" for details.
9  *
10  * "Clonk" is a registered trademark of Matthes Bender, used with permission.
11  * See accompanying file "TRADEMARK" for details.
12  *
13  * To redistribute this file separately, substitute the full license texts
14  * for the above references.
15  */
16 
17 #include "C4Include.h"
19 #include "graphics/C4DrawGL.h"
20 #include "lib/StdMesh.h"
21 #include <algorithm>
22 
23 namespace
24 {
25  struct StdMeshFaceOrderHelper
26  {
27  float z;
28  unsigned int i;
29  };
30 }
31 
32 static int StdMeshFaceCmp(const StdMeshFaceOrderHelper& h1, const StdMeshFaceOrderHelper& h2)
33 {
34  if(h1.z < h2.z) return -1;
35  else if(h1.z > h2.z) return +1;
36  return 0;
37 }
38 
39 #define SORT_NAME StdMesh
40 #define SORT_TYPE StdMeshFaceOrderHelper
41 #define SORT_CMP StdMeshFaceCmp
42 #include "timsort/sort.h"
43 
44 std::vector<StdMeshInstance::SerializableValueProvider::IDBase*>* StdMeshInstance::SerializableValueProvider::IDs = nullptr;
45 
46 namespace
47 {
48  // Helper to sort submeshes so that opaque ones appear before non-opaque ones
49  struct StdMeshSubMeshVisibilityCmpPred
50  {
51  bool operator()(const StdSubMesh& first, const StdSubMesh& second)
52  {
53  return first.GetMaterial().IsOpaque() > second.GetMaterial().IsOpaque();
54  }
55  };
56 
57  // Helper to sort submesh instances so that opaque ones appear before non-opaque ones,
58  // this is required if materials are changed with SetMeshMaterial.
59  struct StdMeshSubMeshInstanceVisibilityCmpPred
60  {
61  bool operator()(const StdSubMeshInstance* first, const StdSubMeshInstance* second)
62  {
63  return first->GetMaterial().IsOpaque() > second->GetMaterial().IsOpaque();
64  }
65  };
66 
67  float StdMeshFaceOrderGetVertexZ(const StdMeshVertex& vtx, const StdMeshMatrix& trans)
68  {
69  // TODO: Need to apply attach matrix in case of attached meshes
70 
71  // We need to evaluate the Z coordinate of the transformed vertex
72  // (for all three vertices of the two faces), something like
73  // float z11 = (trans*m_vertices[face1.Vertices[0]]).z;
74  // However we don't do the full matrix multiplication as we are
75  // only interested in the Z coordinate of the result, also we are
76  // not interested in the resulting normals.
77  return trans(2,0)*vtx.x + trans(2,1)*vtx.y + trans(2,2)*vtx.z + trans(2,3);
78  }
79 
80  float StdMeshFaceOrderGetFaceZ(const StdMeshVertex* vertices, const StdMeshFace& face, const StdMeshMatrix& trans)
81  {
82  const float z1 = StdMeshFaceOrderGetVertexZ(vertices[face.Vertices[0]], trans);
83  const float z2 = StdMeshFaceOrderGetVertexZ(vertices[face.Vertices[1]], trans);
84  const float z3 = StdMeshFaceOrderGetVertexZ(vertices[face.Vertices[2]], trans);
85  return std::max(std::max(z1, z2), z3);
86  }
87 
88  void SortFacesArray(const StdMeshVertex* vertices, std::vector<StdMeshFace>& faces, StdSubMeshInstance::FaceOrdering face_ordering, const StdMeshMatrix& trans)
89  {
90  if(faces.empty()) return;
91 
92  std::vector<StdMeshFaceOrderHelper> helpers(faces.size());
93  for(unsigned int i = 0; i < faces.size(); ++i)
94  {
95  helpers[i].i = i;
96  helpers[i].z = StdMeshFaceOrderGetFaceZ(vertices, faces[i], trans);
97  }
98 
99  // The reason to use timsort here instead of std::sort is for performance
100  // reasons. This is performance critical code, with this function being
101  // called at least once per frame for each semi-transparent object. I have
102  // measured a factor 7 difference between the two sorting algorithms on my
103  // system.
104 
105  // We also pre-compute the Z values that we use for sorting, and sort the
106  // array of Z values, then use the resorted indices to sort the original
107  // faces array. The reason for this is twofold:
108  // 1. We don't need to compute the Z value every time the comparison function
109  // is called. Even though the computation is not very expensive, we have
110  // to do many comparisons, and small things add up. I have measured a
111  // 5-10% performance benefit.
112  // 2. More importantly, due to floating point rounding errors we cannot guarantee
113  // that Z values computed in the sorting function always yield the exact same
114  // number, and the same sorting result for the same faces. This can lead to
115  // a crash, because the f(a1, a2) = -f(a2, a1) property for the sorting function
116  // would no longer be met, resulting in undefined behaviour in the sort call.
117  // See http://bugs.openclonk.org/view.php?id=984.
118  StdMesh_tim_sort(&helpers[0], helpers.size());
119 
120  std::vector<StdMeshFace> new_faces(faces.size());
121  switch(face_ordering)
122  {
124  assert(false);
125  break;
127  for(unsigned int i = 0; i < faces.size(); ++i)
128  new_faces[i] = faces[helpers[i].i];
129  break;
131  for(unsigned int i = 0; i < faces.size(); ++i)
132  new_faces[i] = faces[helpers[faces.size() - i - 1].i];
133  break;
134  default:
135  assert(false);
136  break;
137  }
138 
139  faces.swap(new_faces);
140  }
141 
142  // Serialize a ValueProvider with StdCompiler
143  struct ValueProviderAdapt
144  {
145  ValueProviderAdapt(StdMeshInstance::ValueProvider** Provider):
146  ValueProvider(Provider) {}
147 
148  StdMeshInstance::ValueProvider** ValueProvider;
149 
150  void CompileFunc(StdCompiler* pComp)
151  {
154 
155  if(pComp->isDeserializer())
156  {
157  StdCopyStrBuf id_str;
158  pComp->Value(mkParAdapt(id_str, StdCompiler::RCT_Idtf));
159 
161  if(!id) pComp->excCorrupt("No value provider for ID \"%s\"", id_str.getData());
162  }
163  else
164  {
165  svp = dynamic_cast<StdMeshInstance::SerializableValueProvider*>(*ValueProvider);
166  if(!svp) pComp->excCorrupt("Value provider cannot be compiled");
168  if(!id) pComp->excCorrupt("No ID for value provider registered");
169 
170  StdCopyStrBuf id_str(id->name);
171  pComp->Value(mkParAdapt(id_str, StdCompiler::RCT_Idtf));
172  }
173 
175  pComp->Value(mkContextPtrAdapt(svp, *id, false));
177 
178  if(pComp->isDeserializer())
179  *ValueProvider = svp;
180  }
181  };
182 
183  ValueProviderAdapt mkValueProviderAdapt(StdMeshInstance::ValueProvider** ValueProvider) { return ValueProviderAdapt(ValueProvider); }
184 
185  void CompileFloat(StdCompiler* pComp, float& f)
186  {
187  // TODO: Teach StdCompiler how to handle float
188  if(pComp->isDeserializer())
189  {
190  C4Real r;
191  pComp->Value(r);
192  f = fixtof(r);
193  }
194  else
195  {
196  C4Real r = ftofix(f);
197  pComp->Value(r);
198  }
199  }
200 
201  // Serialize a transformation matrix by name with StdCompiler
202  struct MatrixAdapt
203  {
204  StdMeshMatrix& Matrix;
205  MatrixAdapt(StdMeshMatrix& matrix): Matrix(matrix) {}
206 
207  void CompileFunc(StdCompiler* pComp)
208  {
210  for(unsigned int i = 0; i < 3; ++i)
211  {
212  for(unsigned int j = 0; j < 4; ++j)
213  {
214  if(i != 0 || j != 0) pComp->Separator();
215  CompileFloat(pComp, Matrix(i, j));
216  }
217  }
218 
220  }
221  };
222 
223  struct TransformAdapt
224  {
225  StdMeshTransformation& Trans;
226  TransformAdapt(StdMeshTransformation& trans): Trans(trans) {}
227 
228  void CompileFunc(StdCompiler* pComp)
229  {
231  CompileFloat(pComp, Trans.translate.x);
232  CompileFloat(pComp, Trans.translate.y);
233  CompileFloat(pComp, Trans.translate.z);
234  CompileFloat(pComp, Trans.rotate.w);
235  CompileFloat(pComp, Trans.rotate.x);
236  CompileFloat(pComp, Trans.rotate.y);
237  CompileFloat(pComp, Trans.rotate.z);
238  CompileFloat(pComp, Trans.scale.x);
239  CompileFloat(pComp, Trans.scale.y);
240  CompileFloat(pComp, Trans.scale.z);
242  }
243  };
244 
245  MatrixAdapt mkMatrixAdapt(StdMeshMatrix& Matrix) { return MatrixAdapt(Matrix); }
246  TransformAdapt mkTransformAdapt(StdMeshTransformation& Trans) { return TransformAdapt(Trans); }
247 
248  // Reset all animation list entries corresponding to node or its children
249  void ClearAnimationListRecursively(std::vector<StdMeshInstance::AnimationNode*>& list, StdMeshInstance::AnimationNode* node)
250  {
251  list[node->GetNumber()] = nullptr;
252 
254  {
255  ClearAnimationListRecursively(list, node->GetLeftChild());
256  ClearAnimationListRecursively(list, node->GetRightChild());
257  }
258  }
259 
260  // Mirror is wrt Z axis
261  void MirrorKeyFrame(StdMeshKeyFrame& frame, const StdMeshTransformation& old_bone_transformation, const StdMeshTransformation& new_inverse_bone_transformation)
262  {
263  // frame was a keyframe of a track for old_bone and was now transplanted to new_bone.
264  frame.Transformation.rotate.x = -frame.Transformation.rotate.x;
265  frame.Transformation.rotate.y = -frame.Transformation.rotate.y;
266 
267  StdMeshVector d = old_bone_transformation.scale * (old_bone_transformation.rotate * frame.Transformation.translate);
268  d.z = -d.z;
269  frame.Transformation.translate = new_inverse_bone_transformation.rotate * (new_inverse_bone_transformation.scale * d);
270 
271  // TODO: scale
272  }
273 
274  bool MirrorName(StdStrBuf& buf)
275  {
276  unsigned int len = buf.getLength();
277 
278  if(buf.Compare_(".R", len-2) == 0)
279  buf.getMData()[len-1] = 'L';
280  else if(buf.Compare_(".L", len-2) == 0)
281  buf.getMData()[len-1] = 'R';
282  else
283  return false;
284 
285  return true;
286  }
287 }
288 
289 StdMeshTransformation StdMeshTrack::GetTransformAt(float time, float length) const
290 {
291  std::map<float, StdMeshKeyFrame>::const_iterator iter = Frames.lower_bound(time);
292 
293  // We are at or before the first keyframe. This short typically not
294  // happen, since all animations have a keyframe 0. Simply return the
295  // first keyframe.
296  if (iter == Frames.begin())
297  return iter->second.Transformation;
298 
299  std::map<float, StdMeshKeyFrame>::const_iterator prev_iter = iter;
300  --prev_iter;
301 
302  float iter_pos;
303  if (iter == Frames.end())
304  {
305  // We are beyond the last keyframe.
306  // Interpolate between the last and the first keyframe.
307  // See also bug #1406.
308  iter = Frames.begin();
309  iter_pos = length;
310  }
311  else
312  {
313  iter_pos = iter->first;
314  }
315 
316  // No two keyframes with the same position:
317  assert(iter_pos > prev_iter->first);
318 
319  // Requested position is between the two selected keyframes:
320  assert(time >= prev_iter->first);
321  assert(iter_pos >= time);
322 
323  float dt = iter_pos - prev_iter->first;
324  float weight1 = (time - prev_iter->first) / dt;
325  float weight2 = (iter_pos - time) / dt;
326  (void)weight2; // used in assertion only
327 
328  assert(weight1 >= 0 && weight2 >= 0 && weight1 <= 1 && weight2 <= 1);
329  assert(fabs(weight1 + weight2 - 1) < 1e-6);
330 
331  return StdMeshTransformation::Nlerp(prev_iter->second.Transformation, iter->second.Transformation, weight1);
332 }
333 
335  Name(other.Name), Length(other.Length), Tracks(other.Tracks.size())
336 {
337  // Note that all Tracks are already default-initialized to zero
338  for (unsigned int i = 0; i < Tracks.size(); ++i)
339  if (other.Tracks[i])
340  Tracks[i] = new StdMeshTrack(*other.Tracks[i]);
341 
342  OriginSkeleton = other.OriginSkeleton;
343 }
344 
346 {
347  for (unsigned int i = 0; i < Tracks.size(); ++i)
348  delete Tracks[i];
349 }
350 
352 {
353  if (this == &other) return *this;
354 
355  Name = other.Name;
356  Length = other.Length;
357 
358  for (unsigned int i = 0; i < Tracks.size(); ++i)
359  delete Tracks[i];
360 
361  Tracks.resize(other.Tracks.size());
362 
363  for (unsigned int i = 0; i < Tracks.size(); ++i)
364  if (other.Tracks[i])
365  Tracks[i] = new StdMeshTrack(*other.Tracks[i]);
366 
367  return *this;
368 }
369 
370 StdMeshSkeleton::StdMeshSkeleton()
371 {
372 }
373 
375 {
376  for (unsigned int i = 0; i < Bones.size(); ++i)
377  delete Bones[i];
378 }
379 
380 void StdMeshSkeleton::AddMasterBone(StdMeshBone *bone)
381 {
382  bone->Index = Bones.size(); // Remember index in master bone table
383  Bones.push_back(bone);
384  for (unsigned int i = 0; i < bone->Children.size(); ++i)
385  AddMasterBone(bone->Children[i]);
386 }
387 
389 {
390  // Lookup parent bone
391  for (unsigned int i = 0; i < Bones.size(); ++i)
392  if (Bones[i]->Name == name)
393  return Bones[i];
394 
395  return nullptr;
396 }
397 
399 {
400  StdCopyStrBuf name2(name);
401  std::map<StdCopyStrBuf, StdMeshAnimation>::const_iterator iter = Animations.find(name2);
402  if (iter == Animations.end()) return nullptr;
403  return &iter->second;
404 }
405 
406 std::vector<const StdMeshAnimation*> StdMeshSkeleton::GetAnimations() const
407 {
408  std::vector<const StdMeshAnimation*> result;
409  result.reserve(Animations.size());
410  for (std::map<StdCopyStrBuf, StdMeshAnimation>::const_iterator iter = Animations.begin(); iter != Animations.end(); ++iter)
411  result.push_back(&iter->second);
412  return result;
413 }
414 
416 {
417  StdCopyStrBuf name(animation.Name);
418 
419  // do nothing if the name cannot be switched from *.L to *.R or vice versa
420  // or if the animation already exists
421  if (!MirrorName(name) || Animations.find(name) != Animations.end())
422  {
423  return;
424  }
425 
426  StdMeshAnimation& new_anim = Animations.insert(std::make_pair(name, animation)).first->second;
427  new_anim.Name = name;
428 
429  // Go through all bones
430  for (unsigned int i = 0; i < GetNumBones(); ++i)
431  {
432  const StdMeshBone& bone = GetBone(i);
433  StdCopyStrBuf other_bone_name(bone.Name);
434  if (MirrorName(other_bone_name))
435  {
436  const StdMeshBone* other_bone = GetBoneByName(other_bone_name);
437  if (!other_bone)
438  throw std::runtime_error(std::string("No counterpart for bone ") + bone.Name.getData() + " found");
439 
440  // Make sure to not swap tracks twice
441  if ((animation.Tracks[i] != nullptr || animation.Tracks[other_bone->Index] != nullptr) &&
442  other_bone->Index > bone.Index)
443  {
444  std::swap(new_anim.Tracks[i], new_anim.Tracks[other_bone->Index]);
445 
446  StdMeshTransformation own_trans = bone.GetParent()->InverseTransformation * bone.Transformation;
447  StdMeshTransformation other_own_trans = other_bone->GetParent()->InverseTransformation * other_bone->Transformation;
448 
449  // Mirror all the keyframes of both tracks
450  if (new_anim.Tracks[i] != nullptr)
451  for (std::map<float, StdMeshKeyFrame>::iterator iter = new_anim.Tracks[i]->Frames.begin(); iter != new_anim.Tracks[i]->Frames.end(); ++iter)
452  MirrorKeyFrame(iter->second, own_trans, StdMeshTransformation::Inverse(other_own_trans));
453 
454  if (new_anim.Tracks[other_bone->Index] != nullptr)
455  for (std::map<float, StdMeshKeyFrame>::iterator iter = new_anim.Tracks[other_bone->Index]->Frames.begin(); iter != new_anim.Tracks[other_bone->Index]->Frames.end(); ++iter)
456  MirrorKeyFrame(iter->second, other_own_trans, StdMeshTransformation::Inverse(own_trans));
457  }
458  }
459  else if (bone.Name.Compare_(".N", bone.Name.getLength() - 2) != 0)
460  {
461  if (new_anim.Tracks[i] != nullptr)
462  {
463  StdMeshTransformation own_trans = bone.Transformation;
464  if (bone.GetParent()) own_trans = bone.GetParent()->InverseTransformation * bone.Transformation;
465 
466  for (std::map<float, StdMeshKeyFrame>::iterator iter = new_anim.Tracks[i]->Frames.begin(); iter != new_anim.Tracks[i]->Frames.end(); ++iter)
467  MirrorKeyFrame(iter->second, own_trans, StdMeshTransformation::Inverse(own_trans));
468  }
469  }
470  }
471 }
472 
474 {
475  assert(Animations.find(animation.Name) == Animations.end());
476 
477  Animations.insert(std::make_pair(animation.Name, animation));
478 }
479 
481 {
482  assert(Animations.find(animation.Name) == Animations.end());
483 
484  // get matching bones from the source
485  std::vector<int> bone_index_source = source.GetMatchingBones(*this);
486 
487  // create a new animation and copy the basic data from the other animation
488  StdMeshAnimation anim;
489  anim.Name = animation.Name;
490  anim.Length = animation.Length;
491  anim.Tracks.resize(GetNumBones());
492  anim.OriginSkeleton = &source;
493 
494  // sort the tracks according to the matched bones
495  for (unsigned int i = 0; i < anim.Tracks.size(); ++i)
496  {
497  if (bone_index_source[i] > -1 && animation.Tracks[bone_index_source[i]] != nullptr)
498  {
499  anim.Tracks[i] = new StdMeshTrack(*animation.Tracks[bone_index_source[i]]);
500  }
501  }
502 
503  // and add it to the map
504  Animations.insert(std::make_pair(animation.Name, anim));
505 }
506 
508 {
509  // Mirror .R and .L animations without counterpart
510  for (std::map<StdCopyStrBuf, StdMeshAnimation>::iterator iter = Animations.begin(); iter != Animations.end(); ++iter)
511  {
512  // For debugging purposes:
513  // if(iter->second.Name == "Jump")
514  // MirrorAnimation(StdCopyStrBuf("Jump.Mirror"), iter->second);
515 
516  // mirrors only if necessary
517  MirrorAnimation(iter->second);
518  }
519 }
520 
521 std::vector<int> StdMeshSkeleton::GetMatchingBones(const StdMeshSkeleton& child_skeleton) const
522 {
523  std::vector<int> MatchedBoneInParentSkeleton;
524 
525  // find matching bones names in both skeletons
526  for (unsigned int i = 0; i < child_skeleton.GetNumBones(); ++i)
527  {
528  int parent_bone_index = -1; // instantiate with invalid index == no match
529 
530  for (unsigned int j = 0; j < GetNumBones(); ++j)
531  {
532  // start searching at the same index
533  int sample_index = (i + j) % GetNumBones();
534 
535  if (GetBone(sample_index).Name == child_skeleton.GetBone(i).Name)
536  {
537  parent_bone_index = sample_index;
538  break;
539  }
540  }
541 
542  // add valid or invalid mapped index to list of mapped bones
543  MatchedBoneInParentSkeleton.push_back(parent_bone_index);
544  }
545 
546  return MatchedBoneInParentSkeleton;
547 }
548 
549 StdSubMesh::StdSubMesh() :
550  Material(nullptr), vertex_buffer_offset(0), index_buffer_offset(0)
551 {
552 }
553 
554 StdMesh::StdMesh() :
555  Skeleton(new StdMeshSkeleton)
556 #ifndef USE_CONSOLE
557  , vbo(0), ibo(0), vaoid(0)
558 #endif
559 {
560  BoundingBox.x1 = BoundingBox.y1 = BoundingBox.z1 = 0.0f;
561  BoundingBox.x2 = BoundingBox.y2 = BoundingBox.z2 = 0.0f;
562  BoundingRadius = 0.0f;
563 }
564 
566 {
567 #ifndef USE_CONSOLE
568  if (ibo)
569  glDeleteBuffers(1, &ibo);
570  if (vbo)
571  glDeleteBuffers(1, &vbo);
572  if (vaoid)
573  pGL->FreeVAOID(vaoid);
574 #endif
575 }
576 
578 {
579 #ifndef USE_CONSOLE
580  // Order submeshes so that opaque submeshes come before non-opaque ones
581  std::sort(SubMeshes.begin(), SubMeshes.end(), StdMeshSubMeshVisibilityCmpPred());
582  UpdateVBO();
583  UpdateIBO();
584 
585  // Allocate a VAO ID as well
586  assert(vaoid == 0);
587  vaoid = pGL->GenVAOID();
588 #endif
589 }
590 
591 #ifndef USE_CONSOLE
592 void StdMesh::UpdateVBO()
593 {
594  // We're only uploading vertices once, so there shouldn't be a VBO so far
595  assert(vbo == 0);
596  if (vbo != 0)
597  glDeleteBuffers(1, &vbo);
598  glGenBuffers(1, &vbo);
599 
600  // Calculate total number of vertices
601  size_t total_vertices = SharedVertices.size();
602  for (auto &submesh : SubMeshes)
603  {
604  total_vertices += submesh.GetNumVertices();
605  }
606 
607  glBindBuffer(GL_ARRAY_BUFFER, vbo);
608  pGL->ObjectLabel(GL_BUFFER, vbo, -1, (Label + "/VBO").c_str());
609 
610  // Unmapping the buffer may fail for certain reasons, in which case we need to try again.
611  do
612  {
613  // Allocate VBO backing memory. If this mesh's skeleton has no animations
614  // defined, we assume that the VBO will not change frequently.
615  glBufferData(GL_ARRAY_BUFFER, total_vertices * sizeof(StdMeshVertex), nullptr, GL_STATIC_DRAW);
616  void *map = glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY);
617  uint8_t *buffer = static_cast<uint8_t*>(map);
618  uint8_t *cursor = buffer;
619 
620  // Add shared vertices to buffer
621  if (!SharedVertices.empty())
622  {
623  size_t shared_vertices_size = SharedVertices.size() * sizeof(SharedVertices[0]);
624  std::memcpy(cursor, &SharedVertices[0], shared_vertices_size);
625  cursor += shared_vertices_size;
626  }
627 
628  // Add all submeshes to buffer
629  for (auto &submesh : SubMeshes)
630  {
631  // Store the offset, so the render code can use it later
632  submesh.vertex_buffer_offset = cursor - buffer;
633 
634  if (submesh.Vertices.empty()) continue;
635  size_t vertices_size = sizeof(submesh.Vertices[0]) * submesh.Vertices.size();
636  std::memcpy(cursor, &submesh.Vertices[0], vertices_size);
637  cursor += vertices_size;
638  }
639  } while (glUnmapBuffer(GL_ARRAY_BUFFER) == GL_FALSE);
640  // Unbind the buffer so following rendering calls do not use it
641  glBindBuffer(GL_ARRAY_BUFFER, 0);
642 }
643 
644 void StdMesh::UpdateIBO()
645 {
646  assert(ibo == 0);
647  if (ibo != 0)
648  glDeleteBuffers(1, &ibo);
649  glGenBuffers(1, &ibo);
650  glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);
651  pGL->ObjectLabel(GL_BUFFER, ibo, -1, (Label + "/IBO").c_str());
652 
653  size_t total_faces = 0;
654  for (auto &submesh : SubMeshes)
655  total_faces += submesh.GetNumFaces();
656  glBufferData(GL_ELEMENT_ARRAY_BUFFER, total_faces * 3 * sizeof(GLuint), nullptr, GL_STATIC_DRAW);
657  size_t offset = 0;
658  for (auto &submesh : SubMeshes)
659  {
660  submesh.index_buffer_offset = offset * 3 * sizeof(GLuint);
661  glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, submesh.index_buffer_offset, submesh.GetNumFaces() * 3 * sizeof(GLuint), &submesh.Faces[0]);
662  offset += submesh.GetNumFaces();
663  }
664  glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
665 }
666 #endif
667 
668 StdSubMeshInstance::StdSubMeshInstance(StdMeshInstance& instance, const StdSubMesh& submesh, float completion):
669  base(&submesh), Material(nullptr), CurrentFaceOrdering(FO_Fixed)
670 {
671 #ifndef USE_CONSOLE
672  LoadFacesForCompletion(instance, submesh, completion);
673 #endif
674 
675  SetMaterial(submesh.GetMaterial());
676 }
677 
678 void StdSubMeshInstance::LoadFacesForCompletion(StdMeshInstance& instance, const StdSubMesh& submesh, float completion)
679 {
680 #ifndef USE_CONSOLE
681  // First: Copy all faces
682  Faces.resize(submesh.GetNumFaces());
683  for (unsigned int i = 0; i < submesh.GetNumFaces(); ++i)
684  Faces[i] = submesh.GetFace(i);
685 
686  if(completion < 1.0f)
687  {
688  // Second: Order by Y position. StdMeshInstanceFaceOrderingCmpPred orders by Z position,
689  // however we can simply give an appropriate transformation matrix to the face ordering.
690  // At this point, all vertices are in the OGRE coordinate frame, and Z in OGRE equals
691  // Y in Clonk, so we are fine without additional transformation.
692  const StdMeshVertex* vertices;
693  if(submesh.GetNumVertices() > 0)
694  vertices = &submesh.GetVertices()[0];
695  else
696  vertices = &instance.GetSharedVertices()[0];
697  SortFacesArray(vertices, Faces, FO_FarthestToNearest, StdMeshMatrix::Identity());
698 
699  // Third: Only use the first few ones
700  assert(submesh.GetNumFaces() >= 1);
701  Faces.resize(Clamp<unsigned int>(static_cast<unsigned int>(completion * submesh.GetNumFaces() + 0.5), 1, submesh.GetNumFaces()));
702  }
703 #endif
704 }
705 
707 {
708  Material = &material;
709 
710 #ifndef USE_CONSOLE
711  // Setup initial texture animation data
712  assert(Material->BestTechniqueIndex >= 0);
714  PassData.resize(technique.Passes.size());
715  for (unsigned int i = 0; i < PassData.size(); ++i)
716  {
717  const StdMeshMaterialPass& pass = technique.Passes[i];
718  // Clear from previous material
719  PassData[i].TexUnits.clear();
720 
721  for (unsigned int j = 0; j < pass.TextureUnits.size(); ++j)
722  {
723  TexUnit unit;
724  unit.Phase = 0;
725  unit.PhaseDelay = 0.0f;
726  unit.Position = 0.0;
727  PassData[i].TexUnits.push_back(unit);
728  }
729  }
730 
731  // TODO: Reset face ordering
732 #endif
733 }
734 
736 {
737 #ifndef USE_CONSOLE
738  if (CurrentFaceOrdering != ordering)
739  {
740  CurrentFaceOrdering = ordering;
741  if (ordering == FO_Fixed)
742  {
743  LoadFacesForCompletion(instance, submesh, instance.GetCompletion());
744  }
745  }
746 #endif
747 }
748 
750 {
751 #ifndef USE_CONSOLE
752  bool opaque = Material->IsOpaque();
753 
754  if(!opaque)
755  SetFaceOrdering(instance, submesh, FO_FarthestToNearest);
756  else if( ((clrmod >> 24) & 0xff) != 0xff)
757  SetFaceOrdering(instance, submesh, FO_NearestToFarthest);
758  else
759  SetFaceOrdering(instance, submesh, FO_Fixed);
760 #endif
761 }
762 
764 {
765  // TODO: We should also serialize the texture animation positions
766  if(pComp->isDeserializer())
767  {
768  StdCopyStrBuf material_name;
769  pComp->Value(mkNamingAdapt(material_name, "Material"));
770  if(material_name != Material->Name)
771  {
772  const StdMeshMaterial* material = ::MeshMaterialManager.GetMaterial(material_name.getData());
773  if(!material)
774  {
775  StdStrBuf buf;
776  buf.Format("There is no such material with name \"%s\"", material_name.getData());
777  pComp->excCorrupt(buf.getData());
778  }
779 
780  SetMaterial(*material);
781  }
782  }
783  else
784  {
785  StdCopyStrBuf material_name = Material->Name;
786  pComp->Value(mkNamingAdapt(material_name, "Material"));
787  }
788 }
789 
791 {
792  pComp->Value(Value);
793 }
794 
796  Type(LeafNode), Parent(nullptr)
797 {
798  Leaf.Animation = nullptr;
799  Leaf.Position = nullptr;
800 }
801 
803  Type(LeafNode), Parent(nullptr)
804 {
805  Leaf.Animation = animation;
806  Leaf.Position = position;
807 }
808 
809 StdMeshInstanceAnimationNode::StdMeshInstanceAnimationNode(const StdMeshBone* bone, const StdMeshTransformation& trans):
810  Type(CustomNode), Parent(nullptr)
811 {
812  Custom.BoneIndex = bone->Index;
813  Custom.Transformation = new StdMeshTransformation(trans);
814 }
815 
817  Type(LinearInterpolationNode), Parent(nullptr)
818 {
819  LinearInterpolation.ChildLeft = child_left;
820  LinearInterpolation.ChildRight = child_right;
821  LinearInterpolation.Weight = weight;
822 }
823 
825 {
826  switch (Type)
827  {
828  case LeafNode:
829  delete Leaf.Position;
830  break;
831  case CustomNode:
832  delete Custom.Transformation;
833  break;
835  delete LinearInterpolation.ChildLeft;
836  delete LinearInterpolation.ChildRight;
837  delete LinearInterpolation.Weight;
838  break;
839  }
840 }
841 
842 bool StdMeshInstanceAnimationNode::GetBoneTransform(unsigned int bone, StdMeshTransformation& transformation)
843 {
844  StdMeshTransformation combine_with;
845  StdMeshTrack* track;
846 
847  switch (Type)
848  {
849  case LeafNode:
850  track = Leaf.Animation->Tracks[bone];
851  if (!track) return false;
852  transformation = track->GetTransformAt(fixtof(Leaf.Position->Value), Leaf.Animation->Length);
853  return true;
854  case CustomNode:
855  if(bone == Custom.BoneIndex)
856  transformation = *Custom.Transformation;
857  else
858  return false;
859  return true;
861  if (!LinearInterpolation.ChildLeft->GetBoneTransform(bone, transformation))
862  return LinearInterpolation.ChildRight->GetBoneTransform(bone, transformation);
863  if (!LinearInterpolation.ChildRight->GetBoneTransform(bone, combine_with))
864  return true; // First Child affects bone
865 
866  transformation = StdMeshTransformation::Nlerp(transformation, combine_with, fixtof(LinearInterpolation.Weight->Value));
867  return true;
868  default:
869  assert(false);
870  return false;
871  }
872 }
873 
875 {
876  static const StdEnumEntry<NodeType> NodeTypes[] =
877  {
878  { "Leaf", LeafNode },
879  { "Custom", CustomNode },
880  { "LinearInterpolation", LinearInterpolationNode },
881 
882  { nullptr, static_cast<NodeType>(0) }
883  };
884 
885  pComp->Value(mkNamingAdapt(Slot, "Slot"));
886  pComp->Value(mkNamingAdapt(Number, "Number"));
887  pComp->Value(mkNamingAdapt(mkEnumAdaptT<uint8_t>(Type, NodeTypes), "Type"));
888 
889  switch(Type)
890  {
891  case LeafNode:
892  if(pComp->isDeserializer())
893  {
894  StdCopyStrBuf anim_name;
895  pComp->Value(mkNamingAdapt(toC4CStrBuf(anim_name), "Animation"));
896  Leaf.Animation = Mesh->GetSkeleton().GetAnimationByName(anim_name);
897  if(!Leaf.Animation) pComp->excCorrupt("No such animation: \"%s\"", anim_name.getData());
898  }
899  else
900  {
901  pComp->Value(mkNamingAdapt(mkParAdapt(mkDecompileAdapt(Leaf.Animation->Name), StdCompiler::RCT_All), "Animation"));
902  }
903 
904  pComp->Value(mkNamingAdapt(mkValueProviderAdapt(&Leaf.Position), "Position"));
905  break;
906  case CustomNode:
907  if(pComp->isDeserializer())
908  {
909  StdCopyStrBuf bone_name;
910  pComp->Value(mkNamingAdapt(toC4CStrBuf(bone_name), "Bone"));
911  const StdMeshBone* bone = Mesh->GetSkeleton().GetBoneByName(bone_name);
912  if(!bone) pComp->excCorrupt("No such bone: \"%s\"", bone_name.getData());
913  Custom.BoneIndex = bone->Index;
914  Custom.Transformation = new StdMeshTransformation;
915  }
916  else
917  {
918  pComp->Value(mkNamingAdapt(mkParAdapt(mkDecompileAdapt(Mesh->GetSkeleton().GetBone(Custom.BoneIndex).Name), StdCompiler::RCT_All), "Bone"));
919  }
920 
921  pComp->Value(mkNamingAdapt(mkTransformAdapt(*Custom.Transformation), "Transformation"));
922  break;
924  pComp->Value(mkParAdapt(mkNamingPtrAdapt(LinearInterpolation.ChildLeft, "ChildLeft"), Mesh));
925  pComp->Value(mkParAdapt(mkNamingPtrAdapt(LinearInterpolation.ChildRight, "ChildRight"), Mesh));
926  pComp->Value(mkNamingAdapt(mkValueProviderAdapt(&LinearInterpolation.Weight), "Weight"));
927  if(pComp->isDeserializer())
928  {
929  if(LinearInterpolation.ChildLeft->Slot != Slot)
930  pComp->excCorrupt("Slot of left child does not match parent slot");
931  if(LinearInterpolation.ChildRight->Slot != Slot)
932  pComp->excCorrupt("Slof of right child does not match parent slot");
933  LinearInterpolation.ChildLeft->Parent = this;
934  LinearInterpolation.ChildRight->Parent = this;
935  }
936  break;
937  default:
938  pComp->excCorrupt("Invalid animation node type");
939  break;
940  }
941 }
942 
944 {
945  StdMeshInstance::SerializableValueProvider* value_provider = nullptr;
946  switch(Type)
947  {
948  case LeafNode:
949  value_provider = dynamic_cast<StdMeshInstance::SerializableValueProvider*>(Leaf.Position);
950  break;
951  case CustomNode:
952  value_provider = nullptr;
953  break;
955  value_provider = dynamic_cast<StdMeshInstance::SerializableValueProvider*>(LinearInterpolation.Weight);
956  // non-recursive, StdMeshInstance::DenumeratePointers walks over all nodes
957  break;
958  }
959 
960  if(value_provider) value_provider->DenumeratePointers();
961 }
962 
964 {
965  StdMeshInstance::SerializableValueProvider* value_provider = nullptr;
966  switch(Type)
967  {
968  case LeafNode:
969  value_provider = dynamic_cast<StdMeshInstance::SerializableValueProvider*>(Leaf.Position);
970  break;
971  case CustomNode:
972  value_provider = nullptr;
973  break;
975  value_provider = dynamic_cast<StdMeshInstance::SerializableValueProvider*>(LinearInterpolation.Weight);
976  // non-recursive, StdMeshInstance::ClearPointers walks over all nodes
977  break;
978  }
979 
980  if(value_provider) value_provider->ClearPointers(pObj);
981 }
982 
984  Number(0), Parent(nullptr), Child(nullptr), OwnChild(true), ChildDenumerator(nullptr), ParentBone(0), ChildBone(0), FinalTransformDirty(false)
985 {
986 }
987 
988 StdMeshInstance::AttachedMesh::AttachedMesh(unsigned int number, StdMeshInstance* parent, StdMeshInstance* child, bool own_child, Denumerator* denumerator,
989  unsigned int parent_bone, unsigned int child_bone, const StdMeshMatrix& transform, uint32_t flags):
990  Number(number), Parent(parent), Child(child), OwnChild(own_child), ChildDenumerator(denumerator),
991  ParentBone(parent_bone), ChildBone(child_bone), AttachTrans(transform), Flags(flags),
992  FinalTransformDirty(true)
993 {
994  MapBonesOfChildToParent(parent->GetMesh().GetSkeleton(), child->GetMesh().GetSkeleton());
995 }
996 
998 {
999  if (OwnChild)
1000  delete Child;
1001  delete ChildDenumerator;
1002 }
1003 
1005 {
1006  const StdMeshBone* bone_obj = Parent->GetMesh().GetSkeleton().GetBoneByName(bone);
1007  if (!bone_obj) return false;
1008  ParentBone = bone_obj->Index;
1009 
1010  FinalTransformDirty = true;
1011  return true;
1012 }
1013 
1015 {
1016  const StdMeshBone* bone_obj = Child->GetMesh().GetSkeleton().GetBoneByName(bone);
1017  if (!bone_obj) return false;
1018  ChildBone = bone_obj->Index;
1019 
1020  FinalTransformDirty = true;
1021  return true;
1022 }
1023 
1024 void StdMeshInstance::AttachedMesh::SetAttachTransformation(const StdMeshMatrix& transformation)
1025 {
1026  AttachTrans = transformation;
1027  FinalTransformDirty = true;
1028 }
1029 
1030 void StdMeshInstance::AttachedMesh::CompileFunc(StdCompiler* pComp, DenumeratorFactoryFunc Factory)
1031 {
1032  if(pComp->isDeserializer())
1033  {
1034  FinalTransformDirty = true;
1035  ChildDenumerator = Factory();
1036  }
1037 
1038  const StdBitfieldEntry<uint8_t> AM_Entries[] =
1039  {
1040  { "MatchSkeleton", AM_MatchSkeleton },
1041  { "DrawBefore", AM_DrawBefore },
1042  { nullptr, 0 }
1043  };
1044 
1045  pComp->Value(mkNamingAdapt(Number, "Number"));
1046  pComp->Value(mkNamingAdapt(ParentBone, "ParentBone")); // TODO: Save as string
1047  pComp->Value(mkNamingAdapt(ChildBone, "ChildBone")); // TODO: Save as string (note we can only resolve this in DenumeratePointers then!)
1048  pComp->Value(mkNamingAdapt(mkMatrixAdapt(AttachTrans), "AttachTransformation"));
1049 
1050  uint8_t dwSyncFlags = static_cast<uint8_t>(Flags);
1051  pComp->Value(mkNamingAdapt(mkBitfieldAdapt(dwSyncFlags, AM_Entries), "Flags", 0u));
1052  if(pComp->isDeserializer()) Flags = dwSyncFlags;
1053 
1054  pComp->Value(mkParAdapt(*ChildDenumerator, this));
1055 }
1056 
1058 {
1059  ChildDenumerator->DenumeratePointers(this);
1060 
1061  assert(Child != nullptr);
1062  Child->AttachParent = this;
1063 
1064  MapBonesOfChildToParent(Parent->GetMesh().GetSkeleton(), Child->GetMesh().GetSkeleton());
1065 
1066  if(OwnChild)
1067  Child->DenumeratePointers();
1068 }
1069 
1071 {
1072  return ChildDenumerator->ClearPointers(pObj);
1073 }
1074 
1075 void StdMeshInstance::AttachedMesh::MapBonesOfChildToParent(const StdMeshSkeleton& parent_skeleton, const StdMeshSkeleton& child_skeleton)
1076 {
1077  // not necessary if we do not match anyway.
1078  if (!(Flags & AM_MatchSkeleton)) return;
1079 
1080  // clear array to avoid filling it twice
1081  MatchedBoneInParentSkeleton.clear();
1082  MatchedBoneInParentSkeleton = parent_skeleton.GetMatchingBones(child_skeleton);
1083 }
1084 
1085 StdMeshInstance::StdMeshInstance(const StdMesh& mesh, float completion):
1086  Mesh(&mesh), Completion(completion),
1087  BoneTransforms(Mesh->GetSkeleton().GetNumBones(), StdMeshMatrix::Identity()),
1088  SubMeshInstances(Mesh->GetNumSubMeshes()), AttachParent(nullptr),
1089  BoneTransformsDirty(false)
1090 #ifndef USE_CONSOLE
1091  , ibo(0), vaoid(0)
1092 #endif
1093 {
1094  // Create submesh instances
1095  for (unsigned int i = 0; i < Mesh->GetNumSubMeshes(); ++i)
1096  {
1097  const StdSubMesh& submesh = Mesh->GetSubMesh(i);
1098  SubMeshInstances[i] = new StdSubMeshInstance(*this, submesh, completion);
1099  }
1100 
1101  // copy, order is fine at the moment since only default materials are used.
1103 }
1104 
1106 {
1107 #ifndef USE_CONSOLE
1108  if (ibo) glDeleteBuffers(1, &ibo);
1109  if (vaoid) pGL->FreeVAOID(vaoid);
1110 #endif
1111 
1112  // If we are attached then detach from parent
1113  if (AttachParent)
1115 
1116  // Remove all attach children
1117  while (!AttachChildren.empty())
1118  DetachMesh(AttachChildren.back()->Number);
1119 
1120  while (!AnimationStack.empty())
1121  StopAnimation(AnimationStack.front());
1122  assert(AnimationNodes.empty());
1123 
1124  // Delete submeshes
1125  for (unsigned int i = 0; i < SubMeshInstances.size(); ++i)
1126  {
1127  delete SubMeshInstances[i];
1128  }
1129 }
1130 
1132 {
1133 #ifndef USE_CONSOLE
1134  for (unsigned int i = 0; i < Mesh->GetNumSubMeshes(); ++i)
1135  SubMeshInstances[i]->SetFaceOrdering(*this, Mesh->GetSubMesh(i), ordering);
1136 
1137  // Faces have been reordered: upload new order to GPU
1138  UpdateIBO();
1139 
1140  // Update attachments (only own meshes for now... others might be displayed both attached and non-attached...)
1141  // still not optimal.
1142  for (AttachedMeshIter iter = AttachChildren.begin(); iter != AttachChildren.end(); ++iter)
1143  if ((*iter)->OwnChild)
1144  (*iter)->Child->SetFaceOrdering(ordering);
1145 #endif
1146 }
1147 
1149 {
1150 #ifndef USE_CONSOLE
1151  for (unsigned int i = 0; i < Mesh->GetNumSubMeshes(); ++i)
1152  SubMeshInstances[i]->SetFaceOrderingForClrModulation(*this, Mesh->GetSubMesh(i), clrmod);
1153 
1154  // Faces have been reordered: upload new order to GPU
1155  UpdateIBO();
1156 
1157  // Update attachments (only own meshes for now... others might be displayed both attached and non-attached...)
1158  // still not optimal.
1159  for (AttachedMeshIter iter = AttachChildren.begin(); iter != AttachChildren.end(); ++iter)
1160  if ((*iter)->OwnChild)
1161  (*iter)->Child->SetFaceOrderingForClrModulation(clrmod);
1162 #endif
1163 }
1164 
1165 void StdMeshInstance::SetCompletion(float completion)
1166 {
1167  Completion = completion;
1168 
1169 #ifndef USE_CONSOLE
1170  // TODO: Load all submesh faces and then determine the ones to use from the
1171  // full pool.
1172  for(unsigned int i = 0; i < Mesh->GetNumSubMeshes(); ++i)
1173  SubMeshInstances[i]->LoadFacesForCompletion(*this, Mesh->GetSubMesh(i), completion);
1174 
1175  // Faces have been reordered: upload new order to GPU
1176  UpdateIBO();
1177 #endif
1178 }
1179 
1180 StdMeshInstance::AnimationNode* StdMeshInstance::PlayAnimation(const StdStrBuf& animation_name, int slot, AnimationNode* sibling, ValueProvider* position, ValueProvider* weight, bool stop_previous_animation)
1181 {
1182  const StdMeshAnimation* animation = Mesh->GetSkeleton().GetAnimationByName(animation_name);
1183  if (!animation) { delete position; delete weight; return nullptr; }
1184 
1185  return PlayAnimation(*animation, slot, sibling, position, weight, stop_previous_animation);
1186 }
1187 
1188 StdMeshInstance::AnimationNode* StdMeshInstance::PlayAnimation(const StdMeshAnimation& animation, int slot, AnimationNode* sibling, ValueProvider* position, ValueProvider* weight, bool stop_previous_animation)
1189 {
1190  position->Value = Clamp(position->Value, Fix0, ftofix(animation.Length));
1191  AnimationNode* child = new AnimationNode(&animation, position);
1192  InsertAnimationNode(child, slot, sibling, weight, stop_previous_animation);
1193  return child;
1194 }
1195 
1196 StdMeshInstance::AnimationNode* StdMeshInstance::PlayAnimation(const StdMeshBone* bone, const StdMeshTransformation& trans, int slot, AnimationNode* sibling, ValueProvider* weight, bool stop_previous_animation)
1197 {
1198  AnimationNode* child = new AnimationNode(bone, trans);
1199  InsertAnimationNode(child, slot, sibling, weight, stop_previous_animation);
1200  return child;
1201 }
1202 
1204 {
1205  ClearAnimationListRecursively(AnimationNodes, node);
1206 
1207  AnimationNode* parent = node->Parent;
1208  if (parent == nullptr)
1209  {
1210  AnimationNodeList::iterator iter = GetStackIterForSlot(node->Slot, false);
1211  assert(iter != AnimationStack.end() && *iter == node);
1212  AnimationStack.erase(iter);
1213  delete node;
1214  }
1215  else
1216  {
1217  assert(parent->Type == AnimationNode::LinearInterpolationNode);
1218 
1219  // Remove parent interpolation node and re-link
1220  AnimationNode* other_child;
1221  if (parent->LinearInterpolation.ChildLeft == node)
1222  {
1223  other_child = parent->LinearInterpolation.ChildRight;
1224  parent->LinearInterpolation.ChildRight = nullptr;
1225  }
1226  else
1227  {
1228  other_child = parent->LinearInterpolation.ChildLeft;
1229  parent->LinearInterpolation.ChildLeft = nullptr;
1230  }
1231 
1232  if (parent->Parent)
1233  {
1235  if (parent->Parent->LinearInterpolation.ChildLeft == parent)
1236  parent->Parent->LinearInterpolation.ChildLeft = other_child;
1237  else
1238  parent->Parent->LinearInterpolation.ChildRight = other_child;
1239  other_child->Parent = parent->Parent;
1240  }
1241  else
1242  {
1243  AnimationNodeList::iterator iter = GetStackIterForSlot(node->Slot, false);
1244  assert(iter != AnimationStack.end() && *iter == parent);
1245  *iter = other_child;
1246 
1247  other_child->Parent = nullptr;
1248  }
1249 
1250  AnimationNodes[parent->Number] = nullptr;
1251  // Recursively deletes parent and its descendants
1252  delete parent;
1253  }
1254 
1255  while (!AnimationNodes.empty() && AnimationNodes.back() == nullptr)
1256  AnimationNodes.erase(AnimationNodes.end()-1);
1257  SetBoneTransformsDirty(true);
1258 }
1259 
1261 {
1262  if (number >= AnimationNodes.size()) return nullptr;
1263  return AnimationNodes[number];
1264 }
1265 
1267 {
1268  AnimationNodeList::iterator iter = GetStackIterForSlot(slot, false);
1269  if (iter == AnimationStack.end()) return nullptr;
1270  return *iter;
1271 }
1272 
1274 {
1275  assert(node->GetType() == AnimationNode::LeafNode);
1276  delete node->Leaf.Position;
1277  node->Leaf.Position = position;
1278 
1279  position->Value = Clamp(position->Value, Fix0, ftofix(node->Leaf.Animation->Length));
1280 
1281  SetBoneTransformsDirty(true);
1282 }
1283 
1284 void StdMeshInstance::SetAnimationBoneTransform(AnimationNode* node, const StdMeshTransformation& trans)
1285 {
1286  assert(node->GetType() == AnimationNode::CustomNode);
1287  *node->Custom.Transformation = trans;
1288  SetBoneTransformsDirty(true);
1289 }
1290 
1292 {
1294  delete node->LinearInterpolation.Weight; node->LinearInterpolation.Weight = weight;
1295 
1296  weight->Value = Clamp(weight->Value, Fix0, itofix(1));
1297 
1298  SetBoneTransformsDirty(true);
1299 }
1300 
1302 {
1303  // Iterate from the back since slots might be removed
1304  for (unsigned int i = AnimationStack.size(); i > 0; --i)
1307 
1308 #ifndef USE_CONSOLE
1309  // Update animated textures
1310  for (unsigned int i = 0; i < SubMeshInstances.size(); ++i)
1311  {
1312  StdSubMeshInstance& submesh = *SubMeshInstances[i];
1313  const StdMeshMaterial& material = submesh.GetMaterial();
1314  const StdMeshMaterialTechnique& technique = material.Techniques[material.BestTechniqueIndex];
1315  for (unsigned int j = 0; j < submesh.PassData.size(); ++j)
1316  {
1317  StdSubMeshInstance::Pass& pass = submesh.PassData[j];
1318  for (unsigned int k = 0; k < pass.TexUnits.size(); ++k)
1319  {
1320  const StdMeshMaterialTextureUnit& texunit = technique.Passes[j].TextureUnits[k];
1321  StdSubMeshInstance::TexUnit& texunit_instance = submesh.PassData[j].TexUnits[k];
1322  if (texunit.HasFrameAnimation())
1323  {
1324  const unsigned int NumPhases = texunit.GetNumTextures();
1325  const float PhaseDuration = texunit.Duration / NumPhases;
1326 
1327  const float Position = texunit_instance.PhaseDelay + dt;
1328  const unsigned int AddPhases = static_cast<unsigned int>(Position / PhaseDuration);
1329 
1330  texunit_instance.Phase = (texunit_instance.Phase + AddPhases) % NumPhases;
1331  texunit_instance.PhaseDelay = Position - AddPhases * PhaseDuration;
1332  }
1333 
1334  if (texunit.HasTexCoordAnimation())
1335  texunit_instance.Position += dt;
1336  }
1337  }
1338  }
1339 #endif
1340 
1341  // Update animation for attached meshes
1342  for (AttachedMeshList::iterator iter = AttachChildren.begin(); iter != AttachChildren.end(); ++iter)
1343  (*iter)->Child->ExecuteAnimation(dt);
1344 }
1345 
1346 StdMeshInstance::AttachedMesh* StdMeshInstance::AttachMesh(const StdMesh& mesh, AttachedMesh::Denumerator* denumerator, const StdStrBuf& parent_bone, const StdStrBuf& child_bone, const StdMeshMatrix& transformation, uint32_t flags, unsigned int attach_number)
1347 {
1348  std::unique_ptr<AttachedMesh::Denumerator> auto_denumerator(denumerator);
1349 
1350  StdMeshInstance* instance = new StdMeshInstance(mesh, 1.0f);
1351  AttachedMesh* attach = AttachMesh(*instance, auto_denumerator.release(), parent_bone, child_bone, transformation, flags, true, attach_number);
1352  if (!attach) { delete instance; return nullptr; }
1353  return attach;
1354 }
1355 
1356 StdMeshInstance::AttachedMesh* StdMeshInstance::AttachMesh(StdMeshInstance& instance, AttachedMesh::Denumerator* denumerator, const StdStrBuf& parent_bone, const StdStrBuf& child_bone, const StdMeshMatrix& transformation, uint32_t flags, bool own_child, unsigned int attach_number)
1357 {
1358  std::unique_ptr<AttachedMesh::Denumerator> auto_denumerator(denumerator);
1359 
1360  // Owned attach children must be set via the topmost instance, to ensure
1361  // attach number uniqueness.
1362  if (AttachParent && AttachParent->OwnChild) return nullptr;
1363 
1364  // Find free index.
1365  unsigned int number = 0;
1366  ScanAttachTree(AttachChildren.begin(), AttachChildren.end(), [&number](AttachedMeshList::const_iterator iter) { number = std::max(number, (*iter)->Number); return true; });
1367  number += 1; // One above highest
1368 
1369  StdMeshInstance* direct_parent = this;
1370  if (attach_number != 0)
1371  {
1372  AttachedMesh* attach = GetAttachedMeshByNumber(attach_number);
1373  if (attach == nullptr) return nullptr;
1374  direct_parent = attach->Child;
1375  }
1376 
1377  return direct_parent->AttachMeshImpl(instance, auto_denumerator.release(), parent_bone, child_bone, transformation, flags, own_child, number);
1378 }
1379 
1380 StdMeshInstance::AttachedMesh* StdMeshInstance::AttachMeshImpl(StdMeshInstance& instance, AttachedMesh::Denumerator* denumerator, const StdStrBuf& parent_bone, const StdStrBuf& child_bone, const StdMeshMatrix& transformation, uint32_t flags, bool own_child, unsigned int new_attach_number)
1381 {
1382  std::unique_ptr<AttachedMesh::Denumerator> auto_denumerator(denumerator);
1383 
1384  // We don't allow an instance to be attached to multiple parent instances for now
1385  if (instance.AttachParent) return nullptr;
1386 
1387  // Make sure there are no cyclic attachments
1388  for (StdMeshInstance* Parent = this; Parent->AttachParent != nullptr; Parent = Parent->AttachParent->Parent)
1389  if (Parent == &instance)
1390  return nullptr;
1391 
1392  const StdMeshBone* parent_bone_obj = Mesh->GetSkeleton().GetBoneByName(parent_bone);
1393  const StdMeshBone* child_bone_obj = instance.Mesh->GetSkeleton().GetBoneByName(child_bone);
1394  if (!parent_bone_obj || !child_bone_obj) return nullptr;
1395 
1396  AttachedMesh* attach = new AttachedMesh(new_attach_number, this, &instance, own_child, auto_denumerator.release(), parent_bone_obj->Index, child_bone_obj->Index, transformation, flags);
1397  instance.AttachParent = attach;
1398 
1399  // If DrawInFront is set then sort before others so that drawing order is easy
1400  if(flags & AM_DrawBefore)
1401  AttachChildren.insert(AttachChildren.begin(), attach);
1402  else
1403  AttachChildren.insert(AttachChildren.end(), attach);
1404 
1405  return attach;
1406 }
1407 
1408 bool StdMeshInstance::DetachMesh(unsigned int number)
1409 {
1410  return !ScanAttachTree(AttachChildren.begin(), AttachChildren.end(), [this, number](AttachedMeshList::iterator iter)
1411  {
1412  if ((*iter)->Number == number)
1413  {
1414  AttachedMesh* attached = *iter;
1415 
1416  // Reset attach parent of child so it does not try
1417  // to detach itself on destruction.
1418  attached->Child->AttachParent = nullptr;
1419  attached->Parent->AttachChildren.erase(iter);
1420 
1421  delete attached;
1422 
1423  // Finish scan
1424  return false;
1425  }
1426 
1427  // Continue scan
1428  return true;
1429  });
1430 }
1431 
1433 {
1434  StdMeshInstance::AttachedMesh* result = nullptr;
1435 
1436  ScanAttachTree(AttachChildren.begin(), AttachChildren.end(), [number, &result](AttachedMeshList::const_iterator iter)
1437  {
1438  if ((*iter)->Number == number)
1439  {
1440  result = *iter;
1441  return false;
1442  }
1443 
1444  return true;
1445  });
1446 
1447  return result;
1448 }
1449 
1450 void StdMeshInstance::SetMaterial(size_t i, const StdMeshMaterial& material)
1451 {
1452  assert(i < SubMeshInstances.size());
1453  SubMeshInstances[i]->SetMaterial(material);
1454 #ifndef USE_CONSOLE
1455  std::stable_sort(SubMeshInstancesOrdered.begin(), SubMeshInstancesOrdered.end(), StdMeshSubMeshInstanceVisibilityCmpPred());
1456 #endif
1457 }
1458 
1459 const StdMeshMatrix& StdMeshInstance::GetBoneTransform(size_t i) const
1460 {
1461  if ((AttachParent != nullptr) && (AttachParent->GetFlags() & AM_MatchSkeleton))
1462  {
1463  assert(i < AttachParent->MatchedBoneInParentSkeleton.size());
1464 
1465  int parent_bone_index = AttachParent->MatchedBoneInParentSkeleton[i];
1466 
1467  if (parent_bone_index > -1)
1468  {
1469  return AttachParent->Parent->BoneTransforms[i];
1470  }
1471  }
1472 
1473  return BoneTransforms[i];
1474 }
1475 
1477 {
1478  if ((AttachParent != nullptr) && (AttachParent->GetFlags() & AM_MatchSkeleton))
1479  return AttachParent->MatchedBoneInParentSkeleton.size();
1480  else
1481  return BoneTransforms.size();
1482 }
1483 
1485 {
1486  bool was_dirty = BoneTransformsDirty;
1487 
1488  // Nothing changed since last time
1489  if (BoneTransformsDirty)
1490  {
1491  // Compute transformation matrix for each bone.
1492  for (unsigned int i = 0; i < BoneTransforms.size(); ++i)
1493  {
1494  StdMeshTransformation Transformation;
1495 
1496  const StdMeshBone& bone = Mesh->GetSkeleton().GetBone(i);
1497  const StdMeshBone* parent = bone.GetParent();
1498  assert(!parent || parent->Index < i);
1499 
1500  bool have_transform = false;
1501  for (unsigned int j = 0; j < AnimationStack.size(); ++j)
1502  {
1503  if (have_transform)
1504  {
1505  StdMeshTransformation other;
1506  if (AnimationStack[j]->GetBoneTransform(i, other))
1507  Transformation = StdMeshTransformation::Nlerp(Transformation, other, 1.0f); // TODO: Allow custom weighing for slot combination
1508  }
1509  else
1510  {
1511  have_transform = AnimationStack[j]->GetBoneTransform(i, Transformation);
1512  }
1513  }
1514 
1515  if (!have_transform)
1516  {
1517  if (parent)
1518  BoneTransforms[i] = BoneTransforms[parent->Index];
1519  else
1520  BoneTransforms[i] = StdMeshMatrix::Identity();
1521  }
1522  else
1523  {
1524  BoneTransforms[i] = StdMeshMatrix::Transform(bone.Transformation * Transformation * bone.InverseTransformation);
1525  if (parent) BoneTransforms[i] = BoneTransforms[parent->Index] * BoneTransforms[i];
1526  }
1527  }
1528  }
1529 
1530  // Update attachment's attach transformations. Note this is done recursively.
1531  for (AttachedMeshList::iterator iter = AttachChildren.begin(); iter != AttachChildren.end(); ++iter)
1532  {
1533  AttachedMesh* attach = *iter;
1534  const bool ChildBoneTransformsDirty = attach->Child->BoneTransformsDirty;
1535  attach->Child->UpdateBoneTransforms();
1536 
1537  if (BoneTransformsDirty || ChildBoneTransformsDirty || attach->FinalTransformDirty)
1538  {
1539  was_dirty = true;
1540 
1541  // Compute matrix to change the coordinate system to the one of the attached bone:
1542  // The idea is that a vertex at the child bone's position transforms to the parent bone's position.
1543  // Therefore (read from right to left) we first apply the inverse of the child bone transformation,
1544  // then an optional scaling matrix, and finally the parent bone transformation
1545 
1546  // TODO: we can cache the three matrices in the middle since they don't change over time,
1547  // reducing this to two matrix multiplications instead of four each frame.
1548  // Might even be worth to compute the complete transformation directly when rendering then
1549  // (saves per-instance memory, but requires recomputation if the animation does not change).
1550  // TODO: We might also be able to cache child inverse, and only recomupte it if
1551  // child bone transforms are dirty (saves matrix inversion for unanimated attach children).
1552  attach->FinalTrans = GetBoneTransform(attach->ParentBone)
1553  * StdMeshMatrix::Transform(Mesh->GetSkeleton().GetBone(attach->ParentBone).Transformation)
1554  * attach->AttachTrans
1555  * StdMeshMatrix::Transform(attach->Child->Mesh->GetSkeleton().GetBone(attach->ChildBone).InverseTransformation)
1556  * StdMeshMatrix::Inverse(attach->Child->GetBoneTransform(attach->ChildBone));
1557 
1558  attach->FinalTransformDirty = false;
1559  }
1560  }
1561 
1562  SetBoneTransformsDirty(false);
1563  return was_dirty;
1564 }
1565 
1566 void StdMeshInstance::ReorderFaces(StdMeshMatrix* global_trans)
1567 {
1568 #ifndef USE_CONSOLE
1569  for (unsigned int i = 0; i < SubMeshInstances.size(); ++i)
1570  {
1572  assert((inst.Faces.size() > 0) && "StdMeshInstance sub-mesh instance has zero faces");
1573 
1574  if(inst.Faces.size() > 0 && inst.CurrentFaceOrdering != StdSubMeshInstance::FO_Fixed)
1575  {
1576  const StdMeshVertex* vertices;
1577  if(inst.GetSubMesh().GetNumVertices() > 0)
1578  vertices = &inst.GetSubMesh().GetVertices()[0];
1579  else
1580  vertices = &GetSharedVertices()[0];
1581  SortFacesArray(vertices, inst.Faces, inst.CurrentFaceOrdering, global_trans ? *global_trans : StdMeshMatrix::Identity());
1582  }
1583  }
1584 
1585  // TODO: Also reorder submeshes, attached meshes and include AttachTransformation for attached meshes...
1586 
1587  // Faces have been reordered: upload new order to GPU
1588  UpdateIBO();
1589 #endif
1590 }
1591 
1592 void StdMeshInstance::CompileFunc(StdCompiler* pComp, AttachedMesh::DenumeratorFactoryFunc Factory)
1593 {
1594  if(pComp->isDeserializer())
1595  {
1596  // Only initially created instances can be compiled
1597  assert(!AttachParent);
1598  assert(AttachChildren.empty());
1599  assert(AnimationStack.empty());
1600  SetBoneTransformsDirty(true);
1601 
1602  bool valid;
1603  pComp->Value(mkNamingAdapt(valid, "Valid"));
1604  if(!valid) pComp->excCorrupt("Mesh instance is invalid");
1605 
1606  int32_t iSubMeshCnt;
1607  pComp->Value(mkNamingCountAdapt(iSubMeshCnt, "SubMesh"));
1608  if(static_cast<uint32_t>(iSubMeshCnt) != SubMeshInstances.size())
1609  pComp->excCorrupt("Invalid number of submeshes");
1610  for(int32_t i = 0; i < iSubMeshCnt; ++i)
1611  pComp->Value(mkNamingAdapt(*SubMeshInstances[i], "SubMesh"));
1612  std::stable_sort(SubMeshInstancesOrdered.begin(), SubMeshInstancesOrdered.end(), StdMeshSubMeshInstanceVisibilityCmpPred());
1613 
1614  int32_t iAnimCnt = AnimationStack.size();
1615  pComp->Value(mkNamingCountAdapt(iAnimCnt, "AnimationNode"));
1616 
1617  for(int32_t i = 0; i < iAnimCnt; ++i)
1618  {
1619  AnimationNode* node = nullptr;
1620  pComp->Value(mkParAdapt(mkNamingPtrAdapt(node, "AnimationNode"), Mesh));
1621  AnimationNodeList::iterator iter = GetStackIterForSlot(node->Slot, true);
1622  if(*iter != nullptr) { delete node; pComp->excCorrupt("Duplicate animation slot index"); }
1623  *iter = node;
1624 
1625  // Add nodes into lookup table
1626  std::vector<AnimationNode*> nodes(1, node);
1627  while(!nodes.empty())
1628  {
1629  node = nodes.back();
1630  nodes.erase(nodes.end()-1);
1631 
1632  if (AnimationNodes.size() <= node->Number)
1633  AnimationNodes.resize(node->Number+1);
1634  if(AnimationNodes[node->Number] != nullptr) pComp->excCorrupt("Duplicate animation node number");
1635  AnimationNodes[node->Number] = node;
1636 
1638  {
1639  nodes.push_back(node->LinearInterpolation.ChildLeft);
1640  nodes.push_back(node->LinearInterpolation.ChildRight);
1641  }
1642  }
1643  }
1644 
1645  int32_t iAttachedCnt;
1646  pComp->Value(mkNamingCountAdapt(iAttachedCnt, "Attached"));
1647 
1648  for(int32_t i = 0; i < iAttachedCnt; ++i)
1649  {
1650  AttachChildren.push_back(new AttachedMesh);
1651  AttachedMesh* attach = AttachChildren.back();
1652 
1653  attach->Parent = this;
1654  pComp->Value(mkNamingAdapt(mkParAdapt(*attach, Factory), "Attached"));
1655  }
1656  }
1657  else
1658  {
1659  // Write something to make sure that the parent
1660  // named section ([Mesh] or [ChildInstance]) is written.
1661  // StdCompilerIni does not make a difference between
1662  // non-existing and empty named sections.
1663  bool valid = true;
1664  pComp->Value(mkNamingAdapt(valid, "Valid"));
1665 
1666  int32_t iSubMeshCnt = SubMeshInstances.size();
1667  pComp->Value(mkNamingCountAdapt(iSubMeshCnt, "SubMesh"));
1668  for(int32_t i = 0; i < iSubMeshCnt; ++i)
1669  pComp->Value(mkNamingAdapt(*SubMeshInstances[i], "SubMesh"));
1670 
1671  int32_t iAnimCnt = AnimationStack.size();
1672  pComp->Value(mkNamingCountAdapt(iAnimCnt, "AnimationNode"));
1673 
1674  for(AnimationNodeList::iterator iter = AnimationStack.begin(); iter != AnimationStack.end(); ++iter)
1675  pComp->Value(mkParAdapt(mkNamingPtrAdapt(*iter, "AnimationNode"), Mesh));
1676 
1677  int32_t iAttachedCnt = AttachChildren.size();
1678  pComp->Value(mkNamingCountAdapt(iAttachedCnt, "Attached"));
1679 
1680  for(unsigned int i = 0; i < AttachChildren.size(); ++i)
1681  pComp->Value(mkNamingAdapt(mkParAdapt(*AttachChildren[i], Factory), "Attached"));
1682  }
1683 }
1684 
1686 {
1687  for(unsigned int i = 0; i < AnimationNodes.size(); ++i)
1688  if(AnimationNodes[i])
1689  AnimationNodes[i]->DenumeratePointers();
1690 
1691  for(unsigned int i = 0; i < AttachChildren.size(); ++i)
1692  {
1693  AttachChildren[i]->DenumeratePointers();
1694  }
1695 }
1696 
1698 {
1699  for(unsigned int i = 0; i < AnimationNodes.size(); ++i)
1700  if(AnimationNodes[i])
1701  AnimationNodes[i]->ClearPointers(pObj);
1702 
1703  std::vector<unsigned int> Removal;
1704  for(unsigned int i = 0; i < AttachChildren.size(); ++i)
1705  if(!AttachChildren[i]->ClearPointers(pObj))
1706  Removal.push_back(AttachChildren[i]->Number);
1707 
1708  for(unsigned int i = 0; i < Removal.size(); ++i)
1709  DetachMesh(Removal[i]);
1710 }
1711 
1712 template<typename IteratorType, typename FuncObj>
1713 bool StdMeshInstance::ScanAttachTree(IteratorType begin, IteratorType end, const FuncObj& obj)
1714 {
1715  for (IteratorType iter = begin; iter != end; ++iter)
1716  {
1717  if (!obj(iter)) return false;
1718 
1719  // Scan attached tree of own children. For non-owned children,
1720  // we can't guarantee unique attach numbers.
1721  if( (*iter)->OwnChild)
1722  if (!ScanAttachTree((*iter)->Child->AttachChildren.begin(), (*iter)->Child->AttachChildren.end(), obj))
1723  return false;
1724  }
1725 
1726  return true;
1727 }
1728 
1729 StdMeshInstance::AnimationNodeList::iterator StdMeshInstance::GetStackIterForSlot(int slot, bool create)
1730 {
1731  // TODO: bsearch
1732  for (AnimationNodeList::iterator iter = AnimationStack.begin(); iter != AnimationStack.end(); ++iter)
1733  {
1734  if ((*iter)->Slot == slot)
1735  {
1736  return iter;
1737  }
1738  else if ((*iter)->Slot > slot)
1739  {
1740  if (!create)
1741  return AnimationStack.end();
1742  else
1743  return AnimationStack.insert(iter, nullptr);
1744  }
1745  }
1746 
1747  if (!create)
1748  return AnimationStack.end();
1749  else
1750  return AnimationStack.insert(AnimationStack.end(), nullptr);
1751 }
1752 
1753 void StdMeshInstance::InsertAnimationNode(AnimationNode* node, int slot, AnimationNode* sibling, ValueProvider* weight, bool stop_previous_animation)
1754 {
1755  assert(!sibling || !stop_previous_animation);
1756  // Default
1757  if (!sibling) sibling = GetRootAnimationForSlot(slot);
1758  assert(!sibling || sibling->Slot == slot);
1759 
1760  // Stop any animation already running in this slot?
1761  if (sibling && stop_previous_animation)
1762  {
1763  StopAnimation(sibling);
1764  sibling = nullptr;
1765  }
1766 
1767  // Find two subsequent numbers in case we need to create two nodes, so
1768  // script can deduce the second node.
1769  unsigned int Number1, Number2;
1770  for (Number1 = 0; Number1 < AnimationNodes.size(); ++Number1)
1771  if (AnimationNodes[Number1] == nullptr && (!sibling || Number1+1 == AnimationNodes.size() || AnimationNodes[Number1+1] == nullptr))
1772  break;
1773  /* for(Number2 = Number1+1; Number2 < AnimationNodes.size(); ++Number2)
1774  if(AnimationNodes[Number2] == nullptr)
1775  break;*/
1776  Number2 = Number1 + 1;
1777 
1778  weight->Value = Clamp(weight->Value, Fix0, itofix(1));
1779 
1780  if (Number1 == AnimationNodes.size()) AnimationNodes.push_back( (StdMeshInstance::AnimationNode*) nullptr);
1781  if (sibling && Number2 == AnimationNodes.size()) AnimationNodes.push_back( (StdMeshInstance::AnimationNode*) nullptr);
1782 
1783  AnimationNodes[Number1] = node;
1784  node->Number = Number1;
1785  node->Slot = slot;
1786 
1787  if (sibling)
1788  {
1789  AnimationNode* parent = new AnimationNode(node, sibling, weight);
1790  AnimationNodes[Number2] = parent;
1791  parent->Number = Number2;
1792  parent->Slot = slot;
1793 
1794  node->Parent = parent;
1795  parent->Parent = sibling->Parent;
1796  parent->LinearInterpolation.ChildLeft = sibling;
1797  parent->LinearInterpolation.ChildRight = node;
1798  if (sibling->Parent)
1799  {
1800  if (sibling->Parent->LinearInterpolation.ChildLeft == sibling)
1801  sibling->Parent->LinearInterpolation.ChildLeft = parent;
1802  else
1803  sibling->Parent->LinearInterpolation.ChildRight = parent;
1804  }
1805  else
1806  {
1807  // set new parent
1808  AnimationNodeList::iterator iter = GetStackIterForSlot(slot, false);
1809  // slot must not be empty, since sibling uses same slot
1810  assert(iter != AnimationStack.end() && *iter != nullptr);
1811  *iter = parent;
1812  }
1813 
1814  sibling->Parent = parent;
1815  }
1816  else
1817  {
1818  delete weight;
1819  AnimationNodeList::iterator iter = GetStackIterForSlot(slot, true);
1820  assert(!*iter); // we have a sibling if slot is not empty
1821  *iter = node;
1822  }
1823 
1824  SetBoneTransformsDirty(true);
1825 }
1826 
1828 {
1829  ValueProvider* provider = nullptr;
1830  C4Real min;
1831  C4Real max;
1832 
1833  switch (node->GetType())
1834  {
1836  provider = node->GetPositionProvider();
1837  min = Fix0;
1838  max = ftofix(node->GetAnimation()->Length);
1839  break;
1841  // No execution necessary
1842  return true;
1844  provider = node->GetWeightProvider();
1845  min = Fix0;
1846  max = itofix(1);
1847  break;
1848  default:
1849  assert(false);
1850  break;
1851  }
1852 
1853  assert(provider);
1854  const C4Real old_value = provider->Value;
1855 
1856  if (!provider->Execute())
1857  {
1858  if (node->GetType() == AnimationNode::LeafNode) return false;
1859 
1860  // Remove the child with less weight (normally weight reaches 0.0 or 1.0)
1861  if (node->GetWeight() > itofix(1, 2))
1862  {
1863  // Remove both children (by parent) if other wants to be deleted as well
1864  if (!ExecuteAnimationNode(node->GetRightChild())) return false;
1865  // Remove left child as it has less weight
1866  StopAnimation(node->LinearInterpolation.ChildLeft);
1867  }
1868  else
1869  {
1870  // Remove both children (by parent) if other wants to be deleted as well
1871  if (!ExecuteAnimationNode(node->GetLeftChild())) return false;
1872  // Remove right child as it has less weight
1873  StopAnimation(node->LinearInterpolation.ChildRight);
1874  }
1875  }
1876  else
1877  {
1878  if (provider->Value != old_value)
1879  {
1880  provider->Value = Clamp(provider->Value, min, max);
1881  SetBoneTransformsDirty(true);
1882  }
1883 
1885  {
1886  const bool left_result = ExecuteAnimationNode(node->GetLeftChild());
1887  const bool right_result = ExecuteAnimationNode(node->GetRightChild());
1888 
1889  // Remove this node completely
1890  if (!left_result && !right_result)
1891  return false;
1892 
1893  // Note that either of this also removes node
1894  if (!left_result)
1895  StopAnimation(node->GetLeftChild());
1896  if (!right_result)
1897  StopAnimation(node->GetRightChild());
1898  }
1899  }
1900 
1901  return true;
1902 }
1903 
1905 {
1906  BoneTransformsDirty = value;
1907 
1908  // only if the value is true, so that updates happen
1909  if (value)
1910  {
1911  // Update attachment's attach transformations. Note this is done recursively.
1912  for (AttachedMeshList::iterator iter = AttachChildren.begin(); iter != AttachChildren.end(); ++iter)
1913  {
1914  AttachedMesh* attach = *iter;
1915 
1916  if (attach->GetFlags() & AM_MatchSkeleton)
1917  {
1918  attach->Child->SetBoneTransformsDirty(value);
1919  }
1920  }
1921  }
1922 }
1923 
1924 #ifndef USE_CONSOLE
1926 {
1927  // First, find out whether we have fixed face ordering or not
1928  bool all_submeshes_fixed = true;
1929  for (StdSubMeshInstance* inst : SubMeshInstances)
1930  {
1931  all_submeshes_fixed = (inst->GetFaceOrdering() == StdSubMeshInstance::FO_Fixed);
1932  if (!all_submeshes_fixed) break;
1933 
1934  // If true, submesh is 100% complete
1935  all_submeshes_fixed = inst->GetNumFaces() == inst->GetSubMesh().GetNumFaces();
1936  if (!all_submeshes_fixed) break;
1937  }
1938 
1939  // If the face ordering is fixed, then we don't need a custom
1940  // IBO. This is typically the case for all meshes without transparency
1941  // and 100% completion.
1942  if (all_submeshes_fixed)
1943  {
1944  if (ibo) glDeleteBuffers(1, &ibo);
1945  if (vaoid) pGL->FreeVAOID(vaoid);
1946  ibo = 0; vaoid = 0;
1947  }
1948  else
1949  {
1950  // We have a custom face ordering, or we render only a subset
1951  // of our faces. Create a custom IBO and upload the index
1952  // data.
1953  if (ibo == 0)
1954  {
1955  // This is required, because the IBO binding is part
1956  // of the VAO state. If we create a new IBO we cannot
1957  // keep using any old VAO. But we always create and
1958  // destroy them together, so we can assert here.
1959  assert(vaoid == 0);
1960 
1961  size_t total_faces = 0;
1962  for (unsigned int i = 0; i < Mesh->GetNumSubMeshes(); ++i)
1963  total_faces += Mesh->GetSubMesh(i).GetNumFaces();
1964 
1965  glGenBuffers(1, &ibo);
1966  glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);
1967 
1968  // TODO: Optimize mode. In many cases this is still fairly static.
1969  glBufferData(GL_ELEMENT_ARRAY_BUFFER, total_faces * 3 * sizeof(GLuint), nullptr, GL_STREAM_DRAW);
1970  }
1971  else
1972  {
1973  glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);
1974  }
1975 
1976  for (StdSubMeshInstance* inst : SubMeshInstances)
1977  {
1978  assert(inst->GetNumFaces() <= inst->GetSubMesh().GetNumFaces());
1979  glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, inst->GetSubMesh().GetOffsetInIBO(), inst->GetNumFaces() * 3 * sizeof(GLuint), &inst->Faces[0]);
1980  }
1981 
1982  glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
1983 
1984  if (vaoid == 0)
1985  vaoid = pGL->GenVAOID();
1986  }
1987 }
1988 #endif
FaceOrdering CurrentFaceOrdering
Definition: StdMesh.h:303
const char * getData() const
Definition: StdBuf.h:450
virtual bool Separator(Sep eSep=SEP_SEP)
Definition: StdCompiler.h:129
std::vector< StdSubMeshInstance * > SubMeshInstancesOrdered
Definition: StdMesh.h:658
const StdMeshMaterial & GetMaterial() const
Definition: StdMesh.h:172
AnimationNodeList AnimationStack
Definition: StdMesh.h:654
void LoadFacesForCompletion(class StdMeshInstance &instance, const StdSubMesh &submesh, float completion)
Definition: StdMesh.cpp:678
const StdSubMesh & GetSubMesh() const
Definition: StdMesh.h:267
Definition: StdAdaptors.h:848
#define z
StdMeshInstance(const StdMesh &mesh, float completion=1.0f)
Definition: StdMesh.cpp:1085
void CompileFunc(StdCompiler *pComp)
Definition: StdMesh.cpp:763
Definition: StdAdaptors.h:760
StdNamingCountAdapt< int_t > mkNamingCountAdapt(int_t &iCount, const char *szName)
Definition: StdAdaptors.h:974
void CompileFunc(StdCompiler *pComp, AttachedMesh::DenumeratorFactoryFunc Factory)
Definition: StdMesh.cpp:1592
bool BoneTransformsDirty
Definition: StdMesh.h:665
const StdMeshMaterial * Material
Definition: StdMesh.h:284
const StdMeshMaterial & GetMaterial() const
Definition: StdMesh.h:272
NodeType GetType() const
Definition: StdMesh.h:349
void excCorrupt(const char *szMessage,...)
Definition: StdCompiler.h:258
const std::vector< StdMeshVertex > & GetSharedVertices() const
Definition: StdMesh.h:551
virtual void CompileFunc(StdCompiler *pComp)
Definition: StdMesh.cpp:790
void SetFaceOrderingForClrModulation(uint32_t clrmod)
Definition: StdMesh.cpp:1148
AttachedMesh * GetAttachedMeshByNumber(unsigned int number) const
Definition: StdMesh.cpp:1432
unsigned int vaoid
Definition: StdMesh.h:673
GLuint ibo
Definition: StdMesh.h:672
size_t GetNumFaces() const
Definition: StdMesh.h:170
StdCopyStrBuf Name
Definition: StdMesh.h:99
StdMeshTransformation Transformation
Definition: StdMesh.h:39
std::vector< TexUnit > TexUnits
Definition: StdMesh.h:299
void FreeVAOID(unsigned int vaoid)
Definition: C4DrawGL.cpp:976
void PostInit()
Definition: StdMesh.cpp:507
AnimationNode * GetRootAnimationForSlot(int slot)
Definition: StdMesh.cpp:1266
const StdMeshSkeleton & GetSkeleton() const
Definition: StdMesh.h:205
AnimationNode * GetAnimationNodeByNumber(unsigned int number)
Definition: StdMesh.cpp:1260
void Format(const char *szFmt,...) GNUC_FORMAT_ATTRIBUTE_O
Definition: StdBuf.cpp:181
bool IsOpaque() const
#define z2
ValueProvider * GetWeightProvider()
Definition: StdMesh.h:358
bool SetChildBone(const StdStrBuf &bone)
Definition: StdMesh.cpp:1014
StdMeshInstance * Child
Definition: StdMesh.h:513
void SetFaceOrdering(class StdMeshInstance &instance, const StdSubMesh &submesh, FaceOrdering ordering)
Definition: StdMesh.cpp:735
size_t GetNumSubMeshes() const
Definition: StdMesh.h:590
size_t GetNumSubMeshes() const
Definition: StdMesh.h:201
unsigned int Vertices[3]
Definition: StdMesh.h:63
Definition: C4Real.h:58
T Clamp(T bval, T lbound, T rbound)
Definition: Standard.h:46
void MirrorAnimation(const StdMeshAnimation &animation)
Definition: StdMesh.cpp:415
char * getMData()
Definition: StdBuf.h:451
StdNamingAdapt< T > mkNamingAdapt(T &&rValue, const char *szName)
Definition: StdAdaptors.h:93
const StdMeshMatrix & GetBoneTransform(size_t i) const
Definition: StdMesh.cpp:1459
void InsertAnimationNode(AnimationNode *node, int slot, AnimationNode *sibling, ValueProvider *weight, bool stop_previous_animation)
Definition: StdMesh.cpp:1753
AttachedMesh * AttachMeshImpl(StdMeshInstance &instance, AttachedMesh::Denumerator *denumerator, const StdStrBuf &parent_bone, const StdStrBuf &child_bone, const StdMeshMatrix &transformation, uint32_t flags, bool own_child, unsigned int new_attach_number)
Definition: StdMesh.cpp:1380
void ClearPointers(class C4Object *pObj)
Definition: StdMesh.cpp:1697
void InsertAnimation(const StdMeshAnimation &animation)
Definition: StdMesh.cpp:473
unsigned int GetNumber() const
Definition: StdMesh.h:348
void SetFaceOrderingForClrModulation(class StdMeshInstance &instance, const StdSubMesh &submesh, uint32_t clrmod)
Definition: StdMesh.cpp:749
const StdMeshFace & GetFace(size_t i) const
Definition: StdMesh.h:169
AnimationNode * PlayAnimation(const StdStrBuf &animation_name, int slot, AnimationNode *sibling, ValueProvider *position, ValueProvider *weight, bool stop_previous_animation)
Definition: StdMesh.cpp:1180
void DenumeratePointers()
Definition: StdMesh.cpp:1685
C4Real GetWeight() const
Definition: StdMesh.h:359
const StdMeshBone & GetBone(size_t i) const
Definition: StdMesh.h:118
void PostInit()
Definition: StdMesh.cpp:577
void ClearPointers(class C4Object *pObj)
Definition: StdMesh.cpp:963
size_t GetNumTextures() const
StdBitfieldAdapt< T > mkBitfieldAdapt(T &rVal, const StdBitfieldEntry< T > *pNames)
Definition: StdAdaptors.h:951
void ExecuteAnimation(float dt)
Definition: StdMesh.cpp:1301
AnimationNode * Parent
Definition: StdMesh.h:369
void StopAnimation(AnimationNode *node)
Definition: StdMesh.cpp:1203
StdDecompileAdapt< T > mkDecompileAdapt(const T &rValue)
Definition: StdAdaptors.h:154
void ReorderFaces(StdMeshMatrix *global_trans)
Definition: StdMesh.cpp:1566
ValueProvider * GetPositionProvider()
Definition: StdMesh.h:353
AnimationNode * GetRightChild()
Definition: StdMesh.h:357
bool ClearPointers(class C4Object *pObj)
Definition: StdMesh.cpp:1070
void CompileFunc(StdCompiler *pComp, const StdMesh *Mesh)
Definition: StdMesh.cpp:874
size_t GetNumVertices() const
Definition: StdMesh.h:167
virtual void ClearPointers(class C4Object *pObj)
Definition: StdMesh.h:482
std::vector< Pass > PassData
Definition: StdMesh.h:302
const StdMeshAnimation * GetAnimationByName(const StdStrBuf &name) const
Definition: StdMesh.cpp:398
const StdSubMesh & GetSubMesh(size_t i) const
Definition: StdMesh.h:200
C4Fixed itofix(int32_t x)
Definition: C4Real.h:261
void CompileFunc(StdCompiler *pComp, DenumeratorFactoryFunc Factory)
Definition: StdMesh.cpp:1030
bool HasTexCoordAnimation() const
uint32_t GetFlags() const
Definition: StdMesh.h:521
const StdMesh * Mesh
Definition: StdMesh.h:649
void Value(const T &rStruct)
Definition: StdCompiler.h:170
C4Fixed ftofix(float x)
Definition: C4Real.h:258
void SetAttachTransformation(const StdMeshMatrix &transformation)
Definition: StdMesh.cpp:1024
bool ExecuteAnimationNode(AnimationNode *node)
Definition: StdMesh.cpp:1827
AttachedMeshList::const_iterator AttachedMeshIter
Definition: StdMesh.h:546
virtual bool isDeserializer()
Definition: StdCompiler.h:63
StdMeshInstanceAnimationNode AnimationNode
Definition: StdMesh.h:401
bool DetachMesh(unsigned int number)
Definition: StdMesh.cpp:1408
void SetBoneTransformsDirty(bool value)
Definition: StdMesh.cpp:1904
const StdMeshBone * GetBoneByName(const StdStrBuf &name) const
Definition: StdMesh.cpp:388
const std::vector< Vertex > & GetVertices() const
Definition: StdMesh.h:165
float GetCompletion() const
Definition: StdMesh.h:556
void SetCompletion(float completion)
Definition: StdMesh.cpp:1165
std::vector< StdMeshMaterialPass > Passes
void SetFaceOrdering(FaceOrdering ordering)
Definition: StdMesh.cpp:1131
float Completion
Definition: StdMesh.h:651
bool UpdateBoneTransforms()
Definition: StdMesh.cpp:1484
void SetMaterial(const StdMeshMaterial &material)
Definition: StdMesh.cpp:706
std::vector< StdMeshMaterialTextureUnit > TextureUnits
std::vector< const StdMeshAnimation * > GetAnimations() const
Definition: StdMesh.cpp:406
StdCopyStrBuf Name
Definition: StdMesh.h:36
unsigned int GenVAOID()
Definition: C4DrawGL.cpp:934
AttachedMesh * AttachParent
Definition: StdMesh.h:663
AttachedMesh * AttachMesh(const StdMesh &mesh, AttachedMesh::Denumerator *denumerator, const StdStrBuf &parent_bone, const StdStrBuf &child_bone, const StdMeshMatrix &transformation=StdMeshMatrix::Identity(), uint32_t flags=AM_None, unsigned int attach_number=0)
Definition: StdMesh.cpp:1346
StdMeshTransformation GetTransformAt(float time, float length) const
Definition: StdMesh.cpp:289
void SetMaterial(size_t i, const StdMeshMaterial &material)
Definition: StdMesh.cpp:1450
void SetAnimationPosition(AnimationNode *node, ValueProvider *position)
Definition: StdMesh.cpp:1273
std::vector< StdMeshFace > Faces
Definition: StdMesh.h:282
void SetAnimationWeight(AnimationNode *node, ValueProvider *weight)
Definition: StdMesh.cpp:1291
float fixtof(const C4Fixed &x)
Definition: C4Real.h:257
StdMeshTransformation InverseTransformation
Definition: StdMesh.h:41
unsigned int Index
Definition: StdMesh.h:34
StdCopyStrBuf Name
std::vector< StdMeshMatrix > BoneTransforms
Definition: StdMesh.h:655
void ObjectLabel(uint32_t identifier, uint32_t name, int32_t length, const char *label)
Definition: C4DrawGL.cpp:283
StdParameterAdapt< T, P > mkParAdapt(T &&rObj, P &&rPar)
Definition: StdAdaptors.h:456
const StdMeshAnimation * GetAnimation() const
Definition: StdMesh.h:352
AnimationNodeList AnimationNodes
Definition: StdMesh.h:653
AnimationNode * GetLeftChild()
Definition: StdMesh.h:356
AnimationNodeList::iterator GetStackIterForSlot(int slot, bool create)
Definition: StdMesh.cpp:1729
size_t getLength() const
Definition: StdBuf.h:453
std::vector< StdMeshMaterialTechnique > Techniques
const StdMeshMaterial * GetMaterial(const char *material_name) const
StdMeshAnimation & operator=(const StdMeshAnimation &other)
Definition: StdMesh.cpp:351
std::vector< AttachedMesh * > AttachChildren
Definition: StdMesh.h:662
StdSubMeshInstance(class StdMeshInstance &instance, const StdSubMesh &submesh, float completion)
Definition: StdMesh.cpp:668
CStdGL * pGL
Definition: C4DrawGL.cpp:914
StdPtrAdapt< T > mkNamingPtrAdapt(T *&rpObj, const char *szNaming)
Definition: StdAdaptors.h:602
const StdMesh & GetMesh() const
Definition: StdMesh.h:624
static bool ScanAttachTree(IteratorType begin, IteratorType end, const FuncObj &obj)
Definition: StdMesh.cpp:1713
bool SetParentBone(const StdStrBuf &bone)
Definition: StdMesh.cpp:1004
#define toC4CStrBuf(rBuf)
Definition: StdAdaptors.h:26
bool GetBoneTransform(unsigned int bone, StdMeshTransformation &transformation)
Definition: StdMesh.cpp:842
~StdMesh()
Definition: StdMesh.cpp:565
void UpdateIBO()
Definition: StdMesh.cpp:1925
std::vector< int > GetMatchingBones(const StdMeshSkeleton &skeleton) const
Definition: StdMesh.cpp:521
static const IDBase * Lookup(const char *name)
Definition: StdMesh.h:462
StdMeshMatManager MeshMaterialManager
size_t GetNumBones() const
Definition: StdMesh.h:119
void SetAnimationBoneTransform(AnimationNode *node, const StdMeshTransformation &trans)
Definition: StdMesh.cpp:1284
size_t GetBoneCount() const
Definition: StdMesh.cpp:1476
void CompileFunc(C4Real &rValue, StdCompiler *pComp)
Definition: C4Real.cpp:9033
StdMeshTransformation Transformation
Definition: StdMesh.h:70
StdMeshInstance * Parent
Definition: StdMesh.h:512
StdContextPtrAdapt< T, ContextT > mkContextPtrAdapt(T *&rpObj, const ContextT &ctx, bool fAllowNull=true)
Definition: StdAdaptors.h:607
const C4Real Fix0
Definition: C4Real.h:312
const StdMeshBone * GetParent() const
Definition: StdMesh.h:43
std::vector< StdSubMeshInstance * > SubMeshInstances
Definition: StdMesh.h:657
int Compare_(const char *pCData, size_t iAt=0) const
Definition: StdBuf.h:492