Initial prototype of knob animation.
This commit is contained in:
parent
a58b41e7d2
commit
4d4e474464
@ -27,11 +27,12 @@
|
|||||||
#include <osg/PolygonMode>
|
#include <osg/PolygonMode>
|
||||||
#include <osg/Material>
|
#include <osg/Material>
|
||||||
|
|
||||||
#include <simgear/scene/material/EffectGeode.hxx>
|
|
||||||
#include <simgear/scene/util/SGPickCallback.hxx>
|
#include <simgear/scene/util/SGPickCallback.hxx>
|
||||||
|
#include <simgear/scene/material/EffectGeode.hxx>
|
||||||
#include <simgear/scene/util/SGSceneUserData.hxx>
|
#include <simgear/scene/util/SGSceneUserData.hxx>
|
||||||
#include <simgear/structure/SGBinding.hxx>
|
#include <simgear/structure/SGBinding.hxx>
|
||||||
#include <simgear/scene/util/StateAttributeFactory.hxx>
|
#include <simgear/scene/util/StateAttributeFactory.hxx>
|
||||||
|
#include <simgear/scene/model/SGRotateTransform.hxx>
|
||||||
|
|
||||||
using namespace simgear;
|
using namespace simgear;
|
||||||
|
|
||||||
@ -76,17 +77,14 @@ using OpenThreads::ScopedLock;
|
|||||||
}
|
}
|
||||||
if (!found )
|
if (!found )
|
||||||
return false;
|
return false;
|
||||||
SGBindingList::const_iterator i;
|
|
||||||
for (i = _bindingsDown.begin(); i != _bindingsDown.end(); ++i)
|
fireBindingList(_bindingsDown);
|
||||||
(*i)->fire();
|
|
||||||
_repeatTime = -_repeatInterval; // anti-bobble: delay start of repeat
|
_repeatTime = -_repeatInterval; // anti-bobble: delay start of repeat
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
virtual void buttonReleased(void)
|
virtual void buttonReleased(void)
|
||||||
{
|
{
|
||||||
SGBindingList::const_iterator i;
|
fireBindingList(_bindingsUp);
|
||||||
for (i = _bindingsUp.begin(); i != _bindingsUp.end(); ++i)
|
|
||||||
(*i)->fire();
|
|
||||||
}
|
}
|
||||||
virtual void update(double dt)
|
virtual void update(double dt)
|
||||||
{
|
{
|
||||||
@ -96,9 +94,7 @@ using OpenThreads::ScopedLock;
|
|||||||
_repeatTime += dt;
|
_repeatTime += dt;
|
||||||
while (_repeatInterval < _repeatTime) {
|
while (_repeatInterval < _repeatTime) {
|
||||||
_repeatTime -= _repeatInterval;
|
_repeatTime -= _repeatInterval;
|
||||||
SGBindingList::const_iterator i;
|
fireBindingList(_bindingsDown);
|
||||||
for (i = _bindingsDown.begin(); i != _bindingsDown.end(); ++i)
|
|
||||||
(*i)->fire();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
private:
|
private:
|
||||||
@ -252,23 +248,81 @@ using OpenThreads::ScopedLock;
|
|||||||
osg::ref_ptr<osg::Uniform> colorModeUniform;
|
osg::ref_ptr<osg::Uniform> colorModeUniform;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
SGPickAnimation::innerSetupPickGroup(osg::Group* commonGroup, osg::Group& parent)
|
||||||
|
{
|
||||||
|
// Contains the normal geometry that is interactive
|
||||||
|
osg::ref_ptr<osg::Group> normalGroup = new osg::Group;
|
||||||
|
normalGroup->setName("pick normal group");
|
||||||
|
normalGroup->addChild(commonGroup);
|
||||||
|
|
||||||
|
// Used to render the geometry with just yellow edges
|
||||||
|
osg::Group* highlightGroup = new osg::Group;
|
||||||
|
highlightGroup->setName("pick highlight group");
|
||||||
|
highlightGroup->setNodeMask(simgear::PICK_BIT);
|
||||||
|
highlightGroup->addChild(commonGroup);
|
||||||
|
|
||||||
|
// prepare a state set that paints the edges of this object yellow
|
||||||
|
// The material and texture attributes are set with
|
||||||
|
// OVERRIDE|PROTECTED in case there is a material animation on a
|
||||||
|
// higher node in the scene graph, which would have its material
|
||||||
|
// attribute set with OVERRIDE.
|
||||||
|
osg::StateSet* stateSet = highlightGroup->getOrCreateStateSet();
|
||||||
|
osg::Texture2D* white = StateAttributeFactory::instance()->getWhiteTexture();
|
||||||
|
stateSet->setTextureAttributeAndModes(0, white,
|
||||||
|
(osg::StateAttribute::ON
|
||||||
|
| osg::StateAttribute::OVERRIDE
|
||||||
|
| osg::StateAttribute::PROTECTED));
|
||||||
|
osg::PolygonOffset* polygonOffset = new osg::PolygonOffset;
|
||||||
|
polygonOffset->setFactor(-1);
|
||||||
|
polygonOffset->setUnits(-1);
|
||||||
|
stateSet->setAttribute(polygonOffset, osg::StateAttribute::OVERRIDE);
|
||||||
|
stateSet->setMode(GL_POLYGON_OFFSET_LINE,
|
||||||
|
osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE);
|
||||||
|
osg::PolygonMode* polygonMode = new osg::PolygonMode;
|
||||||
|
polygonMode->setMode(osg::PolygonMode::FRONT_AND_BACK,
|
||||||
|
osg::PolygonMode::LINE);
|
||||||
|
stateSet->setAttribute(polygonMode, osg::StateAttribute::OVERRIDE);
|
||||||
|
osg::Material* material = new osg::Material;
|
||||||
|
material->setColorMode(osg::Material::OFF);
|
||||||
|
material->setAmbient(osg::Material::FRONT_AND_BACK, osg::Vec4f(0, 0, 0, 1));
|
||||||
|
// XXX Alpha < 1.0 in the diffuse material value is a signal to the
|
||||||
|
// default shader to take the alpha value from the material value
|
||||||
|
// and not the glColor. In many cases the pick animation geometry is
|
||||||
|
// transparent, so the outline would not be visible without this hack.
|
||||||
|
material->setDiffuse(osg::Material::FRONT_AND_BACK, osg::Vec4f(0, 0, 0, .95));
|
||||||
|
material->setEmission(osg::Material::FRONT_AND_BACK, osg::Vec4f(1, 1, 0, 1));
|
||||||
|
material->setSpecular(osg::Material::FRONT_AND_BACK, osg::Vec4f(0, 0, 0, 0));
|
||||||
|
stateSet->setAttribute(
|
||||||
|
material, osg::StateAttribute::OVERRIDE | osg::StateAttribute::PROTECTED);
|
||||||
|
// The default shader has a colorMode uniform that mimics the
|
||||||
|
// behavior of Material color mode.
|
||||||
|
osg::Uniform* cmUniform = 0;
|
||||||
|
{
|
||||||
|
ScopedLock<Mutex> lock(colorModeUniformMutex);
|
||||||
|
if (!colorModeUniform.valid()) {
|
||||||
|
colorModeUniform = new osg::Uniform(osg::Uniform::INT, "colorMode");
|
||||||
|
colorModeUniform->set(0); // MODE_OFF
|
||||||
|
colorModeUniform->setDataVariance(osg::Object::STATIC);
|
||||||
|
}
|
||||||
|
cmUniform = colorModeUniform.get();
|
||||||
|
}
|
||||||
|
stateSet->addUniform(cmUniform,
|
||||||
|
osg::StateAttribute::OVERRIDE | osg::StateAttribute::ON);
|
||||||
|
|
||||||
|
// Only add normal geometry if configured
|
||||||
|
if (getConfig()->getBoolValue("visible", true))
|
||||||
|
parent.addChild(normalGroup.get());
|
||||||
|
parent.addChild(highlightGroup);
|
||||||
|
}
|
||||||
|
|
||||||
osg::Group*
|
osg::Group*
|
||||||
SGPickAnimation::createAnimationGroup(osg::Group& parent)
|
SGPickAnimation::createAnimationGroup(osg::Group& parent)
|
||||||
{
|
{
|
||||||
osg::Group* commonGroup = new osg::Group;
|
osg::Group* commonGroup = new osg::Group;
|
||||||
|
innerSetupPickGroup(commonGroup, parent);
|
||||||
// Contains the normal geometry that is interactive
|
SGSceneUserData* ud = SGSceneUserData::getOrCreateSceneUserData(commonGroup);
|
||||||
osg::ref_ptr<osg::Group> normalGroup = new osg::Group;
|
|
||||||
normalGroup->setName("pick normal group");
|
|
||||||
normalGroup->addChild(commonGroup);
|
|
||||||
|
|
||||||
// Used to render the geometry with just yellow edges
|
|
||||||
osg::Group* highlightGroup = new osg::Group;
|
|
||||||
highlightGroup->setName("pick highlight group");
|
|
||||||
highlightGroup->setNodeMask(simgear::PICK_BIT);
|
|
||||||
highlightGroup->addChild(commonGroup);
|
|
||||||
SGSceneUserData* ud;
|
|
||||||
ud = SGSceneUserData::getOrCreateSceneUserData(commonGroup);
|
|
||||||
|
|
||||||
// add actions that become macro and command invocations
|
// add actions that become macro and command invocations
|
||||||
std::vector<SGPropertyNode_ptr> actions;
|
std::vector<SGPropertyNode_ptr> actions;
|
||||||
@ -281,59 +335,137 @@ using OpenThreads::ScopedLock;
|
|||||||
ud->addPickCallback(new VncCallback(actions[i], getModelRoot(),
|
ud->addPickCallback(new VncCallback(actions[i], getModelRoot(),
|
||||||
&parent));
|
&parent));
|
||||||
|
|
||||||
// prepare a state set that paints the edges of this object yellow
|
|
||||||
// The material and texture attributes are set with
|
|
||||||
// OVERRIDE|PROTECTED in case there is a material animation on a
|
|
||||||
// higher node in the scene graph, which would have its material
|
|
||||||
// attribute set with OVERRIDE.
|
|
||||||
osg::StateSet* stateSet = highlightGroup->getOrCreateStateSet();
|
|
||||||
osg::Texture2D* white = StateAttributeFactory::instance()->getWhiteTexture();
|
|
||||||
stateSet->setTextureAttributeAndModes(0, white,
|
|
||||||
(osg::StateAttribute::ON
|
|
||||||
| osg::StateAttribute::OVERRIDE
|
|
||||||
| osg::StateAttribute::PROTECTED));
|
|
||||||
osg::PolygonOffset* polygonOffset = new osg::PolygonOffset;
|
|
||||||
polygonOffset->setFactor(-1);
|
|
||||||
polygonOffset->setUnits(-1);
|
|
||||||
stateSet->setAttribute(polygonOffset, osg::StateAttribute::OVERRIDE);
|
|
||||||
stateSet->setMode(GL_POLYGON_OFFSET_LINE,
|
|
||||||
osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE);
|
|
||||||
osg::PolygonMode* polygonMode = new osg::PolygonMode;
|
|
||||||
polygonMode->setMode(osg::PolygonMode::FRONT_AND_BACK,
|
|
||||||
osg::PolygonMode::LINE);
|
|
||||||
stateSet->setAttribute(polygonMode, osg::StateAttribute::OVERRIDE);
|
|
||||||
osg::Material* material = new osg::Material;
|
|
||||||
material->setColorMode(osg::Material::OFF);
|
|
||||||
material->setAmbient(osg::Material::FRONT_AND_BACK, osg::Vec4f(0, 0, 0, 1));
|
|
||||||
// XXX Alpha < 1.0 in the diffuse material value is a signal to the
|
|
||||||
// default shader to take the alpha value from the material value
|
|
||||||
// and not the glColor. In many cases the pick animation geometry is
|
|
||||||
// transparent, so the outline would not be visible without this hack.
|
|
||||||
material->setDiffuse(osg::Material::FRONT_AND_BACK, osg::Vec4f(0, 0, 0, .95));
|
|
||||||
material->setEmission(osg::Material::FRONT_AND_BACK, osg::Vec4f(1, 1, 0, 1));
|
|
||||||
material->setSpecular(osg::Material::FRONT_AND_BACK, osg::Vec4f(0, 0, 0, 0));
|
|
||||||
stateSet->setAttribute(
|
|
||||||
material, osg::StateAttribute::OVERRIDE | osg::StateAttribute::PROTECTED);
|
|
||||||
// The default shader has a colorMode uniform that mimics the
|
|
||||||
// behavior of Material color mode.
|
|
||||||
osg::Uniform* cmUniform = 0;
|
|
||||||
{
|
|
||||||
ScopedLock<Mutex> lock(colorModeUniformMutex);
|
|
||||||
if (!colorModeUniform.valid()) {
|
|
||||||
colorModeUniform = new osg::Uniform(osg::Uniform::INT, "colorMode");
|
|
||||||
colorModeUniform->set(0); // MODE_OFF
|
|
||||||
colorModeUniform->setDataVariance(osg::Object::STATIC);
|
|
||||||
}
|
|
||||||
cmUniform = colorModeUniform.get();
|
|
||||||
}
|
|
||||||
stateSet->addUniform(cmUniform,
|
|
||||||
osg::StateAttribute::OVERRIDE | osg::StateAttribute::ON);
|
|
||||||
// Only add normal geometry if configured
|
|
||||||
if (getConfig()->getBoolValue("visible", true))
|
|
||||||
parent.addChild(normalGroup.get());
|
|
||||||
parent.addChild(highlightGroup);
|
|
||||||
|
|
||||||
|
|
||||||
return commonGroup;
|
return commonGroup;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
class SGKnobAnimation::KnobPickCallback : public SGPickCallback {
|
||||||
|
public:
|
||||||
|
KnobPickCallback(const SGPropertyNode* configNode,
|
||||||
|
SGPropertyNode* modelRoot) :
|
||||||
|
_direction(DIRECTION_NONE),
|
||||||
|
_repeatInterval(configNode->getDoubleValue("interval-sec", 0.1))
|
||||||
|
{
|
||||||
|
const SGPropertyNode* act = configNode->getChild("action");
|
||||||
|
if (act)
|
||||||
|
_action = readBindingList(act->getChildren("binding"), modelRoot);
|
||||||
|
|
||||||
|
const SGPropertyNode* cw = configNode->getChild("cw");
|
||||||
|
if (cw)
|
||||||
|
_bindingsCW = readBindingList(cw->getChildren("binding"), modelRoot);
|
||||||
|
|
||||||
|
const SGPropertyNode* ccw = configNode->getChild("ccw");
|
||||||
|
if (ccw)
|
||||||
|
_bindingsCCW = readBindingList(ccw->getChildren("binding"), modelRoot);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual bool buttonPressed(int button, const Info&)
|
||||||
|
{
|
||||||
|
_direction = DIRECTION_NONE;
|
||||||
|
if ((button == 0) || (button == 4)) {
|
||||||
|
_direction = DIRECTION_CLOCKWISE;
|
||||||
|
} else if ((button == 1) || (button == 3)) {
|
||||||
|
_direction = DIRECTION_ANTICLOCKWISE;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
_repeatTime = -_repeatInterval; // anti-bobble: delay start of repeat
|
||||||
|
fire();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void buttonReleased(void)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void update(double dt)
|
||||||
|
{
|
||||||
|
_repeatTime += dt;
|
||||||
|
while (_repeatInterval < _repeatTime) {
|
||||||
|
_repeatTime -= _repeatInterval;
|
||||||
|
fire();
|
||||||
|
} // of repeat iteration
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
void fire()
|
||||||
|
{
|
||||||
|
switch (_direction) {
|
||||||
|
case DIRECTION_CLOCKWISE:
|
||||||
|
fireBindingListWithOffset(_action, 1, 1);
|
||||||
|
fireBindingList(_bindingsCW);
|
||||||
|
break;
|
||||||
|
case DIRECTION_ANTICLOCKWISE:
|
||||||
|
fireBindingListWithOffset(_action, -1, 1);
|
||||||
|
fireBindingList(_bindingsCCW);
|
||||||
|
break;
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SGBindingList _action;
|
||||||
|
SGBindingList _bindingsCW,
|
||||||
|
_bindingsCCW;
|
||||||
|
|
||||||
|
enum Direction
|
||||||
|
{
|
||||||
|
DIRECTION_NONE,
|
||||||
|
DIRECTION_CLOCKWISE,
|
||||||
|
DIRECTION_ANTICLOCKWISE
|
||||||
|
};
|
||||||
|
|
||||||
|
Direction _direction;
|
||||||
|
double _repeatInterval;
|
||||||
|
double _repeatTime;
|
||||||
|
};
|
||||||
|
|
||||||
|
class SGKnobAnimation::UpdateCallback : public osg::NodeCallback {
|
||||||
|
public:
|
||||||
|
UpdateCallback(SGExpressiond const* animationValue) :
|
||||||
|
_animationValue(animationValue)
|
||||||
|
{
|
||||||
|
setName("SGKnobAnimation::UpdateCallback");
|
||||||
|
}
|
||||||
|
virtual void operator()(osg::Node* node, osg::NodeVisitor* nv)
|
||||||
|
{
|
||||||
|
SGRotateTransform* transform = static_cast<SGRotateTransform*>(node);
|
||||||
|
transform->setAngleDeg(_animationValue->getValue());
|
||||||
|
traverse(node, nv);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
SGSharedPtr<SGExpressiond const> _animationValue;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
SGKnobAnimation::SGKnobAnimation(const SGPropertyNode* configNode,
|
||||||
|
SGPropertyNode* modelRoot) :
|
||||||
|
SGPickAnimation(configNode, modelRoot)
|
||||||
|
{
|
||||||
|
SGSharedPtr<SGExpressiond> value = read_value(configNode, modelRoot, "-deg",
|
||||||
|
-SGLimitsd::max(), SGLimitsd::max());
|
||||||
|
_animationValue = value->simplify();
|
||||||
|
|
||||||
|
|
||||||
|
readRotationCenterAndAxis(configNode, _center, _axis);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
osg::Group*
|
||||||
|
SGKnobAnimation::createAnimationGroup(osg::Group& parent)
|
||||||
|
{
|
||||||
|
SGRotateTransform* transform = new SGRotateTransform();
|
||||||
|
innerSetupPickGroup(transform, parent);
|
||||||
|
|
||||||
|
UpdateCallback* uc = new UpdateCallback(_animationValue);
|
||||||
|
transform->setUpdateCallback(uc);
|
||||||
|
transform->setCenter(_center);
|
||||||
|
transform->setAxis(_axis);
|
||||||
|
|
||||||
|
SGSceneUserData* ud = SGSceneUserData::getOrCreateSceneUserData(transform);
|
||||||
|
ud->setPickCallback(new KnobPickCallback(getConfig(), getModelRoot()));
|
||||||
|
|
||||||
|
return transform;
|
||||||
|
}
|
||||||
|
|
||||||
|
@ -24,6 +24,8 @@
|
|||||||
|
|
||||||
#include <simgear/scene/model/animation.hxx>
|
#include <simgear/scene/model/animation.hxx>
|
||||||
|
|
||||||
|
// forward decls
|
||||||
|
class SGPickCallback;
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////
|
||||||
// Pick animation
|
// Pick animation
|
||||||
@ -34,10 +36,32 @@ public:
|
|||||||
SGPickAnimation(const SGPropertyNode* configNode,
|
SGPickAnimation(const SGPropertyNode* configNode,
|
||||||
SGPropertyNode* modelRoot);
|
SGPropertyNode* modelRoot);
|
||||||
virtual osg::Group* createAnimationGroup(osg::Group& parent);
|
virtual osg::Group* createAnimationGroup(osg::Group& parent);
|
||||||
|
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void innerSetupPickGroup(osg::Group* commonGroup, osg::Group& parent);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
class PickCallback;
|
class PickCallback;
|
||||||
class VncCallback;
|
class VncCallback;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class SGKnobAnimation : public SGPickAnimation
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
SGKnobAnimation(const SGPropertyNode* configNode,
|
||||||
|
SGPropertyNode* modelRoot);
|
||||||
|
virtual osg::Group* createAnimationGroup(osg::Group& parent);
|
||||||
|
|
||||||
|
private:
|
||||||
|
class KnobPickCallback;
|
||||||
|
class UpdateCallback;
|
||||||
|
|
||||||
|
SGVec3d _axis;
|
||||||
|
SGVec3d _center;
|
||||||
|
SGSharedPtr<SGExpressiond const> _animationValue;
|
||||||
|
};
|
||||||
|
|
||||||
#endif // of SG_SCENE_PICK_ANIMATION_HXX
|
#endif // of SG_SCENE_PICK_ANIMATION_HXX
|
||||||
|
|
||||||
|
@ -396,6 +396,9 @@ SGAnimation::animate(osg::Node* node, const SGPropertyNode* configNode,
|
|||||||
} else if (type == "pick") {
|
} else if (type == "pick") {
|
||||||
SGPickAnimation animInst(configNode, modelRoot);
|
SGPickAnimation animInst(configNode, modelRoot);
|
||||||
animInst.apply(node);
|
animInst.apply(node);
|
||||||
|
} else if (type == "knob") {
|
||||||
|
SGKnobAnimation animInst(configNode, modelRoot);
|
||||||
|
animInst.apply(node);
|
||||||
} else if (type == "range") {
|
} else if (type == "range") {
|
||||||
SGRangeAnimation animInst(configNode, modelRoot);
|
SGRangeAnimation animInst(configNode, modelRoot);
|
||||||
animInst.apply(node);
|
animInst.apply(node);
|
||||||
@ -846,6 +849,33 @@ void SpinAnimCallback::operator()(osg::Node* node, osg::NodeVisitor* nv)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// factored out to share with SGKnobAnimation
|
||||||
|
void readRotationCenterAndAxis(const SGPropertyNode* configNode, SGVec3d& center, SGVec3d& axis)
|
||||||
|
{
|
||||||
|
center = SGVec3d::zeros();
|
||||||
|
if (configNode->hasValue("axis/x1-m")) {
|
||||||
|
SGVec3d v1, v2;
|
||||||
|
v1[0] = configNode->getDoubleValue("axis/x1-m", 0);
|
||||||
|
v1[1] = configNode->getDoubleValue("axis/y1-m", 0);
|
||||||
|
v1[2] = configNode->getDoubleValue("axis/z1-m", 0);
|
||||||
|
v2[0] = configNode->getDoubleValue("axis/x2-m", 0);
|
||||||
|
v2[1] = configNode->getDoubleValue("axis/y2-m", 0);
|
||||||
|
v2[2] = configNode->getDoubleValue("axis/z2-m", 0);
|
||||||
|
center = 0.5*(v1+v2);
|
||||||
|
axis = v2 - v1;
|
||||||
|
} else {
|
||||||
|
axis[0] = configNode->getDoubleValue("axis/x", 0);
|
||||||
|
axis[1] = configNode->getDoubleValue("axis/y", 0);
|
||||||
|
axis[2] = configNode->getDoubleValue("axis/z", 0);
|
||||||
|
}
|
||||||
|
if (8*SGLimitsd::min() < norm(axis))
|
||||||
|
axis = normalize(axis);
|
||||||
|
|
||||||
|
center[0] = configNode->getDoubleValue("center/x-m", center[0]);
|
||||||
|
center[1] = configNode->getDoubleValue("center/y-m", center[1]);
|
||||||
|
center[2] = configNode->getDoubleValue("center/z-m", center[2]);
|
||||||
|
}
|
||||||
|
|
||||||
SGRotateAnimation::SGRotateAnimation(const SGPropertyNode* configNode,
|
SGRotateAnimation::SGRotateAnimation(const SGPropertyNode* configNode,
|
||||||
SGPropertyNode* modelRoot) :
|
SGPropertyNode* modelRoot) :
|
||||||
SGAnimation(configNode, modelRoot)
|
SGAnimation(configNode, modelRoot)
|
||||||
@ -862,28 +892,8 @@ SGRotateAnimation::SGRotateAnimation(const SGPropertyNode* configNode,
|
|||||||
_initialValue = _animationValue->getValue();
|
_initialValue = _animationValue->getValue();
|
||||||
else
|
else
|
||||||
_initialValue = 0;
|
_initialValue = 0;
|
||||||
_center = SGVec3d::zeros();
|
|
||||||
if (configNode->hasValue("axis/x1-m")) {
|
readRotationCenterAndAxis(configNode, _center, _axis);
|
||||||
SGVec3d v1, v2;
|
|
||||||
v1[0] = configNode->getDoubleValue("axis/x1-m", 0);
|
|
||||||
v1[1] = configNode->getDoubleValue("axis/y1-m", 0);
|
|
||||||
v1[2] = configNode->getDoubleValue("axis/z1-m", 0);
|
|
||||||
v2[0] = configNode->getDoubleValue("axis/x2-m", 0);
|
|
||||||
v2[1] = configNode->getDoubleValue("axis/y2-m", 0);
|
|
||||||
v2[2] = configNode->getDoubleValue("axis/z2-m", 0);
|
|
||||||
_center = 0.5*(v1+v2);
|
|
||||||
_axis = v2 - v1;
|
|
||||||
} else {
|
|
||||||
_axis[0] = configNode->getDoubleValue("axis/x", 0);
|
|
||||||
_axis[1] = configNode->getDoubleValue("axis/y", 0);
|
|
||||||
_axis[2] = configNode->getDoubleValue("axis/z", 0);
|
|
||||||
}
|
|
||||||
if (8*SGLimitsd::min() < norm(_axis))
|
|
||||||
_axis = normalize(_axis);
|
|
||||||
|
|
||||||
_center[0] = configNode->getDoubleValue("center/x-m", _center[0]);
|
|
||||||
_center[1] = configNode->getDoubleValue("center/y-m", _center[1]);
|
|
||||||
_center[2] = configNode->getDoubleValue("center/z-m", _center[2]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
osg::Group*
|
osg::Group*
|
||||||
|
@ -34,7 +34,9 @@
|
|||||||
SGExpressiond*
|
SGExpressiond*
|
||||||
read_value(const SGPropertyNode* configNode, SGPropertyNode* modelRoot,
|
read_value(const SGPropertyNode* configNode, SGPropertyNode* modelRoot,
|
||||||
const char* unit, double defMin, double defMax);
|
const char* unit, double defMin, double defMax);
|
||||||
|
|
||||||
|
void readRotationCenterAndAxis(const SGPropertyNode* configNode, SGVec3d& center, SGVec3d& axis);
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////
|
||||||
// Base class for animation installers
|
// Base class for animation installers
|
||||||
//////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
@ -114,3 +114,20 @@ void fireBindingList(const SGBindingList& aBindings)
|
|||||||
b->fire();
|
b->fire();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void fireBindingListWithOffset(const SGBindingList& aBindings, double offset, double max)
|
||||||
|
{
|
||||||
|
BOOST_FOREACH(SGBinding_ptr b, aBindings) {
|
||||||
|
b->fire(offset, max);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SGBindingList readBindingList(const simgear::PropertyList& aNodes, SGPropertyNode* aRoot)
|
||||||
|
{
|
||||||
|
SGBindingList result;
|
||||||
|
BOOST_FOREACH(SGPropertyNode* node, aNodes) {
|
||||||
|
result.push_back(new SGBinding(node, aRoot));
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
@ -136,4 +136,15 @@ typedef std::map<unsigned,SGBindingList> SGBindingMap;
|
|||||||
*/
|
*/
|
||||||
void fireBindingList(const SGBindingList& aBindings);
|
void fireBindingList(const SGBindingList& aBindings);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* fire every binding in a list with a setting value
|
||||||
|
|
||||||
|
*/
|
||||||
|
void fireBindingListWithOffset(const SGBindingList& aBindings, double offset, double max);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* read multiple bindings from property-list format
|
||||||
|
*/
|
||||||
|
SGBindingList readBindingList(const simgear::PropertyList& aNodes, SGPropertyNode* aRoot);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
Loading…
Reference in New Issue
Block a user