From 059c906be55fb060ba70231912cbf96f37fc7290 Mon Sep 17 00:00:00 2001 From: frohlich Date: Thu, 4 Jan 2007 13:22:27 +0000 Subject: [PATCH] Modified Files: src/Cockpit/panel.cxx src/Cockpit/panel.hxx src/Cockpit/panel_io.cxx src/GUI/dialog.cxx src/GUI/dialog.hxx src/GUI/menubar.cxx src/GUI/menubar.hxx src/GUI/new_gui.hxx src/Input/input.cxx src/Input/input.hxx src/Main/renderer.cxx src/Scenery/scenery.cxx src/Scenery/scenery.hxx: Use SGBinding instead of FGBinding. Remove FGBinding. Install hooks to make the pick animation work. --- src/Cockpit/panel.cxx | 2 +- src/Cockpit/panel.hxx | 4 +- src/Cockpit/panel_io.cxx | 6 +- src/GUI/dialog.cxx | 4 +- src/GUI/dialog.hxx | 1 - src/GUI/menubar.cxx | 6 +- src/GUI/menubar.hxx | 4 +- src/GUI/new_gui.hxx | 3 +- src/Input/input.cxx | 152 +++++++++++++-------------------------- src/Input/input.hxx | 119 +++--------------------------- src/Main/renderer.cxx | 24 ++++--- src/Scenery/scenery.cxx | 95 +++++++++++++++++++++++- src/Scenery/scenery.hxx | 3 + 13 files changed, 185 insertions(+), 238 deletions(-) diff --git a/src/Cockpit/panel.cxx b/src/Cockpit/panel.cxx index 90ee33b1d..68151bcb7 100644 --- a/src/Cockpit/panel.cxx +++ b/src/Cockpit/panel.cxx @@ -661,7 +661,7 @@ FGPanelAction::~FGPanelAction () } void -FGPanelAction::addBinding (FGBinding * binding, int updown) +FGPanelAction::addBinding (SGBinding * binding, int updown) { _bindings[updown].push_back(binding); } diff --git a/src/Cockpit/panel.hxx b/src/Cockpit/panel.hxx index 81f7bc3a8..0eb883ddb 100644 --- a/src/Cockpit/panel.hxx +++ b/src/Cockpit/panel.hxx @@ -250,7 +250,7 @@ public: // Setters. // transfer pointer ownership - virtual void addBinding (FGBinding * binding, int updown); + virtual void addBinding (SGBinding * binding, int updown); virtual void setButton (int button) { _button = button; } virtual void setX (int x) { _x = x; } virtual void setY (int y) { _y = y; } @@ -271,7 +271,7 @@ public: virtual bool doAction (int updown); private: - typedef vector binding_list_t; + typedef vector binding_list_t; int _button; int _x; diff --git a/src/Cockpit/panel_io.cxx b/src/Cockpit/panel_io.cxx index 64c94f496..95781b937 100644 --- a/src/Cockpit/panel_io.cxx +++ b/src/Cockpit/panel_io.cxx @@ -178,7 +178,7 @@ readAction (const SGPropertyNode * node, float w_scale, float h_scale) // button-less actions are fired initially if (!node->hasValue("w") || !node->hasValue("h")) { for (i = 0; i < bindings.size(); i++) { - FGBinding b(bindings[i]); + SGBinding b(bindings[i], globals->get_props()); b.fire(); } return 0; @@ -207,7 +207,7 @@ readAction (const SGPropertyNode * node, float w_scale, float h_scale) binding = dest->getChild("binding", j, true); copyProperties(bindings[i], binding); - action->addBinding(new FGBinding(binding), 0); + action->addBinding(new SGBinding(binding, globals->get_props()), 0); } if (node->hasChild("mod-up")) { @@ -219,7 +219,7 @@ readAction (const SGPropertyNode * node, float w_scale, float h_scale) binding = dest->getChild("binding", j, true); copyProperties(bindings[i], binding); - action->addBinding(new FGBinding(binding), 1); + action->addBinding(new SGBinding(binding, globals->get_props()), 1); } } diff --git a/src/GUI/dialog.cxx b/src/GUI/dialog.cxx index 63e3ac7a1..1a1bbd88f 100644 --- a/src/GUI/dialog.cxx +++ b/src/GUI/dialog.cxx @@ -32,7 +32,7 @@ struct GUIInfo virtual ~GUIInfo (); FGDialog * dialog; - vector bindings; + vector bindings; int key; }; @@ -746,7 +746,7 @@ FGDialog::setupObject (puObject * object, SGPropertyNode * props) binding = dest->getChild("binding", j, true); copyProperties(bindings[i], binding); - info->bindings.push_back(new FGBinding(binding)); + info->bindings.push_back(new SGBinding(binding, globals->get_props())); } object->setCallback(action_callback); diff --git a/src/GUI/dialog.hxx b/src/GUI/dialog.hxx index df981c81f..6430b75cd 100644 --- a/src/GUI/dialog.hxx +++ b/src/GUI/dialog.hxx @@ -30,7 +30,6 @@ class GUI_ID { public: GUI_ID(int id) : id(id) {} int id; }; class FGDialog; -class FGBinding; class NewGUI; class FGColor; diff --git a/src/GUI/menubar.cxx b/src/GUI/menubar.cxx index 9cacef59c..da905ee25 100644 --- a/src/GUI/menubar.cxx +++ b/src/GUI/menubar.cxx @@ -156,7 +156,7 @@ void FGMenuBar::fireItem (puObject * item) { const char * name = item->getLegend(); - vector &bindings = _bindings[name]; + vector &bindings = _bindings[name]; int nBindings = bindings.size(); for (int i = 0; i < nBindings; i++) @@ -194,7 +194,7 @@ FGMenuBar::make_menu (SGPropertyNode * node) binding = dest->getChild("binding", m, true); copyProperties(bindings[k], binding); - _bindings[items[j]].push_back(new FGBinding(binding)); + _bindings[items[j]].push_back(new SGBinding(binding, globals->get_props())); } } @@ -283,7 +283,7 @@ FGMenuBar::destroy_menubar () // Delete all those bindings SG_LOG(SG_GENERAL, SG_INFO, "Deleting bindings"); - map >::iterator it; + map >::iterator it; it = _bindings.begin(); for (it = _bindings.begin(); it != _bindings.end(); it++) { SG_LOG(SG_GENERAL, SG_INFO, "Deleting bindings for " << it->first); diff --git a/src/GUI/menubar.hxx b/src/GUI/menubar.hxx index 2bcef85f3..e3a97d57e 100644 --- a/src/GUI/menubar.hxx +++ b/src/GUI/menubar.hxx @@ -21,7 +21,7 @@ SG_USING_STD(vector); class puMenuBar; class puObject; -class FGBinding; +class SGBinding; /** @@ -124,7 +124,7 @@ private: puMenuBar * _menuBar; // A map of bindings for the menubar. - map > _bindings; + map > _bindings; // These are hoops that we have to jump through because PUI doesn't // do memory management for lists. We have to allocate the arrays, diff --git a/src/GUI/new_gui.hxx b/src/GUI/new_gui.hxx index 352024a66..d258399f6 100644 --- a/src/GUI/new_gui.hxx +++ b/src/GUI/new_gui.hxx @@ -27,9 +27,10 @@ SG_USING_STD(string); #include
+class SGBinding; + class FGMenuBar; class FGDialog; -class FGBinding; class FGColor; class FGFontCache; diff --git a/src/Input/input.cxx b/src/Input/input.cxx index 30639bc19..93dfbb902 100644 --- a/src/Input/input.cxx +++ b/src/Input/input.cxx @@ -41,7 +41,9 @@ #include #include +#include #include +#include #include #include @@ -59,7 +61,6 @@ #include #include
-#include SG_USING_STD(ifstream); SG_USING_STD(string); @@ -99,87 +100,6 @@ getModAlt () return bool(fgGetKeyModifiers() & KEYMOD_ALT); } - -//////////////////////////////////////////////////////////////////////// -// Implementation of FGBinding. -//////////////////////////////////////////////////////////////////////// - -FGBinding::FGBinding () - : _command(0), - _arg(new SGPropertyNode), - _setting(0) -{ -} - -FGBinding::FGBinding (const SGPropertyNode * node) - : _command(0), - _arg(0), - _setting(0) -{ - read(node); -} - -FGBinding::~FGBinding () -{ - _arg->getParent()->removeChild(_arg->getName(), _arg->getIndex(), false); -} - -void -FGBinding::read (const SGPropertyNode * node) -{ - const SGPropertyNode * conditionNode = node->getChild("condition"); - if (conditionNode != 0) - setCondition(sgReadCondition(globals->get_props(), conditionNode)); - - _command_name = node->getStringValue("command", ""); - if (_command_name.empty()) { - SG_LOG(SG_INPUT, SG_WARN, "No command supplied for binding."); - _command = 0; - return; - } - - _arg = (SGPropertyNode *)node; - _setting = 0; -} - -void -FGBinding::fire () const -{ - if (test()) { - if (_command == 0) - _command = globals->get_commands()->getCommand(_command_name); - if (_command == 0) { - SG_LOG(SG_INPUT, SG_WARN, "No command attached to binding"); - } else if (!(*_command)(_arg)) { - SG_LOG(SG_INPUT, SG_ALERT, "Failed to execute command " - << _command_name); - } - } -} - -void -FGBinding::fire (double offset, double max) const -{ - if (test()) { - _arg->setDoubleValue("offset", offset/max); - fire(); - } -} - -void -FGBinding::fire (double setting) const -{ - if (test()) { - // A value is automatically added to - // the args - if (_setting == 0) // save the setting node for efficiency - _setting = _arg->getChild("setting", 0, true); - _setting->setDoubleValue(setting); - fire(); - } -} - - //////////////////////////////////////////////////////////////////////// // Implementation of FGInput. @@ -341,6 +261,16 @@ FGInput::doMouseClick (int b, int updown, int x, int y) // Pass on to PUI and the panel if // requested, and return if one of // them consumes the event. + + if (updown != MOUSE_BUTTON_DOWN) { + // Execute the mouse up event in any case, may be we should + // stop processing here? + while (!_activePickCallbacks[b].empty()) { + _activePickCallbacks[b].front()->buttonReleased(); + _activePickCallbacks[b].pop_front(); + } + } + if (mode.pass_through) { if (puMouse(b, updown, x, y)) return; @@ -351,28 +281,33 @@ FGInput::doMouseClick (int b, int updown, int x, int y) else if (fgHandle3DPanelMouseEvent(b, updown, x, y)) return; else { - // pui and the panel didn't want the click event so compute a - // terrain intersection point corresponding to the mouse click - // and be happy. - FGScenery* scenery = globals->get_scenery(); - SGVec3d start, dir, hit; - if (!b && updown == MOUSE_BUTTON_DOWN - && FGRenderer::getPickInfo(start, dir, x, y) - && scenery->get_cart_ground_intersection(start, dir, hit)) { - - SGGeod geod = SGGeod::fromCart(hit); - SGPropertyNode *c = fgGetNode("/sim/input/click", true); - c->setDoubleValue("longitude-deg", geod.getLongitudeDeg()); - c->setDoubleValue("latitude-deg", geod.getLatitudeDeg()); - c->setDoubleValue("elevation-m", geod.getElevationM()); - c->setDoubleValue("elevation-ft", geod.getElevationFt()); - - fgSetBool("/sim/signals/click", 1); + // pui didn't want the click event so compute a + // scenegraph intersection point corresponding to the mouse click + if (updown == MOUSE_BUTTON_DOWN) { + FGScenery* scenery = globals->get_scenery(); + SGVec3d start, dir; + + // Get the list of hit callbacks. Take the first callback that + // accepts the mouse button press and ignore the rest of them + // That is they get sorted by distance and by scenegraph depth. + // The nearest one is the first one and the deepest + // (the most specialized one in the scenegraph) is the first. + if (FGRenderer::getPickInfo(start, dir, x, y)) { + std::vector pickList; + scenery->pick(start, dir, pickList); + std::vector::const_iterator i; + for (i = pickList.begin(); i != pickList.end(); ++i) { + if (i->callback->buttonPressed(b, i->info)) { + _activePickCallbacks[b].push_back(i->callback); + break; + } + } + } } } } - // OK, PUI and the panel didn't want the click + // OK, PUI and the panel didn't want the click if (b >= MAX_MOUSE_BUTTONS) { SG_LOG(SG_INPUT, SG_ALERT, "Mouse button " << b << " where only " << MAX_MOUSE_BUTTONS << " expected"); @@ -924,6 +859,16 @@ FGInput::_update_mouse ( double dt ) m.save_x = m.x; m.save_y = m.y; } + + // handle repeatable mouse press events + std::map > >::iterator mi; + for (mi = _activePickCallbacks.begin(); + mi != _activePickCallbacks.end(); ++mi) { + std::list >::iterator li; + for (li = mi->second.begin(); li != mi->second.end(); ++li) { + (*li)->update(dt); + } + } } void @@ -934,8 +879,9 @@ FGInput::_update_button (button &b, int modifiers, bool pressed, // The press event may be repeated. if (!b.last_state || b.is_repeatable) { SG_LOG( SG_INPUT, SG_DEBUG, "Button has been pressed" ); - for (unsigned int k = 0; k < b.bindings[modifiers].size(); k++) + for (unsigned int k = 0; k < b.bindings[modifiers].size(); k++) { b.bindings[modifiers][k]->fire(x, y); + } } } else { // The release event is never repeated. @@ -963,7 +909,7 @@ FGInput::_read_bindings (const SGPropertyNode * node, if (!strcmp(cmd, "nasal") && _module[0]) bindings[i]->setStringValue("module", _module); - binding_list[modifiers].push_back(new FGBinding(bindings[i])); + binding_list[modifiers].push_back(new SGBinding(bindings[i], globals->get_props())); } // Read nested bindings for modifiers @@ -985,7 +931,7 @@ FGInput::_read_bindings (const SGPropertyNode * node, } -const vector & +const FGInput::binding_list_t& FGInput::_find_key_bindings (unsigned int k, int modifiers) { unsigned char kc = (unsigned char)k; diff --git a/src/Input/input.hxx b/src/Input/input.hxx index c8dcec3ac..ca15e458d 100644 --- a/src/Input/input.hxx +++ b/src/Input/input.hxx @@ -35,15 +35,17 @@ #include #include -#include +#include #include #include +#include #include
#include
#include
#include +#include #include SG_USING_STD(map); @@ -61,110 +63,6 @@ SG_USING_STD(vector); #endif - -//////////////////////////////////////////////////////////////////////// -// General binding support. -//////////////////////////////////////////////////////////////////////// - - -/** - * An input binding of some sort. - * - *

This class represents a binding that can be assigned to a - * keyboard key, a joystick button or axis, or even a panel - * instrument.

- */ -class FGBinding : public SGConditional -{ -public: - - /** - * Default constructor. - */ - FGBinding (); - - - /** - * Convenience constructor. - * - * @param node The binding will be built from this node. - */ - FGBinding (const SGPropertyNode * node); - - - /** - * Destructor. - */ - virtual ~FGBinding (); - - - /** - * Get the command name. - * - * @return The string name of the command for this binding. - */ - virtual const string &getCommandName () const { return _command_name; } - - - /** - * Get the command itself. - * - * @return The command associated with this binding, or 0 if none - * is present. - */ - virtual SGCommandMgr::command_t getCommand () const { return _command; } - - - /** - * Get the argument that will be passed to the command. - * - * @return A property node that will be passed to the command as its - * argument, or 0 if none was supplied. - */ - virtual const SGPropertyNode * getArg () { return _arg; } - - - /** - * Read a binding from a property node. - * - * @param node The property node containing the binding. - */ - virtual void read (const SGPropertyNode * node); - - - /** - * Fire a binding. - */ - virtual void fire () const; - - - /** - * Fire a binding with a scaled movement (rather than absolute position). - */ - virtual void fire (double offset, double max) const; - - - /** - * Fire a binding with a setting (i.e. joystick axis). - * - * A double 'setting' property will be added to the arguments. - * - * @param setting The input setting, usually between -1.0 and 1.0. - */ - virtual void fire (double setting) const; - - -private: - // just to be safe. - FGBinding (const FGBinding &binding); - - string _command_name; - mutable SGCommandMgr::command_t _command; - mutable SGPropertyNode_ptr _arg; - mutable SGPropertyNode_ptr _setting; -}; - - //////////////////////////////////////////////////////////////////////// // General input mapping support. @@ -268,7 +166,7 @@ private: struct mouse; friend struct mouse; - typedef vector binding_list_t; + typedef vector > binding_list_t; /** * Settings for a key or button. @@ -424,8 +322,8 @@ private: /** * Look up the bindings for a key code. */ - const vector &_find_key_bindings (unsigned int k, - int modifiers); + const binding_list_t& _find_key_bindings (unsigned int k, + int modifiers); button _key_bindings[MAX_KEYS]; joystick _joystick_bindings[MAX_JOYSTICKS]; @@ -435,6 +333,11 @@ private: * Nasal module name/namespace. */ char _module[32]; + + /** + * List of currently pressed mouse button events + */ + std::map > > _activePickCallbacks; }; #endif // _INPUT_HXX diff --git a/src/Main/renderer.cxx b/src/Main/renderer.cxx index c123fbf55..a6aa86f8a 100644 --- a/src/Main/renderer.cxx +++ b/src/Main/renderer.cxx @@ -46,16 +46,10 @@ #include #include #include -#include -#include -#include #include +#include #include #include -#include -#include -#include -#include #include #include @@ -136,7 +130,6 @@ public: || (fgGetBool("/sim/ai-traffic/enabled"))) globals->get_ATC_display()->update(delta_time_sec, state); - puDisplay(); // Fade out the splash screen over the first three seconds. @@ -357,6 +350,12 @@ FGRenderer::init( void ) { osg::initNotifyLevel(); + // The number of polygon-offset "units" to place between layers. In + // principle, one is supposed to be enough. In practice, I find that + // my hardware/driver requires many more. + osg::PolygonOffset::setUnitsMultiplier(1); + osg::PolygonOffset::setFactorMultiplier(1); + // Go full screen if requested ... if ( fgGetBool("/sim/startup/fullscreen") ) fgOSFullScreen(); @@ -797,6 +796,12 @@ FGRenderer::update( bool refresh_camera_settings ) { mUpdateVisitor->setLight(direction, l->scene_ambient(), l->scene_diffuse(), l->scene_specular()); mUpdateVisitor->setVisibility(actual_visibility); + + if (fgGetBool("/sim/panel-hotspots")) + sceneView->setCullMask(~0u); + else + sceneView->setCullMask(~SG_NODEMASK_PICK_BIT); + sceneView->update(); sceneView->cull(); sceneView->draw(); @@ -839,9 +844,6 @@ FGRenderer::resize( int width, int height ) { setFOV( viewmgr->get_current_view()->get_h_fov(), viewmgr->get_current_view()->get_v_fov() ); - // cout << "setFOV(" << viewmgr->get_current_view()->get_h_fov() - // << ", " << viewmgr->get_current_view()->get_v_fov() << ")" - // << endl; } } diff --git a/src/Scenery/scenery.cxx b/src/Scenery/scenery.cxx index 1f04b6c1b..bcd7d1865 100644 --- a/src/Scenery/scenery.cxx +++ b/src/Scenery/scenery.cxx @@ -36,11 +36,33 @@ #include #include #include +#include #include
#include "scenery.hxx" +class FGGroundPickCallback : public SGPickCallback { +public: + virtual bool buttonPressed(int button, const Info& info) + { + // only on left mouse button + if (button != 0) + return false; + + SGGeod geod = SGGeod::fromCart(info.wgs84); + SG_LOG( SG_TERRAIN, SG_INFO, "Got ground pick at " << geod ); + + SGPropertyNode *c = fgGetNode("/sim/input/click", true); + c->setDoubleValue("longitude-deg", geod.getLongitudeDeg()); + c->setDoubleValue("latitude-deg", geod.getLatitudeDeg()); + c->setDoubleValue("elevation-m", geod.getElevationM()); + c->setDoubleValue("elevation-ft", geod.getElevationFt()); + fgSetBool("/sim/signals/click", 1); + + return true; + } +}; // Scenery Management system FGScenery::FGScenery() : @@ -64,6 +86,9 @@ void FGScenery::init() { terrain_branch = new osg::Group; terrain_branch->setName( "Terrain" ); scene_graph->addChild( terrain_branch.get() ); + SGSceneUserData* userData; + userData = SGSceneUserData::getOrCreateSceneUserData(terrain_branch.get()); + userData->setPickCallback(new FGGroundPickCallback); models_branch = new osg::Group; models_branch->setName( "Models" ); @@ -192,6 +217,25 @@ FGScenery::get_cart_elevation_m(const SGVec3d& pos, double max_altoff, return hits; } +static const osgUtil::Hit* +getNearestHit(const osgUtil::IntersectVisitor::HitList& hitList, + const SGVec3d& start) +{ + const osgUtil::Hit* nearestHit = 0; + double dist = SGLimitsd::max(); + osgUtil::IntersectVisitor::HitList::const_iterator hit; + for (hit = hitList.begin(); hit != hitList.end(); ++hit) { + SGVec3d point(hit->getWorldIntersectPoint()); + double newdist = length(start - point); + if (newdist < dist) { + dist = newdist; + nearestHit = &*hit; + } + } + + return nearestHit; +} + bool FGScenery::get_cart_ground_intersection(const SGVec3d& pos, const SGVec3d& dir, SGVec3d& nearestHit, bool exact) @@ -215,7 +259,7 @@ FGScenery::get_cart_ground_intersection(const SGVec3d& pos, const SGVec3d& dir, // Make really sure the direction is normalized, is really cheap compared to // computation of ground intersection. SGVec3d start = pos - center; - SGVec3d end = start + 1e5*dir; + SGVec3d end = start + 1e5*normalize(dir); // FIXME visibility ??? osgUtil::IntersectVisitor intersectVisitor; intersectVisitor.setTraversalMask(SG_NODEMASK_TERRAIN_BIT); @@ -246,3 +290,52 @@ FGScenery::get_cart_ground_intersection(const SGVec3d& pos, const SGVec3d& dir, return hits; } +void +FGScenery::pick(const SGVec3d& pos, const SGVec3d& dir, + std::vector& pickList) +{ + pickList.clear(); + + // Make really sure the direction is normalized, is really cheap compared to + // computation of ground intersection. + SGVec3d start = pos - center; + SGVec3d end = start + 1e5*normalize(dir); // FIXME visibility ??? + + osgUtil::IntersectVisitor intersectVisitor; +// osgUtil::PickVisitor intersectVisitor; +// intersectVisitor.setTraversalMask(SG_NODEMASK_TERRAIN_BIT); + osg::ref_ptr lineSegment; + lineSegment = new osg::LineSegment(start.osg(), end.osg()); + intersectVisitor.addLineSegment(lineSegment.get()); + get_scene_graph()->accept(intersectVisitor); + if (!intersectVisitor.hits()) + return; + + // collect all interaction callbacks on the pick ray. + // They get stored in the pickCallbacks list where they are sorted back + // to front and croasest to finest wrt the scenery node they are attached to + osgUtil::IntersectVisitor::HitList::const_iterator hi; + for (hi = intersectVisitor.getHitList(lineSegment.get()).begin(); + hi != intersectVisitor.getHitList(lineSegment.get()).end(); + ++hi) { + + // ok, go back the nodes and ask for intersection callbacks, + // execute them in top down order + const osg::NodePath& np = hi->getNodePath(); + osg::NodePath::const_reverse_iterator npi; + for (npi = np.rbegin(); npi != np.rend(); ++npi) { + SGSceneUserData* ud = SGSceneUserData::getSceneUserData(*npi); + if (!ud) + continue; + SGPickCallback* pickCallback = ud->getPickCallback(); + if (!pickCallback) + continue; + + SGSceneryPick sceneryPick; + sceneryPick.info.wgs84 = center + SGVec3d(hi->getWorldIntersectPoint()); + sceneryPick.info.local = SGVec3d(hi->getLocalIntersectPoint()); + sceneryPick.callback = pickCallback; + pickList.push_back(sceneryPick); + } + } +} diff --git a/src/Scenery/scenery.hxx b/src/Scenery/scenery.hxx index 282bea2af..a1cf2a77b 100644 --- a/src/Scenery/scenery.hxx +++ b/src/Scenery/scenery.hxx @@ -38,6 +38,7 @@ #include #include #include +#include SG_USING_STD(list); @@ -114,6 +115,8 @@ public: /// On success, true is returned. bool get_cart_ground_intersection(const SGVec3d& start, const SGVec3d& dir, SGVec3d& nearestHit, bool exact = false); + void pick(const SGVec3d& pos, const SGVec3d& dir, + std::vector& pickList); const SGVec3d& get_center() const { return center; } void set_center( const SGVec3d& p ); -- 2.39.5