43 #include "SkeletalAnimationPlugin.hh" 46 #include <ObjectTypes/Skeleton/SkeletonObjectData.hh> 47 #include <ObjectTypes/Skeleton/SkinT.hh> 50 #include <QInputDialog> 51 #include <QMessageBox> 53 #include "dialogs/AnimationToolbox.hh" 54 #include "dialogs/AddAnimationDialog.hh" 78 return "SkeletalAnimation";
88 return "Plugin to control skeletal animations";
101 QSize size(300, 300);
113 connect(
pToolbox_->sbFPS, SIGNAL(valueChanged (
int )),
this, SLOT(
changeFPS(
int) ) );
115 connect(
pToolbox_->pbAddAnimation, SIGNAL(clicked()),
this, SLOT(slotAddAnimation()) );
116 connect(
pToolbox_->pbDeleteAnimation, SIGNAL(clicked()),
this, SLOT(slotDeleteAnimation()) );
118 connect(
pToolbox_->pbEditAnimation, SIGNAL(clicked()),
this, SLOT(slotAnimationNameChanged()));
120 pToolbox_->pbAddAnimation->setIcon(QIcon(OpenFlipper::Options::iconDirStr()+OpenFlipper::Options::dirSeparator()+
"addAnimation.png") );
121 pToolbox_->pbDeleteAnimation->setIcon(QIcon(OpenFlipper::Options::iconDirStr()+OpenFlipper::Options::dirSeparator()+
"deleteAnimation.png") );
122 pToolbox_->pbEditAnimation->setIcon(QIcon(OpenFlipper::Options::iconDirStr()+OpenFlipper::Options::dirSeparator()+
"editAnimation.png") );
124 pToolbox_->cbMethod->addItem(
"Linear Blend Skinning");
125 pToolbox_->cbMethod->addItem(
"Dual Quaternion Blend Skinning");
131 toolIcon_ =
new QIcon(OpenFlipper::Options::iconDirStr()+OpenFlipper::Options::dirSeparator()+
"skeletalAnimation.png");
132 emit addToolbox( tr(
"Skeletal Animation") ,
pToolbox_, toolIcon_ );
142 emit setDescriptions();
161 activeSkeletons_.clear();
215 baseSkin = dynamic_cast<BaseSkin*> (bod->
objectData(OBJECTDATA_SKIN));
217 baseSkin = dynamic_cast<BaseSkin*> (bod->
objectData(OBJECTDATA_SKIN));
241 std::cerr <<
"SkeletalAnimationPlugin::checkObjectSelection : unable to get object! " << std::endl;
246 activeSkeletons_.clear();
250 activeSkeletons_.push_back( o_it->id() );
253 if ( activeSkeletons_.empty() ){
255 activeSkeletons_.push_back( o_it->id() );
257 if (activeSkeletons_.size() != 1)
258 activeSkeletons_.clear();
268 void SkeletalAnimationPlugin::slotAnimationNameChanged() {
270 if(
pToolbox_->cbAnimation->currentText() ==
"Reference Pose") {
272 QMessageBox::warning(0,
"Not editable!",
"You cannot change the reference pose's name!");
276 QString newName = QInputDialog::getText(0, tr(
"Change Animation's Name"), tr(
"New Name:"),
277 QLineEdit::Normal,
pToolbox_->cbAnimation->currentText());
280 for (
unsigned int i=0; i < activeSkeletons_.size(); i++){
286 if ( baseObject == 0 )
290 if(!skeletonObject)
continue;
292 if(!skeleton)
continue;
295 if(skeleton != 0 && h.
isValid()) {
296 skeleton->
animation(h)->setName(newName.toStdString());
314 for (
unsigned int i=0; i < activeSkeletons_.size(); i++){
320 if ( baseObject == 0 )
381 for (
unsigned int i=0; i < skeletonData->
skinCount(); i++){
384 int meshId = skeletonData->
skin(i);
393 emit log(
LOGERR, tr(
"Error: Attached skin mesh has no skin-object-data."));
397 BaseSkin* skin =
dynamic_cast< BaseSkin*
> (
object->objectData(OBJECTDATA_SKIN) );
398 skin->deformSkin(_hAni,
method_ );
429 pToolbox_->cbAnimation->setCurrentIndex( 0 );
450 if ( activeSkeletons_.empty() ){
463 if ( skelObject == 0 )
471 pToolbox_->hsFrame->setRange( 0, pAnimation->frameCount() - 1 );
503 for (
unsigned int i=0; i < activeSkeletons_.size(); i++){
509 if ( skelObject == 0 )
561 pToolbox_->hsFrame->setSliderPosition(0);
607 setFrame(currentFrame % frameCount);
622 if(_state == Qt::Checked)
654 for (
unsigned int i=0; i < activeSkeletons_.size(); i++){
660 if ( baseObject == 0 )
697 if( ! activeSkeletons_.empty() )
703 if ( baseObject == 0 )
711 if(skeletonObj->
objectData(OBJECTDATA_SKELETON) == 0)
713 pToolbox_->pbAttachSkin->setEnabled(
true);
714 pToolbox_->pbClearSkins->setEnabled(
false);
715 pToolbox_->skinningBox->setTitle(tr(
"Attached Skins"));
717 pToolbox_->pbAttachSkin->setEnabled(
true);
718 pToolbox_->pbClearSkins->setEnabled(
true);
721 pToolbox_->skinningBox->setTitle(tr(
"Attached Skins (Currently: %1)").arg(skelData->
skinCount()) );
727 pToolbox_->pbAddAnimation->setEnabled(
true);
728 pToolbox_->cbAnimation->setEnabled(
true);
732 pToolbox_->cbAnimation->addItem(
"Reference Pose");
736 while ( animations ) {
753 pToolbox_->pbAddAnimation->setEnabled(
false);
754 pToolbox_->cbAnimation->setEnabled(
false);
760 pToolbox_->pbAttachSkin->setEnabled(
false);
761 pToolbox_->pbClearSkins->setEnabled(
false);
762 pToolbox_->skinningBox->setTitle(tr(
"Attached Skins"));
774 if( activeSkeletons_.size() != 1 ){
775 emit log(
LOGERR, tr(
"Cannot bind mesh. Please select only one skeleton."));
788 emit log(
LOGERR, tr(
"Cannot bind mesh. Please select at least one mesh as target."));
802 emit log(
LOGERR, tr(
"Cannot bind mesh as skin. Mesh is already a skin."));
810 skelData = dynamic_cast< SkeletonObjectData* >(_skeletonObj->
objectData(OBJECTDATA_SKELETON));
821 bool hasSkinWeights =
true;
831 baseSkin->attachSkin();
839 _skeletonObj->
target(
true);
840 _skeletonObj->
source(
false);
842 if( !hasSkinWeights ){
845 emit pluginExists(
"skinningplugin", canCompute);
849 msgBox.setText(
"The mesh is not equipped with skin weights.");
850 msgBox.setInformativeText(
"Do you want to compute them automatically?");
851 msgBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No);
852 msgBox.setDefaultButton(QMessageBox::Yes);
853 int ret = msgBox.exec();
855 if (ret == QMessageBox::Yes)
870 for (
unsigned int i=0; i < activeSkeletons_.size(); i++)
886 for (
int i=skelData->
skinCount()-1; i >= 0; i--){
888 int meshId = skelData->
skin(i);
908 emit log(
LOGERR, tr(
"Cannot detach skin. Skeleton has no object data."));
922 baseSkin->releaseSkin();
935 if ( skelData->skinCount() == 0 ){
945 void SkeletalAnimationPlugin::slotAddAnimation()
948 if( activeSkeletons_.size() != 1 ){
949 emit log(
LOGERR, tr(
"Cannot add animation. Please select only one skeleton."));
954 dialog.animationName->selectAll();
955 dialog.animationName->setFocus();
957 if ( dialog.exec() == QDialog::Accepted ){
958 if ( dialog.animationName->text() ==
"" ){
959 emit log(
LOGERR, tr(
"Cannot add animation with empty name"));
968 emit log(
LOGERR, tr(
"Unable to get object"));
974 if (skeletonObj == 0){
975 emit log(
LOGERR, tr(
"Unable to get skeletonObject"));
981 std::string stdName = dialog.animationName->text().toStdString();
983 if ( skeleton->
animation(stdName) != 0 ){
984 emit log(
LOGERR, tr(
"Animation with this name already exists"));
992 for (
unsigned int i=0; i < skeleton->animation(handle)->
frameCount(); i++){
996 for (
unsigned int j=0; j < skeleton->jointCount(); j++)
1000 emit updatedObject(activeSkeletons_[0],
UPDATE_ALL);
1009 void SkeletalAnimationPlugin::slotDeleteAnimation()
1011 int iAnimation =
pToolbox_->cbAnimation->currentIndex();
1012 unsigned int animationIndex =
pToolbox_->cbAnimation->itemData(iAnimation).toUInt();
1014 if ( iAnimation == 0 ) {
1015 emit log(
LOGERR,
"Reference pose could never be removed!");
1017 pToolbox_->cbAnimation->removeItem(iAnimation);
1041 int iAnimation =
pToolbox_->cbAnimation->currentIndex();
1042 unsigned int animationId =
pToolbox_->cbAnimation->itemData(iAnimation).toUInt();
1046 else if(iAnimation > 0)
1059 for (
int i = 0 ; i <
pToolbox_->cbAnimation->count(); ++i ) {
1060 unsigned int animationId =
pToolbox_->cbAnimation->itemData(i).toUInt();
1062 if ( animationId == _animationIndex ) {
1063 pToolbox_->cbAnimation->setCurrentIndex(i);
void clearObjectData(QString _dataName)
Clear the object data pointer ( this will not delete the object!! )
unsigned int frameCount()
Returns the number of frames stored in this pose.
void slotFrameChanged(int)
Called by the framework when a different frame was selected.
void slotMethodChanged(int _index)
Called as the skin deformation method changed.
size_t animationIndex() const
Returns the animation index (zero based)
SkeletonObject * skeletonObject(BaseObjectData *_object)
Cast an BaseObject to a SkeletonObject if possible.
void changeFPS(int _fps)
Change the frames per second (FPS)
Abstract base class for the skin template, wrapping all template versions of the skin.
#define DATA_TRIANGLE_MESH
void addedEmptyObject(int _id)
Update ui when the object is added.
void setGlobalMatrix(unsigned int _joint, const Matrix &_global, bool _keepGlobalChildPositions=true)
Sets the global coordinate system.
Data object attached to the skeleton.
const UpdateType UPDATE_ALL(UpdateTypeSet(1))
Identifier for all updates.
void setObjectData(QString _dataName, PerObjectData *_data)
void setComboBoxPosition(unsigned int _animationIndex)
Sets the animations combo box to the right entry.
PolyMesh * polyMesh(BaseObjectData *_object)
Get a poly mesh from an object.
void objectDeleted(int _id)
Update ui when the object is deleted.
AnimationToolboxWidget * pToolbox_
A pointer to the toolbox widget.
QScriptValue callFunction(QString _plugin, QString _functionName, std::vector< QScriptValue > _parameters)
Call a function provided by a plugin getting multiple parameters.
ACG::SceneGraph::SkeletonNodeT< Skeleton > * skeletonNode()
Returns the skeleton scenegraph node.
void replaceAnimationName(const std::string &_strOld, const std::string &_strNew)
Returns a pointer to the pose with the given animation handle.
bool getObject(const int _identifier, BaseObject *&_object)
Get the object which has the given identifier.
void pauseAnimation()
Called by the ui and stops the current animation.
void slotSkipFramesChanged(int _state)
Called as the skip frames check box changes state.
AnimationIterator animationsBegin()
Iterator over the animations.
int getNumberOfFrames()
Returns the number of frames in the currently active animation.
TriMesh * triMesh(BaseObjectData *_object)
Get a triangle mesh from an object.
const QStringList ALL_OBJECTS
Iterable object range.
A general pose, used to store the frames of the animation.
Pose * pose(unsigned int _iFrame)
Returns a pointer to the pose stored in the given frame.
int animationOffset_
This frame was selected as the animation was started.
Helper Class for UpdateUI. assigns a bool value and set it to "true". after leaving the scope...
QString description()
returns a plugin description
size_t frame() const
Returns the selected frame (zero based)
void exit()
Plugin gets closed.
bool isValid() const
Returns true if the handle is valid.
const UpdateType UPDATE_GEOMETRY(UpdateTypeSet(4))
Geometry updated.
void slotObjectUpdated(int _id, const UpdateType &_type)
Check activePose if a skeleton was updated.
void addSkin(int _objectId)
Add a skin to the skeleton.
void UpdateUI()
Called when the active object changes and the interface needs to be updated.
bool dataType(DataType _type) const
void animate()
Iterates the animation.
AnimationHandle currentAnimationHandle()
Returns a handle describing the current frame in the active animation.
void playAnimation()
Called by the ui and starts an automatic animation.
unsigned int skinCount()
Get the number of associated skins.
void removeAnimation(std::string _name)
Removes an animation from the list.
DLLEXPORT ObjectIterator objectsEnd()
Return Iterator to Object End.
void slotObjectSelectionChanged(int _id)
Update ui when the object selection changes.
int skin(unsigned int _index)
Get the skin with given index (0 <= _index < skinCount())
void fileOpened(int _id)
Update ui when the object is loaded.
SkeletalAnimationPlugin()
Constructor.
void checkObjectSelection(const int _objectId)
Check source/target selection of objects.
Skeleton * skeleton(BaseObjectData *_object)
Get a skeleton from an object.
void initializePlugin()
initialize the plugin
const std::string & animationName(size_t _index)
Returns the name of the animation with the given index.
Blending::Method method_
The current blending method for the skin.
bool clearSkins(int skeletonId)
Returns the number of frames in the currently active animation.
bool bGuiUpdating_
Used to drop a few messages while the gui is being updated.
Iterator class for the animations attached to a skeleton.
QString name()
returns the plugin name
const QStringList TARGET_OBJECTS("target")
Iterable object range.
void setFrame(int _iFrame)
Displays the given frame from the current animation and updates the view.
void slotAttachSkin()
Called by Qt as the user is trying to connect a mesh to a skeleton.
void pluginsInitialized()
final initializations
void setActivePose(const AnimationHandle &_hAni)
Call this to set the active pose.
QElapsedTimer animationTime_
Time since the animation was started, used to meet the given fps.
void prevFrame()
Called by the ui and goes to previous frame of the current animation.
Animation * animation(std::string _name)
Returns a pointer to the animation to the given name.
void UpdateSkins(BaseObjectData *_pSkeletonObject, AnimationHandle &_hAni)
Changes the mesh's pose to represent the frame given by the animation handle.
bool detachSkin(int skeletonId, int skinId)
Returns the number of frames in the currently active animation.
size_t animationCount()
Returns the number of animations stored in this skeleton.
void stopAnimation()
Called by the ui and stops the current animation.
void slotAnimationIndexChanged(int)
Called by the framework when the animation index changed.
PerObjectData * objectData(QString _dataName)
Returns the object data pointer.
bool attachSkin(int skeletonId, int skinId)
Returns the number of frames in the currently active animation.
int getFrame()
Gets the current frame number.
void removeSkin(int _objectId)
Remove a skin from the skeleton.
void slotClearSkins()
Called by Qt as the user is trying to unbind a mesh from as a skeleton.
AnimationHandle animationHandle(std::string _name)
Get an AnimationHandle to the animation with the given name.
void nextFrame()
Called by the ui and goes to next frame of the current animation.
bool hasObjectData(QString _dataName)
Checks if object data with given name is available.
void slotAllCleared()
clear all occurred
A handle used to refer to an animation or to a specific frame in an animation.
General skin class, used to bind skeleton and mesh and deform the mesh.
QTimer animationTimer_
Timer used to control animations.