Clean this up a bit
parent
084eb8c030
commit
29f8de325c
|
|
@ -24,14 +24,14 @@
|
|||
* The Phoenix Firestorm Project, Inc., 1831 Oakwood Drive, Fairmont, Minnesota 56031-3225 USA
|
||||
* http://www.firestormviewer.org
|
||||
*/
|
||||
|
||||
#include "llviewerprecompiledheaders.h" // regular Firestorm includes
|
||||
#include "llviewercontrol.h"
|
||||
#include "llmath.h" // normal build
|
||||
#include "llviewerobject.h"
|
||||
#include "llframetimer.h"
|
||||
|
||||
#include "llviewerprecompiledheaders.h"
|
||||
#include "fsregioncross.h"
|
||||
//
|
||||
#include "llframetimer.h"
|
||||
#include "llmath.h"
|
||||
#include "llviewercontrol.h"
|
||||
#include "llviewerobject.h"
|
||||
|
||||
// Improved region crossing time limit prediction.
|
||||
//
|
||||
// Applied when
|
||||
|
|
@ -55,15 +55,14 @@
|
|||
// Potential vehicle, but might be just a chair.
|
||||
// We don't start the movement averaging until there's movement at least once.
|
||||
//
|
||||
RegionCrossExtrapolateImpl::RegionCrossExtrapolateImpl(const LLViewerObject& vo) : // constructor
|
||||
mOwner(vo), // back ref to owner
|
||||
mPreviousUpdateTime(0), // time of last update
|
||||
mMoved(false) // has not moved yet
|
||||
RegionCrossExtrapolateImpl::RegionCrossExtrapolateImpl(const LLViewerObject& vo) :
|
||||
mOwner(vo),
|
||||
mPreviousUpdateTime(0),
|
||||
mMoved(false)
|
||||
{
|
||||
LL_INFOS() << "Object " << vo.getID().asString() << " has sitter." << LL_ENDL; // log sit event
|
||||
LL_INFOS() << "Object " << vo.getID().asString() << " has sitter." << LL_ENDL;
|
||||
}
|
||||
|
||||
//
|
||||
// update -- called for each object update message to "vehicle" objects.
|
||||
//
|
||||
// This is called for any object with an avatar sitting on it.
|
||||
|
|
@ -71,42 +70,49 @@ RegionCrossExtrapolateImpl::RegionCrossExtrapolateImpl(const LLViewerObject& vo)
|
|||
// If it has moved, we treat it as a vehicle.
|
||||
//
|
||||
void RegionCrossExtrapolateImpl::update()
|
||||
{
|
||||
if (!mMoved) // if not seen to move
|
||||
{ LLVector3 rawvel = mOwner.getVelocity(); // velocity in world coords
|
||||
if (rawvel.mV[VX] != 0.0 || rawvel.mV[VY] != 0.0 || rawvel.mV[VZ] != 0) // check for nonzero velocity
|
||||
{ mMoved = true; } // moved, has seated avatar, thus is vehicle
|
||||
{
|
||||
if (!mMoved)
|
||||
{
|
||||
LLVector3 rawvel = mOwner.getVelocity(); // velocity in world coords
|
||||
if (rawvel.mV[VX] != 0.f || rawvel.mV[VY] != 0.f || rawvel.mV[VZ] != 0.f) // check for nonzero velocity
|
||||
{
|
||||
mMoved = true; // moved, has seated avatar, thus is vehicle
|
||||
}
|
||||
else
|
||||
{ return; } // sitting on stationary object, skip this
|
||||
{
|
||||
return; // sitting on stationary object, skip this
|
||||
}
|
||||
}
|
||||
|
||||
// Moving seat - do the extrapolation calculations
|
||||
F64 dt = 1.0/45.0; // dt used on first value - one physics frame on server
|
||||
F64 now = LLFrameTimer::getElapsedSeconds(); // timestamp
|
||||
F64 dt = 1.0 / 45.0; // dt used on first value - one physics frame on server
|
||||
F64 now = LLFrameTimer::getElapsedSeconds();
|
||||
if (mPreviousUpdateTime != 0.0)
|
||||
{ dt = now - mPreviousUpdateTime; // change since last update
|
||||
{
|
||||
dt = now - mPreviousUpdateTime; // change since last update
|
||||
// Could adjust here for ping time and time dilation, but the filter isn't that
|
||||
// sensitive to minor variations dt and it would just complicate things.
|
||||
}
|
||||
|
||||
mPreviousUpdateTime = now;
|
||||
LLQuaternion rot = mOwner.getRotationRegion(); // transform in global coords
|
||||
const LLQuaternion& inverserot = rot.conjugate(); // transform global to local
|
||||
LLVector3 vel = mOwner.getVelocity()*inverserot; // velocity in object coords
|
||||
LLVector3 angvel = mOwner.getAngularVelocity()*inverserot; // angular velocity in object coords
|
||||
mFilteredVel.update(vel,dt); // accum into filter in object coords
|
||||
mFilteredAngVel.update(angvel,dt); // accum into filter in object coords
|
||||
LLQuaternion rot = mOwner.getRotationRegion(); // transform in global coords
|
||||
const LLQuaternion& inverserot = rot.conjugate(); // transform global to local
|
||||
LLVector3 vel = mOwner.getVelocity() * inverserot; // velocity in object coords
|
||||
LLVector3 angvel = mOwner.getAngularVelocity() * inverserot; // angular velocity in object coords
|
||||
mFilteredVel.update(vel, dt); // accum into filter in object coords
|
||||
mFilteredAngVel.update(angvel, dt); // accum into filter in object coords
|
||||
}
|
||||
//
|
||||
|
||||
// dividesafe -- floating divide with divide by zero check
|
||||
//
|
||||
// Returns infinity for a divide by near zero.
|
||||
//
|
||||
static inline F32 dividesafe(F32 num, F32 denom)
|
||||
{ return((denom > FP_MAG_THRESHOLD // avoid divide by zero
|
||||
|| denom < -FP_MAG_THRESHOLD)
|
||||
? (num / denom)
|
||||
: std::numeric_limits<F32>::infinity()); // return infinity if zero divide
|
||||
{
|
||||
return ((denom > FP_MAG_THRESHOLD || denom < -FP_MAG_THRESHOLD) // avoid divide by zero
|
||||
? (num / denom) : std::numeric_limits<F32>::infinity()); // return infinity if zero divide
|
||||
}
|
||||
//
|
||||
|
||||
// getextraptimelimit -- don't extrapolate further ahead than this during a region crossing.
|
||||
//
|
||||
// Returns seconds of extrapolation that will probably stay within set limits of error.
|
||||
|
|
@ -117,36 +123,43 @@ F32 RegionCrossExtrapolateImpl::getextraptimelimit() const
|
|||
// The limits can be adjusted as debug symbols or in settings.xml, but that should not be necessary.
|
||||
static LLCachedControl<F32> fsRegionCrossingPositionErrorLimit(gSavedSettings, "FSRegionCrossingPositionErrorLimit");
|
||||
static LLCachedControl<F32> fsRegionCrossingAngleErrorLimit(gSavedSettings, "FSRegionCrossingAngleErrorLimit");
|
||||
// Time limit is max allowed error / error. Returns worst case (smallest) of vel and angular vel limits.
|
||||
|
||||
// Time limit is max allowed error / error. Returns worst case (smallest) of vel and angular vel limits.
|
||||
LLQuaternion rot = mOwner.getRotationRegion(); // transform in global coords
|
||||
const LLQuaternion& inverserot = rot.conjugate(); // transform global to local
|
||||
// Calculate safe extrapolation time limit.
|
||||
F32 extrapTimeLimit = llmin(dividesafe(fsRegionCrossingPositionErrorLimit, ((mOwner.getVelocity()*inverserot - mFilteredVel.get()).length())),
|
||||
dividesafe(fsRegionCrossingAngleErrorLimit, ((mOwner.getAngularVelocity()*inverserot - mFilteredAngVel.get()).length())));
|
||||
LL_INFOS() << "Region cross extrapolation safe limit " << extrapTimeLimit << " secs." << LL_ENDL;
|
||||
return(extrapTimeLimit); // do not extrapolate more than this
|
||||
}
|
||||
|
||||
//
|
||||
// Calculate safe extrapolation time limit.
|
||||
F32 extrapTimeLimit = llmin(dividesafe(fsRegionCrossingPositionErrorLimit, ((mOwner.getVelocity() * inverserot - mFilteredVel.get()).length())),
|
||||
dividesafe(fsRegionCrossingAngleErrorLimit, ((mOwner.getAngularVelocity() * inverserot - mFilteredAngVel.get()).length())));
|
||||
|
||||
LL_INFOS() << "Region cross extrapolation safe limit " << extrapTimeLimit << " secs." << LL_ENDL;
|
||||
return extrapTimeLimit; // do not extrapolate more than this
|
||||
}
|
||||
|
||||
// ifsaton -- True if object is being sat upon.
|
||||
//
|
||||
// Potential vehicle.
|
||||
//
|
||||
BOOL RegionCrossExtrapolate::ifsaton(const LLViewerObject& vo) // true if root object and being sat on
|
||||
{ if (!vo.isRoot()) { return(false); } // not root, cannot be sat upon
|
||||
bool RegionCrossExtrapolate::ifsaton(const LLViewerObject& vo) // true if root object and being sat on
|
||||
{
|
||||
if (!vo.isRoot())
|
||||
{
|
||||
return false; // not root, cannot be sat upon
|
||||
}
|
||||
|
||||
for (auto iter = vo.getChildren().begin(); // check for avatar as child of root
|
||||
iter != vo.getChildren().end(); iter++)
|
||||
{
|
||||
LLViewerObject* child = *iter; // get child
|
||||
if (child->isAvatar()) // avatar as child
|
||||
{
|
||||
return(true); // we have a sitter
|
||||
}
|
||||
}
|
||||
return(false); // no avatar children, not sat on
|
||||
iter != vo.getChildren().end(); iter++)
|
||||
{
|
||||
LLViewerObject* child = *iter;
|
||||
if (child->isAvatar())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false; // no avatar children, not sat on
|
||||
}
|
||||
|
||||
//
|
||||
// LowPassFilter -- the low pass filter for smoothing velocities.
|
||||
//
|
||||
// Works on vectors.
|
||||
|
|
@ -167,17 +180,17 @@ BOOL RegionCrossExtrapolate::ifsaton(const LLViewerObject& vo) // true if root
|
|||
void LowPassFilter::update(const LLVector3& val, F32 secs) // add new value into filter
|
||||
{
|
||||
static LLCachedControl<F32> fsRegionCrossingSmoothingTime(gSavedSettings, "FSRegionCrossingSmoothingTime");
|
||||
if (!mInitialized) // if not initialized yet
|
||||
{ mFiltered = val; // just use new value
|
||||
if (!mInitialized)
|
||||
{
|
||||
mFiltered = val; // just use new value
|
||||
mInitialized = true;
|
||||
return;
|
||||
}
|
||||
F32 filtermult = 1.0; // no filtering if zero filter time
|
||||
if (fsRegionCrossingSmoothingTime > 0.001) // avoid divide by zero
|
||||
{ filtermult = 1.0 - 1.0/pow(1.0+1.0/fsRegionCrossingSmoothingTime,secs); } // filter scale factor
|
||||
mFiltered = val * filtermult + mFiltered*(1.0-filtermult); // low pass filter
|
||||
|
||||
F32 filtermult = 1.0f; // no filtering if zero filter time
|
||||
if (fsRegionCrossingSmoothingTime > F_ALMOST_ZERO) // avoid divide by zero
|
||||
{
|
||||
filtermult = 1.0f - 1.0f / pow(1.0f + 1.0f / fsRegionCrossingSmoothingTime, secs); // filter scale factor
|
||||
}
|
||||
mFiltered = val * filtermult + mFiltered * (1.0f - filtermult); // low pass filter
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -32,9 +32,8 @@
|
|||
// Improved region crossing support.
|
||||
//
|
||||
|
||||
class LLViewerObject; // forward declaration
|
||||
class LLViewerObject;
|
||||
|
||||
//
|
||||
// LowPassFilter -- a simple Kalman low-pass filter.
|
||||
//
|
||||
// Supports nonuniform time deltas between samples, since object update times are not consistent.
|
||||
|
|
@ -43,26 +42,27 @@ class LowPassFilter
|
|||
{
|
||||
private:
|
||||
LLVector3 mFiltered; // filtered value
|
||||
BOOL mInitialized; // true if initialized
|
||||
bool mInitialized;
|
||||
|
||||
public:
|
||||
LowPassFilter() : // constructor
|
||||
LowPassFilter() :
|
||||
mInitialized(false),
|
||||
mFiltered(0.0,0.0,0.0)
|
||||
{}
|
||||
mFiltered()
|
||||
{ }
|
||||
|
||||
void update(const LLVector3& val, F32 dt); // add new value into filter
|
||||
|
||||
|
||||
const LLVector3& get() const // get filtered output
|
||||
{
|
||||
return(mFiltered); // already stored
|
||||
return mFiltered; // already stored
|
||||
}
|
||||
|
||||
void clear()
|
||||
|
||||
void clear()
|
||||
{
|
||||
mInitialized = false; // not initialized yet
|
||||
mInitialized = false;
|
||||
}
|
||||
};
|
||||
|
||||
//
|
||||
// RegionCrossExtrapolateImpl -- the extrapolation limit calculator.
|
||||
//
|
||||
// One of these is created when an object is sat upon. If the
|
||||
|
|
@ -79,16 +79,15 @@ private:
|
|||
F64 mPreviousUpdateTime; // previous update time
|
||||
LowPassFilter mFilteredVel; // filtered velocity
|
||||
LowPassFilter mFilteredAngVel; // filtered angular velocity
|
||||
BOOL mMoved; // seen to move at least once
|
||||
bool mMoved; // seen to move at least once
|
||||
|
||||
public:
|
||||
RegionCrossExtrapolateImpl(const LLViewerObject& vo); // constructor
|
||||
RegionCrossExtrapolateImpl(const LLViewerObject& vo);
|
||||
void update(); // update on object update message
|
||||
F32 getextraptimelimit() const; // don't extrapolate more than this
|
||||
BOOL hasmoved() const { return(mMoved); } // true if has been seen to move with sitter
|
||||
bool hasmoved() const { return (mMoved); } // true if has been seen to move with sitter
|
||||
};
|
||||
|
||||
//
|
||||
// RegionCrossExtrapolate -- calculate safe limit on how long to extrapolate after a region crossing
|
||||
//
|
||||
// Member object of llViewerObject. For vehicles, a RegionCrossExtrapolateImpl is allocated to do the real work.
|
||||
|
|
@ -96,38 +95,57 @@ public:
|
|||
// Call "changedlink" for any object update which changes parenting.
|
||||
// Get the extrapolation limit time with getextraptimelimit.
|
||||
//
|
||||
class LLViewerObject; // forward
|
||||
class RegionCrossExtrapolate {
|
||||
class RegionCrossExtrapolate
|
||||
{
|
||||
private:
|
||||
std::unique_ptr<RegionCrossExtrapolateImpl> mImpl; // pointer to region cross extrapolator, if present
|
||||
|
||||
std::unique_ptr<RegionCrossExtrapolateImpl> mImpl;
|
||||
|
||||
protected:
|
||||
BOOL ifsaton(const LLViewerObject& vo); // true if root object and being sat on
|
||||
|
||||
bool ifsaton(const LLViewerObject& vo); // true if root object and being sat on
|
||||
|
||||
public:
|
||||
void update(const LLViewerObject& vo) // new object update message received
|
||||
{ if (mImpl.get()) { mImpl->update(); } // update extrapolator if present
|
||||
{
|
||||
if (mImpl.get())
|
||||
{
|
||||
mImpl->update(); // update extrapolator if present
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void changedlink(const LLViewerObject& vo) // parent or child changed, check if extrapolation object needed
|
||||
{
|
||||
if (ifsaton(vo)) // if this object is now the root of a linkset with an avatar
|
||||
{ if (!mImpl.get()) // if no extrapolation implementor
|
||||
{ mImpl.reset(new RegionCrossExtrapolateImpl(vo)); } // add an extrapolator
|
||||
} else { // not a vehicle
|
||||
{
|
||||
if (!mImpl.get()) // if no extrapolation implementor
|
||||
{
|
||||
mImpl.reset(new RegionCrossExtrapolateImpl(vo)); // add an extrapolator
|
||||
}
|
||||
}
|
||||
else // not a vehicle
|
||||
{
|
||||
if (mImpl.get())
|
||||
{ mImpl.reset(); } // no longer needed
|
||||
{
|
||||
mImpl.reset(); // no longer needed
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BOOL ismovingssaton(const LLViewerObject &vo)
|
||||
{ if (!mImpl.get()) { return(false); } // not sat on
|
||||
return(mImpl->hasmoved()); // sat on, check for moving
|
||||
|
||||
bool ismovingssaton(const LLViewerObject &vo)
|
||||
{
|
||||
if (!mImpl.get())
|
||||
{
|
||||
return (false); // not sat on
|
||||
}
|
||||
return mImpl->hasmoved(); // sat on, check for moving
|
||||
}
|
||||
|
||||
|
||||
F32 getextraptimelimit() const // get extrapolation time limit
|
||||
{ if (mImpl.get()) { return(mImpl->getextraptimelimit()); } // get extrapolation time limit if vehicle
|
||||
return(std::numeric_limits<F32>::infinity()); // no limit if not a vehicle
|
||||
{
|
||||
if (mImpl.get())
|
||||
{
|
||||
return mImpl->getextraptimelimit(); // get extrapolation time limit if vehicle
|
||||
}
|
||||
return std::numeric_limits<F32>::infinity(); // no limit if not a vehicle
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue