I have already make this job in the cooki3d api the source code will be available as soon as possible (Perhaps Monday).
This class can help you.
You can make play, stop, pause, forward (with setPosition), backward (with setPosition), resize (with setDuration).
Animation.h
/** -*-c++-*- *************************************************************\
* (Remise à zéro le 24/10/04 et le 23/06/06)
* File: Animation.h
* Creation date: June 23, 2006 18:26
* Author: Bertrand Greslier
* Entreprise Individuelle
* Purpose: Declaration of class 'Animation'
*
* Copyright 2006, Bertrand Greslier
* All rights are reserved. Reproduction in whole or part is prohibited
* without the written consent of the copyright owner.
*
\**************************************************************************/
#ifndef _ANIMATION_H
#define _ANIMATION_H
//@START_USER1
#include "MediaEvaluable.h"
#include <osg/Matrixf>
#include <osg/Matrixd>
#include <osg/Quat>
#include <osg/NodeCallback>
#include <osg/AnimationPath>
#include <map>
#include <float.h>
#include "XMLUtil.h "
#include "LoaderGeneric.h"
namespace cooki3d{
//@END_USER1
/[EMAIL PROTECTED]
classe ...
*/
class AFX_EXT_CLASS Animation
: public MediaEvaluable
{
//@START_USER2
public :
typedef map<string,Animation*,less<string > > mapStrAnim;
//@END_USER2
//
// Group: ClassBuilder methods
//
private:
void ConstructorInclude();
void DestructorInclude();
//
// Group: Media
//
public:
virtual void setPosition(double sec);
virtual bool isPlay();
virtual bool isPause();
virtual double eval(std::string methode, double args[10], int nbParam);
double getDebut();
virtual double getDuration();
double getFin();
virtual void pause();
virtual void play();
virtual double getPosition();
virtual void setDuration(double duree);
virtual void stop();
//
// Group: Modes
//
public:
std::string getLoopMode();
void setLoopMode(std::string mode);
std::string traduireLoopModeFromEnumToString(osg::AnimationPath::LoopMode mode);
osg::AnimationPath::LoopMode traduireLoopModeFromStringToEnum(std::string mode);
//
// Group: load
//
public:
void init();
static bool linkAnimation(osg::Node* n, const std::string& pickName,
LoaderGeneric* loader);
static Evaluable* staticCreate(BD* pBD);
bool loadXML(const xmlpp::Node* node, LoaderXML* loaderXML);
virtual void setApc(osg::AnimationPathCallback* pApc);
static bool checkAllInstances(LoaderGeneric* loader);
virtual bool check();
Animation(BD* pBD);
Animation(Animation& anim);
virtual ~Animation();
//
// Group: zdata
//
protected:
osg::AnimationPathCallback* _apc;
bool _automaticSet;
std::string _bufferLoopMode;
int _debut;
int _fin;
int _fps;
std::string _nodeName;
osg::AnimationPath* _path;
osg::AnimationPath* _pathInit;
public:
osg::AnimationPathCallback* getApc() const;
bool getAutomaticSet() const;
void setAutomaticSet(bool automaticSet);
std::string getBufferLoopMode() const;
int getFps() const;
void setFps(int fps);
std::string getNodeName() const;
void setNodeName(std::string nodeName);
//
// Non-Grouped Members
//
//
// Non-Grouped Methods
//
public:
virtual bool isAtomic();
};
#endif
#ifdef CB_INLINES
#ifndef _ANIMATION_H_INLINES
#define _ANIMATION_H_INLINES
//
// Group: zdata
//
/[EMAIL PROTECTED]
Returns the value of member '_apc'.
*/
inline osg::AnimationPathCallback* Animation::getApc() const
{//@CODE_1029
return _apc;
}//@CODE_1029
/[EMAIL PROTECTED]
Returns the value of member '_automaticSet'.
*/
inline bool Animation::getAutomaticSet() const
{//@CODE_4375
return _automaticSet;
}//@CODE_4375
/[EMAIL PROTECTED]
Set the value of member '_automaticSet' to 'automaticSet'.
*/
inline void Animation::setAutomaticSet(bool automaticSet)
{//@CODE_4376
_automaticSet = automaticSet;
}//@CODE_4376
/[EMAIL PROTECTED]
Returns the value of member '_bufferLoopMode'.
*/
inline std::string Animation::getBufferLoopMode() const
{//@CODE_3931
return _bufferLoopMode;
}//@CODE_3931
/[EMAIL PROTECTED]
Returns the value of member '_fps'.
*/
inline int Animation::getFps() const
{//@CODE_1020
return _fps;
}//@CODE_1020
/[EMAIL PROTECTED]
Set the value of member '_fps' to 'fps'.
*/
inline void Animation::setFps(int fps)
{//@CODE_1021
_fps = fps;
}//@CODE_1021
/[EMAIL PROTECTED]
Returns the value of member '_nodeName'.
*/
inline std::string Animation::getNodeName() const
{//@CODE_1014
return _nodeName;
}//@CODE_1014
/[EMAIL PROTECTED]
Set the value of member '_nodeName' to 'nodeName'.
*/
inline void Animation::setNodeName(std::string nodeName)
{//@CODE_1015
_nodeName = nodeName;
}//@CODE_1015
// End of Group: zdata
//@START_USER3
} //end of namespace cooki3d
//@END_USER3
#endif
#endif
Animation.cpp
/** -*-c++-*- *************************************************************\
* (Remise à zéro le 24/10/04 et le 23/06/06)
* File: Animation.cpp
* Creation date: June 23, 2006 18:26
* Author: Bertrand Greslier
* Entreprise Individuelle
* Purpose: Declaration of class 'Animation'
*
* Copyright 2006, Bertrand Greslier
* All rights are reserved. Reproduction in whole or part is prohibited
* without the written consent of the copyright owner.
*
\**************************************************************************/
//@START_USER1
//@END_USER1
// Master include file
#include " CookiMetier.h"
//@START_USER2
#include "Media.h"
#include "BD.h"
#include "Animation.h"
#include "XMLUtil.h"
#include "EnvironnementOSG.h"
//#include "MediaInterface.h"
namespace cooki3d {
//@END_USER2
//
// Group: Media
//
void Animation::setPosition(double sec)
{//@CODE_168
//060621 le reset n'affecte plus _firstTime de la même facon...
double time = getEnv()->getFrameStamp()->getReferenceTime();
_apc->setPause(false);
if (_apc->getAnimationPath() != _path) {
_apc->setAnimationPath(_path);
_apc->reset();
_apc->_firstTime = /*_apc->_firstTime*/time - getDebut();
cout<<"premiere utilisation sur setPosition"<<endl;
}
CTRACE(this,"setPosition")<<" passage"<<endl;
_apc->reset();
_apc->_firstTime = time - getDebut() - sec;
getEnv()->requestRedraw();
pause();
}//@CODE_168
bool Animation::isPlay()
{//@CODE_302
return (_apc->getAnimationPath()==_path);
}//@CODE_302
bool Animation::isPause()
{//@CODE_303
return isPlay() && _apc->_pause;
}//@CODE_303
double Animation::eval(std::string methode, double args[10], int nbParam)
{//@CODE_1201
return Media::eval(methode,args,nbParam);
}//@CODE_1201
double Animation::getDebut()
{//@CODE_203
//cout<<"GEtperiode="<<_path->getPeriod()<<endl;
return double( (double(_debut)/_fps) );
}//@CODE_203
double Animation::getDuration()
{//@CODE_169
return getFin()-getDebut();
}//@CODE_169
double Animation::getFin()
{//@CODE_202
return double( (double(_fin)/_fps) - 0.00001);
}//@CODE_202
void Animation::pause()
{//@CODE_170
_apc->setPause(true);
}//@CODE_170
void Animation::play()
{//@CODE_171
//cout<<"Animation: Salut "<<endl;
assertC( _apc->getAnimationPath() );
if (_apc->getAnimationPath() != _path) {
_apc->setAnimationPath(_path);
_apc->reset();
//060621 le reset n'affecte plus _firstTime de la même facon...
double time = getEnv()->getFrameStamp()->getReferenceTime();
_apc->_firstTime = /*_apc->_firstTime*/time - getDebut();
//_path->setLoopMode(_loopMode);
CTRACE(this,"play")<<"premiere utilisation"<<endl;
//init();
}
//replay
/*else if ((_loopMode == osg::AnimationPath::NO_LOOPING) &&
(_apc->getAnimationTime() > getFin()) && !_apc->_pause) {
cout<<"_apc->getAnimationTime()"<<_apc->getAnimationTime()<<endl;
_apc->reset();
_apc->_firstTime -= getDebut();
}*/
//A eval
//si animation non finie, il faut empiler dans le
//TimerThread une action play avec un timer déclencheur
//égale au restant de l'animation en cours
_apc->setPause(false);
}//@CODE_171
double Animation::getPosition()
{//@CODE_304
//double value;
CERR(this,"getPosition")<<"cette méthode n'est pas implémentée"<<endl;
return 0.0;
//return value;
}//@CODE_304
void Animation::setDuration(double duree)
{//@CODE_632
double dureeInit = getDuration();
osg::AnimationPath::TimeControlPointMap& mapp=
_path->getTimeControlPointMap();
osg::AnimationPath::TimeControlPointMap::iterator it=mapp.begin();
while (it != mapp.end()) {
//double * ad= (double*)&(it->first);
//*ad = it->first * (duree/dureeInit);
*(const_cast<double*>(&(it->first))) = it->first * (duree/dureeInit);
it++;
}
it--;
_fin = int(double(_fin) * (duree/dureeInit));
}//@CODE_632
void Animation::stop()
{//@CODE_172
//_apc->reset();
CTRACE(this,"stop")<<endl;
//_apc->_firstTime -= getDebut();
//_apc->setPause(true);
_apc->setAnimationPath(_pathInit);
_apc->setPause( false ); //060620
}//@CODE_172
// End of Group: Media
//
// Group: Modes
//
std::string Animation::getLoopMode()
{//@CODE_1868
return traduireLoopModeFromEnumToString(_path->getLoopMode());
}//@CODE_1868
void Animation::setLoopMode(std::string mode)
{//@CODE_208
_path->setLoopMode(traduireLoopModeFromStringToEnum(mode));
}//@CODE_208
std::string Animation::traduireLoopModeFromEnumToString(osg::AnimationPath::LoopMode mode)
{//@CODE_1862
switch (mode){
case osg::AnimationPath::NO_LOOPING:
return "NO_LOOPING";
case osg::AnimationPath::LOOP:
return "LOOP";
case osg::AnimationPath::SWING:
return "SWING";
}
assertC(0);
return NULL;
}//@CODE_1862
osg::AnimationPath::LoopMode Animation::traduireLoopModeFromStringToEnum(std::string mode)
{//@CODE_210
if (mode == "NO_LOOPING")
return osg::AnimationPath::LoopMode(osg::AnimationPath::NO_LOOPING);
if (mode == "LOOP")
return osg::AnimationPath::LoopMode(osg::AnimationPath::LOOP);
if (mode == "SWING")
return osg::AnimationPath::LoopMode(osg::AnimationPath::SWING);
CTRACEs("Animation::traduireLoopModeFromStringToEnum")
<<"mode ="<<mode<<endl;
CTRACEnext<<"mode.length() ="<<mode.length()<<endl;
assertC(0);
return osg::AnimationPath::LoopMode(osg::AnimationPath::SWING);//antiwarning
}//@CODE_210
// End of Group: Modes
//
// Group: load
//
void Animation::init()
{//@CODE_212
_apc->setAnimationPath(_pathInit);
_apc->reset();
//060621 le reset n'affecte plus _firstTime de la même facon...
//_apc->_firstTime = _apc->_firstTime - getDebut();
//_path->setLoopMode(_loopMode);
setLoopMode(_bufferLoopMode);
CTRACEs("Animation::linkAnimation")<<" init animation "
<<getName()<<"( "<<this
<<" )"<<endl;
}//@CODE_212
bool Animation::linkAnimation(osg::Node* n, const std::string& pickName,
LoaderGeneric* loader)
{//@CODE_1196
//CTRACEs("Animation::linkAnimation")
//<<"av assert"<<endl;
assertC(n);
bool res=false;
//CTRACEs("Animation::linkAnimation")
//<<"av getName"<<endl;
//std::string pickName = n->getName();
//BUG JVM typeid plante => non probleme antéteur!!
//CTRACEs("Animation::linkAnimation")
//<<" passage linkAnimation su le Node "<<pickName
//<<"("<<typeid(*n).name()<<")"<<endl;
//CTRACEs("Animation::linkAnimation")
//<<"ap getName"<<endl;
if ( n->getUpdateCallback() ){
osg::AnimationPathCallback *apc=dynamic_cast<osg::AnimationPathCallback *>
(n->getUpdateCallback());
if (apc) {
BD::EvaluableIterator itMed(loader->getBD());
CTRACEs("Animation::linkAnimation")<<"search "<<pickName<<"..."<<endl;
Animation * anim ;
//for (unsigned int i=0; i<listeM.size (); i++){
while ( ++itMed ){
anim=dynamic_cast<Animation *>(itMed.Get());
//TODO améliorer le ratio qui catastrophique -> registre
//cout<<" traitement "<<anim<<endl;
if (anim
&& anim->isAtomic()
&& (anim->getNodeName() == pickName) ) {
if (anim->getApc()){
CERRs("Animation::linkAnimation")
<<" APC not NULL for "
<<anim<<", pickName=\""<<pickName<<"\" "
<<"instance =\""<<anim->getName()<<"\""
<<" is already linked !"<<endl;
}else {
anim->setApc(apc);
anim->init();
res=true;
}
}
}
}
else {
CWARNs("Animation::linkAnimation")<<
"suspect dynamic_cast<osg::AnimationPathCallback *> fail !"<<endl;
}
}else {
}
return res;
}//@CODE_1196
Evaluable* Animation::staticCreate(BD* pBD)
{//@CODE_3032
/*Animation * animLoader = new Animation();
animLoader->setNameWithoutPrefix( "staticLoader" );
return animLoader;*/
return new Animation(pBD);
}//@CODE_3032
bool Animation::loadXML(const xmlpp::Node* node, LoaderXML* loaderXML)
{//@CODE_3051
//staticLoader 1 animation XML => n animation instance
// return Animation::staticLoadXML(node);
XMLUtil xml(node);
setName( xml.getFirstText("nom") );
_automaticSet = xml.getFirstText("automaticSet") == "true";
if (! _automaticSet ){
_debut=atoi(xml.getFirstText("debut").c_str());
_fin=atoi(xml.getFirstText("fin").c_str());
_fps=atoi(xml.getFirstText("fps").c_str());
}
_bufferLoopMode = xml.getFirstText("mouv");
setPlayOnStart( xml.getFirstText("playOnStart")=="true");
if (isAtomic()){
setNodeName(xml.getFirstText("nodeName"));
CINFOs<<"XML: new animation \""<<getNodeName()
<<"\" ("<<getName()<<")"<<endl;
}
return true;
}//@CODE_3051
void Animation::setApc(osg::AnimationPathCallback* pApc)
{//@CODE_3168
CINFOs<<"Animation link \""<<getNodeName()<<"\"("<<getName()
<<", "<<this<<") with osg::APC "<<endl;
//CTRACEs("Animation::linkAnimation")" setApc sur "
//<<pickName<<endl;
_apc = pApc;
//if (_path) delete _path;
_path=new osg::AnimationPath;
osg::AnimationPath * origin= pApc->getAnimationPath();
CTRACE(this,"setApc")<<"origin->getFirstTime() = "
<<origin->getFirstTime()<<endl;
CTRACE(this,"setApc")<<"origin->getLastTime() = "
<<origin->getLastTime()<<endl;
if (/*! bInitFromProperties*/ _automaticSet){
_debut = int( origin->getFirstTime() * _fps );
_fin = int( origin->getLastTime() * _fps );
}
//sinon quelques vérifications
else if ((origin->getFirstTime() > getDebut()) ||
(origin->getLastTime() < getFin())) {
CTRACE(this,"setApc")<<"Animation path choisi incohérent"<<endl;
CTRACE(this,"setApc")<<"origin->getFirstTime() = "<<origin->getFirstTime()
<<endl;
CTRACE(this,"setApc")<<"origin->getLastTime()= "<<origin->getLastTime()
<<endl;
CTRACE(this,"setApc")<<"getDebut() = "<<getDebut()<<endl;
CTRACE(this,"setApc")<<"getFin() = "<<getFin()<<endl;
CERR(this,"setApc")<<"incoherent parameters => the object "<<getName()
<<" will be initialized automaticaly from "
<<"the properties of the apc (AnimationPathCallback)"
<<" as if \"automaticSet\" have been cheked "
<<endl;
setApc( pApc );
//" va être détruit"<<endl;
//this->~Animation();
return;
}
//création du premier et denier point de controle
osg::AnimationPath::ControlPoint p;
if (!origin->getInterpolatedControlPoint(getDebut(),p)) assertC(0);
_path->insert(getDebut(),p);
if (!origin->getInterpolatedControlPoint(getFin(),p)) assertC(0);
_path->insert(getFin(),p);
CTRACE(this,"setApc")<<"pour deb,fin ="<<getDebut()
<<", "<<getFin()<<endl<<endl;
//récuparation des points de controles existant
osg::AnimationPath::TimeControlPointMap& mapp=
origin->getTimeControlPointMap();
osg::AnimationPath::TimeControlPointMap::iterator it= mapp.begin();
while (it != mapp.end()) {
if ((it->first > getDebut()+0.00001) && (it->first < getFin()-0.00001)) {
_path->insert(it->first,it->second);
//cout<<"add time control point ="<<it->first<<endl;
}
it++;
}
//création d'un path à une seule image pour que l'objet soit
//en place dès le lancement ou lors d'un stop
_pathInit=new osg::AnimationPath;
if (!origin->getInterpolatedControlPoint(getDebut(),p)) assertC(0);
_pathInit->insert(getDebut(),p);
//référencement pour indiquer que l'on possère un
//exemplaire du pointeur et qu'il ne faut pas le
//détruire
_path->ref();
_pathInit->ref();
}//@CODE_3168
bool Animation::checkAllInstances(LoaderGeneric* loader)
{//@CODE_3171
BD::EvaluableIterator itAnim(loader->getBD());
Animation * anim;
bool resultOk = true;
while (++itAnim){
anim=dynamic_cast<Animation *>(itAnim.Get());
if (anim && anim->getName() != "staticLoader") {
resultOk = resultOk && anim->check();
}
}
return resultOk;
}//@CODE_3171
/[EMAIL PROTECTED]
Check the integritry of the object
*/
bool Animation::check()
{//@CODE_3172
bool resultOk = _path != NULL && _pathInit != NULL && _apc != NULL;
if (!resultOk){
CERR(this,"check")<<" instance \""<<getName()
<<"\", node \""<<getNodeName()
<<"\" is not linked !!"<<endl;
}
return resultOk;
}//@CODE_3172
/[EMAIL PROTECTED]
Constructor method.
*/
Animation::Animation(BD* pBD) //@INIT_167
: MediaEvaluable(pBD)
, _apc(NULL)
, _automaticSet(true)
, _bufferLoopMode("NO_LOOPING")
, _debut(0)
, _fin(100)
, _fps(30)
, _nodeName()
, _path(NULL)
, _pathInit(NULL)
{//@CODE_167
ConstructorInclude();
// Put in your own code
}//@CODE_167
/[EMAIL PROTECTED]
Constructor method.
*/
Animation::Animation(Animation& anim) //@INIT_3982
: MediaEvaluable(anim.getBD())
, _apc(/*anim._apc*/NULL)
, _automaticSet(true)
, _bufferLoopMode(anim._bufferLoopMode)
, _debut(anim._debut)
, _fin(anim._fin)
, _fps(anim._fps)
, _nodeName(/*anim._nodeName*/"")
, _path(anim._path)
, _pathInit(/*anim._pathInit*/NULL)
{//@CODE_3982
ConstructorInclude();
// Put in your own code
}//@CODE_3982
/[EMAIL PROTECTED]
Destructor method.
*/
Animation::~Animation()
{//@CODE_162
DestructorInclude();
// Put in your own code
}//@CODE_162
// End of Group: load
bool Animation::isAtomic()
{//@CODE_3923
return true;
}//@CODE_3923
//{{AFX DO NOT EDIT CODE BELOW THIS LINE !!!
/[EMAIL PROTECTED]
Method which must be called first in a constructor.
*/
void Animation::ConstructorInclude()
{
}
/[EMAIL PROTECTED]
Method which must be called first in a destructor.
*/
void Animation::DestructorInclude()
{
}
// Methods for the relation(s) of the class
//}}AFX DO NOT EDIT CODE ABOVE THIS LINE !!!
//@START_USER3
} //end of namespace cooki3d
On 11/2/06, [EMAIL PROTECTED] <
[EMAIL PROTECTED]> wrote:
Hi Jae,I did this very same thing. Actually I wanted mine to not just PAUSE, but to play forward, reversem and scrub with the mouse. I was reading in an entire scene graph from a file (A .lws, lightwave scene actually), so the AnimationPath stuff was already built in and I did not want to mess with it, or even have to traverse and find the handles for all of the animation paths.What I really wanted to do was be able to set the time myself rather than let the Viewer do it for me. I personally like using osgProducer::OsgCameraGroup rather than the Viewer. The Viewer keeps track of a timer and does all of the following stuff under the hood, and I couldn't find out how to modify that easily (maybe there is Robert?).What is happening underneath is that you create an osg::FrameStamp, set its time and frame number to whatever you want, (normally you keep track of a little timer and update it, but this way you can set the time yourself), then create an osgUtil::UpdateVisitor and set its framestamp to the one you just created, then you have the scene graph accept the update visitor.-- RickHi Jae,
The osg::AnimationPathCallback has code in it for pausing, restarting.
You attach the AnimationPath to the AnimationPathCallback, then
attach this to the Node you want to animate.
Robert.Hi,
Currently I am working on a viewer with scenario feature.
Within the scenario, the user can load a txt file with list of camera position and rotation and the viewer produce a camera path.
This has been achieved by useing the osg::animationPath and osg::Timer.
Now I would like to add start, stop and pause. However I could not find any documentation about stop the animationPath.
Is this possible? If so how?
If it is not possible, is it going to be added in future?
Thank you in advance
Jae
_______________________________________________
osg-users mailing list
[email protected]
http://openscenegraph.net/mailman/listinfo/osg-users
http://www.openscenegraph.org/
--
Bertrand Greslier
http://www.cooki3d.org
_______________________________________________ osg-users mailing list [email protected] http://openscenegraph.net/mailman/listinfo/osg-users http://www.openscenegraph.org/
