1
0
Fork 0

Andy Ross:

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?
This commit is contained in:
curt 2002-10-29 19:44:03 +00:00
parent 5a439826ff
commit 72017fc671
8 changed files with 175 additions and 49 deletions

View 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)
@ -493,6 +502,42 @@ FGPanel::setYOffset (int offset)
_y_offset = offset;
}
/**
* 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::doLocalMouseAction(int button, int updown, int x, int y)
{
// Note a released button and return
if (updown == 1) {
_mouseDown = false;
_mouseInstrument = 0;
return false;
}
// Search for a matching instrument.
for (int i = 0; i < (int)_instruments.size(); i++) {
FGPanelInstrument *inst = _instruments[i];
int ix = inst->getXPos();
int iy = inst->getYPos();
int iw = inst->getWidth() / 2;
int ih = inst->getHeight() / 2;
if (x >= ix - iw && x < ix + iw && y >= iy - ih && y < iy + ih) {
_mouseDown = true;
_mouseDelay = 20;
_mouseInstrument = inst;
_mouseButton = button;
_mouseX = x - ix;
_mouseY = y - iy;
// Always do the action once.
return _mouseInstrument->doMouseAction(_mouseButton, _mouseX, _mouseY);
}
}
return false;
}
/**
* Perform a mouse action.
*/
@ -504,14 +549,6 @@ FGPanel::doMouseAction (int button, int updown, int x, int y)
int ysize = _ysize_node->getIntValue();
float aspect_adjust = get_aspect_adjust(xsize, ysize);
// Note a released button and return
// cerr << "Doing mouse action\n";
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);
@ -525,26 +562,10 @@ FGPanel::doMouseAction (int button, int updown, int x, int y)
x -= _x_offset;
y -= _y_offset;
// Search for a matching instrument.
for (int i = 0; i < (int)_instruments.size(); i++) {
FGPanelInstrument *inst = _instruments[i];
int ix = inst->getXPos();
int iy = inst->getYPos();
int iw = inst->getWidth() / 2;
int ih = inst->getHeight() / 2;
if (x >= ix - iw && x < ix + iw && y >= iy - ih && y < iy + ih) {
_mouseDown = true;
_mouseDelay = 20;
_mouseInstrument = inst;
_mouseButton = button;
_mouseX = x - ix;
_mouseY = y - iy;
// Always do the action once.
return _mouseInstrument->doMouseAction(_mouseButton, _mouseX, _mouseY);
}
}
return false;
}
// Having fixed up the coordinates, fall through to the local
// coordinate handler.
doLocalMouseAction(button, updown, x, y);
}

View 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();

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

View 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.

View 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.
////////////////////////////////////////////////////////////////////

View 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);
}

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

View 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