]> git.mxchange.org Git - flightgear.git/blob - src/GUI/gui.cxx
059b813b2f4999cfd42ec64d966cd178f789b161
[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 SG_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 <GL/gl.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/sg_path.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/fg_init.hxx>
68 #include <Main/fg_io.hxx>
69 #include <Main/globals.hxx>
70 #include <Main/fg_props.hxx>
71 #include <Main/options.hxx>
72 #include <Main/viewmgr.hxx>
73
74 #ifdef FG_NETWORK_OLK
75 #include <NetworkOLK/network.h>
76 #endif
77    
78 #if defined( WIN32 ) && !defined( __CYGWIN__ )
79 #  include <simgear/screen/win32-printer.h>
80 #  include <simgear/screen/GlBitmaps.h>
81 #endif
82
83 #include "gui.h"
84 #include "gui_local.hxx"
85 #include "apt_dlg.hxx"
86 #include "net_dlg.hxx"
87 #include "sgVec3Slider.hxx"
88
89 SG_USING_STD(string);
90
91 #ifndef SG_HAVE_NATIVE_SGI_COMPILERS
92 SG_USING_STD(cout);
93 #endif
94
95 #ifdef  _MSC_VER
96 #define  snprintf    _snprintf
97 #endif   /* _MSC_VER */
98
99 // main.cxx hack, should come from an include someplace
100 extern void fgInitVisuals( void );
101 extern void fgReshape( int width, int height );
102 extern void fgRenderFrame( void );
103
104 puFont guiFnt = 0;
105 fntTexFont *guiFntHandle = 0;
106 int gui_menu_on = 0;
107 static puMenuBar    *mainMenuBar = 0;
108 //static puButton     *hideMenuButton = 0;
109
110 static puDialogBox  *dialogBox = 0;
111 static puFrame      *dialogFrame = 0;
112 static puText       *dialogBoxMessage = 0;
113 static puOneShot    *dialogBoxOkButton = 0;
114
115
116 static puDialogBox  *YNdialogBox = 0;
117 static puFrame      *YNdialogFrame = 0;
118 static puText       *YNdialogBoxMessage = 0;
119 static puOneShot    *YNdialogBoxOkButton = 0;
120 static puOneShot    *YNdialogBoxNoButton = 0;
121
122 static char msg_OK[]     = "OK";
123 static char msg_NO[]     = "NO";
124 static char msg_YES[]    = "YES";
125 static char msg_CANCEL[] = "Cancel";
126 static char msg_RESET[]  = "Reset";
127
128 char *gui_msg_OK;     // "OK"
129 char *gui_msg_NO;     // "NO"
130 char *gui_msg_YES;    // "YES"
131 char *gui_msg_CANCEL; // "CANCEL"
132 char *gui_msg_RESET;  // "RESET"
133
134 static char global_dialog_string[256];
135
136 // from cockpit.cxx
137 extern void fgLatLonFormatToggle( puObject *);
138
139
140 /* ================ General Purpose Functions ================ */
141
142 // Intercept the Escape Key
143 void ConfirmExitDialog(void)
144 {
145     FG_PUSH_PUI_DIALOG( YNdialogBox );
146 }
147
148 // General Purpose Message Box
149 void mkDialog (const char *txt)
150 {
151     strncpy(global_dialog_string, txt, 256);
152     dialogBoxMessage->setLabel(global_dialog_string);
153     FG_PUSH_PUI_DIALOG( dialogBox );
154 }
155
156 // Toggle the Menu and Mouse display state
157 void guiToggleMenu(void)
158 {
159     if( gui_menu_on ) {
160         // printf("Hiding Menu\n");
161         mainMenuBar->hide  ();
162 #if defined(WIN32_CURSOR_TWEAKS)
163         if( mouse_mode == MOUSE_POINTER )
164             TurnCursorOff();
165 #endif // #ifdef WIN32_CURSOR_TWEAKS
166     } else {
167         // printf("Showing Menu\n");
168         mainMenuBar->reveal();
169 #ifdef WIN32
170         TurnCursorOn();
171 #endif // #ifdef WIN32
172     }
173     gui_menu_on = ~gui_menu_on;
174 }
175     
176 /* -----------------------------------------------------------------------
177 the Gui callback functions 
178 ____________________________________________________________________*/
179
180
181 // Hier Neu :-) This is my newly added code
182 // Added by David Findlay <nedz@bigpond.com>
183 // on Sunday 3rd of December
184
185 // Start new Save Dialog Box
186 static puDialogBox     *SaveDialog = 0;
187 static puFrame         *SaveDialogFrame = 0;
188 static puText          *SaveDialogMessage = 0;
189 static puInput         *SaveDialogInput = 0;
190
191 static puOneShot       *SaveDialogOkButton = 0;
192 static puOneShot       *SaveDialogCancelButton = 0;
193 // static puOneShot       *SaveDialogResetButton = 0;
194
195 // Default save filename
196 static char saveFile[256] = "fgfs.sav";
197
198 // Cancel Button
199 void SaveDialogCancel(puObject *) {
200     FG_POP_PUI_DIALOG( SaveDialog );
201 }
202
203 // If press OK do this
204 void SaveDialogOk(puObject*) {
205
206     FG_POP_PUI_DIALOG( SaveDialog );
207
208     char *s;
209     SaveDialogInput->getValue(&s);
210
211     ofstream output(s);
212     cout << saveFile << endl;
213     if (output.good() && fgSaveFlight(output)) {
214         output.close();
215         mkDialog("Saved flight");
216         SG_LOG(SG_INPUT, SG_INFO, "Saved flight");
217     } else {
218         mkDialog("Cannot save flight");
219         SG_LOG(SG_INPUT, SG_ALERT, "Cannot save flight");
220     }
221 }
222
223 // Create Dialog
224 static void saveFlight(puObject *cv) {
225     SaveDialog = new puDialogBox (150, 50);
226     {
227         SaveDialogFrame   = new puFrame           (0,0,350, 150);
228         SaveDialogMessage = new puText            (
229                         (150 - puGetStringWidth( puGetDefaultLabelFont(), "File Name:" ) / 2), 110);
230         SaveDialogMessage ->    setLabel          ("File Name:");
231
232         SaveDialogInput   = new puInput           (50, 70, 300, 100);
233         SaveDialogInput   ->    setValue          (saveFile);
234         SaveDialogInput   ->    acceptInput();
235
236         SaveDialogOkButton     =  new puOneShot   (50, 10, 110, 50);
237         SaveDialogOkButton     ->     setLegend   (gui_msg_OK);
238         SaveDialogOkButton     ->     setCallback ( SaveDialogOk );
239         SaveDialogOkButton     ->     makeReturnDefault(TRUE);
240
241         SaveDialogCancelButton =  new puOneShot   (140, 10, 210, 50);
242         SaveDialogCancelButton ->     setLegend   (gui_msg_CANCEL);
243         SaveDialogCancelButton ->     setCallback ( SaveDialogCancel );
244     }
245     FG_FINALIZE_PUI_DIALOG( SaveDialog );
246    
247     SaveDialog -> reveal();
248 }
249
250 // Load Dialog Start
251 static puDialogBox     *LoadDialog = 0;
252 static puFrame         *LoadDialogFrame = 0;
253 static puText          *LoadDialogMessage = 0;
254 static puInput         *LoadDialogInput = 0;
255
256 static puOneShot       *LoadDialogOkButton = 0;
257 static puOneShot       *LoadDialogCancelButton = 0;
258 // static puOneShot       *LoadDialogResetButton = 0;
259
260 // Default load filename
261 static char loadFile[256] = "fgfs.sav";
262
263 // Do this if the person click okay
264 void LoadDialogOk(puObject *) {
265
266     FG_POP_PUI_DIALOG( LoadDialog );
267
268     char *l;
269     LoadDialogInput->getValue(&l);
270
271     ifstream input(l);
272     if (input.good() && fgLoadFlight(input)) {
273         input.close();
274         mkDialog("Loaded flight");
275         SG_LOG(SG_INPUT, SG_INFO, "Restored flight");
276     } else {
277         mkDialog("Failed to load flight");
278         SG_LOG(SG_INPUT, SG_ALERT, "Cannot load flight");
279     }
280 }
281
282 // Do this is the person presses cancel
283 void LoadDialogCancel(puObject *) {
284     FG_POP_PUI_DIALOG( LoadDialog );
285 }
286
287 // Create Load Dialog
288 static void loadFlight(puObject *cb)
289 {
290     LoadDialog = new puDialogBox (150, 50);
291     {
292         LoadDialogFrame   = new puFrame           (0,0,350, 150);
293         LoadDialogMessage = new puText            (
294                         (150 - puGetStringWidth( puGetDefaultLabelFont(), "File Name:" ) / 2), 110);
295         LoadDialogMessage ->    setLabel          ("File Name:");
296
297         LoadDialogInput   = new puInput           (50, 70, 300, 100);
298         LoadDialogInput   ->    setValue          (loadFile);
299         LoadDialogInput   ->    acceptInput();
300
301         LoadDialogOkButton     =  new puOneShot   (50, 10, 110, 50);
302         LoadDialogOkButton     ->     setLegend   (gui_msg_OK);
303         LoadDialogOkButton     ->     setCallback ( LoadDialogOk );
304         LoadDialogOkButton     ->     makeReturnDefault(TRUE);
305
306         LoadDialogCancelButton =  new puOneShot   (140, 10, 210, 50);
307         LoadDialogCancelButton ->     setLegend   (gui_msg_CANCEL);
308         LoadDialogCancelButton ->     setCallback ( LoadDialogCancel );
309     }
310     FG_FINALIZE_PUI_DIALOG( LoadDialog );
311    
312     LoadDialog -> reveal();
313 }
314
315 // This is the accessor function
316 void guiTogglePanel(puObject *cb)
317 {
318   if (fgGetBool("/sim/panel/visibility"))
319     fgSetBool("/sim/panel/visibility", false);
320   else
321     fgSetBool("/sim/panel/visibility", true);
322
323   fgReshape(fgGetInt("/sim/startup/xsize"),
324             fgGetInt("/sim/startup/ysize"));
325 }
326     
327 //void MenuHideMenuCb(puObject *cb)
328 void hideMenuCb (puObject *cb)
329 {
330     guiToggleMenu();
331 }
332
333 void goodBye(puObject *)
334 {
335     // SG_LOG( SG_INPUT, SG_ALERT,
336     //      "Program exiting normally at user request." );
337     cout << "Program exiting normally at user request." << endl;
338
339 #ifdef FG_NETWORK_OLK    
340     if ( fgGetBool("/sim/networking/network-olk") ) {
341         if ( net_is_registered == 0 ) fgd_send_com( "8", FGFS_host);
342     }
343 #endif
344
345     // close all external I/O connections
346     fgIOShutdownAll();
347
348     exit(0);
349 }
350
351
352 void goAwayCb (puObject *me)
353 {
354     FG_POP_PUI_DIALOG( dialogBox );
355 }
356
357 void mkDialogInit (void)
358 {
359     //  printf("mkDialogInit\n");
360     int x = (fgGetInt("/sim/startup/xsize")/2 - 400/2);
361     int y = (fgGetInt("/sim/startup/ysize")/2 - 100/2);
362     dialogBox = new puDialogBox (x, y); // 150, 50
363     {
364         dialogFrame = new puFrame (0,0,400,100);
365         dialogBoxMessage  =  new puText         (10, 70);
366         dialogBoxMessage  -> setLabel           ("");
367         dialogBoxOkButton =  new puOneShot      (180, 10, 240, 50);
368         dialogBoxOkButton -> setLegend          (gui_msg_OK);
369         dialogBoxOkButton -> makeReturnDefault  (TRUE );
370         dialogBoxOkButton -> setCallback        (goAwayCb);
371     }
372     FG_FINALIZE_PUI_DIALOG( dialogBox );
373 }
374
375 void MayBeGoodBye(puObject *)
376 {
377     ConfirmExitDialog(); 
378 }
379
380 void goAwayYesNoCb(puObject *me)
381 {
382     FG_POP_PUI_DIALOG( YNdialogBox);
383 }
384
385 void ConfirmExitDialogInit(void)
386 {
387     char msg[] = "Really Quit";
388     char *s;
389
390     //  printf("ConfirmExitDialogInit\n");
391     int len = 200 - puGetStringWidth( puGetDefaultLabelFont(), msg )/2;
392
393     int x = (fgGetInt("/sim/startup/xsize")/2 - 400/2);
394     int y = (fgGetInt("/sim/startup/ysize")/2 - 100/2);
395         
396     YNdialogBox = new puDialogBox (x, y); // 150, 50
397     //  YNdialogBox = new puDialogBox (150, 50);
398     {
399         YNdialogFrame = new puFrame (0,0,400, 100);
400         
401         YNdialogBoxMessage  =  new puText         (len, 70);
402         YNdialogBoxMessage  -> setDefaultValue    (msg);
403         YNdialogBoxMessage  -> getDefaultValue    (&s);
404         YNdialogBoxMessage  -> setLabel           (s);
405         
406         YNdialogBoxOkButton =  new puOneShot      (100, 10, 160, 50);
407         YNdialogBoxOkButton -> setLegend          (gui_msg_OK);
408         YNdialogBoxOkButton -> makeReturnDefault  (TRUE );
409         YNdialogBoxOkButton -> setCallback        (goodBye);
410         
411         YNdialogBoxNoButton =  new puOneShot      (240, 10, 300, 50);
412         YNdialogBoxNoButton -> setLegend          (gui_msg_NO);
413         YNdialogBoxNoButton -> setCallback        (goAwayYesNoCb);
414     }
415     FG_FINALIZE_PUI_DIALOG( YNdialogBox );
416 }
417
418 void notCb (puObject *)
419 {
420     mkDialog ("This function isn't implemented yet");
421 }
422
423 void helpCb (puObject *)
424 {
425     string command;
426         
427 #if defined(FX) && !defined(WIN32)
428 #  if defined(XMESA_FX_FULLSCREEN) && defined(XMESA_FX_WINDOW)
429     if ( global_fullscreen ) {
430         global_fullscreen = false;
431         XMesaSetFXmode( XMESA_FX_WINDOW );
432     }
433 #  endif
434 #endif
435         
436     SGPath path( globals->get_fg_root() );
437     path.append( "Docs/index.html" );
438         
439     string help_app = fgGetString("/sim/startup/browser-app");
440
441     if ( system("xwininfo -name Netscape > /dev/null 2>&1") == 0 ) {
442         command = help_app + " -remote \"openURL(" + path.str() + ")\"";
443     } else {
444         command = help_app + " " + path.str();
445     }
446 #if !defined(WIN32)
447     command += " &";
448 #endif
449         
450     system( command.c_str() );
451     mkDialog ("Help started in netscape window.");
452 }
453
454 #define TR_HIRES_SNAP
455 #if defined( TR_HIRES_SNAP)
456 #include <simgear/screen/tr.h>
457 extern void trRenderFrame( void );
458 extern void fgUpdateHUD( GLfloat x_start, GLfloat y_start,
459                          GLfloat x_end, GLfloat y_end );
460
461 void fgHiResDump()
462 {
463     FILE *f;
464     string message;
465     bool show_pu_cursor = false;
466     bool show_menu = false;
467     char *filename = new char [24];
468     static int count = 1;
469
470     int freeze = globals->get_freeze();
471     if(!freeze)
472         globals->set_freeze( true );
473
474     if(gui_menu_on) {
475         show_menu = true;
476         guiToggleMenu();
477     }
478         
479     if ( !puCursorIsHidden() ) {
480         show_pu_cursor = true;
481         puHideCursor();
482     }
483
484     fgInitVisuals();
485     fgReshape( fgGetInt("/sim/startup/xsize"),
486                fgGetInt("/sim/startup/ysize") );
487
488     // we need two render frames here to clear the menu and cursor
489     // ... not sure why but doing an extra fgRenderFrame() shouldn't
490     // hurt anything
491     fgRenderFrame();
492     fgRenderFrame();
493
494     // Make sure we have SSG projection primed for current view
495     glMatrixMode(GL_MODELVIEW);
496     glLoadIdentity();
497     ssgSetCamera( (sgVec4 *)globals->get_current_view()->get_VIEW() );
498     float fov = globals->get_current_view()->get_fov();
499     ssgSetFOV(fov, fov * globals->get_current_view()->get_win_ratio());
500     // ssgSetNearFar( 10.0f, 120000.0f );
501     ssgSetNearFar( 0.5f, 1200000.0f );
502
503         
504     // This ImageSize stuff is a temporary hack
505     // should probably use 128x128 tile size and
506     // support any image size
507
508     // This should be a requester to get multiplier from user
509     int multiplier = 3;
510     int width = fgGetInt("/sim/startup/xsize");
511     int height = fgGetInt("/sim/startup/ysize");
512         
513     /* allocate buffer large enough to store one tile */
514     GLubyte *tile = (GLubyte *)malloc(width * height * 3 * sizeof(GLubyte));
515     if (!tile) {
516         printf("Malloc of tile buffer failed!\n");
517         return;
518     }
519
520     int imageWidth  = multiplier*width;
521     int imageHeight = multiplier*height;
522
523     /* allocate buffer to hold a row of tiles */
524     GLubyte *buffer
525         = (GLubyte *)malloc(imageWidth * height * 3 * sizeof(GLubyte));
526     if (!buffer) {
527         free(tile);
528         printf("Malloc of tile row buffer failed!\n");
529         return;
530     }
531     TRcontext *tr = trNew();
532     trTileSize(tr, width, height, 0);
533     trTileBuffer(tr, GL_RGB, GL_UNSIGNED_BYTE, tile);
534     trImageSize(tr, imageWidth, imageHeight);
535     trRowOrder(tr, TR_TOP_TO_BOTTOM);
536     sgFrustum *frustum = ssgGetFrustum();
537     trFrustum(tr,
538               frustum->getLeft(), frustum->getRight(),
539               frustum->getBot(),  frustum->getTop(), 
540               frustum->getNear(), frustum->getFar());
541         
542     /* Prepare ppm output file */
543     while (count < 1000) {
544         snprintf(filename, 24, "fgfs-screen-%03d.ppm", count++);
545         if ( (f = fopen(filename, "r")) == NULL )
546             break;
547         fclose(f);
548     }
549     f = fopen(filename, "wb");
550     if (!f) {
551         printf("Couldn't open image file: %s\n", filename);
552         free(buffer);
553         free(tile);
554         return;
555     }
556     fprintf(f,"P6\n");
557     fprintf(f,"# ppm-file created by %s\n", "trdemo2");
558     fprintf(f,"%i %i\n", imageWidth, imageHeight);
559     fprintf(f,"255\n");
560
561     /* just to be safe... */
562     glPixelStorei(GL_PACK_ALIGNMENT, 1);
563
564     /* Because the HUD and Panel change the ViewPort we will
565      * need to handle some lowlevel stuff ourselves */
566     int ncols = trGet(tr, TR_COLUMNS);
567     int nrows = trGet(tr, TR_ROWS);
568
569     bool do_hud = fgGetBool("/sim/hud/visibility");
570     GLfloat hud_col_step = 640.0 / ncols;
571     GLfloat hud_row_step = 480.0 / nrows;
572         
573     bool do_panel = fgPanelVisible();
574     GLfloat panel_col_step = current_panel->getWidth() / ncols;
575     GLfloat panel_row_step = current_panel->getHeight() / nrows;
576         
577     /* Draw tiles */
578     int more = 1;
579     while (more) {
580         trBeginTile(tr);
581         int curColumn = trGet(tr, TR_CURRENT_COLUMN);
582         int curRow =  trGet(tr, TR_CURRENT_ROW);
583         trRenderFrame();
584         if ( do_hud )
585             fgUpdateHUD( curColumn*hud_col_step,      curRow*hud_row_step,
586                          (curColumn+1)*hud_col_step, (curRow+1)*hud_row_step );
587         if (do_panel)
588             current_panel->update( curColumn*panel_col_step, panel_col_step,
589                                    curRow*panel_row_step,    panel_row_step );
590         more = trEndTile(tr);
591
592         /* save tile into tile row buffer*/
593         int curTileWidth = trGet(tr, TR_CURRENT_TILE_WIDTH);
594         int bytesPerImageRow = imageWidth * 3*sizeof(GLubyte);
595         int bytesPerTileRow = (width) * 3*sizeof(GLubyte);
596         int xOffset = curColumn * bytesPerTileRow;
597         int bytesPerCurrentTileRow = (curTileWidth) * 3*sizeof(GLubyte);
598         int i;
599         for (i=0;i<height;i++) {
600             memcpy(buffer + i*bytesPerImageRow + xOffset, /* Dest */
601                    tile + i*bytesPerTileRow,              /* Src */
602                    bytesPerCurrentTileRow);               /* Byte count*/
603         }
604
605         if (curColumn == trGet(tr, TR_COLUMNS)-1) {
606             /* write this buffered row of tiles to the file */
607             int curTileHeight = trGet(tr, TR_CURRENT_TILE_HEIGHT);
608             int bytesPerImageRow = imageWidth * 3*sizeof(GLubyte);
609             int i;
610             for (i=0;i<curTileHeight;i++) {
611                 /* Remember, OpenGL images are bottom to top.  Have to reverse. */
612                 GLubyte *rowPtr = buffer + (curTileHeight-1-i) * bytesPerImageRow;
613                 fwrite(rowPtr, 1, imageWidth*3, f);
614             }
615         }
616
617     }
618
619     fgReshape( width, height );
620
621     trDelete(tr);
622
623     fclose(f);
624
625     message = "Snap shot saved to ";
626     message += filename;
627     mkDialog (message.c_str());
628
629     free(tile);
630     free(buffer);
631
632     //  message = "Snap shot saved to ";
633     //  message += filename;
634     //  mkDialog (message.c_str());
635
636     delete [] filename;
637
638     if( show_menu )
639         guiToggleMenu();
640
641     if ( show_pu_cursor ) {
642         puShowCursor();
643     }
644
645     if(!freeze)
646         globals->set_freeze( false );
647 }
648 #endif // #if defined( TR_HIRES_SNAP)
649
650
651 #if defined( WIN32 ) && !defined( __CYGWIN__)
652
653 static void rotateView( double roll, double pitch, double yaw )
654 {
655         // rotate view
656 }
657
658 static GlBitmap *b1 = NULL;
659 extern FGInterface cur_view_fdm;
660 GLubyte *hiResScreenCapture( int multiplier )
661 {
662     float oldfov = fgGetDouble("/sim/field-of-view");
663     float fov = oldfov / multiplier;
664     FGViewer *v = globals->get_current_view();
665     fgSetDouble("/sim/field-of-view", fov);
666     fgInitVisuals();
667     int cur_width = fgGetInt("/sim/startup/xsize");
668     int cur_height = fgGetInt("/sim/startup/ysize");
669     if (b1) delete( b1 );
670     // New empty (mostly) bitmap
671     b1 = new GlBitmap( GL_RGB, 1, 1, (unsigned char *)"123" );
672     int x,y;
673     for ( y = 0; y < multiplier; y++ ) {
674         for ( x = 0; x < multiplier; x++ ) {
675             fgReshape( cur_width, cur_height );
676             // pan to tile
677             rotateView( 0, (y*fov)-((multiplier-1)*fov/2), (x*fov)-((multiplier-1)*fov/2) );
678             fgRenderFrame();
679             // restore view
680             GlBitmap b2;
681             b1->copyBitmap( &b2, cur_width*x, cur_height*y );
682         }
683     }
684     fgSetDouble("/sim/field-of-view", oldfov);
685     return b1->getBitmap();
686 }
687 #endif
688
689
690 #if defined( WIN32 ) && !defined( __CYGWIN__)
691 // win32 print screen function
692 void printScreen ( puObject *obj ) {
693     bool show_pu_cursor = false;
694     TurnCursorOff();
695     if ( !puCursorIsHidden() ) {
696         show_pu_cursor = true;
697         puHideCursor();
698     }
699     BusyCursor( 0 );
700     mainMenuBar->hide();
701
702     CGlPrinter p( CGlPrinter::PRINT_BITMAP );
703     int cur_width = fgGetInt("/sim/startup/xsize");
704     int cur_height = fgGetInt("/sim/startup/ysize");
705     p.Begin( "FlightGear", cur_width*3, cur_height*3 );
706         p.End( hiResScreenCapture(3) );
707
708     if( gui_menu_on ) {
709         mainMenuBar->reveal();
710     }
711     BusyCursor(1);
712     if ( show_pu_cursor ) {
713         puShowCursor();
714     }
715     TurnCursorOn();
716 }
717 #endif // #ifdef WIN32
718
719
720 void dumpSnapShot ( puObject *obj ) {
721     fgDumpSnapShot();
722 }
723
724
725 void dumpHiResSnapShot ( puObject *obj ) {
726     fgHiResDump();
727 }
728
729
730 // do a screen snap shot
731 void fgDumpSnapShot () {
732     bool show_pu_cursor = false;
733     char *filename = new char [24];
734     string message;
735     static int count = 1;
736
737     int freeze = globals->get_freeze();
738     if(!freeze)
739         globals->set_freeze( true );
740
741     mainMenuBar->hide();
742     TurnCursorOff();
743     if ( !puCursorIsHidden() ) {
744         show_pu_cursor = true;
745         puHideCursor();
746     }
747
748     fgInitVisuals();
749     fgReshape( fgGetInt("/sim/startup/xsize"),
750                fgGetInt("/sim/startup/ysize") );
751
752     // we need two render frames here to clear the menu and cursor
753     // ... not sure why but doing an extra fgRenderFrame() shouldn't
754     // hurt anything
755     fgRenderFrame();
756     fgRenderFrame();
757
758     while (count < 1000) {
759         FILE *fp;
760         snprintf(filename, 24, "fgfs-screen-%03d.ppm", count++);
761         if ( (fp = fopen(filename, "r")) == NULL )
762             break;
763         fclose(fp);
764     }
765
766     if ( sg_glDumpWindow( filename,
767                           fgGetInt("/sim/startup/xsize"), 
768                           fgGetInt("/sim/startup/ysize")) ) {
769         message = "Snap shot saved to ";
770         message += filename;
771     } else {
772         message = "Failed to save to ";
773         message += filename;
774     }
775
776     mkDialog (message.c_str());
777
778     delete [] filename;
779
780     if ( show_pu_cursor ) {
781         puShowCursor();
782     }
783
784     TurnCursorOn();
785     if( gui_menu_on ) {
786         mainMenuBar->reveal();
787     }
788
789     if(!freeze)
790         globals->set_freeze( false );
791 }
792
793 #ifdef FG_NETWORK_OLK
794 static void net_display_toggle( puObject *cb)
795 {
796         net_hud_display = (net_hud_display) ? 0 : 1;
797         printf("Toggle net_hud_display : %d\n", net_hud_display);
798 }
799
800 static void net_register( puObject *cb)
801 {
802         fgd_send_com( "1", FGFS_host );
803         net_is_registered = 0;
804         printf("Registering to deamon\n");
805 }
806
807 static void net_unregister( puObject *cb)
808 {
809         fgd_send_com( "8", FGFS_host );
810         net_is_registered = -1;
811         printf("Unregistering from deamon\n");
812 }
813
814 extern void net_fgd_scan(puObject *cb);
815 #endif // #ifdef FG_NETWORK_OLK
816
817 /* -----------------------------------------------------------------------
818 The menu stuff 
819 ---------------------------------------------------------------------*/
820 char *fileSubmenu               [] = {
821     "Exit", /* "Close", "---------", */
822 #if defined( WIN32 ) && !defined( __CYGWIN__)
823     "Print",
824 #endif
825     "Snap Shot",
826     "Hires Snap Shot",
827     "---------", 
828     "Reset", 
829     "Load flight",
830     "Save flight",
831     NULL
832 };
833 puCallback fileSubmenuCb        [] = {
834     MayBeGoodBye, /* hideMenuCb, NULL, */
835 #if defined( WIN32 ) && !defined( __CYGWIN__)
836     printScreen, 
837 #endif
838     /* NULL, notCb, */
839     dumpSnapShot,
840     dumpHiResSnapShot,
841     NULL,
842     reInit, 
843     loadFlight,
844     saveFlight,
845     NULL
846 };
847
848 /*
849 char *editSubmenu               [] = {
850     "Edit text", NULL
851 };
852 puCallback editSubmenuCb        [] = {
853     notCb, NULL
854 };
855 */
856
857 extern void fgHUDalphaAdjust( puObject * );
858 char *viewSubmenu               [] = {
859     "HUD Alpha",
860     "Pilot Offset",
861     /* "Cockpit View > ", "View >","------------", */
862     "Toggle Panel...", NULL
863 };
864 puCallback viewSubmenuCb        [] = {
865     fgHUDalphaAdjust,
866     PilotOffsetAdjust,
867     /* notCb, notCb, NULL, */
868     guiTogglePanel, NULL
869 };
870
871 //  "---------", 
872
873 char *autopilotSubmenu           [] = {
874     "Toggle HUD Format", "Adjust AP Settings",
875     "---------", 
876     "Clear Route", "Skip Current Waypoint", "Add Waypoint",
877     "---------", 
878     "Set Altitude", "Set Heading",
879     NULL
880 };
881
882 puCallback autopilotSubmenuCb    [] = {
883     fgLatLonFormatToggle, fgAPAdjust,
884     NULL,
885     ClearRoute, PopWayPoint, AddWayPoint,
886     NULL,
887     NewAltitude, NewHeading,
888     /* notCb, */ NULL
889 };
890
891 char *environmentSubmenu        [] = {
892     "Goto Airport", /* "Terrain", "Weather", */ NULL
893 };
894 puCallback environmentSubmenuCb [] = {
895     NewAirport, /* notCb, notCb, */ NULL
896 };
897
898 /*
899 char *optionsSubmenu            [] = {
900     "Preferences", "Realism & Reliablity...", NULL
901 };
902 puCallback optionsSubmenuCb     [] = {
903     notCb, notCb, NULL
904 };
905 */
906
907 #ifdef FG_NETWORK_OLK
908 char *networkSubmenu            [] = {
909     "Unregister from FGD ", /* "Send MSG to All", "Send MSG", "Show Pilots", */
910     "Register to FGD",
911     "Scan for Deamons", "Enter Callsign", /* "Display Netinfos", */
912     "Toggle Display", NULL
913 };
914 puCallback networkSubmenuCb     [] = {
915     /* notCb, notCb, notCb, notCb, */ 
916     net_unregister, 
917     net_register, 
918     net_fgd_scan, NewCallSign, 
919     net_display_toggle, NULL
920 };
921 #endif
922
923 char *helpSubmenu               [] = {
924     /* "About...", */ "Help", NULL
925 };
926 puCallback helpSubmenuCb        [] = {
927     /* notCb, */ helpCb, NULL
928 };
929
930
931 /* -------------------------------------------------------------------------
932 init the gui
933 _____________________________________________________________________*/
934
935
936 void guiInit()
937 {
938     char *mesa_win_state;
939
940     // Initialize PUI
941     puInit();
942     puSetDefaultStyle         ( PUSTYLE_SMALL_BEVELLED ); //PUSTYLE_DEFAULT
943     puSetDefaultColourScheme  (0.8, 0.8, 0.8, 0.4);
944
945     // Initialize our GLOBAL GUI STRINGS
946     gui_msg_OK     = msg_OK;     // "OK"
947     gui_msg_NO     = msg_NO;     // "NO"
948     gui_msg_YES    = msg_YES;    // "YES"
949     gui_msg_CANCEL = msg_CANCEL; // "CANCEL"
950     gui_msg_RESET  = msg_RESET;  // "RESET"
951
952     // Next check home directory
953     SGPath fntpath;
954     char* envp = ::getenv( "FG_FONTS" );
955     if ( envp != NULL ) {
956         fntpath.set( envp );
957     } else {
958         fntpath.set( globals->get_fg_root() );
959         fntpath.append( "Fonts" );
960     }
961
962     // Install our fast fonts
963     fntpath.append( "typewriter.txf" );
964     guiFntHandle = new fntTexFont ;
965     guiFntHandle -> load ( (char *)fntpath.c_str() ) ;
966     puFont GuiFont ( guiFntHandle, 15 ) ;
967     puSetDefaultFonts( GuiFont, GuiFont ) ;
968     guiFnt = puGetDefaultLabelFont();
969   
970     if (!fgHasNode("/sim/startup/mouse-pointer")) {
971         // no preference specified for mouse pointer, attempt to autodetect...
972         // Determine if we need to render the cursor, or if the windowing
973         // system will do it.  First test if we are rendering with glide.
974         if ( strstr ( general.get_glRenderer(), "Glide" ) ) {
975             // Test for the MESA_GLX_FX env variable
976             if ( (mesa_win_state = getenv( "MESA_GLX_FX" )) != NULL) {
977                 // test if we are fullscreen mesa/glide
978                 if ( (mesa_win_state[0] == 'f') ||
979                      (mesa_win_state[0] == 'F') ) {
980                     puShowCursor ();
981                 }
982             }
983         }
984 //        mouse_active = ~mouse_active;
985     } else if ( !fgGetBool("/sim/startup/mouse-pointer") ) {
986         // don't show pointer
987     } else {
988         // force showing pointer
989         puShowCursor();
990 //        mouse_active = ~mouse_active;
991     }
992         
993     // MOUSE_VIEW mode stuff
994         initMouseQuat();
995
996     // Set up our Dialog Boxes
997     ConfirmExitDialogInit();
998     NewAirportInit();
999 #ifdef FG_NETWORK_OLK
1000     NewNetIdInit();
1001     NewNetFGDInit();
1002 #endif
1003
1004         mkDialogInit();
1005     
1006     // Make the menu bar
1007     mainMenuBar = new puMenuBar ();
1008     mainMenuBar -> add_submenu ("File", fileSubmenu, fileSubmenuCb);
1009     // mainMenuBar -> add_submenu ("Edit", editSubmenu, editSubmenuCb);
1010     mainMenuBar -> add_submenu ("View", viewSubmenu, viewSubmenuCb);
1011     mainMenuBar -> add_submenu ("Environment", environmentSubmenu, environmentSubmenuCb);
1012     mainMenuBar -> add_submenu ("Autopilot", autopilotSubmenu, autopilotSubmenuCb);
1013     // mainMenuBar -> add_submenu ("Options", optionsSubmenu, optionsSubmenuCb);
1014 #ifdef FG_NETWORK_OLK
1015     if ( fgGetBool("/sim/networking/network-olk") ) {
1016         mainMenuBar -> add_submenu ("Network", networkSubmenu, networkSubmenuCb);
1017     }
1018 #endif
1019     mainMenuBar -> add_submenu ("Help", helpSubmenu, helpSubmenuCb);
1020     mainMenuBar-> close ();
1021     // Set up menu bar toggle
1022     gui_menu_on = ~0;
1023 }
1024