+void
+FGPanel::setupVirtualCockpit()
+{
+ int i;
+ FGViewer* view = globals->get_current_view();
+
+ // Generate corners for the panel quad. Put the top edge of the
+ // panel 1m in and 6 degrees down from the forward direction, and
+ // make the whole thing 60 degrees wide. In principle, these
+ // should be settable per-panel, so that you can have lots of
+ // panel objects plastered about the cockpit in realistic
+ // positions and orientations.
+ float a[3], b[3], c[3];
+ float pw = tan(30*SGD_DEGREES_TO_RADIANS);
+ float ph = 2 * pw * (float)_height/(float)_width;
+ float ptop = -tan(6*SGD_DEGREES_TO_RADIANS);
+ a[0] = -pw; a[1] = ptop-ph; a[2] = -1; // bottom left
+ b[0] = pw; b[1] = ptop-ph; b[2] = -1; // bottom right
+ c[0] = -pw; c[1] = ptop; c[2] = -1; // top left
+
+ // A standard projection, in meters, with especially close clip
+ // planes.
+ glMatrixMode(GL_PROJECTION);
+ glPushMatrix();
+ glLoadIdentity();
+ gluPerspective(view->get_v_fov(), 1/view->get_aspect_ratio(),
+ 0.01, 100);
+
+ glMatrixMode(GL_MODELVIEW);
+ glPushMatrix();
+ glLoadIdentity();
+
+ // Generate a "look at" matrix using OpenGL (!) coordinate
+ // conventions.
+ float lookat[3];
+ float pitch = view->getPitchOffset_deg() * SGD_DEGREES_TO_RADIANS;
+ float rot = view->getHeadingOffset_deg() * SGD_DEGREES_TO_RADIANS;
+ lookat[0] = -sin(rot);
+ lookat[1] = sin(pitch) / cos(pitch);
+ lookat[2] = -cos(rot);
+ if(fabs(lookat[1]) > 9999) lookat[1] = 9999; // FPU sanity
+ gluLookAt(0, 0, 0, lookat[0], lookat[1], lookat[2], 0, 1, 0);
+
+ // Translate the origin to the location of the panel quad
+ glTranslatef(a[0], a[1], a[2]);
+
+ // Generate a matrix to translate unit square coordinates from the
+ // panel to real world coordinates. Use a transposed basis for
+ // the panel quad. Note: this matrix is relatively expensive to
+ // compute, and is invariant. Consider precomputing and storing
+ // it. Also, consider using the plib vector math routines, so the
+ // reuse junkies don't yell at me. (Fine, I hard-coded a cross
+ // product. Just shoot me and be done with it.)
+ float u[3], v[3], w[3], m[16];
+ for(i=0; i<3; i++) u[i] = b[i] - a[i]; // U = B - A
+ for(i=0; i<3; i++) v[i] = c[i] - a[i]; // V = C - A
+ w[0] = u[1]*v[2] - v[1]*u[2]; // W = U x V
+ w[1] = u[2]*v[0] - v[2]*u[0];
+ w[2] = u[0]*v[1] - v[0]*u[1];
+
+ m[0] = u[0]; m[4] = v[0]; m[8] = w[0]; m[12] = 0; // |Ux Vx Wx|
+ m[1] = u[1]; m[5] = v[1]; m[9] = w[1]; m[13] = 0; // m = |Uy Vy Wy|
+ m[2] = u[2]; m[6] = v[2]; m[10] = w[2]; m[14] = 0; // |Uz Vz Wz|
+ m[3] = 0; m[7] = 0; m[11] = 0; m[15] = 1;
+ glMultMatrixf(m);
+
+ // Finally, a scaling factor to map the panel's width and height
+ // to the unit square.
+ glScalef(1./_width, 1./_height, 1);
+
+ // Now, turn off the Z buffer. The panel code doesn't need
+ // it, and we're using different clip planes anyway (meaning we
+ // can't share it without glDepthRange() hackery or much
+ // framebuffer bandwidth wasteage)
+ glDisable(GL_DEPTH_TEST);
+}
+
+void
+FGPanel::cleanupVirtualCockpit()
+{
+ glMatrixMode(GL_PROJECTION);
+ glPopMatrix();
+ glMatrixMode(GL_MODELVIEW);
+ glPopMatrix();
+ glEnable(GL_DEPTH_TEST);
+}
+
+
+/**
+ * Set the panel's visibility.
+ */