diff --git a/AUTHORS b/AUTHORS index dbc9b524d..70854cc72 100644 --- a/AUTHORS +++ b/AUTHORS @@ -94,8 +94,9 @@ Phil Atkin Boris Bralo - txp TerraPage loader. -Sasa Bistrivic +Sasa Bistrovic - option for detailed calculation of the near clipping plane during cull traversal. + - osg::DOFTransform Nikolaus Hanekamp - added support billboards to Open Flight loader. diff --git a/VisualStudio/osg/osg.dsp b/VisualStudio/osg/osg.dsp index 744d4922c..08bda5faa 100755 --- a/VisualStudio/osg/osg.dsp +++ b/VisualStudio/osg/osg.dsp @@ -173,6 +173,10 @@ SOURCE=..\..\src\osg\DisplaySettings.cpp # End Source File # Begin Source File +SOURCE=..\..\src\osg\DOFTransform.cpp +# End Source File +# Begin Source File + SOURCE=..\..\src\osg\Drawable.cpp # End Source File # Begin Source File @@ -485,6 +489,10 @@ SOURCE=..\..\include\osg\DisplaySettings # End Source File # Begin Source File +SOURCE=..\..\include\osg\DOFTransform +# End Source File +# Begin Source File + SOURCE=..\..\Include\Osg\Drawable # End Source File # Begin Source File diff --git a/include/osg/DOFTransform b/include/osg/DOFTransform new file mode 100644 index 000000000..97338f0c5 --- /dev/null +++ b/include/osg/DOFTransform @@ -0,0 +1,138 @@ +//C++ header - Open Scene Graph - Copyright (C) 1998-2002 Robert Osfield +//created by Sasa Bistrovic +//Distributed under the terms of the GNU Library General Public License (LGPL) +//as published by the Free Software Foundation. + +#if !defined(OSG_DOFTRANSFORM) +#define OSG_DOFTRANSFORM + +//base class: +#include + +namespace osg{ +/** DOFTransform - encapsulates Multigen DOF behavior*/ +class SG_EXPORT DOFTransform : public MatrixTransform +{ + public: + /** constructor*/ + DOFTransform(); + + /**copy constructor*/ + DOFTransform(const DOFTransform& dof, const CopyOp& copyop=CopyOp::SHALLOW_COPY): + MatrixTransform(dof, copyop), + _minHPR(dof._minHPR), + _maxHPR(dof._maxHPR), + _currentHPR(dof._currentHPR), + _incrementHPR(dof._incrementHPR), + _minTranslate(dof._minTranslate), + _maxTranslate(dof._maxTranslate), + _currentTranslate(dof._currentTranslate), + _incrementTranslate(dof._incrementTranslate), + _minScale(dof._minScale), + _maxScale(dof._maxScale), + _currentScale(dof._currentScale), + _incrementScale(dof._incrementScale), + _Put(dof._Put), + _inversePut(dof._inversePut), + _limitationFlags(dof._limitationFlags), + _animationOn(dof._animationOn), + _increasingFlags(dof._increasingFlags) {} + + META_Node(osg, DOFTransform); + + void loadMinHPR(const Vec3& hpr) {_minHPR = hpr;} + void loadMaxHPR(const Vec3& hpr) {_maxHPR = hpr;} + void loadCurrentHPR(const Vec3& hpr) {_currentHPR = hpr;} + void loadIncrementHPR(const Vec3& hpr) {_incrementHPR = hpr;} + + void setCurrentHPR(const Vec3& hpr); + + void loadMinTranslate(const Vec3& translate) {_minTranslate = translate;} + void loadMaxTranslate(const Vec3& translate) {_maxTranslate = translate;} + void loadCurrentTranslate(const Vec3& translate){_currentTranslate = translate;} + void loadIncrementTranslate(const Vec3& translate) {_incrementTranslate = translate;} + + void setCurrentTranslate(const Vec3& translate); + + void loadMinScale(const Vec3& scale) {_minScale = scale;} + void loadMaxScale(const Vec3& scale) {_maxScale = scale;} + void loadCurrentScale(const Vec3& scale) {_currentScale = scale;} + void loadIncrementScale(const Vec3& scale) {_incrementScale = scale;} + + void setCurrentScale(const Vec3& scale); + + void setPutMatrix(const Matrix& put) {_Put = put;} + void setInversePutMatrix(const Matrix& inversePut) {_inversePut = inversePut;} + + void setLimitationFlags(const unsigned long flags) {_limitationFlags = flags;} + + inline const Vec3& getCurrentHPR() const {return _currentHPR;} + inline const Vec3& getCurrentTranslate() const {return _currentTranslate;} + inline const Vec3& getCurrentScale() const {return _currentScale;} + + inline const Matrix& getPutMatrix() const {return _Put;} + inline const Matrix& getInversePutMatrix() const {return _inversePut;} + + inline const unsigned long getLimitationFlags() const {return _limitationFlags;} + + inline void setAnimationOn(bool do_animate) {_animationOn = do_animate;} + inline const bool animationOn() const {return _animationOn;} + + // inline const bool increasing() const {return _increasing;} + + void animate(); + + protected: + virtual ~DOFTransform() {} + + Vec3 _minHPR; + Vec3 _maxHPR; + Vec3 _currentHPR; + Vec3 _incrementHPR; + + Vec3 _minTranslate; + Vec3 _maxTranslate; + Vec3 _currentTranslate; + Vec3 _incrementTranslate; + + Vec3 _minScale; + Vec3 _maxScale; + Vec3 _currentScale; + Vec3 _incrementScale; + + Matrix _Put; + Matrix _inversePut; + + unsigned long _limitationFlags; + /* bits from left to right + 0 = x translation limited (2^31) + 1 = y translation limited (2^30) + 2 = z translation limited (2^29) + 3 = pitch limited (2^28) + 4 = roll limited (2^27) + 5 = yaw limited (2^26) + 6 = x scale limited (2^25) + 7 = y scale limited (2^24) + 8 = z scale limited (2^23) + + else reserved + */ + + bool _animationOn; + /** flags indicating whether value is incerasing or decreasing in animation + bits form right to left, 1 means increasing while 0 is decreasing + 0 = x translation + 1 = y translation + 2 = z translation + 3 = pitch + 4 = roll + 5 = yaw + 6 = x scale + 7 = y scale + 8 = z scale + */ + unsigned short _increasingFlags; +}; + +} +#endif diff --git a/src/osg/DOFTransform.cpp b/src/osg/DOFTransform.cpp new file mode 100644 index 000000000..81681b04a --- /dev/null +++ b/src/osg/DOFTransform.cpp @@ -0,0 +1,382 @@ +#include + +#include +#include + +using namespace osg; + +struct DOFCullCallback : public Transform::ComputeTransformCallback +{ + /**/ + virtual const bool computeLocalToWorldMatrix(Matrix& matrix, const Transform* trans, NodeVisitor* nv) const + { + osgUtil::CullVisitor* cv = dynamic_cast(nv); + if(cv) + { + const DOFTransform* dof = dynamic_cast(trans); + if(dof) + { + //here we are: + //put the PUT matrix first: + Matrix l2w(dof->getPutMatrix()); + + //now the current matrix: + Matrix current; + current.makeTranslate(dof->getCurrentTranslate()); + + //now create the local rotation: + current.preMult(Matrix::rotate(dof->getCurrentHPR()[1], 1.0, 0.0, 0.0));//pitch + current.preMult(Matrix::rotate(dof->getCurrentHPR()[2], 0.0, 1.0, 0.0));//roll + current.preMult(Matrix::rotate(dof->getCurrentHPR()[0], 0.0, 0.0, 1.0));//heading + + //and scale: + current.preMult(Matrix::scale(dof->getCurrentScale())); + + l2w.postMult(current); + + //and impose inverse put: + l2w.postMult(dof->getInversePutMatrix()); + + //finally: + matrix.preMult(l2w); + } + } + + return true; + } + + /**/ + virtual const bool computeWorldToLocalMatrix(Matrix& matrix, const Transform* trans, NodeVisitor* nv) const + { + osgUtil::CullVisitor* cv = dynamic_cast(nv); + if(cv) + { + const DOFTransform* dof = dynamic_cast(trans); + if(dof) + { + //here we are: + //put the PUT matrix first: + Matrix w2l(dof->getInversePutMatrix()); + + //now the current matrix: + Matrix current; + current.makeTranslate(-dof->getCurrentTranslate()); + + //now create the local rotation: + + + current.postMult(Matrix::rotate(-dof->getCurrentHPR()[0], 0.0, 0.0, 1.0));//heading + current.postMult(Matrix::rotate(-dof->getCurrentHPR()[2], 0.0, 1.0, 0.0));//roll + current.postMult(Matrix::rotate(-dof->getCurrentHPR()[1], 1.0, 0.0, 0.0));//pitch + + //and scale: + current.postMult(Matrix::scale(1./dof->getCurrentScale()[0], 1./dof->getCurrentScale()[1], 1./dof->getCurrentScale()[2])); + + w2l.postMult(current); + + //and impose inverse put: + w2l.postMult(dof->getPutMatrix()); + + //finally: + matrix.postMult(w2l); + } + } + + return true; + } +}; + +class DOFAnimationAppCallback : public osg::NodeCallback +{ + /** Callback method call by the NodeVisitor when visiting a node.*/ + virtual void operator()(Node* node, NodeVisitor* nv) + { + //this is aspp visitor, see if we have DOFTransform: + DOFTransform* dof = dynamic_cast(node); + if(dof) + { + //see if it is ina animation mode: + dof->animate(); + } + + // note, callback is repsonsible for scenegraph traversal so + // should always include call the traverse(node,nv) to ensure + // that the rest of cullbacks and the scene graph are traversed. + traverse(node,nv); + } +}; + +DOFTransform::DOFTransform(): + _limitationFlags(0), + _animationOn(false), + _increasingFlags(0xffffff) +{ + //default zero-ed Vec3-s are fine for all + //default idenetiy inverse matrix is fine: + + _computeTransformCallback = new DOFCullCallback; + + DOFAnimationAppCallback* dof_animation = new DOFAnimationAppCallback; + + setAppCallback(dof_animation); +} + +void DOFTransform::setCurrentHPR(const Vec3& hpr) +{ + //if there is no constrain on animation + if(!(_limitationFlags & ((unsigned long)1<<26))) + { + //if we have min == max, it is efective constrain, so don't change + if(_minHPR[2] != _maxHPR[2]) + { + _currentHPR[2] = hpr[2]; + unsigned short this_flag = (unsigned short)1<<4;//roll + + if(_currentHPR[2] < _minHPR[2]) + { + _currentHPR[2] = _minHPR[2]; + //force increasing flag to 1 + _increasingFlags |= this_flag; + } + else if(_currentHPR[2] > _maxHPR[2]) + { + _currentHPR[2] = _maxHPR[2]; + //force increasing flag to 0 + _increasingFlags &= ~this_flag; + } + } + } + + + if(!(_limitationFlags & ((unsigned long)1<<27))) + { + if(_minHPR[1] != _maxHPR[1]) + { + _currentHPR[1] = hpr[1]; + unsigned short this_flag = (unsigned short)1<<3;//pitch + + if(_currentHPR[1] < _minHPR[1]) + { + _currentHPR[1] = _minHPR[1]; + _increasingFlags |= this_flag; + } + else if(_currentHPR[1] > _maxHPR[1]) + { + _currentHPR[1] = _maxHPR[1]; + _increasingFlags &= ~this_flag; + } + } + } + + + if(!(_limitationFlags & ((unsigned long)1<<28))) + { + if(_minHPR[0] != _maxHPR[0]) + { + _currentHPR[0] = hpr[0]; + + unsigned short this_flag = (unsigned short)1<<5;//heading + + if(_currentHPR[0] < _minHPR[0]) + { + _currentHPR[0] = _minHPR[0]; + _increasingFlags |= this_flag; + } + else if(_currentHPR[0] > _maxHPR[0]) + { + _currentHPR[0] = _maxHPR[0]; + _increasingFlags &= ~this_flag; + } + } + } +} + +void DOFTransform::setCurrentTranslate(const Vec3& translate) +{ + if(!(_limitationFlags & (unsigned long)1<<29)) + { + if(_minTranslate[2] != _maxTranslate[2]) + { + _currentTranslate[2] = translate[2]; + unsigned short this_flag = (unsigned short)1<<2; + + if(_currentTranslate[2] < _minTranslate[2]) + { + _currentTranslate[2] = _minTranslate[2]; + _increasingFlags |= this_flag; + } + else if(_currentTranslate[2] > _maxTranslate[2]) + { + _currentTranslate[2] = _maxTranslate[2]; + _increasingFlags &= ~this_flag; + } + } + } + + if(!(_limitationFlags & (unsigned long)1<<30)) + { + if(_minTranslate[1] != _maxTranslate[1]) + { + _currentTranslate[1] = translate[1]; + unsigned short this_flag = (unsigned short)1<<1; + + if(_currentTranslate[1] < _minTranslate[1]) + { + _currentTranslate[1] = _minTranslate[1]; + _increasingFlags |= this_flag; + } + else if(_currentTranslate[1] > _maxTranslate[1]) + { + _currentTranslate[1] = _maxTranslate[1]; + _increasingFlags &= ~this_flag; + } + } + } + + if(!(_limitationFlags & (unsigned long)1<<31)) + { + if(_minTranslate[0] != _maxTranslate[0]) + { + _currentTranslate[0] = translate[0]; + unsigned short this_flag = (unsigned short)1; + + if(_currentTranslate[0] < _minTranslate[0]) + { + _currentTranslate[0] = _minTranslate[0]; + _increasingFlags |= this_flag; + } + else if(_currentTranslate[0] > _maxTranslate[0]) + { + _currentTranslate[0] = _maxTranslate[0]; + _increasingFlags &= ~this_flag; + } + } + } +} + +void DOFTransform::setCurrentScale(const Vec3& scale) +{ + + if(!(_limitationFlags & ((unsigned long)1<<23))) + { + if(_minScale[2] != _maxScale[2]) + { + _currentScale[2] = scale[2]; + unsigned short this_flag = (unsigned short)1<<8; + + if(_currentScale[2] < _minScale[2]) + { + _currentScale[2] = _minScale[2]; + _increasingFlags |= this_flag; + } + else if(_currentScale[2] > _maxScale[2]) + { + _currentScale[2] = _maxScale[2]; + _increasingFlags &= ~this_flag; + } + } + } + + if(!(_limitationFlags & ((unsigned long)1<<24))) + { + if(_minScale[1] != _maxScale[1]) + { + _currentScale[1] = scale[1]; + unsigned short this_flag = (unsigned short)1<<7; + + if(_currentScale[1] < _minScale[1]) + { + _currentScale[1] = _minScale[1]; + _increasingFlags |= this_flag; + } + else if(_currentScale[1] > _maxScale[1]) + { + _currentScale[1] = _maxScale[1]; + _increasingFlags &= ~this_flag; + } + } + } + + if(!(_limitationFlags & ((unsigned long)1<<25))) + { + if(_minScale[0] != _maxScale[0]) + { + _currentScale[0] = scale[0]; + unsigned short this_flag = (unsigned short)1<<6; + + if(_currentScale[0] < _minScale[0]) + { + _currentScale[0] = _minScale[0]; + _increasingFlags |= this_flag; + } + else if(_currentScale[0] > _maxScale[0]) + { + _currentScale[0] = _maxScale[0]; + _increasingFlags &= ~this_flag; + } + } + } +} + +void DOFTransform::animate() +{ + if(!_animationOn) return; + //this will increment or decrement all allowed values + + Vec3 new_value = _currentTranslate; + + if(_increasingFlags & 1) + new_value[0] += _incrementTranslate[0]; + else + new_value[0] -= _incrementTranslate[0]; + + if(_increasingFlags & 1<<1) + new_value[1] += _incrementTranslate[1]; + else + new_value[1] -= _incrementTranslate[1]; + + if(_increasingFlags & 1<<2) + new_value[2] += _incrementTranslate[2]; + else + new_value[2] -= _incrementTranslate[2]; + + setCurrentTranslate(new_value); + + new_value = _currentHPR; + + if(_increasingFlags & ((unsigned short)1<<3)) + new_value[1] += _incrementHPR[1]; + else + new_value[1] -= _incrementHPR[1]; + + if(_increasingFlags & ((unsigned short)1<<4)) + new_value[2] += _incrementHPR[2]; + else + new_value[2] -= _incrementHPR[2]; + + if(_increasingFlags & ((unsigned short)1<<5)) + new_value[0] += _incrementHPR[0]; + else + new_value[0] -= _incrementHPR[0]; + + setCurrentHPR(new_value); + + new_value = _currentScale; + + if(_increasingFlags & 1<<6) + new_value[0] += _incrementScale[0]; + else + new_value[0] -= _incrementScale[0]; + + if(_increasingFlags & 1<<7) + new_value[1] += _incrementScale[1]; + else + new_value[1] -= _incrementScale[1]; + + if(_increasingFlags & 1<<8) + new_value[2] += _incrementScale[2]; + else + new_value[2] -= _incrementScale[2]; + + setCurrentScale(new_value); +} diff --git a/src/osg/Makefile b/src/osg/Makefile index 9e07f8594..fb65335f2 100644 --- a/src/osg/Makefile +++ b/src/osg/Makefile @@ -23,6 +23,7 @@ CXXFILES =\ CullStack.cpp\ Depth.cpp\ DisplaySettings.cpp\ + DOFTransform.cpp\ Drawable.cpp\ DrawPixels.cpp\ EarthSky.cpp\ diff --git a/src/osgPlugins/flt/flt2osg.cpp b/src/osgPlugins/flt/flt2osg.cpp index 0b72eaaf9..b71a40111 100644 --- a/src/osgPlugins/flt/flt2osg.cpp +++ b/src/osgPlugins/flt/flt2osg.cpp @@ -23,6 +23,8 @@ #include #include +#include + #include #include #include @@ -620,6 +622,146 @@ osg::Group* ConvertFromFLT::visitOldLOD(osg::Group& osgParent, OldLodRecord* rec // Converted DOF to use transform - jtracy@ist.ucf.edu osg::Group* ConvertFromFLT::visitDOF(osg::Group& osgParent, DofRecord* rec) { +#if 1 + + osg::DOFTransform* transform = new osg::DOFTransform; + transform->setName(rec->getData()->szIdent); + transform->setDataVariance(osg::Object::DYNAMIC); + visitAncillary(osgParent, *transform, rec)->addChild( transform ); + visitPrimaryNode(*transform, (PrimNodeRecord*)rec); + + SDegreeOfFreedom* p_data = rec->getData(); + + //now fill up members: + + //tranlsations: + transform->loadMinTranslate(osg::Vec3(_unitScale*p_data->dfX._dfMin, + _unitScale*p_data->dfY._dfMin, + _unitScale*p_data->dfZ._dfMin)); + + transform->loadMaxTranslate(osg::Vec3(_unitScale*p_data->dfX._dfMax, + _unitScale*p_data->dfY._dfMax, + _unitScale*p_data->dfZ._dfMax)); + + transform->loadCurrentTranslate(osg::Vec3(_unitScale*p_data->dfX._dfCurrent, + _unitScale*p_data->dfY._dfCurrent, + _unitScale*p_data->dfZ._dfCurrent)); + + transform->loadIncrementTranslate(osg::Vec3(_unitScale*p_data->dfX._dfIncrement, + _unitScale*p_data->dfY._dfIncrement, + _unitScale*p_data->dfZ._dfIncrement)); + + //rotations: + transform->loadMinHPR(osg::Vec3(osg::inDegrees(p_data->dfYaw._dfMin), + osg::inDegrees(p_data->dfPitch._dfMin), + osg::inDegrees(p_data->dfRoll._dfMin))); + + transform->loadMaxHPR(osg::Vec3(osg::inDegrees(p_data->dfYaw._dfMax), + osg::inDegrees(p_data->dfPitch._dfMax), + osg::inDegrees(p_data->dfRoll._dfMax))); + + transform->loadCurrentHPR(osg::Vec3(osg::inDegrees(p_data->dfYaw._dfCurrent), + osg::inDegrees(p_data->dfPitch._dfCurrent), + osg::inDegrees(p_data->dfRoll._dfCurrent))); + + transform->loadIncrementHPR(osg::Vec3(osg::inDegrees(p_data->dfYaw._dfIncrement), + osg::inDegrees(p_data->dfPitch._dfIncrement), + osg::inDegrees(p_data->dfRoll._dfIncrement))); + + //scales: + transform->loadMinScale(osg::Vec3(p_data->dfXscale._dfMin, + p_data->dfYscale._dfMin, + p_data->dfZscale._dfMin)); + + transform->loadMaxScale(osg::Vec3(p_data->dfXscale._dfMax, + p_data->dfYscale._dfMax, + p_data->dfZscale._dfMax)); + + transform->loadCurrentScale(osg::Vec3(p_data->dfXscale._dfCurrent, + p_data->dfYscale._dfCurrent, + p_data->dfZscale._dfCurrent)); + + transform->loadIncrementScale(osg::Vec3(p_data->dfXscale._dfIncrement, + p_data->dfYscale._dfIncrement, + p_data->dfZscale._dfIncrement)); + + //now calculate put and inverse put matrix: + //the translation matrix: + osg::Matrix l2g_translation; + + //translation vector + osg::Vec3 origin_translation(p_data->OriginLocalDOF.x(), p_data->OriginLocalDOF.y(), p_data->OriginLocalDOF.z()); + origin_translation *= _unitScale;//of course, has to be scaled to units used + + //so we make translation matrix + l2g_translation.makeTranslate(origin_translation); + + //now we need to construct rotation matrix that describes how is local coordinate system + //rotatoed in global: + osg::Matrix l2g_rotation; + + //we make two normalized osg::Vec3s so we can cross-multiply them .... + + //first we have "point on x axis", i.e. what the DOF local looks like in global + osg::Vec3 point_on_x_axis(p_data->PointOnXaxis.x(), p_data->PointOnXaxis.y(), p_data->PointOnXaxis.z()); + point_on_x_axis *= _unitScale; + point_on_x_axis -= origin_translation;//we need to offset it for the origin + + //second, we have "point in xy plane", so x ^ y gives us local z vector + osg::Vec3 point_in_xy_plane(p_data->PointInXYplane.x(), p_data->PointInXYplane.y(), p_data->PointInXYplane.z()); + point_in_xy_plane *= _unitScale; + point_in_xy_plane -= origin_translation;//also offset it + + //just in case, normalize them: + point_on_x_axis.normalize(); + + //now, local x in global is [1 0 0 1] * rotation_matrix, so we can directly write down first row + l2g_rotation.ptr()[0] = point_on_x_axis.x(); //that is mat[0][0] + l2g_rotation.ptr()[1] = point_on_x_axis.y(); //that is mat[0][1] + l2g_rotation.ptr()[2] = point_on_x_axis.z(); //that is mat[0][2] + + + //the cross product of x ^point_in_local_xy_plane gives local z + osg::Vec3 z_transformed = point_on_x_axis ^ point_in_xy_plane; + z_transformed.normalize();//we have to normalize it, and than we can directly writ it down to rotation matrix + //we can write it down to matrix directly: + l2g_rotation.ptr()[8] = z_transformed.x(); //that is mat[2][0] + l2g_rotation.ptr()[9] = z_transformed.y(); //that is mat[2][1] + l2g_rotation.ptr()[10] = z_transformed.z(); //that is mat[2][2] + + //now that we have x and z, we can get y = z ^ x + osg::Vec3 y_transformed = z_transformed ^ point_on_x_axis; + //and just in case, we can normalize it: + // y_transformed.normalize(); + + //this goes to rotation matrix: + l2g_rotation.ptr()[4] = y_transformed.x(); //that is mat[1][0] + l2g_rotation.ptr()[5] = y_transformed.y(); //that is mat[1][0] + l2g_rotation.ptr()[6] = y_transformed.z(); //that is mat[1][0] + + + //now we have actually the second "PUT" transformation, and the first is inverse + osg::Matrix second_put = l2g_rotation * l2g_translation; + + //and we take invers of it since it has to be done at the end, see FLT spec + osg::Matrix the_first = osg::Matrix::inverse(second_put); + + transform->setPutMatrix(the_first); + transform->setInversePutMatrix(second_put); +/* + //and now do a little ENDIAN to put flags in ordewr as described in OpenFlight spec + unsigned long flags = p_data->dwFlags; + ENDIAN(flags); + + //and setup limitation flags: +// transform->setLimitationFlags(flags); +*/ + transform->setLimitationFlags(p_data->dwFlags); + + return transform; + +#else + osg::MatrixTransform* transform = new osg::MatrixTransform; transform->setName(rec->getData()->szIdent); @@ -690,6 +832,9 @@ osg::Group* ConvertFromFLT::visitDOF(osg::Group& osgParent, DofRecord* rec) transform->setMatrix(dof_matrix); return transform; + +#endif + }