Developer Documentation
SkeletonEditingScripting.cc
1/*===========================================================================*\
2* *
3* OpenFlipper *
4 * Copyright (c) 2001-2015, RWTH-Aachen University *
5 * Department of Computer Graphics and Multimedia *
6 * All rights reserved. *
7 * www.openflipper.org *
8 * *
9 *---------------------------------------------------------------------------*
10 * This file is part of OpenFlipper. *
11 *---------------------------------------------------------------------------*
12 * *
13 * Redistribution and use in source and binary forms, with or without *
14 * modification, are permitted provided that the following conditions *
15 * are met: *
16 * *
17 * 1. Redistributions of source code must retain the above copyright notice, *
18 * this list of conditions and the following disclaimer. *
19 * *
20 * 2. Redistributions in binary form must reproduce the above copyright *
21 * notice, this list of conditions and the following disclaimer in the *
22 * documentation and/or other materials provided with the distribution. *
23 * *
24 * 3. Neither the name of the copyright holder nor the names of its *
25 * contributors may be used to endorse or promote products derived from *
26 * this software without specific prior written permission. *
27 * *
28 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS *
29 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED *
30 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A *
31 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER *
32 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, *
33 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, *
34 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR *
35 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF *
36 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING *
37 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS *
38 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *
39* *
40\*===========================================================================*/
41
42
43
44#include "SkeletonEditingPlugin.hh"
45
47#include <ObjectTypes/Skeleton/Helper/SkeletonTransform.hh>
48#include <ACG/Geometry/Algorithms.hh>
49
50//------------------------------------------------------------------------------
51
56
57 emit setSlotDescription("splitBone(int,int)",
58 tr("insert a joint in the middle of a bone."),
59 QString(tr("objectId,jointId")).split(","),
60 QString(tr("ID of an object,ID of tail joint")).split(","));
61
62 emit
63 setSlotDescription(
64 "addJoint(int,int,Vector)",
65 tr("add a joint to the skeleton."),
66 QString(tr("objectId,jointId,Vector")).split(","),
67 QString(
68 tr(
69 "ID of an object,ID of parent joint,Position for the new joint")).split(
70 ","));
71
72 emit setSlotDescription("deleteJoint(int,int)",
73 tr("delete a joint from the skeleton."),
74 QString(tr("objectId,jointId")).split(","),
75 QString(tr("ID of an object,ID of a joint")).split(","));
76
77 emit setSlotDescription(
78 "transformJoint(int,int,Matrix4x4)",
79 tr("transform a joint with a matrix."),
80 QString(tr("objectId,jointId,Matrix")).split(","),
81 QString(tr("ID of an object,ID of a joint,transformation matrix")).split(
82 ","));
83
84 emit setSlotDescription("globalMatrix(int,int)",
85 tr("get the global matrix of a joint in the active pose."),
86 QString(tr("objectId,jointId")).split(","),
87 QString(tr("ID of an object,ID of a joint")).split(","));
88
89 emit setSlotDescription("localMatrix(int,int)",
90 tr("get the local matrix of a joint in the active pose."),
91 QString(tr("objectId,jointId")).split(","),
92 QString(tr("ID of an object,ID of a joint")).split(","));
93
94 emit setSlotDescription("globalTranslation(int,int)",
95 tr("get the global translation of a joint in the active pose."),
96 QString(tr("objectId,jointId")).split(","),
97 QString(tr("ID of an object,ID of a joint")).split(","));
98
99 emit setSlotDescription("localTranslation(int,int)",
100 tr("get the local translation of a joint in the active pose."),
101 QString(tr("objectId,jointId")).split(","),
102 QString(tr("ID of an object,ID of a joint")).split(","));
103
104 emit setSlotDescription("animationCount(int)",
105 tr("get the number of animations the skeleton has."),
106 QString(tr("objectId")).split(","),
107 QString(tr("ID of an object")).split(","));
108
109 emit setSlotDescription("frameCount(int,int)",
110 tr("get the number of frames a given animation has."),
111 QString(tr("objectId,animationIndex")).split(","),
112 QString(tr("ID of an object,Index of an animation")).split(","));
113
114 emit setSlotDescription("activeAnimation(int)",
115 tr("get the animation which is currently active."),
116 QString(tr("objectId")).split(","),
117 QString(tr("ID of an object")).split(","));
118
119 emit setSlotDescription("activeFrame(int)",
120 tr("get the frame which is currently active"),
121 QString(tr("objectId")).split(","),
122 QString(tr("ID of an object")).split(","));
123
124 emit
125 setSlotDescription(
126 "setActivePose(int,int,int)",
127 tr("set the active pose of the skeleton."),
128 QString(tr("objectId,animationIndex,frame")).split(","),
129 QString(tr("ID of an object,Index of an animation,Index of a frame")).split(
130 ","));
131
132 emit
133 setSlotDescription(
134 "addAnimation(int,QString,int)",
135 tr("add an animation to the skeleton."),
136 QString(tr("objectId,AnimationName,frameCount")).split(","),
137 QString(
138 tr(
139 "ID of an object,name for the animation,number of frames the animation should have")).split(
140 ","));
141}
142
143//------------------------------------------------------------------------------
144
146void SkeletonEditingPlugin::splitBone(int _objectId, int _tailJoint) {
147
148 BaseObjectData* baseObject = 0;
149 PluginFunctions::getObject(_objectId, baseObject);
150
151 if (baseObject == 0)
152 return;
153
154 Skeleton* skeleton = PluginFunctions::skeleton(baseObject);
155
156 if (skeleton == 0)
157 return;
158
159 Skeleton::Joint* tailJoint = skeleton->joint(_tailJoint);
160
161 if (tailJoint == 0) {
162 emit log(
163 LOGERR,
164 tr("Cannot split bone. Unable to find joint with id ")
165 + QString::number(_tailJoint));
166 return;
167 }
168
169 Skeleton::Joint* headJoint = tailJoint->parent();
170
171 //add the new joint
172 Skeleton::Joint* jointNew = new Skeleton::Joint(headJoint);
173 skeleton->addJoint(headJoint, jointNew);
174 tailJoint->setParent(jointNew, *skeleton);
175
176 //set position in refPose
177 Skeleton::Pose* refPose = skeleton->referencePose();
178 refPose->setGlobalTranslation(
179 jointNew->id(),
180 0.5 * refPose->globalTranslation(headJoint->id()) + 0.5
181 * refPose->globalTranslation(tailJoint->id()));
182
183 //set position in animations
184 for (unsigned int a = 0; a < skeleton->animationCount(); a++)
185 if (AnimationHandle(a, 0).isValid()) {
186
187 AnimationT<ACG::Vec3d> *animation = skeleton->animation(
188 AnimationHandle(a, 0));
189
190 if (animation != 0) {
191
192 //set initial joint translation
193 for (int iFrame = 0; iFrame < (int) animation->frameCount(); iFrame++) {
194
195 PoseT<ACG::Vec3d>* pose = skeleton->pose(AnimationHandle(a, iFrame));
196
197 pose->setGlobalMatrix(jointNew->id(),
198 pose->globalMatrix(headJoint->id()));
200 jointNew->id(),
201 0.5 * pose->globalTranslation(headJoint->id()) + 0.5
202 * pose->globalTranslation(tailJoint->id()));
203 }
204 }
205 }
206
207 emit updatedObject(_objectId, UPDATE_GEOMETRY);
208
209 emit scriptInfo("splitBone( ObjectId, " + QString::number(_tailJoint) + " )");
210
211 // Create backup
212 emit createBackup(_objectId, "Split Bone", UPDATE_TOPOLOGY);
213}
214
215//------------------------------------------------------------------------------
216
218void SkeletonEditingPlugin::addJoint(int _objectId, int _parent,
219 Vector _position) {
220
221 BaseObjectData* baseObject = 0;
222 PluginFunctions::getObject(_objectId, baseObject);
223
224 if (baseObject == 0)
225 return;
226
227 Skeleton* skeleton = PluginFunctions::skeleton(baseObject);
228
229 if (skeleton == 0)
230 return;
231
232 Skeleton::Joint* parent = skeleton->joint(_parent);
233
234 if (parent == 0) {
235 emit log(
236 LOGERR,
237 tr("Cannot add joint. Unable to find joint with id ")
238 + QString::number(_parent));
239 return;
240 }
241
242 //add the new joint
243 Skeleton::Joint* jointNew = new Skeleton::Joint(parent);
244 skeleton->addJoint(parent, jointNew);
245
246 //set the position
247
248 setJointPosition(PluginFunctions::skeletonObject(baseObject), jointNew,
249 _position);
250 emit updatedObject(_objectId, UPDATE_ALL);
251
252 emit scriptInfo(
253 "addJoint( ObjectId, " + QString::number(_parent) + ", Vector("
254 + QString::number(_position[0]) + "," + QString::number(_position[1])
255 + "," + QString::number(_position[2]) + ") )");
256
257 // Create backup
258 emit createBackup(_objectId, "Add Joint", UPDATE_TOPOLOGY);
259}
260
261//------------------------------------------------------------------------------
262
264void SkeletonEditingPlugin::deleteJoint(int _objectId, int _jointId) {
265
266 BaseObjectData* baseObject = 0;
267 PluginFunctions::getObject(_objectId, baseObject);
268
269 if (baseObject == 0)
270 return;
271
272 Skeleton* skeleton = PluginFunctions::skeleton(baseObject);
273
274 if (skeleton == 0)
275 return;
276
277 Skeleton::Joint* joint = skeleton->joint(_jointId);
278
279 if (joint == 0) {
280 emit log(
281 LOGERR,
282 tr("Cannot Remove joint. Unable to find joint with id ")
283 + QString::number(_jointId));
284 return;
285 }
286
287 skeleton->removeJoint(joint);
288
289 emit scriptInfo("deleteJoint( ObjectId, " + QString::number(_jointId) + " )");
290
291 // Create backup
292 emit createBackup(_objectId, "Delete Joint", UPDATE_TOPOLOGY);
293
294 emit updatedObject(_objectId, UPDATE_ALL);
295}
296
297//------------------------------------------------------------------------------
298
300void SkeletonEditingPlugin::transformJoint(int _objectId, int _jointId,
301 Matrix4x4 _matrix) {
302
303 BaseObjectData* obj = 0;
304
305 PluginFunctions::getObject(_objectId, obj);
306
307 if (obj == 0) {
308 emit log(LOGERR, tr("Unable to get object"));
309 return;
310 }
311
313
314 if (skeletonObj == 0) {
315 emit log(LOGERR, tr("Unable to get skeletonObject"));
316 return;
317 }
318
319 Skeleton* skeleton = PluginFunctions::skeleton(obj);
320
321 if (skeleton == 0) {
322 emit log(LOGERR, tr("Unable to get skeleton"));
323 return;
324 }
325
326 Skeleton::Joint* joint = skeleton->joint(_jointId);
327
328 if (joint == 0) {
329 emit log(LOGERR, tr("Unable to get joint"));
330 return;
331 }
332
333 bool recursiveJointTransformation = transformChildJoints_;
334
335 AnimationHandle handle = skeletonObj->skeletonNode()->activePose();
336
337 Skeleton::Pose* activePose;
338
339 if (!handle.isValid()) { // reference pose
340 activePose = skeleton->referencePose();
341 } else { // animation pose
342
343 activePose = skeleton->animation(handle.animationIndex())->pose(
344 handle.frame());
345
346 //always transform children otherwise only the local coordsys is rotated
347 recursiveJointTransformation = true;
348
349 // translation changes the skeleton structure
350 // this is only allowed in refPose therefore delete translation
351 Matrix4x4 mat = _matrix;
352 mat(0, 3) = 0.0;
353 mat(1, 3) = 0.0;
354 mat(2, 3) = 0.0;
355 if (mat.is_identity())
356 _matrix = mat;
357 }
358
359 SkeletonTransform transformer(*skeleton);
360
361 if (handle.isValid()) { // animation pose
362
363 //we are in an animation pose -> only rotation allowed
364 transformer.rotateJoint(joint, activePose, _matrix, transformAllFrames_);
365
366 //update the skin
367 bool exists = false;
368
369 emit functionExists("skeletalanimation", "updateSkin()", exists);
370
371 if (exists)
372 RPC::callFunction("skeletalanimation", "updateSkin");
373
374 } else { // reference pose
375
376 // full transformation
377 if (_matrix(0, 0) != 1 || _matrix(1, 1) != 1 || _matrix(2, 2) != 1
378 || _matrix(0, 1) != 0 || _matrix(0, 2) != 0 || _matrix(1, 0) != 0
379 || _matrix(1, 2) != 0 || _matrix(2, 0) != 0 || _matrix(2, 1) != 0) {
380 // apply full transformation
381 transformer.transformJoint(joint, _matrix, !recursiveJointTransformation);
382
383 } else { // translation only
384
385 if (_matrix(0, 3) == 0 && _matrix(1, 3) == 0 && _matrix(2, 3) == 0) // no translation
386 return;
387
388 if (joint->isRoot()) {
389
390 /*
391 * Change translation of root joint.
392 */
393
394 transformer.translateJoint(joint, ACG::Vec3d(_matrix(0, 3), _matrix(1, 3), _matrix(2, 3)), !transformChildJoints_);
395
396 } else {
397
398 /*
399 * Change translation of non-root joint.
400 *
401 * In these cases, the rotation of the coordinate frame of the parent
402 * joint (unless it is not a branching joint) as well as the
403 * the rotation of the coordinate frame of the current joint have to be
404 * corrected in the following way:
405 *
406 * We compute the rotation of the affected joints' coordinate system
407 * such that the local(!) translation of the respective child
408 * joint remains constant. So, in 2D, consider configuration
409 * A --> B --> C, where C is a child of B is a child of A.
410 * If C has translation (2, 0) and B has translation (3,5), then, after
411 * global translation of B, the coordinate frames of A and B have to be rotated
412 * such that the joint axes remain constant, so B lies on the line (0,0) + x*(3,5)
413 * with respect to A's coordinate system and C lies somewhere on the line (0,0) + y*(2,0)
414 * with respect to B's coordinate system.
415 *
416 */
417
418 // init params
419 bool parentIsNotBranch = (joint->parent()->size() == 1);
420 bool hasOneChild = (joint->size() == 1);
421 ACG::Vec3d oldParentAxis(0.0, 0.0, 0.0);
422 ACG::Vec3d oldJointAxis(0.0, 0.0, 0.0);
423 ACG::Vec3d transParentAxis(0.0, 0.0, 0.0);
424 ACG::Vec3d transJointAxis(0.0, 0.0, 0.0);
425 ACG::Vec3d parentRotAxis(0.0, 0.0, 0.0);
426 ACG::Vec3d jointRotAxis(0.0, 0.0, 0.0);
427 double parentRotAngle = 0.0;
428 double jointRotAngle = 0.0;
429
430 // get the original parent axis: parent joint -----> current joint
431 oldParentAxis = activePose->localTranslation(_jointId);
432 // get the original joint axis: current joint -----> child joint
433 if (hasOneChild)
434 oldJointAxis = activePose->localTranslation(joint->child(0)->id());
435
436 // store the joint axes of all animations before the translation of the current joint
437 // so that the rotations can be calculated for the animation poses
438 std::vector<ACG::Vec3d> oldAnimJoint, oldAnimParent;
439 for (unsigned int a = 0; a < skeleton->animationCount(); ++a) {
440 for (unsigned int iFrame = 0; iFrame < skeleton->animation(a)->frameCount(); iFrame++) {
441 Skeleton::Pose* pose = skeleton->animation(a)->pose(iFrame);
442
443 if (hasOneChild)
444 oldAnimJoint.push_back(pose->localTranslation(joint->child(0)->id()));
445
446 oldAnimParent.push_back(pose->localTranslation(_jointId));
447 }
448 }
449
450 // translate the joint
451 transformer.translateJoint(joint, ACG::Vec3d(_matrix(0, 3), _matrix(1, 3), _matrix(2, 3)), !transformChildJoints_);
452
453 // get translated parent axis
454 transParentAxis = activePose->localTranslation(_jointId);
455
456 if (hasOneChild) {
457 // get translated joint axis
458 transJointAxis = activePose->localTranslation(joint->child(0)->id());
459 }
460
461 // now calculate the rotation that has to occur for a translation of the joint:
462
463 // get the rotation axis and angle between the old and new parent axis
464 if (!ACG::Geometry::rotationOfTwoVectors<double>(oldParentAxis, transParentAxis, parentRotAxis, parentRotAngle))
465 return;
466
467 // get rotation axis and angle between old and new joint axis
468 if (hasOneChild) {
469 if (!ACG::Geometry::rotationOfTwoVectors<double>(oldJointAxis, transJointAxis, jointRotAxis, jointRotAngle))
470 return;
471 }
472
473 if (parentIsNotBranch) {
474 // parent rotation matrix
475 ACG::GLMatrixT<double> parentRotMatrix;
476 parentRotMatrix.identity();
477 parentRotMatrix.rotate(parentRotAngle, parentRotAxis);
478
479 // apply rotation to parent joint
480 ACG::Matrix4x4d localParent = activePose->localMatrix(joint->parent()->id());
481 localParent *= parentRotMatrix;
482 activePose->setLocalMatrix(joint->parent()->id(), localParent, false);
483 }
484
485 if (hasOneChild) {
486 // joint rotation matrix
487 ACG::GLMatrixT<double> jointRotMatrix;
488 jointRotMatrix.identity();
489 jointRotMatrix.rotate(jointRotAngle, jointRotAxis);
490
491 // apply current joint
492 ACG::Matrix4x4d localJoint = activePose->localMatrix(joint->id());
493 localJoint *= jointRotMatrix;
494 activePose->setLocalMatrix(joint->id(), localJoint, false);
495 }
496
497 // apply rotations to animation
498 std::vector<ACG::Vec3d>::iterator jointIt, parentIt;
499 jointIt = oldAnimJoint.begin();
500 parentIt = oldAnimParent.begin();
501 for (unsigned int a = 0; a < skeleton->animationCount(); ++a) {
502 for (unsigned int iFrame = 0; iFrame < skeleton->animation(a)->frameCount(); iFrame++) {
503 Skeleton::Pose* pose = skeleton->animation(a)->pose(iFrame);
504
505 // only apply rotation to parent joint if it is not a branch
506 if (parentIsNotBranch) {
507
508 // get the rotation axis and angle between the old and new parent axis
509 ACG::Vec3d translatedParent = pose->localTranslation(_jointId);
510 ACG::Vec3d parentRotAxis(0.0, 0.0, 0.0);
511 double parentRotAngle = 0.0;
512 if (!ACG::Geometry::rotationOfTwoVectors<double>(*parentIt, translatedParent, parentRotAxis,
513 parentRotAngle))
514 return;
515
516 // parent rotation matrix
517 ACG::GLMatrixT<double> parentRotMatrix;
518 parentRotMatrix.identity();
519 parentRotMatrix.rotate(parentRotAngle, parentRotAxis);
520
521 // apply rotation to parent joint
522 ACG::Matrix4x4d parentMat = pose->localMatrix(joint->parent()->id());
523 parentMat *= parentRotMatrix;
524 pose->setLocalMatrix(joint->parent()->id(), parentMat, false);
525
526 ++parentIt;
527 }
528
529 if (hasOneChild) {
530 // get rotation axis and angle between old and new joint axis
531 ACG::Vec3d translatedAxis = pose->localTranslation(joint->child(0)->id());
532 ACG::Vec3d jointRotAxis(0.0, 0.0, 0.0);
533 double jointRotAngle = 0.0;
534
535 if (!ACG::Geometry::rotationOfTwoVectors<double>(*jointIt, translatedAxis, jointRotAxis, jointRotAngle))
536 return;
537
538 // joint rotation matrix
539 ACG::GLMatrixT<double> jointRotMatrix;
540 jointRotMatrix.identity();
541 jointRotMatrix.rotate(jointRotAngle, jointRotAxis);
542
543 // apply rotation to current joint
544 ACG::Matrix4x4d localMat = pose->localMatrix(joint->id());
545 localMat *= jointRotMatrix;
546 pose->setLocalMatrix(joint->id(), localMat, false);
547
548 ++jointIt;
549 }
550 }
551 }
552 }
553 }
554 }
555
556 emit updatedObject(_objectId, UPDATE_GEOMETRY);
557
558 QString matString;
559 for (int i = 0; i < 4; i++)
560 for (int j = 0; j < 4; j++)
561 matString += " , " + QString::number(_matrix(i, j));
562
563 matString = matString.right(matString.length() - 3);
564
565 emit scriptInfo(
566 "transformJoint( ObjectId, " + QString::number(_jointId) + ", Matrix4x4("
567 + matString + " ) )");
568
569 // Create backup if there was a change
570 // the backup is only created when the slot is called via scripting (sender == 0)
571 if (!_matrix.is_identity() && (sender() == 0))
572 emit createBackup(_objectId, "Joint Transformation", UPDATE_GEOMETRY);
573}
574
575//------------------------------------------------------------------------------
576
578Matrix4x4 SkeletonEditingPlugin::globalMatrix(int _objectId, int _jointId) {
579
580 BaseObjectData* obj = 0;
581
582 PluginFunctions::getObject(_objectId, obj);
583
584 if (obj == 0) {
585 emit log(LOGERR, tr("Unable to get object"));
586 return Matrix4x4();
587 }
588
590
591 if (skeletonObj == 0) {
592 emit log(LOGERR, tr("Unable to get skeletonObject"));
593 return Matrix4x4();
594 }
595
596 Skeleton* skeleton = PluginFunctions::skeleton(obj);
597 Skeleton::Joint* joint = skeleton->joint(_jointId);
598
599 if (joint == 0) {
600 emit log(LOGERR, tr("Unable to get joint"));
601 return Matrix4x4();
602 }
603
604 AnimationHandle handle = skeletonObj->skeletonNode()->activePose();
605
606 Skeleton::Pose* activePose;
607
608 if (!handle.isValid())
609 activePose = skeleton->referencePose();
610 else
611 activePose = skeleton->animation(handle.animationIndex())->pose(
612 handle.frame());
613
614 emit
615 scriptInfo("globalMatrix( ObjectId, " + QString::number(_jointId) + " )");
616 return activePose->globalMatrix(joint->id());
617}
618
619//------------------------------------------------------------------------------
620
622Matrix4x4 SkeletonEditingPlugin::localMatrix(int _objectId, int _jointId) {
623
624 BaseObjectData* obj = 0;
625
626 PluginFunctions::getObject(_objectId, obj);
627
628 if (obj == 0) {
629 emit log(LOGERR, tr("Unable to get object"));
630 return Matrix4x4();
631 }
632
634
635 if (skeletonObj == 0) {
636 emit log(LOGERR, tr("Unable to get skeletonObject"));
637 return Matrix4x4();
638 }
639
640 Skeleton* skeleton = PluginFunctions::skeleton(obj);
641 Skeleton::Joint* joint = skeleton->joint(_jointId);
642
643 if (joint == 0) {
644 emit log(LOGERR, tr("Unable to get joint"));
645 return Matrix4x4();
646 }
647
648 AnimationHandle handle = skeletonObj->skeletonNode()->activePose();
649
650 Skeleton::Pose* activePose;
651
652 if (!handle.isValid())
653 activePose = skeleton->referencePose();
654 else
655 activePose = skeleton->animation(handle.animationIndex())->pose(
656 handle.frame());
657
658 emit scriptInfo("localMatrix( ObjectId, " + QString::number(_jointId) + " )");
659 return activePose->localMatrix(joint->id());
660}
661
662//------------------------------------------------------------------------------
663
666
667 BaseObjectData* obj = 0;
668
669 PluginFunctions::getObject(_objectId, obj);
670
671 if (obj == 0) {
672 emit log(LOGERR, tr("Unable to get object"));
673 return Vector();
674 }
675
677
678 if (skeletonObj == 0) {
679 emit log(LOGERR, tr("Unable to get skeletonObject"));
680 return Vector();
681 }
682
683 Skeleton* skeleton = PluginFunctions::skeleton(obj);
684 Skeleton::Joint* joint = skeleton->joint(_jointId);
685
686 if (joint == 0) {
687 emit log(LOGERR, tr("Unable to get joint"));
688 return Vector();
689 }
690
691 AnimationHandle handle = skeletonObj->skeletonNode()->activePose();
692
693 Skeleton::Pose* activePose;
694
695 if (!handle.isValid())
696 activePose = skeleton->referencePose();
697 else
698 activePose = skeleton->animation(handle.animationIndex())->pose(
699 handle.frame());
700
701 emit scriptInfo(
702 "globalTranslation( ObjectId, " + QString::number(_jointId) + " )");
703 return activePose->globalTranslation(joint->id());
704}
705
706//------------------------------------------------------------------------------
707
710
711 BaseObjectData* obj = 0;
712
713 PluginFunctions::getObject(_objectId, obj);
714
715 if (obj == 0) {
716 emit log(LOGERR, tr("Unable to get object"));
717 return Vector();
718 }
719
721
722 if (skeletonObj == 0) {
723 emit log(LOGERR, tr("Unable to get skeletonObject"));
724 return Vector();
725 }
726
727 Skeleton* skeleton = PluginFunctions::skeleton(obj);
728 Skeleton::Joint* joint = skeleton->joint(_jointId);
729
730 if (joint == 0) {
731 emit log(LOGERR, tr("Unable to get joint"));
732 return Vector();
733 }
734
735 AnimationHandle handle = skeletonObj->skeletonNode()->activePose();
736
737 Skeleton::Pose* activePose;
738
739 if (!handle.isValid())
740 activePose = skeleton->referencePose();
741 else
742 activePose = skeleton->animation(handle.animationIndex())->pose(
743 handle.frame());
744
745 emit scriptInfo(
746 "localTranslation( ObjectId, " + QString::number(_jointId) + " )");
747 return activePose->localTranslation(joint->id());
748}
749
750//------------------------------------------------------------------------------
751
754
755 BaseObjectData* obj = 0;
756
757 PluginFunctions::getObject(_objectId, obj);
758
759 if (obj == 0) {
760 emit log(LOGERR, tr("Unable to get object"));
761 return -1;
762 }
763
765
766 if (skeletonObj == 0) {
767 emit log(LOGERR, tr("Unable to get skeletonObject"));
768 return -1;
769 }
770
771 Skeleton* skeleton = PluginFunctions::skeleton(obj);
772
773 emit scriptInfo("animationCount( ObjectId )");
774 return skeleton->animationCount();
775}
776
777//------------------------------------------------------------------------------
778
780int SkeletonEditingPlugin::frameCount(int _objectId, int _animationIndex) {
781
782 BaseObjectData* obj = 0;
783
784 PluginFunctions::getObject(_objectId, obj);
785
786 if (obj == 0) {
787 emit log(LOGERR, tr("Unable to get object"));
788 return -1;
789 }
790
792
793 if (skeletonObj == 0) {
794 emit log(LOGERR, tr("Unable to get skeletonObject"));
795 return -1;
796 }
797
798 Skeleton* skeleton = PluginFunctions::skeleton(obj);
799
800 if ((_animationIndex < 0) || (_animationIndex
801 > (int) skeleton->animationCount())) {
802 emit log(LOGERR, tr("Invalid animationIndex"));
803 return -1;
804 }
805
806 emit scriptInfo(
807 "frameCount( ObjectId, " + QString::number(_animationIndex) + " )");
808 return skeleton->animation(_animationIndex)->frameCount();
809}
810
811//------------------------------------------------------------------------------
812
815
816 BaseObjectData* obj = 0;
817
818 PluginFunctions::getObject(_objectId, obj);
819
820 if (obj == 0) {
821 emit log(LOGERR, tr("Unable to get object"));
822 return -1;
823 }
824
826
827 if (skeletonObj == 0) {
828 emit log(LOGERR, tr("Unable to get skeletonObject"));
829 return -1;
830 }
831
832 AnimationHandle handle = skeletonObj->skeletonNode()->activePose();
833
834 emit scriptInfo("activeAnimation( ObjectId )");
835 return handle.animationIndex();
836}
837
838//------------------------------------------------------------------------------
839
842 BaseObjectData* obj = 0;
843
844 PluginFunctions::getObject(_objectId, obj);
845
846 if (obj == 0) {
847 emit log(LOGERR, tr("Unable to get object"));
848 return -1;
849 }
850
852
853 if (skeletonObj == 0) {
854 emit log(LOGERR, tr("Unable to get skeletonObject"));
855 return -1;
856 }
857
858 AnimationHandle handle = skeletonObj->skeletonNode()->activePose();
859
860 emit scriptInfo("activeFrame( ObjectId )");
861 return handle.frame();
862}
863
864//------------------------------------------------------------------------------
865
867void SkeletonEditingPlugin::setActivePose(int _objectId, int _animationIndex,
868 int _frame) {
869 BaseObjectData* obj = 0;
870
871 PluginFunctions::getObject(_objectId, obj);
872
873 if (obj == 0) {
874 emit log(LOGERR, tr("Unable to get object"));
875 return;
876 }
877
879
880 if (skeletonObj == 0) {
881 emit log(LOGERR, tr("Unable to get skeletonObject"));
882 return;
883 }
884
885 Skeleton* skeleton = PluginFunctions::skeleton(obj);
886
887 if ((_animationIndex < 0) || (_animationIndex
888 > (int) skeleton->animationCount())) {
889 emit log(LOGERR, tr("Invalid animationIndex"));
890 return;
891 }
892
893 if ((_frame < 0) || (_frame
894 > (int) skeleton->animation(_animationIndex)->frameCount())) {
895 emit log(LOGERR, tr("Invalid frame"));
896 return;
897 }
898
899 skeletonObj->skeletonNode()->setActivePose(
900 AnimationHandle(_animationIndex, _frame));
901 emit updatedObject(_objectId, UPDATE_GEOMETRY);
902
903 emit scriptInfo(
904 "setActivePose( ObjectId, " + QString::number(_animationIndex) + ", "
905 + QString::number(_frame) + ")");
906}
907
908//------------------------------------------------------------------------------
909
911void SkeletonEditingPlugin::addAnimation(int _objectId, QString _name,
912 int _frames) {
913 BaseObjectData* obj = 0;
914
915 PluginFunctions::getObject(_objectId, obj);
916
917 if (obj == 0) {
918 emit log(LOGERR, tr("Unable to get object"));
919 return;
920 }
921
923
924 if (skeletonObj == 0) {
925 emit log(LOGERR, tr("Unable to get skeletonObject"));
926 return;
927 }
928
929 Skeleton* skeleton = PluginFunctions::skeleton(obj);
930
931 if (_frames <= 0) {
932 emit log(LOGERR, tr("Invalid frame count"));
933 return;
934 }
935
936 std::string stdName = _name.toStdString();
937
938 if (skeleton->animation(stdName) != 0) {
939 emit log(LOGERR, tr("Animation with this name already exists"));
940 return;
941 }
942
944 skeleton, _frames);
945 AnimationHandle handle = skeleton->addAnimation(stdName, animation);
946
947 //init pose to refPose
948 for (unsigned int i = 0; i < skeleton->animation(handle)->frameCount(); i++) {
949 handle.setFrame(i);
950 Skeleton::Pose* pose = skeleton->pose(handle);
951
952 for (unsigned int j = 0; j < skeleton->jointCount(); j++)
953 pose->setGlobalMatrix(j, skeleton->referencePose()->globalMatrix(j));
954 }
955
956 emit updatedObject(_objectId, UPDATE_ALL);
957 emit scriptInfo(
958 "addAnimation( ObjectId, " + _name + ", " + QString::number(_frames)
959 + ")");
960
961 // Create backup
962 emit createBackup(_objectId, "Add Animation", UPDATE_ALL);
963}
964
965//------------------------------------------------------------------------------
ACG::Matrix4x4d Matrix4x4
Standard Type for a 4x4 Matrix used for scripting.
Definition: DataTypes.hh:183
ACG::Vec3d Vector
Standard Type for 3d Vector used for scripting.
Definition: DataTypes.hh:176
@ LOGERR
void rotate(Scalar angle, Scalar x, Scalar y, Scalar z, MultiplyFrom _mult_from=MULT_FROM_RIGHT)
void identity()
setup an identity matrix
bool is_identity() const
check if the matrix is the identity ( up to an epsilon )
Definition: Matrix4x4T.hh:215
A handle used to refer to an animation or to a specific frame in an animation.
bool isValid() const
Returns true if the handle is valid.
size_t frame() const
Returns the selected frame (zero based)
void setFrame(size_t _iFrame)
Sets the current animation frame (not failsafe)
size_t animationIndex() const
Returns the animation index (zero based)
Represents a single joint in the skeleton.
Definition: JointT.hh:61
void setParent(Joint *_newParent, SkeletonT< PointT > &_skeleton)
access parent of the joint
Definition: JointT_impl.hh:122
size_t size() const
Returns the number of children.
Definition: JointT_impl.hh:197
size_t id() const
returns the joint id
Definition: JointT_impl.hh:97
Joint * child(size_t _index)
Returns the child joint with the given index.
Definition: JointT_impl.hh:211
Joint * parent()
Returns the parent joint.
Definition: JointT_impl.hh:156
A general pose, used to store the frames of the animation.
Definition: PoseT.hh:59
void setLocalMatrix(unsigned int _joint, const Matrix &_local, bool _keepLocalChildPositions=true)
Sets the local coordinate system.
Definition: PoseT_impl.hh:120
const Matrix & localMatrix(unsigned int _joint) const
Returns the local matrix for the given joint.
Definition: PoseT_impl.hh:104
void setGlobalTranslation(unsigned int _joint, const Vector &_position, bool _keepGlobalChildPositions=true)
Sets the global translation vector.
Definition: PoseT_impl.hh:249
const Matrix & globalMatrix(unsigned int _joint) const
Returns the global matrix for the given joint.
Definition: PoseT_impl.hh:193
Vector localTranslation(unsigned int _joint)
Returns the local translation vector.
Definition: PoseT_impl.hh:139
void setGlobalMatrix(unsigned int _joint, const Matrix &_global, bool _keepGlobalChildPositions=true)
Sets the global coordinate system.
Definition: PoseT_impl.hh:211
Vector globalTranslation(unsigned int _joint)
Returns the global translation vector.
Definition: PoseT_impl.hh:227
virtual void functionExists(QString _pluginName, QString _functionName, bool &_exists)
Definition: RPCInterface.hh:83
void transformJoint(int _objectId, int _jointId, Matrix4x4 _matrix)
transform joint with given matrix
int activeFrame(int _objectId)
get active frame
void addJoint(int _objectId, int _parent, Vector _position)
add joint to the skeleton
int animationCount(int _objectId)
get the number of animations
void addAnimation(int _objectId, QString _name, int _frames)
add animation
Matrix4x4 globalMatrix(int _objectId, int _jointId)
get global matrix of a joint in the active pose
void splitBone(int _objectId, int _tailJoint)
insert a joint in the middle of a bone given by its (unique) tailJoint
int frameCount(int _objectId, int _animationIndex)
get the number of frames
Matrix4x4 localMatrix(int _objectId, int _jointId)
get local matrix of a joint in the active pose
void setActivePose(int _objectId, int _animationIndex, int _frame)
set active pose
Vector globalTranslation(int _objectId, int _jointId)
get global translation of a joint in the active pose
Vector localTranslation(int _objectId, int _jointId)
get local translation of a joint in the active pose
void setDescriptions()
Set Descriptions for Scripting Slots.
int activeAnimation(int _objectId)
get active animation
ACG::SceneGraph::SkeletonNodeT< Skeleton > * skeletonNode()
Returns the skeleton scenegraph node.
Pose * referencePose()
Returns a pointer to the reference pose.
size_t jointCount()
Returns the number of joints.
void addJoint(typename SkeletonT< PointT >::Joint *_pParent, typename SkeletonT< PointT >::Joint *_pJoint)
Adds a joint as child of a given parent joint.
size_t animationCount()
Returns the number of animations stored in this skeleton.
AnimationHandle addAnimation(std::string _name, Animation *_animation)
Adds a new animation to the list.
Animation * animation(std::string _name)
Returns a pointer to the animation to the given name.
Pose * pose(const AnimationHandle &_hAni)
Returns a pointer to the pose with the given animation handle.
Joint * joint(const size_t &_index)
Returns the joint with the given index.
void removeJoint(typename SkeletonT< PointT >::Joint *_pJoint)
Remove the given joint from the tree.
Skeleton transformation class.
void transformJoint(Skeleton::Joint *_joint, Matrix4x4 _matrix, bool _keepChildPositions=true)
apply a transformation to a joint in the refPose
void rotateJoint(Skeleton::Joint *_joint, Skeleton::Pose *_pose, Matrix4x4 _rotation, bool _applyToWholeAnimation=true)
rotate a joint in an arbitrary Pose
void translateJoint(Skeleton::Joint *_joint, ACG::Vec3d _translation, bool _keepChildPositions=true)
apply a translation to a joint in the refPose
const UpdateType UPDATE_TOPOLOGY(UpdateTypeSet(8))
Topology updated.
const UpdateType UPDATE_ALL(UpdateTypeSet(1))
Identifier for all updates.
const UpdateType UPDATE_GEOMETRY(UpdateTypeSet(4))
Geometry updated.
SkeletonObject * skeletonObject(BaseObjectData *_object)
Cast an BaseObject to a SkeletonObject if possible.
bool getObject(const int _identifier, BaseObject *&_object)
Get the object which has the given identifier.
Skeleton * skeleton(BaseObjectData *_object)
Get a skeleton from an object.
void callFunction(QString _plugin, QString _functionName)
call a function in another plugin
Definition: RPCWrappers.cc:129