diff --git a/include/osg/Math b/include/osg/Math index 2d848bc68..6d0a1de69 100644 --- a/include/osg/Math +++ b/include/osg/Math @@ -48,6 +48,9 @@ #define sqrtf (float)sqrt #endif +#ifndef fabsf +#define fabs (float)sqrt +#endif namespace osg { diff --git a/include/osg/Matrix b/include/osg/Matrix index 1eedae981..89a882527 100644 --- a/include/osg/Matrix +++ b/include/osg/Matrix @@ -9,6 +9,8 @@ #include #include +#include + #include namespace osg { diff --git a/include/osg/Transform b/include/osg/Transform index c83231663..afb993311 100644 --- a/include/osg/Transform +++ b/include/osg/Transform @@ -69,27 +69,20 @@ class SG_EXPORT Transform : public Group /** Callback attached to an Transform to specifiy how to compute the modelview or projection transformation * for the transform below the Transform node.*/ - class ComputeTransformCallback : public osg::Referenced + struct ComputeTransformCallback : public osg::Referenced { - - public: - - /** Get the transformation matrix which moves from local coords to world coords.*/ - virtual const bool computeLocalToWorldMatrix(Matrix& matrix,const Transform* transform, NodeVisitor* nv) const = 0; + /** Get the transformation matrix which moves from local coords to world coords.*/ + virtual const bool computeLocalToWorldMatrix(Matrix& matrix,const Transform* transform, NodeVisitor* nv) const = 0; - /** Get the transformation matrix which moves from world coords to local coords.*/ - virtual const bool computeWorldToLocalMatrix(Matrix& matrix,const Transform* transform, NodeVisitor* nv) const = 0; - - protected: - - virtual ~ComputeTransformCallback() {} - + /** Get the transformation matrix which moves from world coords to local coords.*/ + virtual const bool computeWorldToLocalMatrix(Matrix& matrix,const Transform* transform, NodeVisitor* nv) const = 0; }; - + + friend struct osg::Transform::ComputeTransformCallback; /** Set the ComputerTransfromCallback which allows users to attach custom computation of the local transformation as * seen by cull traversers and alike.*/ - void setComputeTransformCallback(ComputeTransformCallback* ctc) { _computeTransformCallback=ctc; } + void setComputeTransformCallback(ComputeTransformCallback* ctc) { _computeTransformCallback=ctc; dirtyBound(); } /** Get the non const ComputerTransfromCallback.*/ ComputeTransformCallback* getComputeTransformCallback() { return _computeTransformCallback.get(); } @@ -143,13 +136,13 @@ class SG_EXPORT Transform : public Group * the underlying matrix (calling computeMatrix if required.) */ virtual const bool computeBound() const; - virtual const bool computeLocalToWorldMatrix(Matrix& matrix,NodeVisitor* nv) const + virtual const bool computeLocalToWorldMatrix(Matrix& matrix,NodeVisitor*) const { matrix = *_matrix; return true; } - virtual const bool computeWorldToLocalMatrix(Matrix& matrix,NodeVisitor* nv) const + virtual const bool computeWorldToLocalMatrix(Matrix& matrix,NodeVisitor*) const { matrix.invert(*_matrix); return true; diff --git a/include/osgUtil/Optimizer b/include/osgUtil/Optimizer index faea2c65e..26ce5fc50 100644 --- a/include/osgUtil/Optimizer +++ b/include/osgUtil/Optimizer @@ -10,6 +10,8 @@ #include +#include + namespace osgUtil { /** Insert impostor nodes into scene graph. diff --git a/src/osg/Camera.cpp b/src/osg/Camera.cpp index 98dda72b0..9b2c447f8 100644 --- a/src/osg/Camera.cpp +++ b/src/osg/Camera.cpp @@ -433,7 +433,10 @@ void Camera::attachTransform(const TransformMode mode, Matrix* matrix) { _attachedTransformMode = mode; if (!_modelToEyeTransform.valid()) _modelToEyeTransform = new Matrix; - _modelToEyeTransform->invert(*_eyeToModelTransform); + if (!_modelToEyeTransform->invert(*_eyeToModelTransform)) + { + notify(WARN)<<"Warning: Camera::attachTransform() failed to invert _modelToEyeTransform"<invert(*_modelToEyeTransform); + if (!_eyeToModelTransform->invert(*_modelToEyeTransform)) + { + notify(WARN)<<"Warning: Camera::attachTransform() failed to invert _modelToEyeTransform"<invert(*_eyeToModelTransform); + if (!_modelToEyeTransform->invert(*_eyeToModelTransform)) + { + notify(WARN)<<"Warning: Camera::dirtyTransform() failed to invert _modelToEyeTransform"<invert(*_modelToEyeTransform); + if (!_eyeToModelTransform->invert(*_modelToEyeTransform)) + { + notify(WARN)<<"Warning: Camera::dirtyTransform() failed to invert _eyeToModelTransform"<mult(*_modelViewMatrix,*_projectionMatrix); if (!_inversemp.valid()) _inversemp = new Matrix; - _inversemp->invert(*_mp); + if (!_inversemp->invert(*_mp)) + { + notify(WARN)<<"Warning: Camera::calculateMatricesAndClippingVolume() failed to invert _mp"< +inline T SGL_ABS(T a) +{ + return (a >= 0 ? a : -a); +} + +#ifndef SGL_SWAP +#define SGL_SWAP(a,b,temp) ((temp)=(a),(a)=(b),(b)=(temp)) +#endif + +bool inverse(const Matrix& mat,Matrix& m_matrix) +{ + unsigned int indxc[4], indxr[4], ipiv[4]; + unsigned int i,j,k,l,ll; + unsigned int icol = 0; + unsigned int irow = 0; + float temp, pivinv, dum, big; + + // copy in place this may be unnecessary + m_matrix = mat; + + for (j=0; j<4; j++) ipiv[j]=0; + + for(i=0;i<4;i++) + { + big=(float)0.0; + for (j=0; j<4; j++) + if (ipiv[j] != 1) + for (k=0; k<4; k++) + { + if (ipiv[k] == 0) + { + if (SGL_ABS(m_matrix(j,k)) >= big) + { + big = SGL_ABS(m_matrix(j,k)); + irow=j; + icol=k; + } + } + else if (ipiv[k] > 1) + return false; + } + ++(ipiv[icol]); + if (irow != icol) + for (l=0; l<4; l++) SGL_SWAP(m_matrix(irow,l), + m_matrix(icol,l), + temp); + + indxr[i]=irow; + indxc[i]=icol; + if (m_matrix(icol,icol) == 0) + return false; + + pivinv = 1.0/m_matrix(icol,icol); + m_matrix(icol,icol) = 1; + for (l=0; l<4; l++) m_matrix(icol,l) *= pivinv; + for (ll=0; ll<4; ll++) + if (ll != icol) + { + dum=m_matrix(ll,icol); + m_matrix(ll,icol) = 0; + for (l=0; l<4; l++) m_matrix(ll,l) -= m_matrix(icol,l)*dum; + } + } + for (int lx=4; lx>0; --lx) + { + if (indxr[lx-1] != indxc[lx-1]) + for (k=0; k<4; k++) SGL_SWAP(m_matrix(k,indxr[lx-1]), + m_matrix(k,indxc[lx-1]),temp); + } + + return true; +} + +bool inverseAffine(const Matrix& mat,Matrix& m_matrix) +{ + // | R p |' | R' -R'p |' + // | | -> | | + // | 0 0 0 1 | | 0 0 0 1 | + for (unsigned int i=0; i<3; i++) + { + m_matrix(i,3) = 0; + m_matrix(3,i) = -(mat(i,0)*mat(3,0) + + mat(i,1)*mat(3,1) + + mat(i,2)*mat(3,2)); + for (unsigned int j=0; j<3; j++) + { + m_matrix(i,j) = mat(j,i); + } + } + m_matrix(3,3) = 1; + + return true; +} + + + + Matrix::Matrix() : Object() { makeIdentity(); @@ -47,7 +146,6 @@ Matrix::Matrix( float a00, float a01, float a02, float a03, SET_ROW(3, a30, a31, a32, a33 ) } - Matrix& Matrix::operator = (const Matrix& other ) { if( &other == this ) return *this; @@ -169,6 +267,15 @@ void Matrix::makeRotate( float yaw, float pitch, float roll) void Matrix::mult( const Matrix& lhs, const Matrix& rhs ) { + if (&lhs==this) + { + postMult(rhs); + return; + } + if (&rhs==this) + { + preMult(lhs); + } // PRECONDITION: We assume neither &lhs nor &rhs == this // if it did, use preMult or postMult instead @@ -232,31 +339,33 @@ void Matrix::postMult( const Matrix& other ) #undef SET_ROW #undef INNER_PRODUCT -bool Matrix::invert( const Matrix& other ) +bool Matrix::invert( const Matrix& invm ) { - if (&other==this) - { - Matrix tm(other); + if (&invm==this) { + Matrix tm(invm); return invert(tm); } - -// if ( other._mat[0][3] == 0.0 -// && other._mat[1][3] == 0.0 -// && other._mat[2][3] == 0.0 -// && other._mat[3][3] == 1.0 ) -// { -// return invertAffine( other ); -// } +/* + if ( invm._mat[0][3] == 0.0 + && invm._mat[1][3] == 0.0 + && invm._mat[2][3] == 0.0 + && invm._mat[3][3] == 1.0 ) + { + return inverseAffine( invm,*this ); + } +*/ + return inverse(invm,*this); // code lifted from VR Juggler. // not cleanly added, but seems to work. RO. - const float* a = reinterpret_cast(other._mat); + + const float* a = reinterpret_cast(invm._mat); float* b = reinterpret_cast(_mat); int n = 4; int i, j, k; int r[ 4], c[ 4], row[ 4], col[ 4]; - float m[ 4][ 4*2], pivot, maxother, tmpother, fac; + float m[ 4][ 4*2], pivot, max_m, tmp_m, fac; /* Initialization */ for ( i = 0; i < n; i ++ ) @@ -265,7 +374,7 @@ bool Matrix::invert( const Matrix& other ) row[ i] = col[ i] = 0; } - /* Set working Matrix */ + /* Set working matrix */ for ( i = 0; i < n; i++ ) { for ( j = 0; j < n; j++ ) @@ -279,16 +388,16 @@ bool Matrix::invert( const Matrix& other ) for ( k = 0; k < n; k++ ) { /* Choosing the pivot */ - for ( i = 0, maxother = 0; i < n; i++ ) + for ( i = 0, max_m = 0; i < n; i++ ) { if ( row[ i] ) continue; for ( j = 0; j < n; j++ ) { if ( col[ j] ) continue; - tmpother = fabs( m[ i][j]); - if ( tmpother > maxother) + tmp_m = fabs( m[ i][j]); + if ( tmp_m > max_m) { - maxother = tmpother; + max_m = tmp_m; r[ k] = i; c[ k] = j; } @@ -299,9 +408,9 @@ bool Matrix::invert( const Matrix& other ) if ( fabs( pivot) <= 1e-20) { - notify(WARN) << "Warning: pivot = "<< pivot <<" in Matrix::invert(), cannot compute inverse."<maxbins)?primStats[0].getBins():maxbins; delete [] primStats; // free up diff --git a/src/osgUtil/CullVisitor.cpp b/src/osgUtil/CullVisitor.cpp index 17d024a5c..71eb95fd1 100644 --- a/src/osgUtil/CullVisitor.cpp +++ b/src/osgUtil/CullVisitor.cpp @@ -497,6 +497,7 @@ void CullVisitor::pushCullViewState(Matrix* matrix) inverse_world = createOrReuseMatrix(); inverse_world->invert(*(matrix)); + nvs->_inverse = inverse_world; } @@ -937,7 +938,7 @@ void CullVisitor::apply(Billboard& node) */ Matrix* billboard_matrix = createOrReuseMatrix(); - node.calcTransform(eye_local,up_local,pos,*billboard_matrix); + node.getMatrix(*billboard_matrix,eye_local,up_local,pos); if (matrix) { @@ -1053,8 +1054,6 @@ void CullVisitor::apply(Transform& node) node.getLocalToWorldMatrix(*matrix,this); pushCullViewState(matrix.get()); -// pushCullViewState(&node.getMatrix()); - traverse(node); popCullViewState();