50 #include <QInputDialog>
51 #include <QMessageBox>
53 #include "SkeletalAnimationPlugin.hh"
54 #include <ObjectTypes/Skeleton/SkeletonObjectData.hh>
55 #include <ObjectTypes/Skeleton/SkinT.hh>
57 #include "AddAnimationDialog.hh"
81 return "SkeletalAnimation";
91 return "Plugin to control skeletal animations";
104 QSize size(300, 300);
116 connect(
pToolbox_->sbFPS, SIGNAL(valueChanged (
int )),
this, SLOT(
changeFPS(
int) ) );
118 connect(
pToolbox_->pbAddAnimation, SIGNAL(clicked()),
this, SLOT(slotAddAnimation()) );
119 connect(
pToolbox_->pbDeleteAnimation, SIGNAL(clicked()),
this, SLOT(slotDeleteAnimation()) );
121 connect(
pToolbox_->pbEditAnimation, SIGNAL(clicked()),
this, SLOT(slotAnimationNameChanged()));
123 pToolbox_->pbAddAnimation->setIcon(QIcon(OpenFlipper::Options::iconDirStr()+OpenFlipper::Options::dirSeparator()+
"addAnimation.png") );
124 pToolbox_->pbDeleteAnimation->setIcon(QIcon(OpenFlipper::Options::iconDirStr()+OpenFlipper::Options::dirSeparator()+
"deleteAnimation.png") );
125 pToolbox_->pbEditAnimation->setIcon(QIcon(OpenFlipper::Options::iconDirStr()+OpenFlipper::Options::dirSeparator()+
"editAnimation.png") );
127 pToolbox_->cbMethod->addItem(
"Linear Blend Skinning");
128 pToolbox_->cbMethod->addItem(
"Dual Quaternion Blend Skinning");
134 toolIcon_ =
new QIcon(OpenFlipper::Options::iconDirStr()+OpenFlipper::Options::dirSeparator()+
"skeletalAnimation.png");
135 emit addToolbox( tr(
"Skeletal Animation") ,
pToolbox_, toolIcon_ );
145 emit setDescriptions();
164 activeSkeletons_.clear();
218 baseSkin = dynamic_cast<BaseSkin*> (bod->
objectData(OBJECTDATA_SKIN));
220 baseSkin = dynamic_cast<BaseSkin*> (bod->
objectData(OBJECTDATA_SKIN));
244 std::cerr <<
"SkeletalAnimationPlugin::checkObjectSelection : unable to get object! " << std::endl;
249 activeSkeletons_.clear();
253 activeSkeletons_.push_back( o_it->id() );
256 if ( activeSkeletons_.empty() ){
258 activeSkeletons_.push_back( o_it->id() );
260 if (activeSkeletons_.size() != 1)
261 activeSkeletons_.clear();
271 void SkeletalAnimationPlugin::slotAnimationNameChanged() {
273 if(
pToolbox_->cbAnimation->currentText() ==
"Reference Pose") {
275 QMessageBox::warning(0,
"Not editable!",
"You cannot change the reference pose's name!");
279 QString newName = QInputDialog::getText(0, tr(
"Change Animation's Name"), tr(
"New Name:"),
283 for (
unsigned int i=0; i < activeSkeletons_.size(); i++){
289 if ( baseObject == 0 )
293 if(!skeletonObject)
continue;
295 if(!skeleton)
continue;
298 if(skeleton != 0 && h.
isValid()) {
299 skeleton->
animation(h)->setName(newName.toStdString());
317 for (
unsigned int i=0; i < activeSkeletons_.size(); i++){
323 if ( baseObject == 0 )
384 for (
unsigned int i=0; i < skeletonData->
skinCount(); i++){
387 int meshId = skeletonData->
skin(i);
396 emit log(
LOGERR, tr(
"Error: Attached skin mesh has no skin-object-data."));
400 BaseSkin* skin =
dynamic_cast< BaseSkin*
> (
object->objectData(OBJECTDATA_SKIN) );
401 skin->deformSkin(_hAni,
method_ );
432 pToolbox_->cbAnimation->setCurrentIndex( 0 );
453 if ( activeSkeletons_.empty() ){
466 if ( skelObject == 0 )
474 pToolbox_->hsFrame->setRange( 0, pAnimation->frameCount() - 1 );
506 for (
unsigned int i=0; i < activeSkeletons_.size(); i++){
512 if ( skelObject == 0 )
564 pToolbox_->hsFrame->setSliderPosition(0);
610 setFrame(currentFrame % frameCount);
625 if(_state == Qt::Checked)
657 for (
unsigned int i=0; i < activeSkeletons_.size(); i++){
663 if ( baseObject == 0 )
700 if( ! activeSkeletons_.empty() )
706 if ( baseObject == 0 )
714 if(skeletonObj->
objectData(OBJECTDATA_SKELETON) == 0)
716 pToolbox_->pbAttachSkin->setEnabled(
true);
717 pToolbox_->pbClearSkins->setEnabled(
false);
718 pToolbox_->skinningBox->setTitle(tr(
"Attached Skins"));
720 pToolbox_->pbAttachSkin->setEnabled(
true);
721 pToolbox_->pbClearSkins->setEnabled(
true);
724 pToolbox_->skinningBox->setTitle(tr(
"Attached Skins (Currently: %1)").arg(skelData->
skinCount()) );
730 pToolbox_->pbAddAnimation->setEnabled(
true);
731 pToolbox_->cbAnimation->setEnabled(
true);
735 pToolbox_->cbAnimation->addItem(
"Reference Pose");
739 while ( animations ) {
756 pToolbox_->pbAddAnimation->setEnabled(
false);
757 pToolbox_->cbAnimation->setEnabled(
false);
763 pToolbox_->pbAttachSkin->setEnabled(
false);
764 pToolbox_->pbClearSkins->setEnabled(
false);
765 pToolbox_->skinningBox->setTitle(tr(
"Attached Skins"));
777 if( activeSkeletons_.size() != 1 ){
778 emit log(
LOGERR, tr(
"Cannot bind mesh. Please select only one skeleton."));
791 emit log(
LOGERR, tr(
"Cannot bind mesh. Please select at least one mesh as target."));
805 emit log(
LOGERR, tr(
"Cannot bind mesh as skin. Mesh is already a skin."));
813 skelData = dynamic_cast< SkeletonObjectData* >(_skeletonObj->
objectData(OBJECTDATA_SKELETON));
824 bool hasSkinWeights =
true;
834 baseSkin->attachSkin();
842 _skeletonObj->
target(
true);
843 _skeletonObj->
source(
false);
845 if( !hasSkinWeights ){
848 emit pluginExists(
"skinningplugin", canCompute);
852 msgBox.setText(
"The mesh is not equipped with skin weights.");
853 msgBox.setInformativeText(
"Do you want to compute them automatically?");
854 msgBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No);
855 msgBox.setDefaultButton(QMessageBox::Yes);
856 int ret = msgBox.exec();
858 if (ret == QMessageBox::Yes)
873 for (
unsigned int i=0; i < activeSkeletons_.size(); i++)
889 for (
int i=skelData->
skinCount()-1; i >= 0; i--){
891 int meshId = skelData->
skin(i);
911 emit log(
LOGERR, tr(
"Cannot detach skin. Skeleton has no object data."));
925 baseSkin->releaseSkin();
948 void SkeletalAnimationPlugin::slotAddAnimation()
951 if( activeSkeletons_.size() != 1 ){
952 emit log(
LOGERR, tr(
"Cannot add animation. Please select only one skeleton."));
957 dialog.animationName->selectAll();
958 dialog.animationName->setFocus();
960 if ( dialog.exec() == QDialog::Accepted ){
961 if ( dialog.animationName->text() ==
"" ){
962 emit log(
LOGERR, tr(
"Cannot add animation with empty name"));
971 emit log(
LOGERR, tr(
"Unable to get object"));
977 if (skeletonObj == 0){
978 emit log(
LOGERR, tr(
"Unable to get skeletonObject"));
984 std::string stdName = dialog.animationName->text().toStdString();
986 if ( skeleton->
animation(stdName) != 0 ){
987 emit log(
LOGERR, tr(
"Animation with this name already exists"));
995 for (
unsigned int i=0; i < skeleton->animation(handle)->
frameCount(); i++){
999 for (
unsigned int j=0; j < skeleton->jointCount(); j++)
1000 pose->
setGlobalMatrix(j, skeleton->referencePose()->globalMatrix(j) );
1003 emit updatedObject(activeSkeletons_[0],
UPDATE_ALL);
1012 void SkeletalAnimationPlugin::slotDeleteAnimation()
1014 int iAnimation =
pToolbox_->cbAnimation->currentIndex();
1015 unsigned int animationIndex =
pToolbox_->cbAnimation->itemData(iAnimation).toUInt();
1017 if ( iAnimation == 0 ) {
1018 emit log(
LOGERR,
"Reference pose could never be removed!");
1020 pToolbox_->cbAnimation->removeItem(iAnimation);
1044 int iAnimation =
pToolbox_->cbAnimation->currentIndex();
1045 unsigned int animationId =
pToolbox_->cbAnimation->itemData(iAnimation).toUInt();
1049 else if(iAnimation > 0)
1062 for (
int i = 0 ; i <
pToolbox_->cbAnimation->count(); ++i ) {
1063 unsigned int animationId =
pToolbox_->cbAnimation->itemData(i).toUInt();
1065 if ( animationId == _animationIndex ) {
1066 pToolbox_->cbAnimation->setCurrentIndex(i);
1076 #if QT_VERSION < 0x050000
int getNumberOfFrames()
Returns the number of frames in the currently active animation.
Animation * animation(std::string _name)
Returns a pointer to the animation to the given name.
A handle used to refer to an animation or to a specific frame in an animation.
void setActivePose(const AnimationHandle &_hAni)
Call this to set the active pose.
PerObjectData * objectData(QString _dataName)
Returns the object data pointer.
QString name()
returns the plugin name
bool dataType(DataType _type) const
void replaceAnimationName(const std::string &_strOld, const std::string &_strNew)
Returns a pointer to the pose with the given animation handle.
AnimationToolboxWidget * pToolbox_
A pointer to the toolbox widget.
TriMesh * triMesh(BaseObjectData *_object)
Get a triangle mesh from an object.
void checkObjectSelection(const int _objectId)
Check source/target selection of objects.
Pose * pose(unsigned int _iFrame)
Returns a pointer to the pose stored in the given frame.
bool detachSkin(int skeletonId, int skinId)
Returns the number of frames in the currently active animation.
bool getObject(int _identifier, BSplineCurveObject *&_object)
bool bGuiUpdating_
Used to drop a few messages while the gui is being updated.
void stopAnimation()
Called by the ui and stops the current animation.
Add normals to mesh item (vertices/faces)
SkeletalAnimationPlugin()
Constructor.
const std::string & animationName(size_t _index)
Returns the name of the animation with the given index.
QTime animationTime_
Time since the animation was started, used to meet the given fps.
PolyMesh * polyMesh(BaseObjectData *_object)
Get a poly mesh from an object.
SkeletonObject * skeletonObject(BaseObjectData *_object)
Cast an BaseObject to a SkeletonObject if possible.
void UpdateSkins(BaseObjectData *_pSkeletonObject, AnimationHandle &_hAni)
Changes the mesh's pose to represent the frame given by the animation handle.
bool hasObjectData(QString _dataName)
Checks if object data with given name is available.
void nextFrame()
Called by the ui and goes to next frame of the current animation.
void addedEmptyObject(int _id)
Update ui when the object is added.
void setObjectData(QString _dataName, PerObjectData *_data)
void playAnimation()
Called by the ui and starts an automatic animation.
void removeAnimation(std::string _name)
Removes an animation from the list.
int animationOffset_
This frame was selected as the animation was started.
unsigned int frameCount()
Returns the number of frames stored in this pose.
bool attachSkin(int skeletonId, int skinId)
Returns the number of frames in the currently active animation.
void slotObjectUpdated(int _id, const UpdateType &_type)
Check activePose if a skeleton was updated.
void animate()
Iterates the animation.
void exit()
Plugin gets closed.
size_t frame() const
Returns the selected frame (zero based)
AnimationIterator animationsBegin()
Iterator over the animations.
void setFrame(int _iFrame)
Displays the given frame from the current animation and updates the view.
int skin(unsigned int _index)
Get the skin with given index (0 <= _index < skinCount())
Iterator class for the animations attached to a skeleton.
void slotAttachSkin()
Called by Qt as the user is trying to connect a mesh to a skeleton.
void slotAnimationIndexChanged(int)
Called by the framework when the animation index changed.
ACG::SceneGraph::SkeletonNodeT< Skeleton > * skeletonNode()
Returns the skeleton scenegraph node.
void clearObjectData(QString _dataName)
Clear the object data pointer ( this will not delete the object!! )
QString description()
returns a plugin description
void slotFrameChanged(int)
Called by the framework when a different frame was selected.
unsigned int skinCount()
Get the number of associated skins.
#define DATA_TRIANGLE_MESH
bool clearSkins(int skeletonId)
Returns the number of frames in the currently active animation.
void slotClearSkins()
Called by Qt as the user is trying to unbind a mesh from as a skeleton.
Data object attached to the skeleton.
void UpdateUI()
Called when the active object changes and the interface needs to be updated.
AnimationHandle animationHandle(std::string _name)
Get an AnimationHandle to the animation with the given name.
A general pose, used to store the frames of the animation.
void setComboBoxPosition(unsigned int _animationIndex)
Sets the animations combo box to the right entry.
size_t animationIndex() const
Returns the animation index (zero based)
void slotObjectSelectionChanged(int _id)
Update ui when the object selection changes.
void removeSkin(int _objectId)
Remove a skin from the skeleton.
AnimationHandle currentAnimationHandle()
Returns a handle describing the current frame in the active animation.
QTimer animationTimer_
Timer used to control animations.
const QStringList ALL_OBJECTS
Iterable object range.
void pluginsInitialized()
final initializations
int getFrame()
Gets the current frame number.
void objectDeleted(int _id)
Update ui when the object is deleted.
const UpdateType UPDATE_ALL(UpdateTypeSet(1))
Identifier for all updates.
const UpdateType UPDATE_GEOMETRY(UpdateTypeSet(1)<< 2)
Geometry updated.
void initializePlugin()
initialize the plugin
QScriptValue callFunction(QString _plugin, QString _functionName, std::vector< QScriptValue > _parameters)
Call a function provided by a plugin getting multiple parameters.
DLLEXPORT ObjectIterator objectsEnd()
Return Iterator to Object End.
Helper Class for UpdateUI. assigns a bool value and set it to "true". after leaving the scope...
void pauseAnimation()
Called by the ui and stops the current animation.
size_t animationCount()
Returns the number of animations stored in this skeleton.
void fileOpened(int _id)
Update ui when the object is loaded.
General skin class, used to bind skeleton and mesh and deform the mesh.
bool isValid() const
Returns true if the handle is valid.
void prevFrame()
Called by the ui and goes to previous frame of the current animation.
Abstract base class for the skin template, wrapping all template versions of the skin.
void slotAllCleared()
clear all occurred
BaseSkin::Method method_
The current blending method for the skin.
const QStringList TARGET_OBJECTS("target")
Iterable object range.
void setGlobalMatrix(unsigned int _joint, const Matrix &_global, bool _keepGlobalChildPositions=true)
Sets the global coordinate system.
void slotMethodChanged(int _index)
Called as the skin deformation method changed.
The skeletal animation plugin is used to interact with the skeleton.
void changeFPS(int _fps)
Change the frames per second (FPS)
Skeleton * skeleton(BaseObjectData *_object)
Get a skeleton from an object.
void slotSkipFramesChanged(int _state)
Called as the skip frames check box changes state.
void addSkin(int _objectId)
Add a skin to the skeleton.