Initial prototype of knob animation.

This commit is contained in:
James Turner 2013-01-31 00:15:09 +00:00
parent a58b41e7d2
commit 4d4e474464
6 changed files with 297 additions and 101 deletions

View File

@ -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;
}

View File

@ -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

View File

@ -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*

View File

@ -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
////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////

View File

@ -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;
}

View File

@ -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