]> git.mxchange.org Git - flightgear.git/blob - src/GUI/gui.cxx
Added a file load / save entry box so you can specify a file name (contributed
[flightgear.git] / src / GUI / gui.cxx
1 /**************************************************************************
2  * gui.cxx
3  *
4  * Written 1998 by Durk Talsma, started Juni, 1998.  For the flight gear
5  * project.
6  *
7  * Additional mouse supported added by David Megginson, 1999.
8  *
9  * This program is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU General Public License as
11  * published by the Free Software Foundation; either version 2 of the
12  * License, or (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful, but
15  * WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  * General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22  *
23  * $Id$
24  **************************************************************************/
25
26
27 #ifdef HAVE_CONFIG_H
28 #  include <config.h>
29 #endif
30
31 #include <simgear/compiler.h>
32
33 #ifdef FG_MATH_EXCEPTION_CLASH
34 #  include <math.h>
35 #endif
36
37 #ifdef HAVE_WINDOWS_H
38 #  include <windows.h>
39 #endif
40
41 #include <GL/glut.h>
42 #include <simgear/xgl/xgl.h>
43
44 #if defined(FX) && defined(XMESA)
45 #  include <GL/xmesa.h>
46 #endif
47
48 #include STL_FSTREAM
49 #include STL_STRING
50
51 #include <stdlib.h>
52 #include <string.h>
53
54 #include <simgear/constants.h>
55 #include <simgear/debug/logstream.hxx>
56 #include <simgear/misc/fgpath.hxx>
57 #include <simgear/screen/screen-dump.hxx>
58
59 #include <Include/general.hxx>
60 #include <Aircraft/aircraft.hxx>
61 #include <Airports/simple.hxx>
62 #include <Autopilot/auto_gui.hxx>
63 #include <Autopilot/newauto.hxx>
64 #include <Cockpit/panel.hxx>
65 #include <Controls/controls.hxx>
66 #include <FDM/flight.hxx>
67 #include <Main/bfi.hxx>
68 #include <Main/fg_init.hxx>
69 #include <Main/fg_io.hxx>
70 #include <Main/globals.hxx>
71 #include <Main/save.hxx>
72 #ifdef FG_NETWORK_OLK
73 #include <NetworkOLK/network.h>
74 #endif
75
76 #if defined( WIN32 ) && !defined( __CYGWIN__ )
77 #  include <simgear/screen/win32-printer.h>
78 #  include <simgear/screen/GlBitmaps.h>
79 #endif
80
81 /*
82  * trackball.h
83  * A virtual trackball implementation
84  * Written by Gavin Bell for Silicon Graphics, November 1988.
85  */
86 /*
87  * Pass the x and y coordinates of the last and current positions of
88  * the mouse, scaled so they are from (-1.0 ... 1.0).
89  *
90  * The resulting rotation is returned as a quaternion rotation in the
91  * first paramater.
92  */
93 void
94 trackball(float q[4], float p1x, float p1y, float p2x, float p2y);
95
96 /*
97  * Given two quaternions, add them together to get a third quaternion.
98  * Adding quaternions to get a compound rotation is analagous to adding
99  * translations to get a compound translation.  When incrementally
100  * adding rotations, the first argument here should be the new
101
102   * rotation, the second and third the total rotation (which will be
103  * over-written with the resulting new total rotation).
104  */
105 void
106 add_quats(float *q1, float *q2, float *dest);
107
108 /*
109  * A useful function, builds a rotation matrix in Matrix based on
110  * given quaternion.
111  */
112 void
113 build_rotmatrix(float m[4][4], float q[4]);
114
115 /*
116  * This function computes a quaternion based on an axis (defined by
117  * the given vector) and an angle about which to rotate.  The angle is
118  * expressed in radians.  The result is put into the third argument.
119  */
120 void
121 axis_to_quat(float a[3], float phi, float q[4]);
122
123
124 #include "gui.h"
125
126 FG_USING_STD(string);
127
128 #ifndef FG_HAVE_NATIVE_SGI_COMPILERS
129 FG_USING_STD(cout);
130 #endif
131
132 #if defined(WIN32) || defined(__CYGWIN32__)
133 #define WIN32_CURSOR_TWEAKS
134 #elif (GLUT_API_VERSION >= 4 || GLUT_XLIB_IMPLEMENTATION >= 9)
135 #define X_CURSOR_TWEAKS
136 #endif
137
138 // hack, should come from an include someplace
139 extern void fgInitVisuals( void );
140 extern void fgReshape( int width, int height );
141 extern void fgRenderFrame( void );
142
143 puFont guiFnt = 0;
144 fntTexFont *guiFntHandle = 0;
145
146 static puMenuBar    *mainMenuBar = 0;
147 //static puButton     *hideMenuButton = 0;
148
149 static puDialogBox  *dialogBox = 0;
150 static puFrame      *dialogFrame = 0;
151 static puText       *dialogBoxMessage = 0;
152 static puOneShot    *dialogBoxOkButton = 0;
153
154
155 static puDialogBox  *YNdialogBox = 0;
156 static puFrame      *YNdialogFrame = 0;
157 static puText       *YNdialogBoxMessage = 0;
158 static puOneShot    *YNdialogBoxOkButton = 0;
159 static puOneShot    *YNdialogBoxNoButton = 0;
160
161 static char msg_OK[]     = "OK";
162 static char msg_NO[]     = "NO";
163 static char msg_YES[]    = "YES";
164 static char msg_CANCEL[] = "Cancel";
165 static char msg_RESET[]  = "Reset";
166
167 char *gui_msg_OK;     // "OK"
168 char *gui_msg_NO;     // "NO"
169 char *gui_msg_YES;    // "YES"
170 char *gui_msg_CANCEL; // "CANCEL"
171 char *gui_msg_RESET;  // "RESET"
172
173 static char global_dialog_string[256];
174
175 // from autopilot.cxx
176 // extern void NewAltitude( puObject *cb );
177 // extern void NewHeading( puObject *cb );
178 // extern void fgAPAdjust( puObject * );
179 // extern void NewTgtAirport( puObject *cb );
180 // bool fgAPTerrainFollowEnabled( void );
181 // bool fgAPAltitudeEnabled( void );
182 // bool fgAPHeadingEnabled( void );
183 // bool fgAPWayPointEnabled( void );
184 // bool fgAPAutoThrottleEnabled( void );
185
186 // from cockpit.cxx
187 extern void fgLatLonFormatToggle( puObject *);
188
189 /* --------------------------------------------------------------------
190 Mouse stuff
191 ---------------------------------------------------------------------*/
192
193 static int _mX = 0;
194 static int _mY = 0;
195 static int _savedX = 0;
196 static int _savedY = 0;
197 static int last_buttons = 0 ;
198 static int mouse_active = 0;
199 static int menu_on = 0;
200 static int mouse_joystick_control = 0;
201
202 //static time_t mouse_off_time;
203 //static int mouse_timed_out;
204
205 // to allow returning to previous view
206 // on second left click in MOUSE_VIEW mode
207 // This has file scope so that it can be reset
208 // if the little rodent is moved  NHV
209 static  int _mVtoggle;
210
211 // we break up the glutGetModifiers return mask
212 // once per loop and stash what we need in these
213 static int glut_active_shift;
214 static int glut_active_ctrl;
215 static int glut_active_alt;
216
217 static float lastquat[4];
218 static float curquat[4];
219 static float _quat0[4];
220 float quat_mat[4][4];
221
222 // uncomment this for view to exactly follow mouse in MOUSE_VIEW mode
223 // else smooth out the view panning to .01 radian per frame
224 // see view_offset smoothing mechanism in main.cxx
225 #define NO_SMOOTH_MOUSE_VIEW
226
227 // uncomment following to
228 #define RESET_VIEW_ON_LEAVING_MOUSE_VIEW
229
230 /* --------------------------------------------------------------------
231 Support for mouse as control yoke (david@megginson.com)
232
233 - right button toggles between pointer and yoke
234 - horizontal drag with no buttons moves ailerons
235 - vertical drag with no buttons moves elevators
236 - horizontal drag with left button moves brakes (left=on)
237 - vertical drag with left button moves throttle (up=more)
238 - horizontal drag with middle button moves rudder
239 - vertical drag with middle button moves trim
240
241 For the *_sensitivity variables, a lower number means more sensitive.
242
243 TODO: figure out how to keep pointer from leaving window in yoke mode.
244 TODO: add thresholds and null zones
245 TODO: sensitivity should be configurable at user option.
246 TODO: allow differential braking (this will be useful if FlightGear
247       ever supports tail-draggers like the DC-3)
248 ---------------------------------------------------------------------*/
249
250 typedef enum {
251     MOUSE_POINTER,
252     MOUSE_YOKE,
253     MOUSE_VIEW
254 } MouseMode;
255
256 MouseMode mouse_mode = MOUSE_POINTER;
257
258 static double aileron_sensitivity = 1.0/500.0;
259 static double elevator_sensitivity = 1.0/500.0;
260 static double brake_sensitivity = 1.0/250.0;
261 static double throttle_sensitivity = 1.0/250.0;
262 static double rudder_sensitivity = 1.0/500.0;
263 static double trim_sensitivity = 1.0/1000.0;
264
265 static inline void Quat0( void ) {
266     curquat[0] = _quat0[0];
267     curquat[1] = _quat0[1];
268     curquat[2] = _quat0[2];
269     curquat[3] = _quat0[3];
270 }
271
272 static inline int left_button( void ) {
273     return( last_buttons & (1 << GLUT_LEFT_BUTTON) );
274 }
275
276 static inline int middle_button( void ) {
277     return( last_buttons & (1 << GLUT_MIDDLE_BUTTON) );
278 }
279
280 static inline int right_button( void ) {
281     return( last_buttons & (1 << GLUT_RIGHT_BUTTON) );
282 }
283
284 static inline void TurnCursorOn( void )
285 {
286     mouse_active = ~0;
287 #if defined(WIN32_CURSOR_TWEAKS)
288     switch (mouse_mode) {
289         case MOUSE_POINTER:
290             glutSetCursor(GLUT_CURSOR_INHERIT);
291             break;
292         case MOUSE_YOKE:
293             glutSetCursor(GLUT_CURSOR_CROSSHAIR);
294             break;
295         case MOUSE_VIEW:
296             glutSetCursor(GLUT_CURSOR_LEFT_RIGHT);
297             break;
298     }
299 #endif
300 #if defined(X_CURSOR_TWEAKS)
301     glutWarpPointer( globals->get_options()->get_xsize()/2,
302                      globals->get_options()->get_ysize()/2);
303 #endif
304 }
305
306 static inline void TurnCursorOff( void )
307 {
308     mouse_active = 0;
309 #if defined(WIN32_CURSOR_TWEAKS)
310     glutSetCursor(GLUT_CURSOR_NONE);
311 #elif defined(X_CURSOR_TWEAKS)
312     glutWarpPointer( globals->get_options()->get_xsize(),
313                      globals->get_options()->get_ysize());
314 #endif
315 }
316
317 void maybeToggleMouse( void )
318 {
319 #if defined(WIN32_CURSOR_TWEAKS)
320     static int first_time = ~0;
321     static int mouse_changed = 0;
322
323     if ( first_time ) {
324         if(!mouse_active) {
325             mouse_changed = ~mouse_changed;
326             TurnCursorOn();
327         }
328     } else {
329         if( mouse_mode != MOUSE_POINTER )
330             return;
331         if( mouse_changed ) {
332             mouse_changed = ~mouse_changed;
333             if(mouse_active) {
334                 TurnCursorOff();
335             }
336         }
337     }
338     first_time = ~first_time;
339 #endif // #ifdef WIN32
340 }
341
342 // Call with FALSE to init and TRUE to restore
343 void BusyCursor( int restore )
344 {
345     static GLenum cursor = (GLenum) 0;
346     if( restore ) {
347         glutSetCursor(cursor);
348     } else {
349         cursor = (GLenum) glutGet( (GLenum) GLUT_WINDOW_CURSOR );
350 #if defined(WIN32_CURSOR_TWEAKS)
351         TurnCursorOn();
352 #endif
353         glutSetCursor( GLUT_CURSOR_WAIT );
354     }
355 }
356
357 int guiGetMouseButton(void)
358 {
359     return last_buttons;
360 }
361
362 void guiGetMouse(int *x, int *y)
363 {
364     *x = _mX;
365     *y = _mY;
366 };
367
368 void guiMotionFunc ( int x, int y )
369 {
370     int ww, wh, need_warp = 0;
371     float W, H;
372     double offset;
373
374     if (mouse_mode == MOUSE_POINTER) {
375         puMouse ( x, y ) ;
376         glutPostRedisplay () ;
377     } else {
378         if( x == _mX && y == _mY)
379             return;
380         
381         // reset left click MOUSE_VIEW toggle feature
382         _mVtoggle = 0;
383         
384         ww = globals->get_options()->get_xsize();
385         wh = globals->get_options()->get_ysize();
386         
387         switch (mouse_mode) {
388             case MOUSE_YOKE:
389                 if( !mouse_joystick_control ) {
390                     mouse_joystick_control = 1;
391                     globals->get_options()->set_control_mode( FGOptions::FG_MOUSE );
392                 } else {
393                     if ( left_button() ) {
394                         offset = (_mX - x) * brake_sensitivity;
395                         controls.move_brake(FGControls::ALL_WHEELS, offset);
396                         offset = (_mY - y) * throttle_sensitivity;
397                         controls.move_throttle(FGControls::ALL_ENGINES, offset);
398                     } else if ( right_button() ) {
399                         if( ! current_autopilot->get_HeadingEnabled() ) {
400                             offset = (x - _mX) * rudder_sensitivity;
401                             controls.move_rudder(offset);
402                         }
403                         if( ! current_autopilot->get_AltitudeEnabled() ) {
404                             offset = (_mY - y) * trim_sensitivity;
405                             controls.move_elevator_trim(offset);
406                         }
407                     } else {
408                         if( ! current_autopilot->get_HeadingEnabled() ) {
409                             offset = (x - _mX) * aileron_sensitivity;
410                             controls.move_aileron(offset);
411                         }
412                         if( ! current_autopilot->get_AltitudeEnabled() ) {
413                             offset = (_mY - y) * elevator_sensitivity;
414                             controls.move_elevator(offset);
415                         }
416                     }
417                 }
418                 // Keep the mouse in the window.
419                 if (x < 5 || x > ww-5 || y < 5 || y > wh-5) {
420                     x = ww / 2;
421                     y = wh / 2;
422                     need_warp = 1;
423                 }
424                 break;
425                 
426             case MOUSE_VIEW:
427                 if( y <= 0 ) {
428 #define CONTRAINED_MOUSE_VIEW_Y
429 #ifdef CONTRAINED_MOUSE_VIEW_Y
430                     y = 1;
431 #else
432                     y = wh-2;
433 #endif // CONTRAINED_MOUSE_VIEW_Y
434                     need_warp = 1;
435                 } else if( y >= wh-1) {
436 #ifdef CONTRAINED_MOUSE_VIEW_Y
437                     y = wh-2;
438 #else
439                     y = 1;
440 #endif // CONTRAINED_MOUSE_VIEW_Y
441                     need_warp = 1;
442                 }
443                 // wrap MOUSE_VIEW mode cursor x position
444                 if ( x <= 0 ) {
445                     need_warp = 1;
446                     x = ww-2;
447                 } else if ( x >= ww-1 ) {
448                     need_warp = 1;
449                     x = 1;
450                 }
451                 // try to get FG_PI movement in each half of screen
452                 // do spherical pan
453                 W = ww;
454                 H = wh;
455                 if( middle_button() ) {
456                     trackball(lastquat,
457                               (2.0f * _mX - W) / W,
458                               0, //(H - 2.0f * y) / H,         // 3
459                               (2.0f * x - W) / W,
460                               0 //(H - 2.0f * _mY) / H       // 1
461                              );
462                     x = _mX;
463                     y = _mY;
464                     need_warp = 1;
465                 } else {
466                     trackball(lastquat,
467                               0, //(2.0f * _mX - W) / W,  // 0
468                               (H - 2.0f * y) / H,         // 3
469                               0, //(2.0f * x - W) / W,    // 2
470                               (H - 2.0f * _mY) / H        // 1 
471                              );
472                 }
473                 add_quats(lastquat, curquat, curquat);
474                 build_rotmatrix(quat_mat, curquat);
475                 
476                 // do horizontal pan
477                 // this could be done in above quat
478                 // but requires redoing view pipeline
479                 offset = globals->get_current_view()->get_goal_view_offset();
480                 offset += ((_mX - x) * FG_2PI / W );
481                 while (offset < 0.0) {
482                     offset += FG_2PI;
483                 }
484                 while (offset > FG_2PI) {
485                     offset -= FG_2PI;
486                 }
487                 globals->get_current_view()->set_goal_view_offset(offset);
488 #ifdef NO_SMOOTH_MOUSE_VIEW
489                 globals->get_current_view()->set_view_offset(offset);
490 #endif
491                 break;
492             
493             default:
494                 break;
495         }
496     }
497     if( need_warp)
498         glutWarpPointer(x, y);
499     
500     // Record the new mouse position.
501     _mX = x;
502     _mY = y;
503 }
504
505
506 void guiMouseFunc(int button, int updown, int x, int y)
507 {
508     int glutModifiers;
509
510     // private MOUSE_VIEW state variables
511     // to allow alternate left clicks in MOUSE_VIEW mode
512     // to toggle between current offsets and straight ahead
513     // uses _mVtoggle
514     static int _mVx, _mVy, _Vx, _Vy;
515     static float _quat[4];
516     static double _view_offset;
517     
518     // general purpose variables
519     double offset;
520             
521     glutModifiers = glutGetModifiers();
522     glut_active_shift = glutModifiers & GLUT_ACTIVE_SHIFT;
523     glut_active_ctrl  = glutModifiers & GLUT_ACTIVE_CTRL; 
524     glut_active_alt   = glutModifiers & GLUT_ACTIVE_ALT;
525     
526     // Was the left button pressed?
527     if (updown == GLUT_DOWN ) {
528         if( button == GLUT_LEFT_BUTTON)
529         {
530             switch (mouse_mode) {
531                 case MOUSE_POINTER:
532                     break;
533                 case MOUSE_YOKE:
534                     break;
535                 case MOUSE_VIEW:
536                     if(_mVtoggle) {
537                         // resume previous view offsets
538                         _mX = _mVx;
539                         _mY = _mVy;
540                         x = _Vx;
541                         y = _Vy;
542                         curquat[0] = _quat[0];
543                         curquat[1] = _quat[1];
544                         curquat[2] = _quat[2];
545                         curquat[3] = _quat[3];
546                         globals->get_current_view()->set_goal_view_offset(_view_offset);
547 #ifdef NO_SMOOTH_MOUSE_VIEW
548                         globals->get_current_view()->set_view_offset(_view_offset);
549 #endif
550                     } else {
551                         // center view
552                         _mVx = _mX;
553                         _mVy = _mY;
554                         _Vx = x;
555                         _Vy = y;
556                         _quat[0] = curquat[0];
557                         _quat[1] = curquat[1];
558                         _quat[2] = curquat[2];
559                         _quat[3] = curquat[3];
560                         x = globals->get_options()->get_xsize()/2;
561                         y = globals->get_options()->get_ysize()/2;
562                         Quat0();
563                         _view_offset =
564                             globals->get_current_view()->get_goal_view_offset();
565                         globals->get_current_view()->set_goal_view_offset(0.0);
566 #ifdef NO_SMOOTH_MOUSE_VIEW
567                         globals->get_current_view()->set_view_offset(0.0);
568 #endif
569                     }
570                     glutWarpPointer( x , y);
571                     build_rotmatrix(quat_mat, curquat);
572                     _mVtoggle = ~_mVtoggle;
573                     break;
574             }
575         }else if ( button == GLUT_RIGHT_BUTTON) {
576             switch (mouse_mode) {
577                 case MOUSE_POINTER:
578                     mouse_mode = MOUSE_YOKE;
579                     mouse_joystick_control = 0;
580                     _savedX = x;
581                     _savedY = y;
582                     // start with zero point in center of screen
583                     _mX = globals->get_options()->get_xsize()/2;
584                     _mY = globals->get_options()->get_ysize()/2;
585                     
586                     // try to have the MOUSE_YOKE position
587                     // reflect the current stick position
588                     offset = controls.get_aileron();
589                     x = _mX - (int)(offset * aileron_sensitivity);
590                     offset = controls.get_elevator();
591                     y = _mY - (int)(offset * elevator_sensitivity);
592                     
593                     glutSetCursor(GLUT_CURSOR_CROSSHAIR);
594                     FG_LOG( FG_INPUT, FG_INFO, "Mouse in yoke mode" );
595                     break;
596                     
597                 case MOUSE_YOKE:
598                     mouse_mode = MOUSE_VIEW;
599                     globals->get_options()->set_control_mode( FGOptions::FG_JOYSTICK );
600                     x = globals->get_options()->get_xsize()/2;
601                     y = globals->get_options()->get_ysize()/2;
602                     _mVtoggle = 0;
603                     Quat0();
604                     build_rotmatrix(quat_mat, curquat);
605                     glutSetCursor(GLUT_CURSOR_LEFT_RIGHT);
606                     FG_LOG( FG_INPUT, FG_INFO, "Mouse in view mode" );
607                     break;
608                     
609                 case MOUSE_VIEW:
610                     mouse_mode = MOUSE_POINTER;
611                     x = _savedX;
612                     y = _savedY;
613 #ifdef RESET_VIEW_ON_LEAVING_MOUSE_VIEW
614                     Quat0();
615                     build_rotmatrix(quat_mat, curquat);
616                     globals->get_current_view()->set_goal_view_offset(0.0);
617 #ifdef NO_SMOOTH_MOUSE_VIEW
618                     globals->get_current_view()->set_view_offset(0.0);
619 #endif
620 #endif      // RESET_VIEW_ON_LEAVING_MOUSE_VIEW
621                     glutSetCursor(GLUT_CURSOR_INHERIT);
622                     
623                     if(!menu_on)
624                         TurnCursorOff();
625                     
626                     FG_LOG( FG_INPUT, FG_INFO, "Mouse in pointer mode" );
627                     break;
628             }     
629             glutWarpPointer( x, y );
630         } // END RIGHT BUTTON
631     } // END UPDOWN == GLUT_DOWN
632     
633     // Note which button is pressed.
634     if ( updown == GLUT_DOWN ) {
635         last_buttons |=  ( 1 << button ) ;
636     } else {
637         last_buttons &= ~( 1 << button ) ;
638     }
639     
640     // If we're in pointer mode, let PUI
641     // know what's going on.
642     if (mouse_mode == MOUSE_POINTER) {
643       if (!puMouse (button, updown, x,y)) {
644         current_panel->doMouseAction(button, updown, x, y);
645       }
646     }
647     
648     // Register the new position (if it
649     // hasn't been registered already).
650     _mX = x;
651     _mY = y;
652     
653     glutPostRedisplay ();
654 }
655
656 /* ================ General Purpose Functions ================ */
657
658 // Intercept the Escape Key
659 void ConfirmExitDialog(void)
660 {
661     FG_PUSH_PUI_DIALOG( YNdialogBox );
662 }
663
664 // General Purpose Message Box
665 void mkDialog (const char *txt)
666 {
667     strncpy(global_dialog_string, txt, 256);
668     dialogBoxMessage->setLabel(global_dialog_string);
669     FG_PUSH_PUI_DIALOG( dialogBox );
670 }
671
672 // Toggle the Menu and Mouse display state
673 void guiToggleMenu(void)
674 {
675     if( menu_on ) {
676         // printf("Hiding Menu\n");
677         mainMenuBar->hide  ();
678 #if defined(WIN32_CURSOR_TWEAKS)
679         if( mouse_mode == MOUSE_POINTER )
680             TurnCursorOff();
681 #endif // #ifdef WIN32_CURSOR_TWEAKS
682     } else {
683         // printf("Showing Menu\n");
684         mainMenuBar->reveal();
685 #ifdef WIN32
686         TurnCursorOn();
687 #endif // #ifdef WIN32
688     }
689     menu_on = ~menu_on;
690 }
691     
692 /* -----------------------------------------------------------------------
693 the Gui callback functions 
694 ____________________________________________________________________*/
695
696
697 // Hier Neu :-) This is my newly added code
698 // Added by David Findlay <nedz@bigpond.com>
699 // on Sunday 3rd of December
700
701 // Start new Save Dialog Box
702 static puDialogBox     *SaveDialog = 0;
703 static puFrame         *SaveDialogFrame = 0;
704 static puText          *SaveDialogMessage = 0;
705 static puInput         *SaveDialogInput = 0;
706
707 static puOneShot       *SaveDialogOkButton = 0;
708 static puOneShot       *SaveDialogCancelButton = 0;
709 static puOneShot       *SaveDialogResetButton = 0;
710
711 // Default save filename
712 static char saveFile[256] = "fgfs.sav";
713
714 // Cancel Button
715 void SaveDialogCancel(puObject *) {
716     FG_POP_PUI_DIALOG( SaveDialog );
717 }
718
719 // If press OK do this
720 void SaveDialogOk(puObject*) {
721
722     FG_POP_PUI_DIALOG( SaveDialog );
723
724     char *s;
725     SaveDialogInput->getValue(&s);
726
727     ofstream output(s);
728     cout << saveFile << endl;
729     if (output.good() && fgSaveFlight(output)) {
730         output.close();
731         mkDialog("Saved flight");
732         FG_LOG(FG_INPUT, FG_INFO, "Saved flight");
733     } else {
734         mkDialog("Cannot save flight");
735         FG_LOG(FG_INPUT, FG_ALERT, "Cannot save flight");
736     }
737 }
738
739 // Create Dialog
740 static void saveFlight(puObject *cv) {
741     SaveDialog = new puDialogBox (150, 50);
742     {
743         SaveDialogFrame   = new puFrame           (0,0,350, 150);
744         SaveDialogMessage = new puText            ((150 - puGetStringWidth( puGetDefaultLabelFont(), "File Name:" ) / 2), 110);
745         SaveDialogMessage ->    setLabel          ("File Name:");
746
747         SaveDialogInput   = new puInput           (50, 70, 300, 100);
748         SaveDialogInput   ->    setValue          (saveFile);
749         SaveDialogInput   ->    acceptInput();
750
751         SaveDialogOkButton     =  new puOneShot   (50, 10, 110, 50);
752         SaveDialogOkButton     ->     setLegend   (gui_msg_OK);
753         SaveDialogOkButton     ->     setCallback ( SaveDialogOk );
754         SaveDialogOkButton     ->     makeReturnDefault(TRUE);
755
756         SaveDialogCancelButton =  new puOneShot   (140, 10, 210, 50);
757         SaveDialogCancelButton ->     setLegend   (gui_msg_CANCEL);
758         SaveDialogCancelButton ->     setCallback ( SaveDialogCancel );
759     }
760     FG_FINALIZE_PUI_DIALOG( SaveDialog );
761    
762     SaveDialog -> reveal();
763 }
764
765 // Load Dialog Start
766 static puDialogBox     *LoadDialog = 0;
767 static puFrame         *LoadDialogFrame = 0;
768 static puText          *LoadDialogMessage = 0;
769 static puInput         *LoadDialogInput = 0;
770
771 static puOneShot       *LoadDialogOkButton = 0;
772 static puOneShot       *LoadDialogCancelButton = 0;
773 static puOneShot       *LoadDialogResetButton = 0;
774
775 // Default load filename
776 static char loadFile[256] = "fgfs.sav";
777
778 // Do this if the person click okay
779 void LoadDialogOk(puObject *) {
780
781     FG_POP_PUI_DIALOG( LoadDialog );
782
783     char *l;
784     LoadDialogInput->getValue(&l);
785
786     ifstream input(l);
787     if (input.good() && fgLoadFlight(input)) {
788         input.close();
789         mkDialog("Loaded flight");
790         FG_LOG(FG_INPUT, FG_INFO, "Restored flight");
791     } else {
792         mkDialog("Failed to load flight");
793         FG_LOG(FG_INPUT, FG_ALERT, "Cannot load flight");
794     }
795 }
796
797 // Do this is the person presses cancel
798 void LoadDialogCancel(puObject *) {
799     FG_POP_PUI_DIALOG( LoadDialog );
800 }
801
802 // Create Load Dialog
803 static void loadFlight(puObject *cb)
804 {
805     LoadDialog = new puDialogBox (150, 50);
806     {
807         LoadDialogFrame   = new puFrame           (0,0,350, 150);
808         LoadDialogMessage = new puText            ((150 - puGetStringWidth( puGetDefaultLabelFont(), "File Name:" ) / 2), 110);
809         LoadDialogMessage ->    setLabel          ("File Name:");
810
811         LoadDialogInput   = new puInput           (50, 70, 300, 100);
812         LoadDialogInput   ->    setValue          (loadFile);
813         LoadDialogInput   ->    acceptInput();
814
815         LoadDialogOkButton     =  new puOneShot   (50, 10, 110, 50);
816         LoadDialogOkButton     ->     setLegend   (gui_msg_OK);
817         LoadDialogOkButton     ->     setCallback ( LoadDialogOk );
818         LoadDialogOkButton     ->     makeReturnDefault(TRUE);
819
820         LoadDialogCancelButton =  new puOneShot   (140, 10, 210, 50);
821         LoadDialogCancelButton ->     setLegend   (gui_msg_CANCEL);
822         LoadDialogCancelButton ->     setCallback ( LoadDialogCancel );
823     }
824     FG_FINALIZE_PUI_DIALOG( LoadDialog );
825    
826     LoadDialog -> reveal();
827 }
828
829 void reInit(puObject *cb)
830 {
831     BusyCursor(0);
832     Quat0();
833     build_rotmatrix(quat_mat, curquat);
834     fgReInitSubsystems();
835     BusyCursor(1);
836 }
837
838 // This is the accessor function
839 void guiTogglePanel(puObject *cb)
840 {
841     globals->get_options()->toggle_panel();
842 }
843     
844 //void MenuHideMenuCb(puObject *cb)
845 void hideMenuCb (puObject *cb)
846 {
847     guiToggleMenu();
848 }
849
850 void goodBye(puObject *)
851 {
852     // FG_LOG( FG_INPUT, FG_ALERT,
853     //      "Program exiting normally at user request." );
854     cout << "Program exiting normally at user request." << endl;
855
856 #ifdef FG_NETWORK_OLK    
857     if ( globals->get_options()->get_network_olk() ) {
858         if ( net_is_registered == 0 ) fgd_send_com( "8", FGFS_host);
859     }
860 #endif
861
862     // close all external I/O connections
863     fgIOShutdownAll();
864
865     exit(0);
866 }
867
868
869 void goAwayCb (puObject *me)
870 {
871     FG_POP_PUI_DIALOG( dialogBox );
872 }
873
874 void mkDialogInit (void)
875 {
876     //  printf("mkDialogInit\n");
877     int x = (globals->get_options()->get_xsize()/2 - 400/2);
878     int y = (globals->get_options()->get_ysize()/2 - 100/2);
879     dialogBox = new puDialogBox (x, y); // 150, 50
880     {
881         dialogFrame = new puFrame (0,0,400,100);
882         dialogBoxMessage  =  new puText         (10, 70);
883         dialogBoxMessage  -> setLabel           ("");
884         dialogBoxOkButton =  new puOneShot      (180, 10, 240, 50);
885         dialogBoxOkButton -> setLegend          (gui_msg_OK);
886         dialogBoxOkButton -> makeReturnDefault  (TRUE );
887         dialogBoxOkButton -> setCallback        (goAwayCb);
888     }
889     FG_FINALIZE_PUI_DIALOG( dialogBox );
890 }
891
892 void MayBeGoodBye(puObject *)
893 {
894     ConfirmExitDialog(); 
895 }
896
897 void goAwayYesNoCb(puObject *me)
898 {
899     FG_POP_PUI_DIALOG( YNdialogBox);
900 }
901
902 void ConfirmExitDialogInit(void)
903 {
904     char msg[] = "Really Quit";
905     char *s;
906
907     //  printf("ConfirmExitDialogInit\n");
908     int len = 200 - puGetStringWidth( puGetDefaultLabelFont(), msg )/2;
909
910     int x = (globals->get_options()->get_xsize()/2 - 400/2);
911     int y = (globals->get_options()->get_ysize()/2 - 100/2);
912         
913     YNdialogBox = new puDialogBox (x, y); // 150, 50
914     //  YNdialogBox = new puDialogBox (150, 50);
915     {
916         YNdialogFrame = new puFrame (0,0,400, 100);
917         
918         YNdialogBoxMessage  =  new puText         (len, 70);
919         YNdialogBoxMessage  -> setDefaultValue    (msg);
920         YNdialogBoxMessage  -> getDefaultValue    (&s);
921         YNdialogBoxMessage  -> setLabel           (s);
922         
923         YNdialogBoxOkButton =  new puOneShot      (100, 10, 160, 50);
924         YNdialogBoxOkButton -> setLegend          (gui_msg_OK);
925         YNdialogBoxOkButton -> makeReturnDefault  (TRUE );
926         YNdialogBoxOkButton -> setCallback        (goodBye);
927         
928         YNdialogBoxNoButton =  new puOneShot      (240, 10, 300, 50);
929         YNdialogBoxNoButton -> setLegend          (gui_msg_NO);
930         YNdialogBoxNoButton -> setCallback        (goAwayYesNoCb);
931     }
932     FG_FINALIZE_PUI_DIALOG( YNdialogBox );
933 }
934
935 void notCb (puObject *)
936 {
937     mkDialog ("This function isn't implemented yet");
938 }
939
940 void helpCb (puObject *)
941 {
942     string command;
943         
944 #if defined(FX) && !defined(WIN32)
945 #  if defined(XMESA_FX_FULLSCREEN) && defined(XMESA_FX_WINDOW)
946     if ( global_fullscreen ) {
947         global_fullscreen = false;
948         XMesaSetFXmode( XMESA_FX_WINDOW );
949     }
950 #  endif
951 #endif
952         
953 #if !defined(WIN32)
954     string url = "http://www.flightgear.org/Docs/InstallGuide/getstart.html";
955         
956     if ( system("xwininfo -name Netscape > /dev/null 2>&1") == 0 ) {
957         command = "netscape -remote \"openURL(" + url + ")\" &";
958     } else {
959         command = "netscape " + url + " &";
960     }
961 #else
962     command = "webrun.bat";
963 #endif
964         
965     system( command.c_str() );
966     //string text = "Help started in netscape window.";
967
968     //mkDialog (text.c_str());
969     mkDialog ("Help started in netscape window.");
970 }
971
972 #if defined( WIN32 ) && !defined( __CYGWIN__)
973
974 static void rotateView( double roll, double pitch, double yaw )
975 {
976         // rotate view
977 }
978
979 static GlBitmap *b1 = NULL;
980 extern FGInterface cur_view_fdm;
981 GLubyte *hiResScreenCapture( int multiplier )
982 {
983     float oldfov = globals->get_options()->get_fov();
984     float fov = oldfov / multiplier;
985     FGViewer *v = globals->get_current_view();
986     globals->get_options()->set_fov(fov);
987     fgInitVisuals();
988     int cur_width = globals->get_options()->get_xsize( );
989     int cur_height = globals->get_options()->get_ysize( );
990     if (b1) delete( b1 );
991     // New empty (mostly) bitmap
992     b1 = new GlBitmap( GL_RGB, 1, 1, (unsigned char *)"123" );
993     int x,y;
994     for ( y = 0; y < multiplier; y++ ) {
995         for ( x = 0; x < multiplier; x++ ) {
996             fgReshape( cur_width, cur_height );
997             // pan to tile
998             rotateView( 0, (y*fov)-((multiplier-1)*fov/2), (x*fov)-((multiplier-1)*fov/2) );
999             fgRenderFrame();
1000             // restore view
1001             GlBitmap b2;
1002             b1->copyBitmap( &b2, cur_width*x, cur_height*y );
1003         }
1004     }
1005     globals->get_options()->set_fov(oldfov);
1006     return b1->getBitmap();
1007 }
1008 #endif
1009
1010
1011 #if defined( WIN32 ) && !defined( __CYGWIN__)
1012 // win32 print screen function
1013 void printScreen ( puObject *obj ) {
1014     bool show_pu_cursor = false;
1015     TurnCursorOff();
1016     if ( !puCursorIsHidden() ) {
1017         show_pu_cursor = true;
1018         puHideCursor();
1019     }
1020     BusyCursor( 0 );
1021     mainMenuBar->hide();
1022
1023     CGlPrinter p( CGlPrinter::PRINT_BITMAP );
1024     int cur_width = globals->get_options()->get_xsize( );
1025     int cur_height = globals->get_options()->get_ysize( );
1026     p.Begin( "FlightGear", cur_width*3, cur_height*3 );
1027         p.End( hiResScreenCapture(3) );
1028
1029     if( menu_on ) {
1030         mainMenuBar->reveal();
1031     }
1032     BusyCursor(1);
1033     if ( show_pu_cursor ) {
1034         puShowCursor();
1035     }
1036     TurnCursorOn();
1037 }
1038 #endif // #ifdef WIN32
1039
1040
1041 void dumpSnapShot ( puObject *obj ) {
1042     fgDumpSnapShot();
1043 }
1044
1045
1046 // do a screen snap shot
1047 void fgDumpSnapShot () {
1048     bool show_pu_cursor = false;
1049
1050     int freeze = globals->get_freeze();
1051     if(!freeze)
1052         globals->set_freeze( true );
1053
1054     mainMenuBar->hide();
1055     TurnCursorOff();
1056     if ( !puCursorIsHidden() ) {
1057         show_pu_cursor = true;
1058         puHideCursor();
1059     }
1060
1061     fgInitVisuals();
1062     fgReshape( globals->get_options()->get_xsize(),
1063                globals->get_options()->get_ysize() );
1064
1065     // we need two render frames here to clear the menu and cursor
1066     // ... not sure why but doing an extra fgFenderFrame() shoulnd't
1067     // hurt anything
1068     fgRenderFrame();
1069     fgRenderFrame();
1070
1071     my_glDumpWindow( "fgfs-screen.ppm", 
1072                      globals->get_options()->get_xsize(), 
1073                      globals->get_options()->get_ysize() );
1074     
1075     mkDialog ("Snap shot saved to fgfs-screen.ppm");
1076
1077     if ( show_pu_cursor ) {
1078         puShowCursor();
1079     }
1080
1081     TurnCursorOn();
1082     if( menu_on ) {
1083         mainMenuBar->reveal();
1084     }
1085
1086     if(!freeze)
1087         globals->set_freeze( false );
1088 }
1089
1090
1091 /// The beginnings of teleportation :-)
1092 //  Needs cleaning up but works
1093 //  These statics should disapear when this is a class
1094 static puDialogBox     *AptDialog = 0;
1095 static puFrame         *AptDialogFrame = 0;
1096 static puText          *AptDialogMessage = 0;
1097 static puInput         *AptDialogInput = 0;
1098
1099 static char NewAirportId[16];
1100 static char NewAirportLabel[] = "Enter New Airport ID"; 
1101
1102 static puOneShot       *AptDialogOkButton = 0;
1103 static puOneShot       *AptDialogCancelButton = 0;
1104 static puOneShot       *AptDialogResetButton = 0;
1105
1106 void AptDialog_Cancel(puObject *)
1107 {
1108     FG_POP_PUI_DIALOG( AptDialog );
1109 }
1110
1111 void AptDialog_OK (puObject *)
1112 {
1113     FGPath path( globals->get_options()->get_fg_root() );
1114     path.append( "Airports" );
1115     path.append( "simple.mk4" );
1116     FGAirports airports( path.c_str() );
1117
1118     FGAirport a;
1119     
1120     int freeze = globals->get_freeze();
1121     if(!freeze)
1122         globals->set_freeze( true );
1123
1124     char *s;
1125     AptDialogInput->getValue(&s);
1126     string AptId(s);
1127
1128         cout << "AptDialog_OK " << AptId << " " << AptId.length() << endl;
1129     
1130     AptDialog_Cancel( NULL );
1131     
1132     if ( AptId.length() ) {
1133         // set initial position from airport id
1134         FG_LOG( FG_GENERAL, FG_INFO,
1135                 "Attempting to set starting position from airport code "
1136                 << AptId );
1137
1138         if ( airports.search( AptId, &a ) )
1139         {
1140             globals->get_options()->set_airport_id( AptId.c_str() );
1141             globals->get_options()->set_altitude( -9999.0 );
1142             // fgSetPosFromAirportID( AptId );
1143             fgSetPosFromAirportIDandHdg( AptId, 
1144                                          cur_fdm_state->get_Psi() * RAD_TO_DEG);
1145             BusyCursor(0);
1146             fgReInitSubsystems();
1147             BusyCursor(1);
1148         } else {
1149             AptId  += " not in database.";
1150             mkDialog(AptId.c_str());
1151         }
1152     }
1153     if(!freeze)
1154         globals->set_freeze( false );
1155 }
1156
1157 void AptDialog_Reset(puObject *)
1158 {
1159     //  strncpy( NewAirportId, globals->get_options()->get_airport_id().c_str(), 16 );
1160     sprintf( NewAirportId, "%s", globals->get_options()->get_airport_id().c_str() );
1161     AptDialogInput->setValue ( NewAirportId );
1162     AptDialogInput->setCursor( 0 ) ;
1163 }
1164
1165 void NewAirport(puObject *cb)
1166 {
1167     //  strncpy( NewAirportId, globals->get_options()->get_airport_id().c_str(), 16 );
1168     sprintf( NewAirportId, "%s", globals->get_options()->get_airport_id().c_str() );
1169 //      cout << "NewAirport " << NewAirportId << endl;
1170     AptDialogInput->setValue( NewAirportId );
1171
1172     FG_PUSH_PUI_DIALOG( AptDialog );
1173 }
1174
1175 static void NewAirportInit(void)
1176 {
1177     sprintf( NewAirportId, "%s", globals->get_options()->get_airport_id().c_str() );
1178     int len = 150 - puGetStringWidth( puGetDefaultLabelFont(),
1179                                       NewAirportLabel ) / 2;
1180
1181     AptDialog = new puDialogBox (150, 50);
1182     {
1183         AptDialogFrame   = new puFrame           (0,0,350, 150);
1184         AptDialogMessage = new puText            (len, 110);
1185         AptDialogMessage ->    setLabel          (NewAirportLabel);
1186
1187         AptDialogInput   = new puInput           (50, 70, 300, 100);
1188         AptDialogInput   ->    setValue          (NewAirportId);
1189         AptDialogInput   ->    acceptInput();
1190
1191         AptDialogOkButton     =  new puOneShot   (50, 10, 110, 50);
1192         AptDialogOkButton     ->     setLegend   (gui_msg_OK);
1193         AptDialogOkButton     ->     setCallback (AptDialog_OK);
1194         AptDialogOkButton     ->     makeReturnDefault(TRUE);
1195
1196         AptDialogCancelButton =  new puOneShot   (140, 10, 210, 50);
1197         AptDialogCancelButton ->     setLegend   (gui_msg_CANCEL);
1198         AptDialogCancelButton ->     setCallback (AptDialog_Cancel);
1199
1200         AptDialogResetButton  =  new puOneShot   (240, 10, 300, 50);
1201         AptDialogResetButton  ->     setLegend   (gui_msg_RESET);
1202         AptDialogResetButton  ->     setCallback (AptDialog_Reset);
1203     }
1204         cout << "NewAirportInit " << NewAirportId << endl;
1205     FG_FINALIZE_PUI_DIALOG( AptDialog );
1206 }
1207
1208 #ifdef FG_NETWORK_OLK
1209
1210 /// The beginnings of networking :-)
1211 //  Needs cleaning up but works
1212 //  These statics should disapear when this is a class
1213 static puDialogBox     *NetIdDialog = 0;
1214 static puFrame         *NetIdDialogFrame = 0;
1215 static puText          *NetIdDialogMessage = 0;
1216 static puInput         *NetIdDialogInput = 0;
1217
1218 static char NewNetId[16];
1219 static char NewNetIdLabel[] = "Enter New Callsign"; 
1220 extern char *fgd_callsign;
1221
1222 static puOneShot       *NetIdDialogOkButton = 0;
1223 static puOneShot       *NetIdDialogCancelButton = 0;
1224
1225 void NetIdDialog_Cancel(puObject *)
1226 {
1227     FG_POP_PUI_DIALOG( NetIdDialog );
1228 }
1229
1230 void NetIdDialog_OK (puObject *)
1231 {
1232     string NetId;
1233     
1234     bool freeze = globals->get_freeze();
1235     if(!freeze)
1236         globals->set_freeze( true );
1237 /*  
1238    The following needs some cleanup because 
1239    "string options.NetId" and "char *net_callsign" 
1240 */
1241     NetIdDialogInput->getValue(&net_callsign);
1242     NetId = net_callsign;
1243     
1244     NetIdDialog_Cancel( NULL );
1245     globals->get_options()->set_net_id( NetId.c_str() );
1246     strcpy( fgd_callsign, net_callsign);
1247 //    strcpy( fgd_callsign, globals->get_options()->get_net_id().c_str());
1248 /* Entering a callsign indicates : user wants Net HUD Info */
1249     net_hud_display = 1;
1250
1251     if(!freeze)
1252         globals->set_freeze( false );
1253 }
1254
1255 void NewCallSign(puObject *cb)
1256 {
1257     sprintf( NewNetId, "%s", globals->get_options()->get_net_id().c_str() );
1258 //    sprintf( NewNetId, "%s", fgd_callsign );
1259     NetIdDialogInput->setValue( NewNetId );
1260
1261     FG_PUSH_PUI_DIALOG( NetIdDialog );
1262 }
1263
1264 static void NewNetIdInit(void)
1265 {
1266     sprintf( NewNetId, "%s", globals->get_options()->get_net_id().c_str() );
1267 //    sprintf( NewNetId, "%s", fgd_callsign );
1268     int len = 150 - puGetStringWidth( puGetDefaultLabelFont(),
1269                                       NewNetIdLabel ) / 2;
1270
1271     NetIdDialog = new puDialogBox (150, 50);
1272     {
1273         NetIdDialogFrame   = new puFrame           (0,0,350, 150);
1274         NetIdDialogMessage = new puText            (len, 110);
1275         NetIdDialogMessage ->    setLabel          (NewNetIdLabel);
1276
1277         NetIdDialogInput   = new puInput           (50, 70, 300, 100);
1278         NetIdDialogInput   ->    setValue          (NewNetId);
1279         NetIdDialogInput   ->    acceptInput();
1280
1281         NetIdDialogOkButton     =  new puOneShot   (50, 10, 110, 50);
1282         NetIdDialogOkButton     ->     setLegend   (gui_msg_OK);
1283         NetIdDialogOkButton     ->     setCallback (NetIdDialog_OK);
1284         NetIdDialogOkButton     ->     makeReturnDefault(TRUE);
1285
1286         NetIdDialogCancelButton =  new puOneShot   (240, 10, 300, 50);
1287         NetIdDialogCancelButton ->     setLegend   (gui_msg_CANCEL);
1288         NetIdDialogCancelButton ->     setCallback (NetIdDialog_Cancel);
1289
1290     }
1291     FG_FINALIZE_PUI_DIALOG( NetIdDialog );
1292 }
1293
1294 static void net_display_toggle( puObject *cb)
1295 {
1296         net_hud_display = (net_hud_display) ? 0 : 1;
1297         printf("Toggle net_hud_display : %d\n", net_hud_display);
1298 }
1299
1300 static void net_register( puObject *cb)
1301 {
1302         fgd_send_com( "1", FGFS_host );
1303         net_is_registered = 0;
1304         printf("Registering to deamon\n");
1305 }
1306
1307 static void net_unregister( puObject *cb)
1308 {
1309         fgd_send_com( "8", FGFS_host );
1310         net_is_registered = -1;
1311         printf("Unregistering from deamon\n");
1312 }
1313
1314
1315 /*************** Deamon communication **********/
1316
1317 //  These statics should disapear when this is a class
1318 static puDialogBox     *NetFGDDialog = 0;
1319 static puFrame         *NetFGDDialogFrame = 0;
1320 static puText          *NetFGDDialogMessage = 0;
1321 //static puInput         *NetFGDDialogInput = 0;
1322
1323 //static char NewNetId[16];
1324 static char NewNetFGDLabel[] = "Scan for deamon                        "; 
1325 static char NewFGDHost[64] = "olk.mcp.de"; 
1326 static int  NewFGDPortLo = 10000;
1327 static int  NewFGDPortHi = 10001;
1328  
1329 //extern char *fgd_callsign;
1330 extern u_short base_port, end_port;
1331 extern int fgd_ip, verbose, current_port;
1332 extern char *fgd_host;
1333
1334
1335 static puOneShot       *NetFGDDialogOkButton = 0;
1336 static puOneShot       *NetFGDDialogCancelButton = 0;
1337 static puOneShot       *NetFGDDialogScanButton = 0;
1338
1339 static puInput         *NetFGDHostDialogInput = 0;
1340 static puInput         *NetFGDPortLoDialogInput = 0;
1341 static puInput         *NetFGDPortHiDialogInput = 0;
1342
1343 void NetFGDDialog_Cancel(puObject *)
1344 {
1345     FG_POP_PUI_DIALOG( NetFGDDialog );
1346 }
1347
1348 void NetFGDDialog_OK (puObject *)
1349 {
1350     char *NetFGD;    
1351
1352     bool freeze = globals->get_freeze();
1353     if(!freeze)
1354         globals->set_freeze( true );
1355     NetFGDHostDialogInput->getValue( &NetFGD );
1356     strcpy( fgd_host, NetFGD);
1357     NetFGDPortLoDialogInput->getValue( (int *) &base_port );
1358     NetFGDPortHiDialogInput->getValue( (int *) &end_port );
1359     NetFGDDialog_Cancel( NULL );
1360     if(!freeze)
1361         globals->set_freeze( false );
1362 }
1363
1364 void NetFGDDialog_SCAN (puObject *)
1365 {
1366     char *NetFGD;
1367     int fgd_port;
1368     
1369     bool freeze = globals->get_freeze();
1370     if(!freeze)
1371         globals->set_freeze( true );
1372 //    printf("Vor getvalue %s\n");
1373     NetFGDHostDialogInput->getValue( &NetFGD );
1374 //    printf("Vor strcpy %s\n", (char *) NetFGD);
1375     strcpy( fgd_host, NetFGD);
1376     NetFGDPortLoDialogInput->getValue( (int *) &base_port );
1377     NetFGDPortHiDialogInput->getValue( (int *) &end_port );
1378     printf("FGD: %s  Port-Start: %d Port-End: %d\n", fgd_host, 
1379                  base_port, end_port);
1380     net_resolv_fgd(fgd_host);
1381     printf("Resolve : %d\n", net_r);
1382     if(!freeze)
1383         globals->set_freeze( false );
1384     if ( net_r == 0 ) {
1385       fgd_port = 10000;
1386       strcpy( fgd_name, "");
1387       for( current_port = base_port; ( current_port <= end_port); current_port++) {
1388           fgd_send_com("0" , FGFS_host);
1389           sprintf( NewNetFGDLabel , "Scanning for deamon Port: %d", current_port); 
1390           printf("FGD: searching %s\n", fgd_name);
1391           if ( strcmp( fgd_name, "") != 0 ) {
1392              sprintf( NewNetFGDLabel , "Found %s at Port: %d", 
1393                                               fgd_name, current_port);
1394              fgd_port = current_port;
1395              current_port = end_port+1;
1396           }
1397       }
1398       current_port = end_port = base_port = fgd_port;
1399     }
1400     NetFGDDialog_Cancel( NULL );
1401 }
1402
1403
1404 void net_fgd_scan(puObject *cb)
1405 {
1406     NewFGDPortLo = base_port;
1407     NewFGDPortHi = end_port;
1408     strcpy( NewFGDHost, fgd_host);
1409     NetFGDPortLoDialogInput->setValue( NewFGDPortLo );
1410     NetFGDPortHiDialogInput->setValue( NewFGDPortHi );
1411     NetFGDHostDialogInput->setValue( NewFGDHost );
1412
1413     FG_PUSH_PUI_DIALOG( NetFGDDialog );
1414 }
1415
1416
1417 static void NewNetFGDInit(void)
1418 {
1419 //    sprintf( NewNetId, "%s", globals->get_options()->get_net_id().c_str() );
1420 //    sprintf( NewNetId, "%s", fgd_callsign );
1421     int len = 170 - puGetStringWidth( puGetDefaultLabelFont(),
1422                                       NewNetFGDLabel ) / 2;
1423
1424     NetFGDDialog = new puDialogBox (310, 30);
1425     {
1426         NetFGDDialogFrame   = new puFrame           (0,0,320, 170);
1427         NetFGDDialogMessage = new puText            (len, 140);
1428         NetFGDDialogMessage ->    setLabel          (NewNetFGDLabel);
1429
1430         NetFGDPortLoDialogInput   = new puInput           (50, 70, 127, 100);
1431         NetFGDPortLoDialogInput   ->    setValue          (NewFGDPortLo);
1432         NetFGDPortLoDialogInput   ->    acceptInput();
1433
1434         NetFGDPortHiDialogInput   = new puInput           (199, 70, 275, 100);
1435         NetFGDPortHiDialogInput   ->    setValue          (NewFGDPortHi);
1436         NetFGDPortHiDialogInput   ->    acceptInput();
1437
1438         NetFGDHostDialogInput   = new puInput           (50, 100, 275, 130);
1439         NetFGDHostDialogInput   ->    setValue          (NewFGDHost);
1440         NetFGDHostDialogInput   ->    acceptInput();
1441
1442         NetFGDDialogScanButton     =  new puOneShot   (130, 10, 200, 50);
1443         NetFGDDialogScanButton     ->     setLegend   ("Scan");
1444         NetFGDDialogScanButton     ->     setCallback (NetFGDDialog_SCAN);
1445         NetFGDDialogScanButton     ->     makeReturnDefault(FALSE);
1446
1447         NetFGDDialogOkButton     =  new puOneShot   (50, 10, 120, 50);
1448         NetFGDDialogOkButton     ->     setLegend   (gui_msg_OK);
1449         NetFGDDialogOkButton     ->     setCallback (NetFGDDialog_OK);
1450         NetFGDDialogOkButton     ->     makeReturnDefault(TRUE);
1451
1452         NetFGDDialogCancelButton =  new puOneShot   (210, 10, 280, 50);
1453         NetFGDDialogCancelButton ->     setLegend   (gui_msg_CANCEL);
1454         NetFGDDialogCancelButton ->     setCallback (NetFGDDialog_Cancel);
1455
1456     }
1457     FG_FINALIZE_PUI_DIALOG( NetFGDDialog );
1458 }
1459
1460 /*
1461 static void net_display_toggle( puObject *cb)
1462 {
1463         net_hud_display = (net_hud_display) ? 0 : 1;
1464         printf("Toggle net_hud_display : %d\n", net_hud_display);
1465 }
1466
1467 */
1468
1469 #endif
1470
1471 /***************  End Networking  **************/
1472
1473
1474
1475 /* -----------------------------------------------------------------------
1476 The menu stuff 
1477 ---------------------------------------------------------------------*/
1478 char *fileSubmenu               [] = {
1479     "Exit", /* "Close", "---------", */
1480 #if defined( WIN32 ) && !defined( __CYGWIN__)
1481     "Print",
1482 #endif
1483     "Snap Shot",
1484     "---------", 
1485     "Reset", 
1486     "Load flight",
1487     "Save flight",
1488     NULL
1489 };
1490 puCallback fileSubmenuCb        [] = {
1491     MayBeGoodBye, /* hideMenuCb, NULL, */
1492 #if defined( WIN32 ) && !defined( __CYGWIN__)
1493     printScreen, 
1494 #endif
1495     /* NULL, notCb, */
1496     dumpSnapShot,
1497     NULL,
1498     reInit, 
1499     loadFlight,
1500     saveFlight,
1501     NULL
1502 };
1503
1504 /*
1505 char *editSubmenu               [] = {
1506     "Edit text", NULL
1507 };
1508 puCallback editSubmenuCb        [] = {
1509     notCb, NULL
1510 };
1511 */
1512
1513 extern void fgHUDalphaAdjust( puObject * );
1514 char *viewSubmenu               [] = {
1515     "HUD Alpha",
1516     /* "Cockpit View > ", "View >","------------", */
1517     "Toggle Panel...", NULL
1518 };
1519 puCallback viewSubmenuCb        [] = {
1520     fgHUDalphaAdjust,
1521     /* notCb, notCb, NULL, */
1522     guiTogglePanel, NULL
1523 };
1524
1525 //  "---------", 
1526
1527 char *autopilotSubmenu           [] = {
1528     "Toggle HUD Format", "Adjust AP Settings",
1529     "---------", 
1530     "Clear Route", "Skip Current Waypoint", "Add Waypoint",
1531     "---------", 
1532     "Set Altitude", "Set Heading",
1533     NULL
1534 };
1535
1536 puCallback autopilotSubmenuCb    [] = {
1537     fgLatLonFormatToggle, fgAPAdjust,
1538     NULL,
1539     ClearRoute, PopWayPoint, AddWayPoint,
1540     NULL,
1541     NewAltitude, NewHeading,
1542     /* notCb, */ NULL
1543 };
1544
1545 char *environmentSubmenu        [] = {
1546     "Goto Airport", /* "Terrain", "Weather", */ NULL
1547 };
1548 puCallback environmentSubmenuCb [] = {
1549     NewAirport, /* notCb, notCb, */ NULL
1550 };
1551
1552 /*
1553 char *optionsSubmenu            [] = {
1554     "Preferences", "Realism & Reliablity...", NULL
1555 };
1556 puCallback optionsSubmenuCb     [] = {
1557     notCb, notCb, NULL
1558 };
1559 */
1560
1561 #ifdef FG_NETWORK_OLK
1562 char *networkSubmenu            [] = {
1563     "Unregister from FGD ", /* "Send MSG to All", "Send MSG", "Show Pilots", */
1564     "Register to FGD",
1565     "Scan for Deamons", "Enter Callsign", /* "Display Netinfos", */
1566     "Toggle Display", NULL
1567 };
1568 puCallback networkSubmenuCb     [] = {
1569     /* notCb, notCb, notCb, notCb, */ 
1570     net_unregister, 
1571     net_register, 
1572     net_fgd_scan, NewCallSign, 
1573     net_display_toggle, NULL
1574 };
1575 #endif
1576
1577 char *helpSubmenu               [] = {
1578     /* "About...", */ "Help", NULL
1579 };
1580 puCallback helpSubmenuCb        [] = {
1581     /* notCb, */ helpCb, NULL
1582 };
1583
1584
1585 /* -------------------------------------------------------------------------
1586 init the gui
1587 _____________________________________________________________________*/
1588
1589
1590 void guiInit()
1591 {
1592     char *mesa_win_state;
1593
1594     // Initialize PUI
1595     puInit();
1596     puSetDefaultStyle         ( PUSTYLE_SMALL_BEVELLED ); //PUSTYLE_DEFAULT
1597     puSetDefaultColourScheme  (0.8, 0.8, 0.8, 0.4);
1598
1599     // Initialize our GLOBAL GUI STRINGS
1600     gui_msg_OK     = msg_OK;     // "OK"
1601     gui_msg_NO     = msg_NO;     // "NO"
1602     gui_msg_YES    = msg_YES;    // "YES"
1603     gui_msg_CANCEL = msg_CANCEL; // "CANCEL"
1604     gui_msg_RESET  = msg_RESET;  // "RESET"
1605
1606     // Next check home directory
1607     FGPath fntpath;
1608     char* envp = ::getenv( "FG_FONTS" );
1609     if ( envp != NULL ) {
1610         fntpath.set( envp );
1611     } else {
1612         fntpath.set( globals->get_options()->get_fg_root() );
1613         fntpath.append( "Fonts" );
1614     }
1615
1616     // Install our fast fonts
1617     fntpath.append( "typewriter.txf" );
1618     guiFntHandle = new fntTexFont ;
1619     guiFntHandle -> load ( (char *)fntpath.c_str() ) ;
1620     puFont GuiFont ( guiFntHandle, 15 ) ;
1621     puSetDefaultFonts( GuiFont, GuiFont ) ;
1622     guiFnt = puGetDefaultLabelFont();
1623   
1624     if ( globals->get_options()->get_mouse_pointer() == 0 ) {
1625         // no preference specified for mouse pointer, attempt to autodetect...
1626         // Determine if we need to render the cursor, or if the windowing
1627         // system will do it.  First test if we are rendering with glide.
1628         if ( strstr ( general.get_glRenderer(), "Glide" ) ) {
1629             // Test for the MESA_GLX_FX env variable
1630             if ( (mesa_win_state = getenv( "MESA_GLX_FX" )) != NULL) {
1631                 // test if we are fullscreen mesa/glide
1632                 if ( (mesa_win_state[0] == 'f') ||
1633                      (mesa_win_state[0] == 'F') ) {
1634                     puShowCursor ();
1635                 }
1636             }
1637         }
1638         mouse_active = ~mouse_active;
1639     } else if ( globals->get_options()->get_mouse_pointer() == 1 ) {
1640         // don't show pointer
1641     } else if ( globals->get_options()->get_mouse_pointer() == 2 ) {
1642         // force showing pointer
1643         puShowCursor();
1644         mouse_active = ~mouse_active;
1645     }
1646         
1647     // MOUSE_VIEW mode stuff
1648     trackball(_quat0, 0.0, 0.0, 0.0, 0.0);  
1649     Quat0();
1650     build_rotmatrix(quat_mat, curquat);
1651
1652     // Set up our Dialog Boxes
1653     ConfirmExitDialogInit();
1654     NewAirportInit();
1655 #ifdef FG_NETWORK_OLK
1656     NewNetIdInit();
1657     NewNetFGDInit();
1658 #endif
1659     mkDialogInit();
1660     
1661     // Make the menu bar
1662     mainMenuBar = new puMenuBar ();
1663     mainMenuBar -> add_submenu ("File", fileSubmenu, fileSubmenuCb);
1664     // mainMenuBar -> add_submenu ("Edit", editSubmenu, editSubmenuCb);
1665     mainMenuBar -> add_submenu ("View", viewSubmenu, viewSubmenuCb);
1666     mainMenuBar -> add_submenu ("Environment", environmentSubmenu, environmentSubmenuCb);
1667     mainMenuBar -> add_submenu ("Autopilot", autopilotSubmenu, autopilotSubmenuCb);
1668     // mainMenuBar -> add_submenu ("Options", optionsSubmenu, optionsSubmenuCb);
1669 #ifdef FG_NETWORK_OLK
1670     if ( globals->get_options()->get_network_olk() ) {
1671         mainMenuBar -> add_submenu ("Network", networkSubmenu, networkSubmenuCb);
1672     }
1673 #endif
1674     mainMenuBar -> add_submenu ("Help", helpSubmenu, helpSubmenuCb);
1675     mainMenuBar-> close ();
1676     // Set up menu bar toggle
1677     menu_on = ~0;
1678 }
1679
1680
1681
1682 /*
1683  * Trackball code:
1684  *
1685  * Implementation of a virtual trackball.
1686  * Implemented by Gavin Bell, lots of ideas from Thant Tessman and
1687  *   the August '88 issue of Siggraph's "Computer Graphics," pp. 121-129.
1688  *
1689  * Vector manip code:
1690  *
1691  * Original code from:
1692  * David M. Ciemiewicz, Mark Grossman, Henry Moreton, and Paul Haeberli
1693  *
1694  * Much mucking with by:
1695  * Gavin Bell
1696  */
1697 #if defined(_WIN32) && !defined( __CYGWIN32__ )
1698 #pragma warning (disable:4244)          /* disable bogus conversion warnings */
1699 #endif
1700 #include <math.h>
1701 #include <stdio.h>
1702 //#include "trackball.h"
1703
1704 /*
1705  * This size should really be based on the distance from the center of
1706  * rotation to the point on the object underneath the mouse.  That
1707  * point would then track the mouse as closely as possible.  This is a
1708  * simple example, though, so that is left as an Exercise for the
1709  * Programmer.
1710  */
1711 #define TRACKBALLSIZE  (0.8f)
1712 #define SQRT(x) sqrt(x)
1713
1714 /*
1715  * Local function prototypes (not defined in trackball.h)
1716  */
1717 static float tb_project_to_sphere(float, float, float);
1718 static void normalize_quat(float [4]);
1719
1720 static void
1721 vzero(float *v)
1722 {
1723     v[0] = 0.0;
1724     v[1] = 0.0;
1725     v[2] = 0.0;
1726 }
1727
1728 static void
1729 vset(float *v, float x, float y, float z)
1730 {
1731     v[0] = x;
1732     v[1] = y;
1733     v[2] = z;
1734 }
1735
1736 static void
1737 vsub(const float *src1, const float *src2, float *dst)
1738 {
1739     dst[0] = src1[0] - src2[0];
1740     dst[1] = src1[1] - src2[1];
1741     dst[2] = src1[2] - src2[2];
1742 }
1743
1744 static void
1745 vcopy(const float *v1, float *v2)
1746 {
1747     register int i;
1748     for (i = 0 ; i < 3 ; i++)
1749         v2[i] = v1[i];
1750 }
1751
1752 static void
1753 vcross(const float *v1, const float *v2, float *cross)
1754 {
1755     float temp[3];
1756
1757     temp[0] = (v1[1] * v2[2]) - (v1[2] * v2[1]);
1758     temp[1] = (v1[2] * v2[0]) - (v1[0] * v2[2]);
1759     temp[2] = (v1[0] * v2[1]) - (v1[1] * v2[0]);
1760     vcopy(temp, cross);
1761 }
1762
1763 static float
1764 vlength(const float *v)
1765 {
1766     float tmp = v[0] * v[0] + v[1] * v[1] + v[2] * v[2];
1767     return SQRT(tmp);
1768 }
1769
1770 static void
1771 vscale(float *v, float div)
1772 {
1773     v[0] *= div;
1774     v[1] *= div;
1775     v[2] *= div;
1776 }
1777
1778 static void
1779 vnormal(float *v)
1780 {
1781     vscale(v,1.0/vlength(v));
1782 }
1783
1784 static float
1785 vdot(const float *v1, const float *v2)
1786 {
1787     return v1[0]*v2[0] + v1[1]*v2[1] + v1[2]*v2[2];
1788 }
1789
1790 static void
1791 vadd(const float *src1, const float *src2, float *dst)
1792 {
1793     dst[0] = src1[0] + src2[0];
1794     dst[1] = src1[1] + src2[1];
1795     dst[2] = src1[2] + src2[2];
1796 }
1797
1798 /*
1799  *  Given an axis and angle, compute quaternion.
1800  */
1801 void
1802 axis_to_quat(float a[3], float phi, float q[4])
1803 {
1804     double sinphi2, cosphi2;
1805     double phi2 = phi/2.0;
1806     sinphi2 = sin(phi2);
1807     cosphi2 = cos(phi2);
1808     vnormal(a);
1809     vcopy(a,q);
1810     vscale(q,sinphi2);
1811     q[3] = cosphi2;
1812 }
1813
1814 /*
1815  * Project an x,y pair onto a sphere of radius r OR a hyperbolic sheet
1816  * if we are away from the center of the sphere.
1817  */
1818 static float
1819 tb_project_to_sphere(float r, float x, float y)
1820 {
1821     float d, t, z, tmp;
1822
1823     tmp = x*x + y*y;
1824     d = SQRT(tmp);
1825     if (d < r * 0.70710678118654752440) {    /* Inside sphere */
1826         tmp = r*r - d*d;
1827         z = SQRT(tmp);
1828     } else {           /* On hyperbola */
1829         t = r / 1.41421356237309504880;
1830         z = t*t / d;
1831     }
1832     return z;
1833 }
1834
1835 /*
1836  * Quaternions always obey:  a^2 + b^2 + c^2 + d^2 = 1.0
1837  * If they don't add up to 1.0, dividing by their magnitued will
1838  * renormalize them.
1839  *
1840  * Note: See the following for more information on quaternions:
1841  *
1842  * - Shoemake, K., Animating rotation with quaternion curves, Computer
1843  *   Graphics 19, No 3 (Proc. SIGGRAPH'85), 245-254, 1985.
1844  * - Pletinckx, D., Quaternion calculus as a basic tool in computer
1845  *   graphics, The Visual Computer 5, 2-13, 1989.
1846  */
1847 static void
1848 normalize_quat(float q[4])
1849 {
1850     int i;
1851     float mag, tmp;
1852
1853     tmp = q[0]*q[0] + q[1]*q[1] + q[2]*q[2] + q[3]*q[3];
1854     mag = 1.0 / SQRT(tmp);
1855     for (i = 0; i < 4; i++)
1856         q[i] *= mag;
1857 }
1858
1859 /*
1860  * Ok, simulate a track-ball.  Project the points onto the virtual
1861  * trackball, then figure out the axis of rotation, which is the cross
1862  * product of P1 P2 and O P1 (O is the center of the ball, 0,0,0)
1863  * Note:  This is a deformed trackball-- is a trackball in the center,
1864  * but is deformed into a hyperbolic sheet of rotation away from the
1865  * center.  This particular function was chosen after trying out
1866  * several variations.
1867  *
1868  * It is assumed that the arguments to this routine are in the range
1869  * (-1.0 ... 1.0)
1870  */
1871 void
1872 trackball(float q[4], float p1x, float p1y, float p2x, float p2y)
1873 {
1874     float a[3]; /* Axis of rotation */
1875     float phi;  /* how much to rotate about axis */
1876     float p1[3], p2[3], d[3];
1877     float t;
1878
1879     if (p1x == p2x && p1y == p2y) {
1880         /* Zero rotation */
1881         vzero(q);
1882         q[3] = 1.0;
1883         return;
1884     }
1885
1886     /*
1887      * First, figure out z-coordinates for projection of P1 and P2 to
1888      * deformed sphere
1889      */
1890     vset(p1,p1x,p1y,tb_project_to_sphere(TRACKBALLSIZE,p1x,p1y));
1891     vset(p2,p2x,p2y,tb_project_to_sphere(TRACKBALLSIZE,p2x,p2y));
1892
1893     /*
1894      *  Now, we want the cross product of P1 and P2
1895      */
1896     vcross(p2,p1,a);
1897
1898     /*
1899      *  Figure out how much to rotate around that axis.
1900      */
1901     vsub(p1,p2,d);
1902     t = vlength(d) / (2.0*TRACKBALLSIZE);
1903
1904     /*
1905      * Avoid problems with out-of-control values...
1906      */
1907     if (t > 1.0) t = 1.0;
1908     if (t < -1.0) t = -1.0;
1909     phi = 2.0 * asin(t);
1910
1911     axis_to_quat(a,phi,q);
1912 }
1913
1914 /*
1915  * Given two rotations, e1 and e2, expressed as quaternion rotations,
1916  * figure out the equivalent single rotation and stuff it into dest.
1917  *
1918  * This routine also normalizes the result every RENORMCOUNT times it is
1919  * called, to keep error from creeping in.
1920  *
1921  * NOTE: This routine is written so that q1 or q2 may be the same
1922  * as dest (or each other).
1923  */
1924
1925 #define RENORMCOUNT 97
1926
1927 void
1928 add_quats(float q1[4], float q2[4], float dest[4])
1929 {
1930     static int count=0;
1931     float t1[4], t2[4], t3[4];
1932     float tf[4];
1933
1934 #if 0
1935 printf("q1 = %f %f %f %f\n", q1[0], q1[1], q1[2], q1[3]);
1936 printf("q2 = %f %f %f %f\n", q2[0], q2[1], q2[2], q2[3]);
1937 #endif
1938
1939     vcopy(q1,t1);
1940     vscale(t1,q2[3]);
1941
1942     vcopy(q2,t2);
1943     vscale(t2,q1[3]);
1944
1945     vcross(q2,q1,t3);
1946     vadd(t1,t2,tf);
1947     vadd(t3,tf,tf);
1948     tf[3] = q1[3] * q2[3] - vdot(q1,q2);
1949
1950 #if 0
1951 printf("tf = %f %f %f %f\n", tf[0], tf[1], tf[2], tf[3]);
1952 #endif
1953
1954     dest[0] = tf[0];
1955     dest[1] = tf[1];
1956     dest[2] = tf[2];
1957     dest[3] = tf[3];
1958
1959     if (++count > RENORMCOUNT) {
1960         count = 0;
1961         normalize_quat(dest);
1962     }
1963 }
1964
1965 /*
1966  * Build a rotation matrix, given a quaternion rotation.
1967  *
1968  */
1969 void
1970 build_rotmatrix(float m[4][4], float q[4])
1971 {
1972 //#define TRANSPOSED_QUAT
1973 #ifndef TRANSPOSED_QUAT
1974     m[0][0] = 1.0 - 2.0 * (q[1] * q[1] + q[2] * q[2]);
1975     m[0][1] = 2.0 * (q[0] * q[1] - q[2] * q[3]);
1976     m[0][2] = 2.0 * (q[2] * q[0] + q[1] * q[3]);
1977     m[0][3] = 0.0;
1978
1979     m[1][0] = 2.0 * (q[0] * q[1] + q[2] * q[3]);
1980     m[1][1]= 1.0 - 2.0 * (q[2] * q[2] + q[0] * q[0]);
1981     m[1][2] = 2.0 * (q[1] * q[2] - q[0] * q[3]);
1982     m[1][3] = 0.0;
1983
1984     m[2][0] = 2.0 * (q[2] * q[0] - q[1] * q[3]);
1985     m[2][1] = 2.0 * (q[1] * q[2] + q[0] * q[3]);
1986     m[2][2] = 1.0 - 2.0 * (q[1] * q[1] + q[0] * q[0]);
1987     
1988     m[2][3] = 0.0;
1989     m[3][0] = 0.0;
1990     m[3][1] = 0.0;
1991     m[3][2] = 0.0;
1992     m[3][3] = 1.0;
1993 #else //  TRANSPOSED_QUAT
1994     m[0][0] = 1.0 - 2.0 * (q[1] * q[1] + q[2] * q[2]);
1995     m[0][1] = 2.0 * (q[0] * q[1] + q[2] * q[3]);
1996     m[0][2] = 2.0 * (q[2] * q[0] - q[1] * q[3]);
1997     m[0][3] = 0.0;
1998
1999     m[1][0] = 2.0 * (q[0] * q[1] - q[2] * q[3]);
2000     m[1][1] = 1.0 - 2.0 * (q[2] * q[2] + q[0] * q[0]);
2001     m[1][2] = 2.0 * (q[1] * q[2] + q[0] * q[3]);
2002     m[1][3] = 0.0;
2003
2004     m[2][0] = 2.0 * (q[2] * q[0] + q[1] * q[3]);
2005     m[2][1] = 2.0 * (q[1] * q[2] - q[0] * q[3]);
2006     m[2][2] = 1.0 - 2.0 * (q[1] * q[1] + q[0] * q[0]);
2007     m[2][3] = 0.0;
2008     
2009     m[3][0] = 0.0;
2010     m[3][1] = 0.0;
2011     m[3][2] = 0.0;
2012     m[3][3] = 1.0;
2013 #endif // 0
2014 }
2015