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
General skin class, used to bind skeleton and mesh and deform the mesh.
bool isValid() const
Returns true if the handle is valid.
void stopAnimation()
Called by the ui and stops the current animation.
void setGlobalMatrix(unsigned int _joint, const Matrix &_global, bool _keepGlobalChildPositions=true)
Sets the global coordinate system.
BaseSkin::Method method_
The current blending method for the skin.
void pauseAnimation()
Called by the ui and stops the current animation.
SkeletonObject * skeletonObject(BaseObjectData *_object)
Cast an BaseObject to a SkeletonObject if possible.
QString description()
returns a plugin description
void initializePlugin()
initialize the plugin
const QStringList ALL_OBJECTS
Iterable object range.
const UpdateType UPDATE_GEOMETRY(UpdateTypeSet(1)<< 2)
Geometry updated.
void setActivePose(const AnimationHandle &_hAni)
Call this to set the active pose.
QString name()
returns the plugin name
PerObjectData * objectData(QString _dataName)
Returns the object data pointer.
void objectDeleted(int _id)
Update ui when the object is deleted.
void pluginsInitialized()
final initializations
void slotFrameChanged(int)
Called by the framework when a different frame was selected.
void slotMethodChanged(int _index)
Called as the skin deformation method changed.
Iterator class for the animations attached to a skeleton.
bool attachSkin(int skeletonId, int skinId)
Returns the number of frames in the currently active animation.
const UpdateType UPDATE_ALL(UpdateTypeSet(1))
Identifier for all updates.
void slotObjectUpdated(int _id, const UpdateType &_type)
Check activePose if a skeleton was updated.
Helper Class for UpdateUI. assigns a bool value and set it to "true". after leaving the scope...
bool getObject(int _identifier, BSplineCurveObject *&_object)
PolyMesh * polyMesh(BaseObjectData *_object)
Get a poly mesh from an object.
void exit()
Plugin gets closed.
void UpdateSkins(BaseObjectData *_pSkeletonObject, AnimationHandle &_hAni)
Changes the mesh's pose to represent the frame given by the animation handle.
Animation * animation(std::string _name)
Returns a pointer to the animation to the given name.
void removeAnimation(std::string _name)
Removes an animation from the list.
void fileOpened(int _id)
Update ui when the object is loaded.
A general pose, used to store the frames of the animation.
unsigned int animationIndex() const
Returns the animation index (zero based)
void slotObjectSelectionChanged(int _id)
Update ui when the object selection changes.
Abstract base class for the skin template, wrapping all template versions of the skin.
const QStringList TARGET_OBJECTS("target")
Iterable object range.
void nextFrame()
Called by the ui and goes to next frame of the current animation.
bool dataType(DataType _type) const
void checkObjectSelection(const int _objectId)
Check source/target selection of objects.
AnimationHandle animationHandle(std::string _name)
Get an AnimationHandle to the animation with the given name.
int animationOffset_
This frame was selected as the animation was started.
void removeSkin(int _objectId)
Remove a skin from the skeleton.
void slotAllCleared()
clear all occurred
TriMesh * triMesh(BaseObjectData *_object)
Get a triangle mesh from an object.
void addedEmptyObject(int _id)
Update ui when the object is added.
bool hasObjectData(QString _dataName)
Checks if object data with given name is available.
void prevFrame()
Called by the ui and goes to previous frame of the current animation.
void setObjectData(QString _dataName, PerObjectData *_data)
DLLEXPORT ObjectIterator objectsEnd()
Return Iterator to Object End.
void replaceAnimationName(const std::string &_strOld, const std::string &_strNew)
Returns a pointer to the pose with the given animation handle.
unsigned int skinCount()
Get the number of associated skins.
Pose * pose(unsigned int _iFrame)
Returns a pointer to the pose stored in the given frame.
void slotSkipFramesChanged(int _state)
Called as the skip frames check box changes state.
unsigned int animationCount()
Returns the number of animations stored in this skeleton.
QScriptValue callFunction(QString _plugin, QString _functionName, std::vector< QScriptValue > _parameters)
Call a function provided by a plugin getting multiple parameters.
void clearObjectData(QString _dataName)
Clear the object data pointer ( this will not delete the object!! )
void setComboBoxPosition(unsigned int _animationIndex)
Sets the animations combo box to the right entry.
unsigned int frame() const
Returns the selected frame (zero based)
QTime animationTime_
Time since the animation was started, used to meet the given fps.
int getFrame()
Gets the current frame number.
The skeletal animation plugin is used to interact with the skeleton.
void addSkin(int _objectId)
Add a skin to the skeleton.
SkeletalAnimationPlugin()
Constructor.
bool detachSkin(int skeletonId, int skinId)
Returns the number of frames in the currently active animation.
void slotAnimationIndexChanged(int)
Called by the framework when the animation index changed.
Add normals to mesh item (vertices/faces)
void setFrame(int _iFrame)
Displays the given frame from the current animation and updates the view.
A handle used to refer to an animation or to a specific frame in an animation.
AnimationHandle currentAnimationHandle()
Returns a handle describing the current frame in the active animation.
void changeFPS(int _fps)
Change the frames per second (FPS)
int skin(unsigned int _index)
Get the skin with given index (0 <= _index < skinCount())
void UpdateUI()
Called when the active object changes and the interface needs to be updated.
const std::string & animationName(unsigned int _index)
Returns the name of the animation with the given index.
bool bGuiUpdating_
Used to drop a few messages while the gui is being updated.
Skeleton * skeleton(BaseObjectData *_object)
Get a skeleton from an object.
#define DATA_TRIANGLE_MESH
void slotAttachSkin()
Called by Qt as the user is trying to connect a mesh to a skeleton.
void slotClearSkins()
Called by Qt as the user is trying to unbind a mesh from as a skeleton.
ACG::SceneGraph::SkeletonNodeT< Skeleton > * skeletonNode()
Returns the skeleton scenegraph node.
bool clearSkins(int skeletonId)
Returns the number of frames in the currently active animation.
Data object attached to the skeleton.
AnimationIterator animationsBegin()
Iterator over the animations.
int getNumberOfFrames()
Returns the number of frames in the currently active animation.
void animate()
Iterates the animation.
QTimer animationTimer_
Timer used to control animations.
void playAnimation()
Called by the ui and starts an automatic animation.
AnimationToolboxWidget * pToolbox_
A pointer to the toolbox widget.
unsigned int frameCount()
Returns the number of frames stored in this pose.