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