/* -*-c++-*- * Copyright (C) 2008 Cedric Pinson * * 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_H #define OSGANIMATION_TARGET_H #include #include #include #include #include #include #include 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 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 inline void TemplateTarget::lerp(float t, const T& a, const T& b) { _target = a * (1.0f - t) + b * t; } template <> inline void TemplateTarget::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 QuatTarget; typedef TemplateTarget Vec3Target; typedef TemplateTarget Vec4Target; typedef TemplateTarget Vec2Target; typedef TemplateTarget FloatTarget; typedef TemplateTarget DoubleTarget; } #endif