Hi Robert, I don't necessarily agree that a way to check if the transforms along a nodepath using integers is not worthwhile, as you replace hundreds of double-operations with a few integer ones, and the comparison becomes the comparison of two ints. That seems useful, especially as there is hardly any overhead (a few bytes per transform).
I'll leave that discussion and submit a new update of the AntiSquish. It now inherits Transform rather than MatrixTransform, so there are no changes to the object while traversing (apart from one cache). This solves most of your objections as we rely on the standardness of the Transform. One question is however what to do when there is no node-path available, such as the Transform::computeBound(). In those cases I rely on the cache (if available). But if I do that, I should really dirty the bound when I re-compute my cache. This is implemented now in the version I'm sending, but I'm not sure it is necessary. It will create an overload of computeBound calls. I opted to lock the cache as this is the only way to protect from corrupt cache if there are multiple traversals going on at the same time. We don't do that, but I thought it's safer. Best regards, Kristofer Tingdahl
AntiSquish
Description: Binary data
/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield
*
* This library is open source and may be redistributed and/or modified under
* the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
* (at your option) any later version. The full license is in LICENSE file
* included with this distribution, and on the openscenegraph.org website.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* OpenSceneGraph Public License for more details.
*/
//osgManipulator - Copyright (C) 2007 Fugro-Jason B.V.
#include <osgManipulator/AntiSquish>
using namespace osgManipulator;
AntiSquish::AntiSquish() : _usePivot(true), _usePosition(false), _cacheDirty( true )
{
}
AntiSquish::AntiSquish(const osg::Vec3d& pivot) : _pivot(pivot), _usePivot(true), _usePosition(false), _cacheDirty( true )
{
}
AntiSquish::AntiSquish(const osg::Vec3d& pivot, const osg::Vec3d& pos)
: _pivot(pivot), _usePivot(true), _position(pos), _usePosition(true), _cacheDirty( true )
{
}
AntiSquish::AntiSquish(const AntiSquish& pat,const osg::CopyOp& copyop) :
Transform(pat,copyop),
_pivot(pat._pivot),
_usePivot(pat._usePivot),
_position(pat._position),
_usePosition(pat._usePosition),
_cacheDirty(pat._cacheDirty),
_cacheLocalToWorld(pat._cacheLocalToWorld),
_cache(pat._cache)
{
}
AntiSquish::~AntiSquish()
{
}
bool AntiSquish::computeLocalToWorldMatrix(osg::Matrix& matrix,osg::NodeVisitor* nv) const
{
osg::Matrix unsquishedMatrix;
if ( !computeUnSquishedMatrix( nv, unsquishedMatrix ) )
return Transform::computeLocalToWorldMatrix( matrix, nv );
if (_referenceFrame==RELATIVE_RF)
{
matrix.preMult(unsquishedMatrix);
}
else // absolute
{
matrix = unsquishedMatrix;
}
return true;
}
bool AntiSquish::computeWorldToLocalMatrix(osg::Matrix& matrix,osg::NodeVisitor* nv) const
{
osg::Matrix unsquishedMatrix;
if ( !computeUnSquishedMatrix( nv, unsquishedMatrix ) )
return Transform::computeWorldToLocalMatrix( matrix, nv );
osg::Matrixd inverse;
inverse.invert( unsquishedMatrix );
if (_referenceFrame==RELATIVE_RF)
{
matrix.postMult(inverse);
}
else // absolute
{
matrix = inverse;
}
return true;
}
bool AntiSquish::computeUnSquishedMatrix(const osg::NodeVisitor* nv, osg::Matrix& unsquished) const
{
OpenThreads::ScopedLock<OpenThreads::Mutex> lock( _cacheLock );
if ( !nv )
{
if ( !_cacheDirty )
{
unsquished = _cache;
return true;
}
return false;
}
osg::NodePath np = nv->getNodePath();
// Remove the last node which is the anti squish node itself.
np.pop_back();
// Get the accumulated modeling matrix.
const osg::Matrix localToWorld = osg::computeLocalToWorld(np);
if ( !_cacheDirty && _cacheLocalToWorld==localToWorld )
{
unsquished = _cache;
return true;
}
osg::Vec3d t, s;
osg::Quat r, so;
localToWorld.decompose(t, r, s, so);
// Let's take an average of the scale.
double av = (s[0] + s[1] + s[2])/3.0;
s[0] = av; s[1] = av; s[2]=av;
if (av == 0)
return false;
//
// Final Matrix: [-Pivot][SO]^[S][SO][R][T][Pivot][LOCALTOWORLD]^[position]
// OR [SO]^[S][SO][R][T][LOCALTOWORLD]^
//
if (_usePivot)
{
unsquished.postMultTranslate(-_pivot);
osg::Matrix tmps, invtmps;
so.get(tmps);
if (!invtmps.invert(tmps))
return false;
//SO^
unsquished.postMult(invtmps);
//S
unsquished.postMultScale(s);
//SO
unsquished.postMult(tmps);
//R
unsquished.postMultRotate(r);
//T
unsquished.postMultTranslate(t);
osg::Matrix invltw;
if (!invltw.invert(localToWorld))
return false;
// LTW^
unsquished.postMult( invltw );
// Position
if (_usePosition)
unsquished.postMultTranslate(_position);
else
unsquished.postMultTranslate(_pivot);
}
else
{
osg::Matrix tmps, invtmps;
so.get(tmps);
if (!invtmps.invert(tmps))
return false;
unsquished.postMult(invtmps);
unsquished.postMultScale(s);
unsquished.postMult(tmps);
unsquished.postMultRotate(r);
unsquished.postMultTranslate(t);
osg::Matrix invltw;
if (!invltw.invert(localToWorld))
return false;
unsquished.postMult( invltw );
}
if (unsquished.isNaN())
return false;
_cache = unsquished;
_cacheLocalToWorld = localToWorld;
_cacheDirty = false;
//As Transform::computeBounde calls us without a node-path it relies on
//The cache. Hence a new _cache affects the bound.
const_cast<AntiSquish*>(this)->dirtyBound();
return true;
}
_______________________________________________ osg-submissions mailing list [email protected] http://lists.openscenegraph.org/listinfo.cgi/osg-submissions-openscenegraph.org
