OpenSceneGraph/include/osgAnimation/Target
2012-03-21 17:36:20 +00:00

135 lines
3.8 KiB
C++

/* -*-c++-*-
* Copyright (C) 2008 Cedric Pinson <cedric.pinson@plopbyte.net>
*
* 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.
*/
#ifndef OSGANIMATION_TARGET
#define OSGANIMATION_TARGET 1
#include <vector>
#include <osg/Quat>
#include <osg/Vec3>
#include <osg/Vec2>
#include <osg/Vec4>
#include <osg/Referenced>
#include <osgAnimation/Export>
namespace osgAnimation
{
class Channel;
class OSGANIMATION_EXPORT Target : public osg::Referenced
{
public:
Target();
virtual ~Target() {}
void reset() { _weight = 0; _priorityWeight = 0; }
int getCount() const { return referenceCount(); }
float getWeight() const { return _weight; }
protected:
float _weight;
float _priorityWeight;
int _lastPriority;
};
template <class T>
class TemplateTarget : public Target
{
public:
TemplateTarget() : _target() {}
TemplateTarget(const T& v) { setValue(v); }
TemplateTarget(const TemplateTarget& v) { setValue(v.getValue()); }
inline void lerp(float t, const T& a, const T& b);
/**
* The priority is used to detect a change of priority
* It's important to update animation target in priority
* order. eg:
* all animation with priority 1
* all animation with priority 0
* all animation with priority -1
* ...
*/
void update(float weight, const T& val, int priority)
{
if (_weight || _priorityWeight)
{
if (_lastPriority != priority)
{
// change in priority
// add to weight with the same previous priority cumulated weight
_weight += _priorityWeight * (1.0 - _weight);
_priorityWeight = 0;
_lastPriority = priority;
}
_priorityWeight += weight;
float t = (1.0 - _weight) * weight / _priorityWeight;
lerp(t, _target, val);
}
else
{
_priorityWeight = weight;
_lastPriority = priority;
_target = val;
}
}
const T& getValue() const { return _target; }
void setValue(const T& value) { _target = value; }
protected:
T _target;
};
template <class T>
inline void TemplateTarget<T>::lerp(float t, const T& a, const T& b)
{
_target = a * (1.0f - t) + b * t;
}
template <>
inline void TemplateTarget<osg::Quat>::lerp(float t, const osg::Quat& a, const osg::Quat& b)
{
if (a.asVec4() * b.asVec4() < 0.0)
{
_target = a * (1.0f - t) + b * -t;
}
else
{
_target = a * (1.0f - t) + b * t;
}
osg::Quat::value_type len2 = _target.length2();
if ( len2 != 1.0 && len2 != 0.0)
_target *= 1.0/sqrt(len2);
}
typedef TemplateTarget<osg::Matrixf> MatrixTarget;
typedef TemplateTarget<osg::Quat> QuatTarget;
typedef TemplateTarget<osg::Vec3> Vec3Target;
typedef TemplateTarget<osg::Vec4> Vec4Target;
typedef TemplateTarget<osg::Vec2> Vec2Target;
typedef TemplateTarget<float> FloatTarget;
typedef TemplateTarget<double> DoubleTarget;
}
#endif