]> git.mxchange.org Git - flightgear.git/commitdiff
Andy Ross:
authorcurt <curt>
Tue, 29 Oct 2002 19:44:03 +0000 (19:44 +0000)
committercurt <curt>
Tue, 29 Oct 2002 19:44:03 +0000 (19:44 +0000)
The biggest and coolest patch adds mouse sensitivity to the 3D
cockpits, so we can finally work the radios.  This ended up requiring
significant modifications outside of the 3D cockpit code.  Stuff folks
will want to look at:

+ The list of all "3D" cockpits is stored statically in the
   panelnode.cxx file.  This is clumsy, and won't migrate well to a
   multiple-aircraft feature.  Really, there should be a per-model list
   of 3D panels, but I couldn't find a clean place to put this.  The
   only handle you get back after parsing a model is a generic ssg
   node, to which I obviously can't add panel-specific methods.

+ The aircraft model is parsed *very* early in the initialization
   order.  Earlier, in fact, than the static list of allowable command
   bindings is built in fgInitCommands().  This is bad, as it means
   that mouse bindings on the instruments can't work yet.  I moved the
   call to fgInitCommands, but someone should look carefully to see
   that I picked the right place.  There's a lot of initialization
   code, and I got a little lost in there... :)

+ I added yet another "update" hook to the fgRenderFrame routine to
   hook the updates for the 3D panels.  This is only required for
   "mouse press delay", and it's a fairly clumsy mechanism based on
   frame rate instead of real time.  There appears to be delay handling
   already in place in the Input stuff, and there's a discussion going
   on about different mouse behavior right now.  Maybe this is a good
   time to unify these two (now three) approaches?

src/Cockpit/panel.cxx
src/Cockpit/panel.hxx
src/Input/input.cxx
src/Main/fg_init.cxx
src/Main/main.cxx
src/Model/panelnode.cxx
src/Model/panelnode.hxx
src/Scenery/tileentry.cxx

index 6ec50fd59f57f242085fec72db8e359f731aea1d..d2332b9d8fc54e2903a605723163f5b55302fbef 100644 (file)
@@ -279,14 +279,7 @@ FGPanel::update (double dt)
         return;
     }
 
-                               // If the mouse is down, do something
-    if (_mouseDown) {
-        _mouseDelay--;
-        if (_mouseDelay < 0) {
-            _mouseInstrument->doMouseAction(_mouseButton, _mouseX, _mouseY);
-            _mouseDelay = 2;
-        }
-    }
+    updateMouseDelay();
 
                                // Now, draw the panel
     float aspect_adjust = get_aspect_adjust(_xsize_node->getIntValue(),
@@ -297,6 +290,22 @@ FGPanel::update (double dt)
         update(WIN_X, WIN_W, WIN_Y, int(WIN_H / aspect_adjust));
 }
 
+/**
+ * Handle repeatable mouse events.  Called from update() and from
+ * fgUpdate3DPanels().  This functionality needs to move into the
+ * input subsystem.  Counting a tick every two frames is clumsy...
+ */
+void FGPanel::updateMouseDelay()
+{
+    if (_mouseDown) {
+        _mouseDelay--;
+        if (_mouseDelay < 0) {
+            _mouseInstrument->doMouseAction(_mouseButton, _mouseX, _mouseY);
+            _mouseDelay = 2;
+        }
+    }
+}
+
 
 void
 FGPanel::update (GLfloat winx, GLfloat winw, GLfloat winy, GLfloat winh)
@@ -494,38 +503,21 @@ FGPanel::setYOffset (int offset)
 }
 
 /**
- * Perform a mouse action.
+ * Handle a mouse action in panel-local (not screen) coordinates.
+ * Used by the 3D panel code in Model/panelnode.cxx, in situations
+ * where the panel doesn't control its own screen location.
  */
 bool
-FGPanel::doMouseAction (int button, int updown, int x, int y)
+FGPanel::doLocalMouseAction(int button, int updown, int x, int y)
 {
-                               // FIXME: this same code appears in update()
-  int xsize = _xsize_node->getIntValue();
-  int ysize = _ysize_node->getIntValue();
-  float aspect_adjust = get_aspect_adjust(xsize, ysize);
-
-                               // Note a released button and return
-  // cerr << "Doing mouse action\n";
+  // Note a released button and return
   if (updown == 1) {
     _mouseDown = false;
     _mouseInstrument = 0;
     return false;
   }
 
-                               // Scale for the real window size.
-  if (aspect_adjust < 1.0) {
-    x = int(((float)x / xsize) * WIN_W * aspect_adjust);
-    y = int(WIN_H - ((float(y) / ysize) * WIN_H));
-  } else {
-    x = int(((float)x / xsize) * WIN_W);
-    y = int((WIN_H - ((float(y) / ysize) * WIN_H)) / aspect_adjust);
-  }
-
-                               // Adjust for offsets.
-  x -= _x_offset;
-  y -= _y_offset;
-
-                               // Search for a matching instrument.
+  // Search for a matching instrument.
   for (int i = 0; i < (int)_instruments.size(); i++) {
     FGPanelInstrument *inst = _instruments[i];
     int ix = inst->getXPos();
@@ -539,13 +531,42 @@ FGPanel::doMouseAction (int button, int updown, int x, int y)
       _mouseButton = button;
       _mouseX = x - ix;
       _mouseY = y - iy;
-                               // Always do the action once.
+      // Always do the action once.
       return _mouseInstrument->doMouseAction(_mouseButton, _mouseX, _mouseY);
     }
   }
   return false;
 }
 
+/**
+ * Perform a mouse action.
+ */
+bool
+FGPanel::doMouseAction (int button, int updown, int x, int y)
+{
+                               // FIXME: this same code appears in update()
+  int xsize = _xsize_node->getIntValue();
+  int ysize = _ysize_node->getIntValue();
+  float aspect_adjust = get_aspect_adjust(xsize, ysize);
+
+                               // Scale for the real window size.
+  if (aspect_adjust < 1.0) {
+    x = int(((float)x / xsize) * WIN_W * aspect_adjust);
+    y = int(WIN_H - ((float(y) / ysize) * WIN_H));
+  } else {
+    x = int(((float)x / xsize) * WIN_W);
+    y = int((WIN_H - ((float(y) / ysize) * WIN_H)) / aspect_adjust);
+  }
+
+                               // Adjust for offsets.
+  x -= _x_offset;
+  y -= _y_offset;
+
+  // Having fixed up the coordinates, fall through to the local
+  // coordinate handler.
+  doLocalMouseAction(button, updown, x, y);
+} 
+
 
 \f
 ////////////////////////////////////////////////////////////////////////.
index d0d1b9805d493d619533d0ca5a935396410a0474..0b41c2d259ccd1f2f03f364b20150246345255cf 100644 (file)
@@ -145,6 +145,8 @@ public:
   virtual void update (double dt);
   virtual void update (GLfloat winx, GLfloat winw, GLfloat winy, GLfloat winh);
 
+  virtual void updateMouseDelay();
+
                                // transfer pointer ownership!!!
   virtual void addInstrument (FGPanelInstrument * instrument);
 
@@ -180,6 +182,7 @@ public:
 
                                // Handle a mouse click.
   virtual bool doMouseAction (int button, int updown, int x, int y);
+  virtual bool doLocalMouseAction(int button, int updown, int x, int y);
 
 private:
   void setupVirtualCockpit();
index 818b7a35294412ee77de2bf568614aa91219b156..21df71d57ec1dcc7c7b796daf7dd49b4f8e6df1f 100644 (file)
@@ -54,6 +54,7 @@
 #include <Cockpit/panel.hxx>
 #include <Cockpit/panel_io.hxx>
 #include <GUI/gui.h>
+#include <Model/panelnode.hxx>
 
 #include <Main/globals.hxx>
 #include <Main/fg_props.hxx>
@@ -378,7 +379,9 @@ FGInput::doMouseClick (int b, int updown, int x, int y)
     if (puMouse(b, updown, x, y))
       return;
     else if ((current_panel != 0) &&
-            current_panel->doMouseAction(b, updown, x, y))
+             current_panel->doMouseAction(b, updown, x, y))
+      return;
+    else if (fgHandle3DPanelMouseEvent(b, updown, x, y))
       return;
   }
 
index 65c52b1e356f41a887ede947cb63ab025b6b578c..af0c1d25c0981d884cb848ec66467db28733b280 100644 (file)
@@ -1125,12 +1125,6 @@ bool fgInitSubsystems( void ) {
         globals->get_AI_mgr()->init();
     }
 
-    ////////////////////////////////////////////////////////////////////
-    // Initialize the built-in commands.
-    ////////////////////////////////////////////////////////////////////
-    fgInitCommands();
-
-
 #ifdef ENABLE_AUDIO_SUPPORT
     ////////////////////////////////////////////////////////////////////
     // Initialize the sound subsystem.
index 4c402c8d33526d4942273d75239b46125a371b46..1c1de3625612c13cb3fe5418967e790a397dd82b 100644 (file)
@@ -107,6 +107,7 @@ SG_USING_STD(endl);
 #include <Model/model.hxx>
 #include <Model/modelmgr.hxx>
 #include <Main/location.hxx>
+#include <Model/panelnode.hxx>
 #ifdef FG_NETWORK_OLK
 #include <NetworkOLK/network.h>
 #endif
@@ -133,6 +134,7 @@ SG_USING_STD(endl);
 #include <FDM/ADA.hxx>
 #include <Scenery/tileentry.hxx>
 
+#include "fg_commands.hxx"
 
 // #define FG_EXPERIMENTAL_LIGHTING
 #ifdef FG_EXPERIMENTAL_LIGHTING
@@ -840,6 +842,7 @@ void fgRenderFrame() {
        if ( current_panel != NULL ) {
            current_panel->update(delta_time_sec);
        }
+        fgUpdate3DPanels();
 
        // We can do translucent menus, so why not. :-)
        menus->apply();
@@ -1637,6 +1640,11 @@ int mainLoop( int argc, char **argv ) {
     globals->get_scenery()->init();
     globals->get_scenery()->bind();
 
+    ////////////////////////////////////////////////////////////////////
+    // Initialize the property-based built-in commands
+    ////////////////////////////////////////////////////////////////////
+    fgInitCommands();
+
     ////////////////////////////////////////////////////////////////////
     // Initialize the general model subsystem.
     ////////////////////////////////////////////////////////////////////
index 5b979f6aa79e27157c4372aa15ffb4a07f5e59a4..ee6c9a0c60c4a68c5f3f6f92cee02fa5c1ec75d3 100644 (file)
@@ -2,18 +2,51 @@
 #  include <config.h>
 #endif
 
+#include <vector>
+
+#include <GL/gl.h>
+#include <plib/sg.h>
+
 #include <Main/fg_props.hxx>
 #include <Cockpit/panel.hxx>
 #include <Cockpit/panel_io.hxx>
-#include <GL/gl.h>
 #include "panelnode.hxx"
 
+// Static (!) handling for all 3D panels in the program.  Very
+// clumsy.  Replace with per-aircraft handling.
+vector<FGPanelNode*> all_3d_panels;
+bool fgHandle3DPanelMouseEvent(int button, int updown, int x, int y)
+{
+    for(int i=0; i<all_3d_panels.size(); i++)
+        if(all_3d_panels[i]->doMouseAction(button, updown, x, y))
+            return true;
+    return false;
+}
+
+void fgUpdate3DPanels()
+{
+    for(int i=0; i<all_3d_panels.size(); i++)
+        all_3d_panels[i]->getPanel()->updateMouseDelay();
+}
+
 FGPanelNode::FGPanelNode(SGPropertyNode* props)
 {
     // Make an FGPanel object.  But *don't* call init() or bind() on
     // it -- those methods touch static state.
     _panel = fgReadPanel(props->getStringValue("path"));
 
+    // Never mind.  We *have* to call init to make sure the static
+    // state is initialized (it's not, if there aren't any 2D
+    // panels).  This is a memory leak and should be fixed!`
+    _panel->init();
+
+    // Initialize the matrices to the identity.  PLib prints warnings
+    // when trying to invert singular matrices (e.g. when not using a
+    // 3D panel).
+    for(int i=0; i<4; i++)
+        for(int j=0; j<4; j++)
+            _lastModelview[4*i+j] = _lastProjection[4*i+j] = i==j ? 1 : 0;
+
     // Read out the pixel-space info
     _xmax = _panel->getWidth();
     _ymax = _panel->getHeight();
@@ -34,7 +67,7 @@ FGPanelNode::FGPanelNode(SGPropertyNode* props)
     _bottomRight[1] = pt->getFloatValue("y-m");
     _bottomRight[2] = pt->getFloatValue("z-m");
 
-    // Now generate out transformation matrix.  For shorthand, use
+    // Now generate our transformation matrix.  For shorthand, use
     // "a", "b", and "c" as our corners and "m" as the matrix. The
     // vector u goes from a to b, v from a to c, and w is a
     // perpendicular cross product.
@@ -74,6 +107,9 @@ FGPanelNode::FGPanelNode(SGPropertyNode* props)
                    (cz-a[2])*(cz-a[2]));
     bsphere.setCenter(cx, cy, cz);
     bsphere.setRadius(r);
+
+    // All done.  Add us to the list
+    all_3d_panels.push_back(this);
 }
 
 FGPanelNode::~FGPanelNode()
@@ -92,13 +128,60 @@ void FGPanelNode::draw_geometry()
     glMatrixMode(GL_MODELVIEW);
     glPushMatrix();
     glMultMatrixf(_xform);
+
+    // Grab the matrix state, so that we can get back from screen
+    // coordinates to panel coordinates when the user clicks the
+    // mouse.
+    glGetFloatv(GL_MODELVIEW_MATRIX, _lastModelview);
+    glGetFloatv(GL_PROJECTION_MATRIX, _lastProjection);
+    glGetIntegerv(GL_VIEWPORT, _lastViewport);
+
     _panel->draw();
+
+
     glPopMatrix();
 }
 
+bool FGPanelNode::doMouseAction(int button, int updown, int x, int y)
+{
+    // Covert the screen coordinates to viewport coordinates in the
+    // range [0:1], then transform to OpenGL "post projection" coords
+    // in [-1:1].  Remember the difference in Y direction!
+    float vx = (x + 0.5 - _lastViewport[0]) / _lastViewport[2];
+    float vy = (y + 0.5 - _lastViewport[1]) / _lastViewport[3];
+    vx = 2*vx - 1;
+    vy = 1 - 2*vy;
+
+    // Make two vectors in post-projection coordinates at the given
+    // screen, one in the near field and one in the far field.
+    sgVec3 a, b;
+    a[0] = b[0] = vx;
+    a[1] = b[1] = vy;
+    a[2] =  0.75; // "Near" Z value
+    b[2] = -0.75; // "Far" Z value
+
+    // Run both vectors "backwards" through the OpenGL matrix
+    // transformation.  Remember to w-normalize the vectors!
+    sgMat4 m;
+    sgMultMat4(m, *(sgMat4*)_lastProjection, *(sgMat4*)_lastModelview);
+    sgInvertMat4(m);
+
+    sgFullXformPnt3(a, m);
+    sgFullXformPnt3(b, m);
+
+    // And find their intersection on the z=0 plane.  The resulting X
+    // and Y coordinates are the hit location in panel coordinates.
+    float dxdz = (b[0] - a[0]) / (b[2] - a[2]);
+    float dydz = (b[1] - a[1]) / (b[2] - a[2]);
+    int panelX = (int)(a[0] - a[2]*dxdz + 0.5);
+    int panelY = (int)(a[1] - a[2]*dydz + 0.5);
+
+    return _panel->doLocalMouseAction(button, updown, panelX, panelY);
+}
+
 void FGPanelNode::die()
 {
     SG_LOG(SG_ALL,SG_ALERT,"Unimplemented function called on FGPanelNode");
-    *(int*)0=0;
+    exit(1);
 }
 
index f3c75daa636a6f3ed3102bd7995245428a48e15d..0aee8d7fba460f647e6e91113733119c7e98777a 100644 (file)
@@ -8,6 +8,12 @@ class SGPropertyNode;
 // many methods, mostly involved with modelling and runtime
 // inspection, are unimplemented.
 
+// Static mouse handler for all FGPanelNodes.  Very clumsy; this
+// should really be done through our container (an aircraft model,
+// typically).
+bool fgHandle3DPanelMouseEvent(int button, int updown, int x, int y);
+void fgUpdate3DPanels();
+
 class FGPanelNode : public ssgLeaf 
 {
 protected:
@@ -18,7 +24,9 @@ public:
     virtual ~FGPanelNode();
 
     virtual void draw();
-    void mouseEvent(int button, int updown, int x, int y);
+    bool doMouseAction(int button, int updown, int x, int y);
+
+    FGPanel* getPanel() { return _panel; }
 
     virtual void recalcBSphere() { bsphere_is_invalid = 0; }
 
index 49029c3bbc95d3dcff421375fb586e50d648378e..80a1621cb077ef01afb7068b10e5fc0baa665211 100644 (file)
@@ -886,10 +886,16 @@ void FGTileEntry::prep_ssg_node( const Point3D& p, sgVec3 up, float vis) {
         sgVec3 lift_vec;
         sgCopyVec3( lift_vec, up );
 
+        // we fudge agl by 30 meters so that the lifting function
+        // doesn't phase in until we are > 30m agl.
         double agl;
         agl = globals->get_current_view()->getAltitudeASL_ft()
-            * SG_FEET_TO_METER - globals->get_scenery()->get_cur_elev();
-
+            * SG_FEET_TO_METER - globals->get_scenery()->get_cur_elev()
+            - 30.0;
+        if ( agl < 30.0 ) {
+            agl = 0.0;
+        }
+        
         // sgTrans just happens to be the
         // vector from scenery center to the center of this tile which
         // is what we want to calculate the distance of