TDME2  1.9.200
ObjectAnimation.cpp
Go to the documentation of this file.
2 
3 #include <memory>
4 #include <string>
5 #include <unordered_map>
6 #include <vector>
7 
8 #include <tdme/tdme.h>
13 #include <tdme/engine/model/Node.h>
16 #include <tdme/engine/Engine.h>
17 #include <tdme/engine/Timing.h>
18 #include <tdme/math/Math.h>
19 #include <tdme/math/Matrix4x4.h>
20 #include <tdme/math/Vector3.h>
21 #include <tdme/utilities/Console.h>
22 
23 using std::string;
24 using std::to_string;
25 using std::unique_ptr;
26 using std::unordered_map;
27 using std::vector;
28 
38 using tdme::math::Math;
42 
43 ObjectAnimation::ObjectAnimation(Model* model, Engine::AnimationProcessingTarget animationProcessingTarget)
44 {
45  this->animationProcessingTarget = animationProcessingTarget;
46  this->model = model;
47  // skinning
48  hasSkinning = false;
49  if (model->hasSkinning() == true) {
50  hasSkinning = true;
53  skinningNodesMatrices.resize(skinningNodes.size());
54  for (auto i = 0; i < skinningNodes.size(); i++) {
55  vector<FlattenedNode> nodeListIgnored;
57  }
58  }
60  //
61  baseAnimationIdx = 0;
62  // animation
63  setAnimation(Model::ANIMATIONSETUP_DEFAULT);
64  // create transform matrices
65  transformMatrices.emplace_back();
66  nodeLists.emplace_back();
68  // calculate transform matrices
70  // skinning ...
71  if (hasSkinning == true) {
72  for (auto i = 0; i < skinningNodes.size(); i++) {
73  skinningNodesNodeSkinningJoints.emplace_back();
74  for (auto& skinningJoint: skinningNodes[i]->getSkinning()->getJoints()) {
75  auto transformMatrixIt = transformMatrices[0].find(skinningJoint.getNodeId());
76  if (transformMatrixIt == transformMatrices[0].end()) continue;
77  auto skinningNodeMatrixIt = skinningNodesMatrices[i].find(skinningJoint.getNodeId());
78  if (skinningNodeMatrixIt == skinningNodesMatrices[i].end()) continue;
79  skinningNodesNodeSkinningJoints[i].emplace_back(
80  &skinningJoint,
81  transformMatrixIt->second,
82  skinningNodeMatrixIt->second
83  );
84  }
85  }
87  }
88  // reset animation
89  if (baseAnimations.size() == 0) baseAnimations.emplace_back();
90  baseAnimations[baseAnimationIdx].endAtTime = -1LL;
92  baseAnimations[baseAnimationIdx].currentAtTime = 0LL;
93  baseAnimations[baseAnimationIdx].time = 0.0f;
94  baseAnimations[baseAnimationIdx].finished = false;
95 }
96 
98  for (const auto& baseAnimationTransformMatrices: transformMatrices) {
99  for (const auto& [id, matrix]: baseAnimationTransformMatrices) {
100  delete matrix;
101  }
102  }
103  for (const auto& skinningNodeMatricesEntity: skinningNodesMatrices) {
104  for (const auto& [id, matrix]: skinningNodeMatricesEntity) {
105  delete matrix;
106  }
107  }
108  for (const auto& [id, matrix]: overriddenTransformMatrices) {
109  delete matrix;
110  }
111 }
112 
113 void ObjectAnimation::setAnimation(const string& id, float speed)
114 {
115  auto animationActiveSetup = model->getAnimationSetup(id);
116 
117  // only switch animation if we have one
118  if (animationActiveSetup != nullptr) {
119  if (baseAnimations.size() == 0) {
120  baseAnimations.emplace_back(
121  animationActiveSetup,
122  -1LL,
123  0LL,
125  false,
126  0.0f,
127  speed
128  );
129  baseAnimationIdx = 0;
130  } else
131  if (baseAnimations.size() == 1) {
132  baseAnimations.emplace_back(
133  animationActiveSetup,
134  -1LL,
135  0LL,
137  false,
138  0.0f,
139  speed
140  );
141  baseAnimationIdx = 1;
142  transformMatrices.emplace_back();
143  nodeLists.emplace_back();
145  transformMatrices.emplace_back();
146  nodeLists.emplace_back();
148  } else {
151  animationActiveSetup,
152  -1LL,
153  0LL,
155  false,
156  0.0f,
157  speed
158  );
159  }
160  if (baseAnimations.size() > 1) {
161  auto baseAnimationIdxLast = (baseAnimationIdx + 1) % 2;
162  auto& baseAnimationLast = baseAnimations[baseAnimationIdxLast];
163  baseAnimationLast.endAtTime = baseAnimationLast.currentAtTime;
164  }
165  } else {
166  Console::println("ObjectAnimation::setAnimation(): " + model->getId() + ": missing animation: " + id);
167  }
168 }
169 
171  if (baseAnimations.size() == 0) return;
172  baseAnimations[baseAnimationIdx].speed = speed;
173 }
174 
176 {
177  // remove active overlay animation with given ids
179  // check overlay animation
180  auto animationSetup = model->getAnimationSetup(id);
181  if (animationSetup == nullptr) return;
182  if (animationSetup->getOverlayFromNodeId().size() == 0) return;
183  // create animation state
184  auto animationState = new AnimationState();
185  animationState->setup = animationSetup;
186  animationState->lastAtTime = Timing::UNDEFINED;
187  animationState->currentAtTime = 0LL;
188  animationState->time = 0.0f;
189  animationState->speed = 1.0f;
190  animationState->finished = false;
191  // register overlay animation
192  overlayAnimationsById[id] = animationState;
193  overlayAnimationsByJointId[animationSetup->getOverlayFromNodeId()] = animationState;
194  //
195  updateNodeLists();
196 }
197 
199 {
200  auto animationStateIt = overlayAnimationsById.find(id);
201  if (animationStateIt == overlayAnimationsById.end()) return;
202  //
203  auto animationState = unique_ptr<AnimationState>(animationStateIt->second);
204  overlayAnimationsById.erase(animationStateIt);
205  overlayAnimationsByJointId.erase(animationState->setup->getOverlayFromNodeId());
206  //
207  updateNodeLists();
208 }
209 
211 {
212  // determine finished overlay animations
213  vector<string> overlayAnimationsToRemove;
214  for (const auto& [animationId, animationState]: overlayAnimationsById) {
215  if (animationState->finished == true) {
216  overlayAnimationsToRemove.push_back(animationId);
217  }
218  }
219  // remove them
220  for (const auto& animationState: overlayAnimationsToRemove) {
221  removeOverlayAnimation(animationState);
222  }
223 }
224 
226 {
227  // remove them
228  vector<string> overlayAnimationsToRemove;
229  for (const auto& [animationId, animationState]: overlayAnimationsById) {
230  overlayAnimationsToRemove.push_back(animationId);
231  }
232  for (const auto& animationState: overlayAnimationsToRemove) {
233  removeOverlayAnimation(animationState);
234  }
235 }
236 
238 {
239  return baseAnimations[baseAnimationIdx].setup == nullptr ? "none" : baseAnimations[baseAnimationIdx].setup->getId();
240 }
241 
243 {
244  return baseAnimations[baseAnimationIdx].time;
245 }
246 
248 {
249  return overlayAnimationsById.find(id) != overlayAnimationsById.end();
250 }
251 
253 {
254  AnimationState* animationState = nullptr;
255  auto animationStateIt = overlayAnimationsById.find(id);
256  if (animationStateIt != overlayAnimationsById.end()) {
257  animationState = animationStateIt->second;
258  }
259  return animationState == nullptr ? 1.0f : animationState->time;
260 }
261 
263 {
264  auto overriddenTransformMatrixIt = overriddenTransformMatrices.find(id);
265  if (overriddenTransformMatrixIt != overriddenTransformMatrices.end()) {
266  return *overriddenTransformMatrixIt->second;
267  } else {
268  auto transformMatrixIt = transformMatrices[0].find(id);
269  if (transformMatrixIt != transformMatrices[0].end()) {
270  return *transformMatrixIt->second;
271  }
272  Console::println("ObjectAnimation::getTransformMatrix(): " + id + ": node not found");
273  }
274  return Matrix4x4().identity();
275 }
276 
277 void ObjectAnimation::setNodeTransformMatrix(const string& id, const Matrix4x4& matrix)
278 {
279  auto overriddenTransformMatrixIt = overriddenTransformMatrices.find(id);
280  if (overriddenTransformMatrixIt != overriddenTransformMatrices.end()) {
281  *overriddenTransformMatrixIt->second = matrix;
282  } else {
283  overriddenTransformMatrices[id] = new Matrix4x4(matrix);
284  }
285  //
286  updateNodeLists();
287 }
288 
290 {
291  auto overriddenTransformMatrixIt = overriddenTransformMatrices.find(id);
292  if (overriddenTransformMatrixIt != overriddenTransformMatrices.end()) {
293  delete overriddenTransformMatrixIt->second;
294  overriddenTransformMatrices.erase(overriddenTransformMatrixIt);
295  }
296  //
297  updateNodeLists();
298 }
299 
300 void ObjectAnimation::createNodesTransformMatrices(unordered_map<string, Matrix4x4*>& matrices, vector<FlattenedNode>& nodeList, const unordered_map<string, Node*>& nodes, Matrix4x4* parentTransformMatrix, AnimationState* animationState)
301 {
302  // iterate through nodes
303  for (const auto& [nodeId, node]: nodes) {
304  //
305  auto nodeAnimationState = animationState;
306  // put and associate transform matrices with node
307  auto matrix = new Matrix4x4();
308  matrix->identity();
309  matrices[node->getId()] = matrix;
310  // overridden matrix
311  Matrix4x4* overriddenTransformMatrix = nullptr;
312  auto overriddenTransformMatrixIt = overriddenTransformMatrices.find(node->getId());
313  if (overriddenTransformMatrixIt != overriddenTransformMatrices.end()) overriddenTransformMatrix = overriddenTransformMatrixIt->second;
314  // overlay animation
315  auto overlayAnimationIt = overlayAnimationsByJointId.find(node->getId());
316  if (overlayAnimationIt != overlayAnimationsByJointId.end()) {
317  nodeAnimationState = overlayAnimationIt->second;
318  }
319  nodeList.emplace_back(
320  node->getId(),
321  &node->getTransformMatrix(),
322  overriddenTransformMatrix,
323  node->getAnimation(),
324  animationState,
325  parentTransformMatrix,
326  matrix
327  );
328  // do sub nodes
329  const auto& subNodes = node->getSubNodes();
330  if (subNodes.size() > 0) {
331  createNodesTransformMatrices(matrices, nodeList, subNodes, matrix, nodeAnimationState);
332  }
333  }
334 }
335 
336 void ObjectAnimation::updateNodeList(vector<FlattenedNode>& nodeList, int& nodeIdx, const unordered_map<string, Node*>& nodes, AnimationState* animationState) {
337  // iterate through nodes
338  for (const auto& [nodeId, node]: nodes) {
339  //
340  auto nodeAnimationState = animationState;
341  // put and associate transform matrices with node
342  // overridden matrix
343  Matrix4x4* overriddenTransformMatrix = nullptr;
344  auto overriddenTransformMatrixIt = overriddenTransformMatrices.find(node->getId());
345  if (overriddenTransformMatrixIt != overriddenTransformMatrices.end()) overriddenTransformMatrix = overriddenTransformMatrixIt->second;
346  // overlay animation
347  auto overlayAnimationIt = overlayAnimationsByJointId.find(node->getId());
348  if (overlayAnimationIt != overlayAnimationsByJointId.end()) {
349  nodeAnimationState = overlayAnimationIt->second;
350  }
351  // update node list
352  nodeList[nodeIdx].nodeOverriddenTransformMatrix = overriddenTransformMatrix;
353  nodeList[nodeIdx].nodeAnimationState = nodeAnimationState;
354  nodeIdx++;
355  // do sub nodes
356  const auto& subNodes = node->getSubNodes();
357  if (subNodes.size() > 0) {
358  updateNodeList(nodeList, nodeIdx, subNodes, nodeAnimationState);
359  }
360  }
361 }
362 
363 void ObjectAnimation::computeNodesTransformMatrices(vector<FlattenedNode>& nodeList, const Matrix4x4 parentTransformMatrix, AnimationState* animationState)
364 {
365  // iterate through flattened nodes
366  Matrix4x4 transformMatrix;
367  for (auto& flattenedNode: nodeList) {
368  auto nodeAnimationState = flattenedNode.nodeAnimationState != nullptr?flattenedNode.nodeAnimationState:animationState;
369  // compute animation matrix if animation setups exist
370  auto animation = flattenedNode.nodeAnimation;
371  // TODO: check if its better to not compute animation matrix if finished
372  if (animation != nullptr && nodeAnimationState != nullptr && nodeAnimationState->setup != nullptr) {
373  const auto& animationMatrices = animation->getTransformMatrices();
374  auto frames = nodeAnimationState->setup->getFrames();
375  auto fps = model->getFPS();
376  // determine current and last matrix
377  auto frameAtLast = (nodeAnimationState->lastAtTime / 1000.0f) * fps * nodeAnimationState->setup->getSpeed() * nodeAnimationState->speed;
378  auto frameAtCurrent = (nodeAnimationState->currentAtTime / 1000.0f) * fps * nodeAnimationState->setup->getSpeed() * nodeAnimationState->speed;
379  // check if looping is disabled
380  if (nodeAnimationState->setup->isLoop() == false && frameAtCurrent >= frames) {
381  frameAtLast = frames - 1;
382  frameAtCurrent = frames - 1;
383  nodeAnimationState->finished = true;
384  }
385  auto matrixAtLast = static_cast<int32_t>(frameAtLast) % frames;
386  auto matrixAtCurrent = static_cast<int32_t>(frameAtCurrent) % frames;
387  nodeAnimationState->time = frames <= 1?0.0f:static_cast<float>(matrixAtCurrent) / static_cast<float>((frames - 1));
388  // compute animation transform matrix
389  auto t = frameAtCurrent - static_cast<float>(Math::floor(frameAtLast));
390  if (t < 1.0f) {
391  if (matrixAtLast == matrixAtCurrent) {
392  matrixAtCurrent+= 1;
393  if (matrixAtCurrent >= frames) {
394  if (nodeAnimationState->setup->isLoop() == true) {
395  matrixAtCurrent = matrixAtCurrent % frames;
396  } else {
397  matrixAtCurrent = frames - 1;
398  }
399  }
400  }
401  transformMatrix = Matrix4x4::interpolateLinear(
402  animationMatrices[matrixAtLast + nodeAnimationState->setup->getStartFrame()],
403  animationMatrices[matrixAtCurrent + nodeAnimationState->setup->getStartFrame()],
404  t
405  );
406  } else {
407  transformMatrix.set(animationMatrices[matrixAtCurrent + nodeAnimationState->setup->getStartFrame()]);
408  }
409  } else {
410  if (flattenedNode.nodeOverriddenTransformMatrix != nullptr) {
411  transformMatrix.set(*flattenedNode.nodeOverriddenTransformMatrix);
412  } else {
413  // no animation matrix, set up local transform matrix up as node matrix
414  transformMatrix.set(*flattenedNode.nodeTransformMatrix);
415  }
416  }
417  // apply parent transform matrix
418  transformMatrix.multiply(flattenedNode.parentTransformMatrix != nullptr?*flattenedNode.parentTransformMatrix:parentTransformMatrix);
419  // put and associate transform matrices with node
420  flattenedNode.transformMatrix->set(transformMatrix);
421  }
422 }
423 
425  for (auto& skinningNodeNodeSkinningJoints: skinningNodesNodeSkinningJoints)
426  for (auto& skinningNodeNodeSkinningJoint: skinningNodeNodeSkinningJoints) {
427  skinningNodeNodeSkinningJoint.skinningNodeTransformMatrix->set(skinningNodeNodeSkinningJoint.joint->getBindMatrix()).multiply(*skinningNodeNodeSkinningJoint.nodeTransformMatrix);
428  }
429 }
430 
431 void ObjectAnimation::computeAnimation(vector<FlattenedNode>& nodeList, const Matrix4x4& instanceTransformMatrix, AnimationState& baseAnimation, int contextIdx, int64_t lastFrameAtTime, int64_t currentFrameAtTime)
432 {
433  // do transform if we have a animation
434  if (baseAnimation.setup != nullptr) {
435  // animation timing
436  // do progress of base animation
437  if (lastFrameAtTime != Timing::UNDEFINED && baseAnimation.lastAtTime != -1LL) {
438  baseAnimation.currentAtTime+= currentFrameAtTime - lastFrameAtTime;
439  }
440  // do progress of overlay animations
441  for (const auto& [id, overlayAnimationState]: overlayAnimationsById) {
442  if (lastFrameAtTime != Timing::UNDEFINED && overlayAnimationState->lastAtTime != -1LL) {
443  overlayAnimationState->currentAtTime+= currentFrameAtTime - lastFrameAtTime;
444  }
445  overlayAnimationState->lastAtTime = overlayAnimationState->currentAtTime;
446  }
447  // set up parent transform matrix
448  Matrix4x4 parentTransformMatrix;
449  parentTransformMatrix.set(model->getImportTransformMatrix());
450  if (animationProcessingTarget == Engine::AnimationProcessingTarget::CPU_NORENDERING) {
451  parentTransformMatrix.multiply(instanceTransformMatrix);
452  }
453  // calculate transform matrices
454  computeNodesTransformMatrices(nodeList, parentTransformMatrix, &baseAnimation);
455  //
456  baseAnimation.lastAtTime = baseAnimation.currentAtTime;
457  } else
458  if (animationProcessingTarget == Engine::AnimationProcessingTarget::CPU_NORENDERING) {
459  // set up parent transform matrix
460  Matrix4x4 parentTransformMatrix;
461  parentTransformMatrix.set(model->getImportTransformMatrix());
462  if (animationProcessingTarget == Engine::AnimationProcessingTarget::CPU_NORENDERING) {
463  parentTransformMatrix.multiply(instanceTransformMatrix);
464  }
465  // calculate transform matrices
466  computeNodesTransformMatrices(nodeList, parentTransformMatrix, &baseAnimation);
467  }
468 }
469 
470 void ObjectAnimation::computeAnimation(int contextIdx, const Matrix4x4& instanceTransformMatrix, int64_t lastFrameAtTime, int64_t currentFrameAtTime) {
471  // compute last animation matrices if required
472  auto baseAnimationIdxLast = transformMatrices.size() > 1?(baseAnimationIdx + 1) % 2:-1;
473  if (baseAnimationIdxLast != -1 &&
474  baseAnimations[baseAnimationIdxLast].lastAtTime != -1LL) {
475  computeAnimation(nodeLists[1 + baseAnimationIdxLast], instanceTransformMatrix, baseAnimations[baseAnimationIdxLast], contextIdx, lastFrameAtTime, currentFrameAtTime);
476  } else {
477  baseAnimationIdxLast = -1;
478  }
479 
480  // compute current animation matrices
481  computeAnimation(nodeLists[nodeLists.size() > 1?1 + baseAnimationIdx:baseAnimationIdx], instanceTransformMatrix, baseAnimations[baseAnimationIdx], contextIdx, lastFrameAtTime, currentFrameAtTime);
482 
483  // blend if required
484  if (transformMatrices.size() > 1) {
485  for (auto i = 0; i < nodeLists[0].size(); i++) {
486  if (baseAnimationIdxLast != -1 &&
487  baseAnimations[baseAnimationIdxLast].endAtTime != -1LL) {
488  auto blendingAnimationDuration = static_cast<float>(baseAnimations[baseAnimationIdxLast].currentAtTime - baseAnimations[baseAnimationIdxLast].endAtTime) / Engine::getAnimationBlendingTime();
489  *nodeLists[0][i].transformMatrix = Matrix4x4::interpolateLinear(
490  *nodeLists[1 + baseAnimationIdxLast][i].transformMatrix,
491  *nodeLists[1 + baseAnimationIdx][i].transformMatrix,
492  Math::min(
493  blendingAnimationDuration,
494  1.0f
495  )
496  );
497  if (blendingAnimationDuration >= 1.0f) {
498  auto& animationStateLast = baseAnimations[baseAnimationIdxLast];
499  animationStateLast.setup = nullptr;
500  animationStateLast.endAtTime = -1LL;
501  animationStateLast.currentAtTime = -1LL;
502  animationStateLast.lastAtTime = -1LL;
503  animationStateLast.finished = true;
504  animationStateLast.time = -1LL;
505  }
506  } else {
507  nodeLists[0][i].transformMatrix->set(*nodeLists[1 + baseAnimationIdx][i].transformMatrix);
508  }
509  }
510  }
511  if (hasSkinning == true) updateSkinningJoints();
512 }
513 
514 int32_t ObjectAnimation::determineSkinnedNodeCount(const unordered_map<string, Node*>& nodes)
515 {
516  return determineSkinnedNodeCount(nodes, 0);
517 }
518 
519 int32_t ObjectAnimation::determineSkinnedNodeCount(const unordered_map<string, Node*>& nodes, int32_t count)
520 {
521  // iterate through nodes
522  for (const auto& [nodeId, node]: nodes) {
523  //
524  if (node->getSkinning() != nullptr)
525  count++;
526  // calculate sub nodes
527  const auto& subNodes = node->getSubNodes();
528  if (subNodes.size() > 0) {
529  count = determineSkinnedNodeCount(subNodes, count);
530  }
531  }
532  return count;
533 }
534 
535 int32_t ObjectAnimation::determineSkinnedNodes(const unordered_map<string, Node*>& nodes, vector<Node*>& skinningNodes, int32_t idx)
536 {
537  // iterate through nodes
538  for (const auto& [nodeId, node]: nodes) {
539  // fetch skinning nodes
540  if (node->getSkinning() != nullptr) {
541  skinningNodes[idx++] = node;
542  }
543  // calculate sub nodes
544  const auto& subNodes = node->getSubNodes();
545  if (subNodes.size() > 0) {
546  idx = determineSkinnedNodes(subNodes, skinningNodes, idx);
547  }
548  }
549  return idx;
550 }
551 
552 unordered_map<string, Matrix4x4*>* ObjectAnimation::getSkinningNodesTransformMatrices(Node* node)
553 {
554  if (hasSkinning == false) return nullptr;
555  for (auto i = 0; i < skinningNodes.size(); i++) {
556  if (skinningNodes[i] == node) {
557  return &skinningNodesMatrices[i];
558  }
559  }
560  return nullptr;
561 }
Engine main class.
Definition: Engine.h:131
static float getAnimationBlendingTime()
Definition: Engine.h:700
Timing class.
Definition: Timing.h:16
static constexpr int64_t UNDEFINED
Definition: Timing.h:20
Joint / Bone.
Definition: Joint.h:19
Representation of a 3D model.
Definition: Model.h:35
unordered_map< string, Node * > & getSubNodes()
Returns object's sub nodes.
Definition: Model.h:220
AnimationSetup * getAnimationSetup(const string &id)
Definition: Model.h:274
const Matrix4x4 & getImportTransformMatrix()
Definition: Model.h:340
const string & getId()
Definition: Model.h:128
Model node.
Definition: Node.h:32
Skinning definition for nodes.
Definition: Skinning.h:25
void setAnimation(const string &id, float speed=1.0f)
Sets up a base animation to play.
vector< unordered_map< string, Matrix4x4 * > > transformMatrices
void computeNodesTransformMatrices(vector< FlattenedNode > &nodeList, const Matrix4x4 parentTransformMatrix, AnimationState *animationState)
Comutes all nodes transform matrices.
const Matrix4x4 getNodeTransformMatrix(const string &id)
Returns transform matrix for given node.
void setNodeTransformMatrix(const string &id, const Matrix4x4 &matrix)
Set transform matrix for given node.
void computeAnimation(vector< FlattenedNode > &nodeList, const Matrix4x4 &instanceTransformMatrix, AnimationState &baseAnimation, int contextIdx, int64_t lastFrameAtTime, int64_t currentFrameAtTime)
Compute animation for given animation state into nodes transform matrices given by flattened node lis...
void addOverlayAnimation(const string &id)
Overlays a animation above the base animation.
unordered_map< string, AnimationState * > overlayAnimationsById
Engine::AnimationProcessingTarget animationProcessingTarget
float getOverlayAnimationTime(const string &id)
Returns current overlay animation time.
void createNodesTransformMatrices(unordered_map< string, Matrix4x4 * > &matrices, vector< FlattenedNode > &nodeList, const unordered_map< string, Node * > &nodes, Matrix4x4 *parentTransformMatrix=nullptr, AnimationState *animationState=nullptr)
Creates all nodes transform matrices.
void removeOverlayAnimation(const string &id)
Removes a overlay animation.
bool hasOverlayAnimation(const string &id)
Returns if there is currently running a overlay animation with given id.
unordered_map< string, Matrix4x4 * > overriddenTransformMatrices
void updateSkinningJoints()
Update skinning transform matrices.
vector< vector< NodeSkinningJoint > > skinningNodesNodeSkinningJoints
unordered_map< string, AnimationState * > overlayAnimationsByJointId
unordered_map< string, Matrix4x4 * > * getSkinningNodesTransformMatrices(Node *node)
Get skinning nodes transform matrices.
int32_t determineSkinnedNodeCount(const unordered_map< string, Node * > &nodes)
Determine skinned node count.
void setAnimationSpeed(float speed)
Set up animation speed.
vector< unordered_map< string, Matrix4x4 * > > skinningNodesMatrices
void removeOverlayAnimations()
Removes all overlay animations.
void updateNodeList(vector< FlattenedNode > &nodeList, int &nodeIdx, const unordered_map< string, Node * > &nodes, AnimationState *animationState=nullptr)
Update node list.
void unsetNodeTransformMatrix(const string &id)
Unset transform matrix for given node.
float getAnimationTime()
Returns current base animation time.
void removeFinishedOverlayAnimations()
Removes all finished overlay animations.
int32_t determineSkinnedNodes(const unordered_map< string, Node * > &nodes, vector< Node * > &skinningNodes, int32_t idx)
Determine skinned nodes.
Standard math functions.
Definition: Math.h:19
Matrix4x4 class representing matrix4x4 mathematical structure and operations for 3d space.
Definition: Matrix4x4.h:23
Matrix4x4 & identity()
Creates identity matrix.
Definition: Matrix4x4.h:158
Vector3 multiply(const Vector3 &vector3) const
Multiplies this matrix with vector3.
Definition: Matrix4x4.h:225
Matrix4x4 & set(float r0c0, float r0c1, float r0c2, float r0c3, float r1c0, float r1c1, float r1c2, float r1c3, float r2c0, float r2c1, float r2c2, float r2c3, float r3c0, float r3c1, float r3c2, float r3c3)
Sets this matrix by its components.
Definition: Matrix4x4.h:108
Vector3 class representing vector3 mathematical structure and operations with x, y,...
Definition: Vector3.h:20
Vector3 & set(float x, float y, float z)
Sets this vector3 by its components.
Definition: Vector3.h:70
Console class.
Definition: Console.h:29