Added support for recording camera animation paths in osgGLUT::Viewer, and fixed

the osgGA::AnimationPathManipulator to handle it.

Added a new Drawable::ConstAttributeFunctor and make the accept(PrimitiveFunctor)
be a const method so can disallows modification.  Added Drawable::supports(...) methods
for each of the AttributeFunctor, ConstAttributeFunctor and PrimitiveFunctor so
that programs can querry whether it is possible to use functors with that object type.
This commit is contained in:
Robert Osfield
2002-11-06 10:24:33 +00:00
parent afa27a13ec
commit 5eb65f65cc
21 changed files with 422 additions and 115 deletions

View File

@@ -150,7 +150,10 @@ int main( int argc, char **argv )
if( !pathfile.empty() ) {
osgGA::AnimationPathManipulator *apm = new osgGA::AnimationPathManipulator(pathfile);
if( apm->valid() )
viewer.registerCameraManipulator(apm);
{
unsigned int no = viewer.registerCameraManipulator(apm);
viewer.selectCameraManipulator(no);
}
else
delete apm;
}

View File

@@ -20,14 +20,14 @@ bool AnimationPath::getInterpolatedControlPoint(double time,ControlPoint& contro
double fraction_part = modulated_time - floor(modulated_time);
if (fraction_part>0.5) fraction_part = 1.0-fraction_part;
time = (fraction_part*2.0) * getPeriod();
time = getFirstTime()+(fraction_part*2.0) * getPeriod();
break;
}
case(LOOP):
{
double modulated_time = (time - getFirstTime())/getPeriod();
double fraction_part = modulated_time - floor(modulated_time);
time = fraction_part * getPeriod();
time = getFirstTime()+fraction_part * getPeriod();
break;
}
case(NO_LOOPING):

View File

@@ -239,13 +239,13 @@ struct ComputeBound : public Drawable::PrimitiveFunctor
{
ComputeBound():_vertices(0) {}
virtual void setVertexArray(unsigned int,Vec3* vertices) { _vertices = vertices; }
virtual void setVertexArray(unsigned int,const Vec3* vertices) { _vertices = vertices; }
virtual void drawArrays(GLenum,GLint first,GLsizei count)
{
if (_vertices)
{
osg::Vec3* vert = _vertices+first;
const osg::Vec3* vert = _vertices+first;
for(;count>0;--count,++vert)
{
_bb.expandBy(*vert);
@@ -253,7 +253,7 @@ struct ComputeBound : public Drawable::PrimitiveFunctor
}
}
virtual void drawElements(GLenum,GLsizei count,GLubyte* indices)
virtual void drawElements(GLenum,GLsizei count,const GLubyte* indices)
{
if (_vertices)
{
@@ -264,7 +264,7 @@ struct ComputeBound : public Drawable::PrimitiveFunctor
}
}
virtual void drawElements(GLenum,GLsizei count,GLushort* indices)
virtual void drawElements(GLenum,GLsizei count,const GLushort* indices)
{
if (_vertices)
{
@@ -275,7 +275,7 @@ struct ComputeBound : public Drawable::PrimitiveFunctor
}
}
virtual void drawElements(GLenum,GLsizei count,GLuint* indices)
virtual void drawElements(GLenum,GLsizei count,const GLuint* indices)
{
if (_vertices)
{
@@ -291,7 +291,7 @@ struct ComputeBound : public Drawable::PrimitiveFunctor
virtual void vertex(float x,float y,float z) { _bb.expandBy(x,y,z); }
virtual void end() {}
Vec3* _vertices;
const Vec3* _vertices;
BoundingBox _bb;
};

View File

@@ -880,8 +880,32 @@ void GeoSet::accept(AttributeFunctor& auf)
}
}
void GeoSet::accept(ConstAttributeFunctor& auf) const
{
if (_numcoords == 0) computeNumVerts();
void GeoSet::accept(PrimitiveFunctor& functor)
if (_coords && _numcoords)
{
auf.apply(VERTICES,_numcoords,_coords);
}
if (_normals && _numnormals)
{
auf.apply(NORMALS,_numnormals,_normals);
}
if (_colors && _numcolors)
{
auf.apply(COLORS,_numcolors,_colors);
}
if (_tcoords && _numtcoords)
{
auf.apply(TEXTURE_COORDS_0,_numtcoords,_tcoords);
}
}
void GeoSet::accept(PrimitiveFunctor& functor) const
{
// will easily convert into a Geometry.

View File

@@ -842,22 +842,105 @@ void Geometry::drawImmediateMode(State& state)
}
class AttrbuteFunctorArrayVisitor : public ArrayVisitor
{
public:
AttrbuteFunctorArrayVisitor(Drawable::AttributeFunctor& af):
_af(af) {}
virtual ~AttrbuteFunctorArrayVisitor() {}
virtual void apply(ByteArray& array) { if (!array.empty()) _af.apply(_type,array.size(),&(array.front())); }
virtual void apply(ShortArray& array) { if (!array.empty()) _af.apply(_type,array.size(),&(array.front())); }
virtual void apply(IntArray& array) { if (!array.empty()) _af.apply(_type,array.size(),&(array.front())); }
virtual void apply(UByteArray& array) { if (!array.empty()) _af.apply(_type,array.size(),&(array.front())); }
virtual void apply(UShortArray& array) { if (!array.empty()) _af.apply(_type,array.size(),&(array.front())); }
virtual void apply(UIntArray& array) { if (!array.empty()) _af.apply(_type,array.size(),&(array.front())); }
virtual void apply(UByte4Array& array) { if (!array.empty()) _af.apply(_type,array.size(),&(array.front())); }
virtual void apply(FloatArray& array) { if (!array.empty()) _af.apply(_type,array.size(),&(array.front())); }
virtual void apply(Vec2Array& array) { if (!array.empty()) _af.apply(_type,array.size(),&(array.front())); }
virtual void apply(Vec3Array& array) { if (!array.empty()) _af.apply(_type,array.size(),&(array.front())); }
virtual void apply(Vec4Array& array) { if (!array.empty()) _af.apply(_type,array.size(),&(array.front())); }
inline void apply(Drawable::AttributeType type,Array* array)
{
if (array)
{
_type = type;
array->accept(*this);
}
}
Drawable::AttributeFunctor& _af;
Drawable::AttributeType _type;
};
void Geometry::accept(AttributeFunctor& af)
{
if (_vertexArray.valid() && !_vertexArray->empty())
{
af.apply(VERTICES,_vertexArray->size(),&(_vertexArray->front()));
}
AttrbuteFunctorArrayVisitor afav(af);
if (_normalArray.valid() && !_normalArray->empty())
afav.apply(VERTICES,_vertexArray.get());
afav.apply(NORMALS,_normalArray.get());
afav.apply(COLORS,_colorArray.get());
for(unsigned unit=0;unit<_texCoordList.size();++unit)
{
af.apply(NORMALS,_normalArray->size(),&(_normalArray->front()));
afav.apply((AttributeType)(TEXTURE_COORDS_0+unit),_texCoordList[unit].first.get());
}
// need to add other attriubtes
}
void Geometry::accept(PrimitiveFunctor& functor)
class ConstAttrbuteFunctorArrayVisitor : public ConstArrayVisitor
{
public:
ConstAttrbuteFunctorArrayVisitor(Drawable::ConstAttributeFunctor& af):
_af(af) {}
virtual ~ConstAttrbuteFunctorArrayVisitor() {}
virtual void apply(const ByteArray& array) { if (!array.empty()) _af.apply(_type,array.size(),&(array.front())); }
virtual void apply(const ShortArray& array) { if (!array.empty()) _af.apply(_type,array.size(),&(array.front())); }
virtual void apply(const IntArray& array) { if (!array.empty()) _af.apply(_type,array.size(),&(array.front())); }
virtual void apply(const UByteArray& array) { if (!array.empty()) _af.apply(_type,array.size(),&(array.front())); }
virtual void apply(const UShortArray& array) { if (!array.empty()) _af.apply(_type,array.size(),&(array.front())); }
virtual void apply(const UIntArray& array) { if (!array.empty()) _af.apply(_type,array.size(),&(array.front())); }
virtual void apply(const UByte4Array& array) { if (!array.empty()) _af.apply(_type,array.size(),&(array.front())); }
virtual void apply(const FloatArray& array) { if (!array.empty()) _af.apply(_type,array.size(),&(array.front())); }
virtual void apply(const Vec2Array& array) { if (!array.empty()) _af.apply(_type,array.size(),&(array.front())); }
virtual void apply(const Vec3Array& array) { if (!array.empty()) _af.apply(_type,array.size(),&(array.front())); }
virtual void apply(const Vec4Array& array) { if (!array.empty()) _af.apply(_type,array.size(),&(array.front())); }
inline void apply(Drawable::AttributeType type,const Array* array)
{
if (array)
{
_type = type;
array->accept(*this);
}
}
Drawable::ConstAttributeFunctor& _af;
Drawable::AttributeType _type;
};
void Geometry::accept(ConstAttributeFunctor& af) const
{
ConstAttrbuteFunctorArrayVisitor afav(af);
afav.apply(VERTICES,_vertexArray.get());
afav.apply(NORMALS,_normalArray.get());
afav.apply(COLORS,_colorArray.get());
for(unsigned unit=0;unit<_texCoordList.size();++unit)
{
afav.apply((AttributeType)(TEXTURE_COORDS_0+unit),_texCoordList[unit].first.get());
}
}
void Geometry::accept(PrimitiveFunctor& functor) const
{
if (!_vertexArray.valid() || _vertexArray->empty()) return;
@@ -866,7 +949,7 @@ void Geometry::accept(PrimitiveFunctor& functor)
{
functor.setVertexArray(_vertexArray->size(),&(_vertexArray->front()));
for(PrimitiveSetList::iterator itr=_primitives.begin();
for(PrimitiveSetList::const_iterator itr=_primitives.begin();
itr!=_primitives.end();
++itr)
{
@@ -875,11 +958,11 @@ void Geometry::accept(PrimitiveFunctor& functor)
}
else
{
for(PrimitiveSetList::iterator itr=_primitives.begin();
for(PrimitiveSetList::const_iterator itr=_primitives.begin();
itr!=_primitives.end();
++itr)
{
PrimitiveSet* primitiveset = itr->get();
const PrimitiveSet* primitiveset = itr->get();
GLenum mode=primitiveset->getMode();
switch(primitiveset->getType())
{
@@ -977,7 +1060,8 @@ void Geometry::accept(PrimitiveFunctor& functor)
}
}
}
}
}
return;
}
bool Geometry::verifyBindings() const

View File

@@ -121,7 +121,13 @@ void ImpostorSprite::accept(AttributeFunctor& af)
af.apply(TEXTURE_COORDS_0,4,_texcoords);
}
void ImpostorSprite::accept(PrimitiveFunctor& functor)
void ImpostorSprite::accept(ConstAttributeFunctor& af) const
{
af.apply(VERTICES,4,_coords);
af.apply(TEXTURE_COORDS_0,4,_texcoords);
}
void ImpostorSprite::accept(PrimitiveFunctor& functor) const
{
functor.setVertexArray(4,_coords);
functor.drawArrays( GL_QUADS, 0, 4);

View File

@@ -7,7 +7,7 @@ void DrawArrays::draw() const
glDrawArrays(_mode,_first,_count);
}
void DrawArrays::accept(Drawable::PrimitiveFunctor& functor)
void DrawArrays::accept(Drawable::PrimitiveFunctor& functor) const
{
functor.drawArrays(_mode,_first,_count);
}
@@ -24,10 +24,10 @@ void DrawArrayLengths::draw() const
}
}
void DrawArrayLengths::accept(Drawable::PrimitiveFunctor& functor)
void DrawArrayLengths::accept(Drawable::PrimitiveFunctor& functor) const
{
GLint first = _first;
for(VectorSizei::iterator itr=begin();
for(VectorSizei::const_iterator itr=begin();
itr!=end();
++itr)
{
@@ -53,7 +53,7 @@ void DrawElementsUByte::draw() const
glDrawElements(_mode,size(),GL_UNSIGNED_BYTE,&front());
}
void DrawElementsUByte::accept(Drawable::PrimitiveFunctor& functor)
void DrawElementsUByte::accept(Drawable::PrimitiveFunctor& functor) const
{
if (!empty()) functor.drawElements(_mode,size(),&front());
}
@@ -74,7 +74,7 @@ void DrawElementsUShort::draw() const
glDrawElements(_mode,size(),GL_UNSIGNED_SHORT,&front());
}
void DrawElementsUShort::accept(Drawable::PrimitiveFunctor& functor)
void DrawElementsUShort::accept(Drawable::PrimitiveFunctor& functor) const
{
if (!empty()) functor.drawElements(_mode,size(),&front());
}
@@ -95,7 +95,7 @@ void DrawElementsUInt::draw() const
glDrawElements(_mode,size(),GL_UNSIGNED_INT,&front());
}
void DrawElementsUInt::accept(Drawable::PrimitiveFunctor& functor)
void DrawElementsUInt::accept(Drawable::PrimitiveFunctor& functor) const
{
if (!empty()) functor.drawElements(_mode,size(),&front());
}

View File

@@ -12,7 +12,7 @@ class DrawShapeVisitor : public ConstShapeVisitor
{
public:
DrawShapeVisitor(State& state,TessellationHints* hints):
DrawShapeVisitor(State& state,const TessellationHints* hints):
_state(state),
_hints(hints) {}
@@ -29,7 +29,7 @@ class DrawShapeVisitor : public ConstShapeVisitor
virtual void apply(const CompositeShape&);
State& _state;
TessellationHints* _hints;
const TessellationHints* _hints;
};
@@ -802,7 +802,7 @@ class PrimitiveShapeVisitor : public ConstShapeVisitor
{
public:
PrimitiveShapeVisitor(Drawable::PrimitiveFunctor& functor,TessellationHints* hints):
PrimitiveShapeVisitor(Drawable::PrimitiveFunctor& functor,const TessellationHints* hints):
_functor(functor),
_hints(hints) {}
@@ -819,7 +819,7 @@ class PrimitiveShapeVisitor : public ConstShapeVisitor
virtual void apply(const CompositeShape&);
Drawable::PrimitiveFunctor& _functor;
TessellationHints* _hints;
const TessellationHints* _hints;
};
@@ -1198,10 +1198,6 @@ void PrimitiveShapeVisitor::apply(const HeightField& field)
float dx = field.getXInterval();
float dy = field.getYInterval();
float du = 1.0f/((float)field.getNumColumns()-1.0f);
float dv = 1.0f/((float)field.getNumRows()-1.0f);
float vBase = 0.0f;
for(unsigned int row=0;row<field.getNumRows()-1;++row)
{
@@ -1264,11 +1260,11 @@ void ProceduralGeometry::drawImmediateMode(State& state)
}
}
void ProceduralGeometry::accept(AttributeFunctor&)
void ProceduralGeometry::accept(ConstAttributeFunctor&) const
{
}
void ProceduralGeometry::accept(PrimitiveFunctor& pf)
void ProceduralGeometry::accept(PrimitiveFunctor& pf) const
{
if (_shape.valid())
{

View File

@@ -6,6 +6,8 @@ using namespace osgGA;
AnimationPathManipulator::AnimationPathManipulator(osg::AnimationPath* animationPath)
{
_animationPath = animationPath;
_timeOffset = 0.0f;
_timeScale = 1.0f;
}
AnimationPathManipulator::AnimationPathManipulator( const std::string& filename )
@@ -35,6 +37,19 @@ AnimationPathManipulator::AnimationPathManipulator( const std::string& filename
fclose(fp);
}
void AnimationPathManipulator::home(const GUIEventAdapter& ea,GUIActionAdapter&)
{
if (_animationPath.valid())
{
_timeOffset = _animationPath->getFirstTime()-ea.time();
}
}
void AnimationPathManipulator::init(const GUIEventAdapter& ea,GUIActionAdapter& aa)
{
home(ea,aa);
}
bool AnimationPathManipulator::handle(const osgGA::GUIEventAdapter& ea,osgGA::GUIActionAdapter& us)
{
if( !valid() ) return false;
@@ -49,6 +64,15 @@ bool AnimationPathManipulator::handle(const osgGA::GUIEventAdapter& ea,osgGA::GU
retval = true;
break;
case GUIEventAdapter::KEYBOARD:
if (ea.getKey()==' ')
{
home(ea,us);
us.requestRedraw();
us.requestContinuousUpdate(false);
return true;
}
return false;
retval = false;
break;
default:
@@ -60,17 +84,14 @@ bool AnimationPathManipulator::handle(const osgGA::GUIEventAdapter& ea,osgGA::GU
void AnimationPathManipulator::handleFrame( double time )
{
osg::AnimationPath::ControlPoint cp;
_animationPath->getInterpolatedControlPoint( time, cp );
_animationPath->getInterpolatedControlPoint( (time+_timeOffset)*_timeScale, cp );
osg::Matrix mat;
cp.getMatrix( mat );
osg::Vec3 eye(mat(3,0), mat(3,1), mat(3,2));
mat(3,0) = 0.0;
mat(3,1) = 0.0;
mat(3,2) = 0.0;
osg::Vec3 look = eye + (osg::Vec3(0,1,0) * mat);
osg::Vec3 up = osg::Vec3(0,0,1) * mat;
if( _camera.valid() )
_camera->setView( eye, look, up );
osg::Matrix matrix;
cp.getMatrix( matrix );
if (_camera.valid())
{
_camera->home();
_camera->transformLookAt(matrix);
}
}

View File

@@ -129,17 +129,7 @@ Viewer::Viewer()
_displaySettings = osgNew osg::DisplaySettings;
_recordingAnimationPath = false;
}
@@ -392,21 +382,34 @@ float Viewer::app(unsigned int viewport)
ea->adaptFrame(_frameStamp->getReferenceTime());
bool handled = false;
for ( EventHandlerList::iterator eh =
_viewportList[viewport]._eventHandlerList.begin();
eh != _viewportList[viewport]._eventHandlerList.end(); eh++ ) {
if ( eh->valid() ) {
if ( (*eh)->handle(*ea,*this) ) {
for (EventHandlerList::iterator eh = _viewportList[viewport]._eventHandlerList.begin();
eh != _viewportList[viewport]._eventHandlerList.end();
eh++ )
{
if ( eh->valid() )
{
if ( (*eh)->handle(*ea,*this) )
{
handled = true;
break;
}
}
}
if ( !handled ) {
// if ( !handled ) {
_viewportList[viewport]._cameraManipulator->handle(*ea,*this);
}
// }
if (getRecordingAnimationPath() && getAnimationPath())
{
osg::Camera* camera = getViewportSceneView(viewport)->getCamera();
osg::Matrix matrix;
matrix.invert(camera->getModelViewMatrix());
osg::Quat quat;
quat.set(matrix);
getAnimationPath()->insert(_frameStamp->getReferenceTime(),osg::AnimationPath::ControlPoint(matrix.getTrans(),quat));
}
// do app traversal.
getViewportSceneView(viewport)->setFrameStamp(_frameStamp.get());
@@ -912,7 +915,7 @@ void Viewer::keyboard(unsigned char key, int x, int y)
if (key>='1' && key<='4')
{
int pos = key-'1';
selectCameraManipulator(pos);
selectCameraManipulator(pos,_focusedViewport);
}
osgUtil::SceneView* sceneView = getViewportSceneView(_focusedViewport);
@@ -1322,6 +1325,68 @@ void Viewer::keyboard(unsigned char key, int x, int y)
}
break;
case 'Z' :
case 'z' :
if (getRecordingAnimationPath())
{
// have already been recording so switch of recording.
setRecordingAnimationPath(false);
osg::notify(osg::NOTICE) << "Finished recording camera animation, press 'Z' to reply."<< std::endl;
if (getAnimationPath())
{
std::ofstream fout("saved_animation.path");
const AnimationPath::TimeControlPointMap& tcpm = getAnimationPath()->getTimeControlPointMap();
for(AnimationPath::TimeControlPointMap::const_iterator tcpmitr=tcpm.begin();
tcpmitr!=tcpm.end();
++tcpmitr)
{
const AnimationPath::ControlPoint& cp = tcpmitr->second;
fout<<tcpmitr->first<<" "<<cp._position<<" "<<cp._rotation<<std::endl;
}
fout.close();
osg::notify(osg::NOTICE) << "Saved camera animation to 'saved_animation.path'"<< std::endl;
}
}
else if (key=='z')
{
setRecordingAnimationPath(true);
setAnimationPath(new osg::AnimationPath());
getAnimationPath()->setLoopMode(osg::AnimationPath::LOOP);
osg::notify(osg::NOTICE) << "Recording camera animation, press 'z' to finish recording."<< std::endl;
}
if (key=='Z')
{
osgGA::AnimationPathManipulator* apm = 0;
int apmNo = 0;
CameraManipList& cmlist = _viewportList[_focusedViewport]._cameraManipList;
for(CameraManipList::iterator cmlitr=cmlist.begin();
cmlitr!=cmlist.end() && apm==0;
++cmlitr,++apmNo)
{
apm = dynamic_cast<osgGA::AnimationPathManipulator*>(cmlitr->get());
}
if (!apm)
{
apm = new osgGA::AnimationPathManipulator();
apmNo = registerCameraManipulator(apm,_focusedViewport);
}
apm->setAnimationPath(getAnimationPath());
apm->home(*ea,*this);
selectCameraManipulator(apmNo,_focusedViewport);
}
break;
case 27 :
_exit = true;
@@ -1412,6 +1477,12 @@ void Viewer::help(std::ostream& fout)
<<" it just maximizes the window and leaves the window's borders."<< std::endl
<<" If started in full screen mode on Linux, window will be borderless"<< std::endl
<<" and will resize down, but will remain borderless."<< std::endl
<< std::endl
<<"y Reduce fog density."<< std::endl
<<"Y Increase fog density."<< std::endl
<< std::endl
<<"z Toggle recording of camera path."<< std::endl
<<"Z Reply recorded camera path."<< std::endl
<<"Space Reset scene to the default view."<< std::endl
<<"Esc Exit sgv."<< std::endl;
}