Developer Documentation
Loading...
Searching...
No Matches
SkeletonObject.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//=============================================================================
45//
46// MyTypes
47//
48//=============================================================================
49
50#define SKELETONOBJECT_C
51
52//== INCLUDES =================================================================
53
54#include <string>
55#include <sstream>
56#include <ACG/Scenegraph/TextNode.hh>
57#include <ACG/Scenegraph/LineNode.hh>
59#include "Skeleton.hh"
60
61#include <ACG/Scenegraph/MaterialNode.hh>
62#include <ACG/Scenegraph/SeparatorNode.hh>
63
64//== DEFINES ==================================================================
65
66//== TYPEDEFS =================================================================
67
68//== CLASS DEFINITION =========================================================
69
78 skeleton_(NULL),
79 skeletonNode_(NULL)
80{
82 init();
83}
84
85//-----------------------------------------------------------------------------
86
88 BaseObjectData(_other)
89{
90 init(_other.skeleton_);
91
92 setName(name());
93}
94
95//-----------------------------------------------------------------------------
96
101{
102 // Delete the data attached to this object ( this will remove all perObject data)
103 // Not the best way to do it but it will work.
104 // This is only necessary if people use references to the skeleton below and
105 // they do something with the skeleton in the destructor of their
106 // perObjectData.
107 deleteData();
108
109 // Delete the Skeleton only, if this object contains a mesh
110 if ( skeleton_ != NULL) {
111 delete skeleton_;
112 skeleton_ = NULL;
113 } else {
114 std::cerr << "Destructor error : Skeleton already deleted" << std::endl;
115 }
116
117 // No need to delete the scenegraph Nodes as this will be managed by baseplugin
118 skeletonNode_ = NULL;
119}
120
121//-----------------------------------------------------------------------------
122
127 // Delete the Skeleton only, if this object contains a line
128 if ( skeleton_ != NULL) {
129 delete skeleton_;
130 skeleton_ = NULL;
131 } else {
132 std::cerr << "Cleanup error : Skeleton already deleted" << std::endl;
133 }
134
136
137 skeletonNode_ = NULL;
138
140
141 init();
142
143}
144
145//-----------------------------------------------------------------------------
146
151 skeleton_ = new Skeleton();
152
153 if ( materialNode() == NULL)
154 std::cerr << "Error when creating Skeleton Object! materialNode is NULL!" << std::endl;
155
158
159 //set defaults for the material
160 materialNode()->set_color(ACG::Vec4f(0.654f, 0.8f, 1.0f, 1.0f));
164
165}
166
167//-----------------------------------------------------------------------------
168
169void SkeletonObject::init(Skeleton *_pSkeleton)
170{
171 skeleton_ = new Skeleton(*_pSkeleton);
172
173 if(materialNode() == NULL)
174 std::cerr << "Error when creating Skeleton Object! materialNode is NULL!" << std::endl;
175
178
179 //set defaults for the material
180 materialNode()->set_color(ACG::Vec4f(0.654f, 0.8f, 1.0f, 1.0f));
184}
185
186// ===============================================================================
187// Name/Path Handling
188// ===============================================================================
189
193void SkeletonObject::setName( QString _name ) {
195
196 std::string nodename = std::string("SkeletonNode for Skeleton " + _name.toUtf8() );
197 skeletonNode_->name( nodename );
198}
199
200// ===============================================================================
201// Content
202// ===============================================================================
203
210
211// ===============================================================================
212// Visualization
213// ===============================================================================
214
218
219// ===============================================================================
220// Object information
221// ===============================================================================
222
229 QString output;
230
231 output += "========================================================================\n";
233
234 if ( dataType( DATA_SKELETON ) )
235 output += "Object Contains a Skeleton : ";
236
237 output += QString::number( skeleton()->jointCount()) + " joints.\n";
238
239 output += "========================================================================\n";
240 return output;
241}
242
243// ===============================================================================
244// Picking
245// ===============================================================================
246
253bool SkeletonObject::picked( uint _node_idx ) {
254 return ( _node_idx == skeletonNode_->id() );
255}
256
257//-----------------------------------------------------------------------------
258
259void SkeletonObject::enablePicking( bool _enable ) {
260 skeletonNode_->enablePicking( _enable );
261}
262
263//-----------------------------------------------------------------------------
264
266 return skeletonNode_->pickingEnabled();
267}
268
269//-----------------------------------------------------------------------------
270
272 return skeletonNode()->activePose();
273}
274
275//-----------------------------------------------------------------------------
276
286{
287 skeletonNode()->setActivePose(_hAni);
288
289 updateIndices(_hAni);
290 updateMotionPath(_hAni);
291}
292
293//-----------------------------------------------------------------------------
294
304
305//-----------------------------------------------------------------------------
306
315{
317 if(!getAdditionalNode(pMatNode, "SkeletonPlugin", "Text material node"))
318 return;
319
320 // update the position of existing nodes
321 PoseT<OpenMesh::Vec3d> *pose = skeleton_->pose(_hAni);
322 for(unsigned int i = 0; i < skeleton_->jointCount(); ++i)
323 {
324 std::stringstream buf;
325 std::string nameTransformNode;
326
327 buf << "TextNode " << i << " Transform";
328 nameTransformNode = buf.str();
329
331 if(!getAdditionalNode(pTransNode, "SkeletonPlugin", nameTransformNode.c_str()))
332 continue;
333
334 pTransNode->loadIdentity();
335 pTransNode->translate(pose->globalTranslation(i));
336 pTransNode->scale(skeletonNode_->frameSize()*0.5);
337 }
338
339 // find and prune redundant nodes
340 unsigned int i = skeleton_->jointCount();
341 bool bAdditionalNodes = true;
342 do{
343 std::stringstream buf;
344 std::string nameTransformNode;
345
346 buf << "TextNode " << i << " Transform";
347 nameTransformNode = buf.str();
348
350 if(getAdditionalNode(pTransNode, "SkeletonPlugin", nameTransformNode.c_str()))
351 {
352 removeAdditionalNode(pTransNode, "SkeletonPlugin", nameTransformNode.c_str());
353 ++i;
354 continue;
355 } else {
356 bAdditionalNodes = false;
357 }
358 }while(bAdditionalNodes);
359}
360
361//-----------------------------------------------------------------------------
362
370void SkeletonObject::showIndices(bool _bVisible)
371{
373 if(!getAdditionalNode(pMatNode, "SkeletonPlugin", "Text material node"))
374 {
375 pMatNode = new ACG::SceneGraph::MaterialNode(baseNode(), "Text material node");
376 addAdditionalNode(pMatNode, "SkeletonPlugin", "Text material node");
377 }
378
379 pMatNode->set_color(ACG::Vec4f(0, 0, 0, 1.0));
380 if(_bVisible)
381 pMatNode->show();
382 else
384
385 // find and prune redundant nodes
386 unsigned int jointCount = skeleton_->jointCount();
387 bool bAdditionalNodes = true;
388 do{
389 std::stringstream buf;
390 std::string nameTransformNode;
391
392 buf << "TextNode " << jointCount << " Transform";
393 nameTransformNode = buf.str();
394
396 if(getAdditionalNode(pTransNode, "SkeletonPlugin", nameTransformNode.c_str()))
397 {
398 removeAdditionalNode(pTransNode, "SkeletonPlugin", nameTransformNode.c_str());
399 ++jointCount;
400 continue;
401 } else {
402 bAdditionalNodes = false;
403 }
404 } while(bAdditionalNodes);
405
406 // add or update nodes
408 for(unsigned int i = 0; i < skeleton_->jointCount(); ++i)
409 {
410 std::stringstream buf;
411 std::string nameJoint, nameTextNode, nameTransformNode, nameSubMatNode;
412
413 buf.str("");
414 buf << i;
415 nameJoint = buf.str();
416
417 buf.str("");
418 buf << "TextNode " << i;
419 nameTextNode = buf.str();
420
421 buf << " Transform";
422 nameTransformNode = buf.str();
423
424 buf << " Material";
425 nameSubMatNode = buf.str();
426
428 if(!getAdditionalNode(pTransNode, "SkeletonPlugin", nameTransformNode.c_str()))
429 {
430 pTransNode = new ACG::SceneGraph::TransformNode(pMatNode, nameTransformNode.c_str());
431 addAdditionalNode(pTransNode, "SkeletonPlugin", nameTransformNode.c_str());
432 }
433 pTransNode->loadIdentity();
434 pTransNode->translate(ref->globalTranslation(i));
435 pTransNode->scale(skeletonNode_->frameSize()*0.5);
436
438 if(!getAdditionalNode(pSubMatNode, "SkeletonPlugin", nameSubMatNode.c_str()))
439 {
440 pSubMatNode = new ACG::SceneGraph::MaterialNode(pTransNode, nameSubMatNode.c_str());
441 addAdditionalNode(pSubMatNode, "SkeletonPlugin", nameSubMatNode.c_str());
442 }
443 // pSubMatNode->set_color(skeleton_->joint(i)->color());
444
445 ACG::SceneGraph::TextNode *pTextNode = NULL;
446 if(!getAdditionalNode(pTextNode, "SkeletonPlugin", nameTextNode.c_str()))
447 {
448 pTextNode = new ACG::SceneGraph::TextNode(pSubMatNode,
449 nameTextNode.c_str(),
450 ACG::SceneGraph::TextNode::SCREEN_ALIGNED,
451 true);
452 addAdditionalNode(pTextNode, "SkeletonPlugin", nameTextNode.c_str());
453 }
454 pTextNode->setText(" " + nameJoint);
455 pTextNode->setSize(1);
456 pTextNode->multipassNodeSetActive(8, true);
457 }
458
459 //update the indices with the current animationhandle
461}
462
463//-----------------------------------------------------------------------------
464
466{
468 if(!getAdditionalNode(pMatNode, "SkeletonPlugin", "Text material node"))
469 return false;
470
471 return ( pMatNode->status() == ACG::SceneGraph::BaseNode::Active );
472}
473
474//-----------------------------------------------------------------------------
475
477{
479 if(!getAdditionalNode(pMatNode, "SkeletonPlugin", "Motion material node"))
480 return false;
481
482 return ( pMatNode->status() == ACG::SceneGraph::BaseNode::Active );
483}
484
485//-----------------------------------------------------------------------------
486
494
495//-----------------------------------------------------------------------------
496
506{
507
509 if(!getAdditionalNode(pMatNode, "SkeletonPlugin", "Motion material node"))
510 return;
511
512 // update the position of existing nodes
513 PoseT<OpenMesh::Vec3d>* pose = skeleton_->pose(_hAni);
514
515 for(unsigned int i = 0; i < skeleton_->jointCount(); ++i)
516 {
517
518 std::stringstream buf;
519 std::string nameTransformNode;
520
521 buf << "LineNode " << i << " Transform";
522 nameTransformNode = buf.str();
523
525 if(!getAdditionalNode(pTransNode, "SkeletonPlugin", nameTransformNode.c_str()))
526 continue;
527
528 pTransNode->loadIdentity();
529 pTransNode->translate( pose->globalTranslation(i) );
530 }
531
532 // find and prune redundant nodes
533 unsigned int i = skeleton_->jointCount();
534 bool bAdditionalNodes = true;
535 do{
536 std::stringstream buf;
537 std::string nameTransformNode;
538
539 buf << "LineNode " << i << " Transform";
540 nameTransformNode = buf.str();
541
543 if(getAdditionalNode(pTransNode, "SkeletonPlugin", nameTransformNode.c_str()))
544 {
545 removeAdditionalNode(pTransNode, "SkeletonPlugin", nameTransformNode.c_str());
546 ++i;
547 continue;
548 } else {
549 bAdditionalNodes = false;
550 }
551 }while(bAdditionalNodes);
552}
553
554//-----------------------------------------------------------------------------
555
564{
566 if(!getAdditionalNode(pMatNode, "SkeletonPlugin", "Motion material node"))
567 {
568 pMatNode = new ACG::SceneGraph::MaterialNode(baseNode(), "Motion material node");
569 addAdditionalNode(pMatNode, "SkeletonPlugin", "Motion material node");
570 }
571 pMatNode->set_color(ACG::Vec4f(0, 0, 0, 1.0));
572
573 if(_visible)
574 pMatNode->show();
575 else
577
578 // find and prune redundant nodes
579 unsigned int jointCount = skeleton_->jointCount();
580 bool bAdditionalNodes = true;
581 do{
582 std::stringstream buf;
583 std::string nameTransformNode;
584
585 buf << "LineNode " << jointCount << " Transform";
586 nameTransformNode = buf.str();
587
589 if(getAdditionalNode(pTransNode, "SkeletonPlugin", nameTransformNode.c_str()))
590 {
591 removeAdditionalNode(pTransNode, "SkeletonPlugin", nameTransformNode.c_str());
592 ++jointCount;
593 continue;
594 } else {
595 bAdditionalNodes = false;
596 }
597 }while(bAdditionalNodes);
598
599
600 // add or update nodes
602
603 for(unsigned int i = 0; i < skeleton_->jointCount(); ++i)
604 {
605 std::stringstream buf;
606 std::string nameLineNode, nameTransformNode;
607
608 buf.str("");
609 buf << "LineNode " << i;
610 nameLineNode = buf.str();
611
612 buf << " Transform";
613 nameTransformNode = buf.str();
614
616 if(!getAdditionalNode(pTransNode, "SkeletonPlugin", nameTransformNode.c_str()))
617 {
618 pTransNode = new ACG::SceneGraph::TransformNode(pMatNode, nameTransformNode.c_str());
619 addAdditionalNode(pTransNode, "SkeletonPlugin", nameTransformNode.c_str());
620 }
621 pTransNode->loadIdentity();
623 pTransNode->scale(mat); //this is just a hack to set the global matrix
624
625 ACG::SceneGraph::LineNode *pLineNode = NULL;
626 if(!getAdditionalNode(pLineNode, "SkeletonPlugin", nameLineNode.c_str()))
627 {
628 pLineNode = new ACG::SceneGraph::LineNode( ACG::SceneGraph::LineNode::LineSegmentsMode, pTransNode, nameLineNode.c_str());
629 addAdditionalNode(pLineNode, "SkeletonPlugin", nameLineNode.c_str());
630 }
631 pLineNode->clear();
632
633 Skeleton::Joint* joint = skeleton_->joint(i);
634
635 if ( joint->size() > 0 ){
636
637 for (uint c=0; c < joint->size(); c++ ){
638 Skeleton::Joint* child = joint->child(c);
639
640 for (unsigned int a = 0; a < skeleton_->animationCount(); a++){
641
642 AnimationHandle animHandle = AnimationHandle(a, 0 );
643
644 //get animation
645 AnimationT<ACG::Vec3d>* animation = skeleton_->animation( animHandle );
646
647 if (animation->name() == "")
648 continue;
649
650 ACG::Vec3d lastPos(0.0, 0.0, 0.0);
651
652 // every frame of that animation
653 for(unsigned int k = 0; k < animation->frameCount(); ++k){
654 animHandle.setFrame(k);
655 Skeleton::Pose* pose = skeleton_->pose( animHandle );
656
657 ACG::Matrix4x4d globalInv = pose->globalMatrix( joint->id() );
658 globalInv.invert();
659
660 ACG::Matrix4x4d local = pose->globalMatrix(child->id());
661 ACG::Matrix4x4d unified = pose->unifiedMatrix( joint->id() );
662
663 ACG::Vec3d trans = pose->globalTranslation(child->id()) - pose->globalTranslation(joint->id());
664 trans *= 0.5;
665
666 pLineNode->add_line( ACG::Vec3d(0.0, 0.0, 0.0), trans );
667 pLineNode->add_color( ACG::Vec3uc(180,255,180));
668
669 pLineNode->add_line( lastPos, trans );
670 pLineNode->add_color( ACG::Vec3uc(110,160,110));
671
672 lastPos = trans;
673 }
674 }
675
676 ACG::Vec3d trans = ref->globalTranslation(child->id())-ref->globalTranslation(joint->id());
677 trans *= 0.6;
678
679 pLineNode->add_line( ACG::Vec3d(0.0, 0.0, 0.0), trans);
680 pLineNode->add_color( ACG::Vec3uc(255,0,0));
681 }
682 }
683 }
684
685 //update the indices with the current animationhandle
686 updateMotionPath( skeletonNode_->activePose() );
687}
688
689//-----------------------------------------------------------------------------
690
692{
693 SkeletonObject *pObject = new SkeletonObject(*this);
694 return dynamic_cast<BaseObject*>(pObject);
695}
696
697// ===============================================================================
698// Update
699// ===============================================================================
700
701
705
706//=============================================================================
707
SkeletonT< ACG::Vec3d > Skeleton
Simple Name for the Skeleton, based on double vectors.
#define DATA_SKELETON
Definition Skeleton.hh:64
const Scalar * get_raw_data() const
bool invert()
matrix inversion (returns true on success)
@ HideSubtree
Hide this node and its children.
Definition BaseNode.hh:398
@ Active
Draw node & children.
Definition BaseNode.hh:392
void multipassNodeSetActive(const unsigned int _i, bool _active)
Set Node status to traverse in a specific pass.
Definition BaseNode.cc:228
StatusMode status() const
Get node's status.
Definition BaseNode.hh:401
void set_status(StatusMode _s)
Set the status of this node.
Definition BaseNode.hh:403
void show()
Show node: set status to Active.
Definition BaseNode.hh:407
void add_line(const Vec3d &_v0, const Vec3d &_v1)
add line (for LineMode == LineSegmentsMode)
Definition LineNode.cc:151
void add_color(const ACG::Vec3uc &_c)
add color (only for LineMode == LineSegmentsMode)
Definition LineNode.cc:162
void clear()
clear points/lines and colors
Definition LineNode.cc:101
void set_color(const Vec4f &_c)
set color (base, ambient, diffuse, specular) based on _c
void set_round_points(bool _b)
set round points enabled
void set_line_width(float _sz)
set line width (default: 1.0)
void set_point_size(float _sz)
set point size (default: 1.0)
void setSize(const double _size)
sets the size by which the quads displaying the text will be scaled
Definition TextNode.cc:214
void setText(std::string _text)
sets the string that will be rendered
Definition TextNode.cc:203
void scale(double _s)
Add scaling to the current Transformation.
void translate(const Vec3d &_v)
Add a translation to the current Transformation.
A handle used to refer to an animation or to a specific frame in an animation.
void setFrame(size_t _iFrame)
Sets the current animation frame (not failsafe)
Stores a single animation.
Definition AnimationT.hh:59
bool removeAdditionalNode(NodeT *&_node, QString _pluginName, QString _nodeName, int _id=0)
remove an additional node from the object
bool getAdditionalNode(NodeT *&_node, QString _pluginName, QString _nodeName, int _id=0)
get an addition node from the object
SeparatorNode * baseNode()
virtual void setName(QString _name) override
path to the file from which the object is loaded ( defaults to "." )
MaterialNode * materialNode()
get a pointer to the materialnode
virtual void cleanup() override
bool addAdditionalNode(NodeT *_node, QString _pluginName, QString _nodeName, int _id=0)
add an additional node to the object
virtual QString getObjectinfo()
Get all Info for the Object as a string.
QString name() const
return the name of the object. The name defaults to NONAME if unset.
void setDataType(DataType _type)
virtual void update(UpdateType _type=UPDATE_ALL)
This function is called to update the object.
void deleteData()
Delete all data attached to this object ( calls delete on each object )
DataType dataType() const
BaseObject * child(int row)
return a child
int id() const
Represents a single joint in the skeleton.
Definition JointT.hh:61
size_t size() const
Returns the number of children.
size_t id() const
returns the joint id
Joint * child(size_t _index)
Returns the child joint with the given index.
A general pose, used to store the frames of the animation.
Definition PoseT.hh:59
const Matrix & unifiedMatrix(size_t _joint)
Returns the unified matrix.
const Matrix & globalMatrix(unsigned int _joint) const
Returns the global matrix for the given joint.
Vector globalTranslation(unsigned int _joint)
Returns the global translation vector.
bool indicesVisible()
Returns true if the picked node given by _node_idx is this objects scenegraph node.
virtual ~SkeletonObject()
Destructor.
AnimationHandle activePose()
Returns true if the picked node given by _node_idx is this objects scenegraph node.
ACG::SceneGraph::SkeletonNodeT< Skeleton > * skeletonNode()
Returns the skeleton scenegraph node.
bool pickingEnabled()
Check if picking is enabled for this object.
bool picked(uint _node_idx)
Returns true if the picked node given by _node_idx is this objects scenegraph node.
ACG::SceneGraph::SkeletonNodeT< Skeleton > * skeletonNode_
A pointer to the scenegraph node.
void setActivePose(const AnimationHandle &_hAni)
Call this to set the active pose.
void showMotionPath(bool _visible=true)
Shows or hides the local motion space for a joint.
void updateIndices()
Updates the joint index text node positions.
void setName(QString _name)
Set the name of the Object.
void updateMotionPath()
Updates the node that visualizes the local space of joint motions.
SkeletonObject()
Constructor.
Skeleton * skeleton()
Returns a pointer to the skeleton.
void enablePicking(bool _enable)
Enable or disable picking for this object.
virtual void init()
Initialize current object, including all related nodes.
Skeleton * skeleton_
A pointer to the skeleton data.
virtual void cleanup()
Reset current object, including all related nodes.
void showIndices(bool _bVisible=true)
Shows or hides the indices.
void update(UpdateType _type=UPDATE_ALL)
This function is called to update the object.
virtual BaseObject * copy()
Returns a full copy of the object.
QString getObjectinfo()
Returns a string holding information on this object.
bool motionPathVisible()
Returns true if the picked node given by _node_idx is this objects scenegraph node.
Pose * referencePose()
Returns a pointer to the reference pose.
size_t jointCount()
Returns the number of joints.
size_t animationCount()
Returns the number of animations stored in this skeleton.
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.
Update type class.
Definition UpdateType.hh:59
DrawMode POINTS
draw unlighted points using the default base color
Definition DrawModes.cc:73
DrawMode SOLID_FLAT_SHADED
draw flat shaded faces (requires face normals)
Definition DrawModes.cc:81