From 1ae0f9c19d52de2f0b0fa213bf9c01730212f70d Mon Sep 17 00:00:00 2001 From: Torsten Dreyer Date: Sat, 22 May 2010 23:35:01 +0200 Subject: [PATCH] New pick animation capability from Alex Perry Alex Perry: Adds a new pick animation capability which parallels the existing "action" for a named object. Specifying "vncaction" and a transform from model space will enable all mouse clicks on that object to be delivered directly to the OSG image. Currently, the readers for VNC and PDF files yield interactive images; more are likely to be added over time. --- simgear/scene/material/TextureBuilder.cxx | 7 +- simgear/scene/model/animation.cxx | 138 ++++++++++++++++++++++ simgear/scene/model/animation.hxx | 1 + 3 files changed, 143 insertions(+), 3 deletions(-) diff --git a/simgear/scene/material/TextureBuilder.cxx b/simgear/scene/material/TextureBuilder.cxx index c2723eaa..d60e767d 100644 --- a/simgear/scene/material/TextureBuilder.cxx +++ b/simgear/scene/material/TextureBuilder.cxx @@ -96,7 +96,7 @@ TexEnv* buildTexEnv(Effect* effect, const SGPropertyNode* prop) if (colorProp) env->setColor(toOsg(colorProp->getValue())); return env; - } +} void TextureUnitBuilder::buildAttribute(Effect* effect, Pass* pass, @@ -132,7 +132,9 @@ void TextureUnitBuilder::buildAttribute(Effect* effect, Pass* pass, options); } catch (BuilderException& e) { - SG_LOG(SG_INPUT, SG_ALERT, "No image file for texture, using white "); + SG_LOG(SG_INPUT, SG_ALERT, "No image file, " + << "maybe the reader did not set the filename attribute, " + << "using white on " << pass->getName()); texture = StateAttributeFactory::instance()->getWhiteTexture(); } pass->setTextureAttributeAndModes(unit, texture); @@ -682,7 +684,6 @@ TexGen* buildTexGen(Effect* effect, const SGPropertyNode* tgenProp) if (!isAttributeActive(effect, tgenProp)) return 0; TexGen* result = new TexGen; - const SGPropertyNode* p = 0; TexGen::Mode mode = TexGen::OBJECT_LINEAR; findAttr(tgenModes, getEffectPropertyChild(effect, tgenProp, "mode"), mode); result->setMode(mode); diff --git a/simgear/scene/model/animation.cxx b/simgear/scene/model/animation.cxx index 80c08be2..e8486653 100644 --- a/simgear/scene/model/animation.cxx +++ b/simgear/scene/model/animation.cxx @@ -39,6 +39,7 @@ #include #include #include +#include #include #include #include @@ -2139,6 +2140,136 @@ private: double _repeatTime; }; +class VncVisitor : public osg::NodeVisitor { + public: + VncVisitor(double x, double y, int mask) : + osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN), + _texX(x), _texY(y), _mask(mask), _done(false) + { + SG_LOG(SG_INPUT, SG_DEBUG, "VncVisitor constructor " + << x << "," << y << " mask " << mask); + } + + virtual void apply(osg::Node &node) + { + // Some nodes have state sets attached + touchStateSet(node.getStateSet()); + if (!_done) + traverse(node); + if (_done) return; + // See whether we are a geode worth exploring + osg::Geode *g = dynamic_cast(&node); + if (!g) return; + // Go find all its drawables + int i = g->getNumDrawables(); + while (--i >= 0) { + osg::Drawable *d = g->getDrawable(i); + if (d) touchDrawable(*d); + } + // Out of optimism, do the same for EffectGeode + simgear::EffectGeode *eg = dynamic_cast(&node); + if (!eg) return; + for (simgear::EffectGeode::DrawablesIterator di = eg->drawablesBegin(); + di != eg->drawablesEnd(); di++) { + touchDrawable(**di); + } + // Now see whether the EffectGeode has an Effect + simgear::Effect *e = eg->getEffect(); + if (e) { + touchStateSet(e->getDefaultStateSet()); + } + } + + inline void touchDrawable(osg::Drawable &d) + { + osg::StateSet *ss = d.getStateSet(); + touchStateSet(ss); + } + + void touchStateSet(osg::StateSet *ss) + { + if (!ss) return; + osg::StateAttribute *sa = ss->getTextureAttribute(0, + osg::StateAttribute::TEXTURE); + if (!sa) return; + osg::Texture *t = sa->asTexture(); + if (!t) return; + osg::Image *img = t->getImage(0); + if (!img) return; + if (!_done) { + int pixX = _texX * img->s(); + int pixY = _texY * img->t(); + _done = img->sendPointerEvent(pixX, pixY, _mask); + SG_LOG(SG_INPUT, SG_DEBUG, "VncVisitor image said " << _done + << " to coord " << pixX << "," << pixY); + } + } + + inline bool wasSuccessful() + { + return _done; + } + + private: + double _texX, _texY; + int _mask; + bool _done; +}; + + +class SGPickAnimation::VncCallback : public SGPickCallback { +public: + VncCallback(const SGPropertyNode* configNode, + SGPropertyNode* modelRoot, + osg::Group *node) + : _node(node) + { + SG_LOG(SG_INPUT, SG_DEBUG, "Configuring VNC callback"); + const char *cornernames[3] = {"top-left", "top-right", "bottom-left"}; + SGVec3d *cornercoords[3] = {&_topLeft, &_toRight, &_toDown}; + for (int c =0; c < 3; c++) { + const SGPropertyNode* cornerNode = configNode->getChild(cornernames[c]); + *cornercoords[c] = SGVec3d( + cornerNode->getDoubleValue("x"), + cornerNode->getDoubleValue("y"), + cornerNode->getDoubleValue("z")); + } + _toRight -= _topLeft; + _toDown -= _topLeft; + _squaredRight = dot(_toRight, _toRight); + _squaredDown = dot(_toDown, _toDown); + } + + virtual bool buttonPressed(int button, const Info& info) + { + SGVec3d loc(info.local); + SG_LOG(SG_INPUT, SG_DEBUG, "VNC pressed " << button << ": " << loc); + loc -= _topLeft; + _x = dot(loc, _toRight) / _squaredRight; + _y = dot(loc, _toDown) / _squaredDown; + if (_x<0) _x = 0; else if (_x > 1) _x = 1; + if (_y<0) _y = 0; else if (_y > 1) _y = 1; + VncVisitor vv(_x, _y, 1 << button); + _node->accept(vv); + return vv.wasSuccessful(); + + } + virtual void buttonReleased(void) + { + SG_LOG(SG_INPUT, SG_DEBUG, "VNC release"); + VncVisitor vv(_x, _y, 0); + _node->accept(vv); + } + virtual void update(double dt) + { + } +private: + double _x, _y; + osg::ref_ptr _node; + SGVec3d _topLeft, _toRight, _toDown; + double _squaredRight, _squaredDown; +}; + SGPickAnimation::SGPickAnimation(const SGPropertyNode* configNode, SGPropertyNode* modelRoot) : SGAnimation(configNode, modelRoot) @@ -2162,10 +2293,17 @@ SGPickAnimation::createAnimationGroup(osg::Group& parent) highlightGroup->addChild(commonGroup); SGSceneUserData* ud; ud = SGSceneUserData::getOrCreateSceneUserData(commonGroup); + + // add actions that become macro and command invocations std::vector 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 osg::StateSet* stateSet = highlightGroup->getOrCreateStateSet(); diff --git a/simgear/scene/model/animation.hxx b/simgear/scene/model/animation.hxx index 4ea07fd2..1e2b1331 100644 --- a/simgear/scene/model/animation.hxx +++ b/simgear/scene/model/animation.hxx @@ -342,6 +342,7 @@ public: virtual osg::Group* createAnimationGroup(osg::Group& parent); private: class PickCallback; + class VncCallback; }; #endif // _SG_ANIMATION_HXX -- 2.39.5