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,11 +248,10 @@ using OpenThreads::ScopedLock;
|
|||||||
osg::ref_ptr<osg::Uniform> colorModeUniform;
|
osg::ref_ptr<osg::Uniform> colorModeUniform;
|
||||||
}
|
}
|
||||||
|
|
||||||
osg::Group*
|
|
||||||
SGPickAnimation::createAnimationGroup(osg::Group& parent)
|
|
||||||
{
|
|
||||||
osg::Group* commonGroup = new osg::Group;
|
|
||||||
|
|
||||||
|
void
|
||||||
|
SGPickAnimation::innerSetupPickGroup(osg::Group* commonGroup, osg::Group& parent)
|
||||||
|
{
|
||||||
// Contains the normal geometry that is interactive
|
// Contains the normal geometry that is interactive
|
||||||
osg::ref_ptr<osg::Group> normalGroup = new osg::Group;
|
osg::ref_ptr<osg::Group> normalGroup = new osg::Group;
|
||||||
normalGroup->setName("pick normal group");
|
normalGroup->setName("pick normal group");
|
||||||
@ -267,19 +262,6 @@ using OpenThreads::ScopedLock;
|
|||||||
highlightGroup->setName("pick highlight group");
|
highlightGroup->setName("pick highlight group");
|
||||||
highlightGroup->setNodeMask(simgear::PICK_BIT);
|
highlightGroup->setNodeMask(simgear::PICK_BIT);
|
||||||
highlightGroup->addChild(commonGroup);
|
highlightGroup->addChild(commonGroup);
|
||||||
SGSceneUserData* ud;
|
|
||||||
ud = SGSceneUserData::getOrCreateSceneUserData(commonGroup);
|
|
||||||
|
|
||||||
// add actions that become macro and command invocations
|
|
||||||
std::vector<SGPropertyNode_ptr> actions;
|
|
||||||
actions = getConfig()->getChildren("action");
|
|
||||||
for (unsigned int i = 0; i < actions.size(); ++i)
|
|
||||||
ud->addPickCallback(new PickCallback(actions[i], getModelRoot()));
|
|
||||||
// Look for the VNC sessions that want raw mouse input
|
|
||||||
actions = getConfig()->getChildren("vncaction");
|
|
||||||
for (unsigned int i = 0; i < actions.size(); ++i)
|
|
||||||
ud->addPickCallback(new VncCallback(actions[i], getModelRoot(),
|
|
||||||
&parent));
|
|
||||||
|
|
||||||
// prepare a state set that paints the edges of this object yellow
|
// prepare a state set that paints the edges of this object yellow
|
||||||
// The material and texture attributes are set with
|
// The material and texture attributes are set with
|
||||||
@ -328,12 +310,162 @@ using OpenThreads::ScopedLock;
|
|||||||
}
|
}
|
||||||
stateSet->addUniform(cmUniform,
|
stateSet->addUniform(cmUniform,
|
||||||
osg::StateAttribute::OVERRIDE | osg::StateAttribute::ON);
|
osg::StateAttribute::OVERRIDE | osg::StateAttribute::ON);
|
||||||
|
|
||||||
// Only add normal geometry if configured
|
// Only add normal geometry if configured
|
||||||
if (getConfig()->getBoolValue("visible", true))
|
if (getConfig()->getBoolValue("visible", true))
|
||||||
parent.addChild(normalGroup.get());
|
parent.addChild(normalGroup.get());
|
||||||
parent.addChild(highlightGroup);
|
parent.addChild(highlightGroup);
|
||||||
|
}
|
||||||
|
|
||||||
|
osg::Group*
|
||||||
|
SGPickAnimation::createAnimationGroup(osg::Group& parent)
|
||||||
|
{
|
||||||
|
osg::Group* commonGroup = new osg::Group;
|
||||||
|
innerSetupPickGroup(commonGroup, parent);
|
||||||
|
SGSceneUserData* ud = SGSceneUserData::getOrCreateSceneUserData(commonGroup);
|
||||||
|
|
||||||
|
// add actions that become macro and command invocations
|
||||||
|
std::vector<SGPropertyNode_ptr> actions;
|
||||||
|
actions = getConfig()->getChildren("action");
|
||||||
|
for (unsigned int i = 0; i < actions.size(); ++i)
|
||||||
|
ud->addPickCallback(new PickCallback(actions[i], getModelRoot()));
|
||||||
|
// Look for the VNC sessions that want raw mouse input
|
||||||
|
actions = getConfig()->getChildren("vncaction");
|
||||||
|
for (unsigned int i = 0; i < actions.size(); ++i)
|
||||||
|
ud->addPickCallback(new VncCallback(actions[i], getModelRoot(),
|
||||||
|
&parent));
|
||||||
|
|
||||||
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")) {
|
|
||||||
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]);
|
readRotationCenterAndAxis(configNode, _center, _axis);
|
||||||
_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