Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | File Members

glutmain.cpp

Go to the documentation of this file.
00001 // glutmain.cpp
00002 // 
00003 // Copyright (C) 2001, Chris Laurel <claurel@shatters.net>
00004 //
00005 // GLUT front-end for Celestia.
00006 //
00007 // This program is free software; you can redistribute it and/or
00008 // modify it under the terms of the GNU General Public License
00009 // as published by the Free Software Foundation; either version 2
00010 // of the License, or (at your option) any later version.
00011 
00012 #include <iostream>
00013 #include <fstream>
00014 #include <algorithm>
00015 #include <cstdlib>
00016 #include <cctype>
00017 #include <cstring>
00018 #include <time.h>
00019 #include <unistd.h>
00020 #include <celengine/gl.h>
00021 #ifndef MACOSX
00022 #include <GL/glut.h>
00023 #else
00024 #include <Carbon/Carbon.h>
00025 #include <GLUT/glut.h>
00026 #endif
00027 #include <celengine/celestia.h>
00028 #include <celmath/vecmath.h>
00029 #include <celmath/quaternion.h>
00030 #include <celutil/util.h>
00031 #include <celutil/debug.h>
00032 #include <celmath/mathlib.h>
00033 #include <celengine/astro.h>
00034 #include "celestiacore.h"
00035 /* what are you supposed to be?
00036 #include "popt.h"
00037 */
00038 
00039 using namespace std;
00040 
00041 
00042 char AppName[] = "Celestia";
00043 
00044 static CelestiaCore* appCore = NULL;
00045 
00046 //static bool fullscreen = false;
00047 static bool ready = false;
00048 
00049 
00050 // Mouse motion tracking
00051 static int lastX = 0;
00052 static int lastY = 0;
00053 static bool leftButton = false;
00054 static bool middleButton = false;
00055 static bool rightButton = false;
00056 
00057 static int mainWindow = 1;
00058 
00059 // Mouse wheel button assignments
00060 #define MOUSE_WHEEL_UP   3
00061 #define MOUSE_WHEEL_DOWN 4
00062 
00063 
00064 
00065 static void Resize(int w, int h)
00066 {
00067     appCore->resize(w, h);
00068 }
00069 
00070 
00071 /*
00072  * Definition of GLUT callback functions
00073  */
00074 
00075 static void Display(void)
00076 {
00077     if (ready)
00078     {
00079         appCore->draw();
00080         glutSwapBuffers();
00081     }
00082 }
00083 
00084 static void Idle(void)
00085 {
00086     if (glutGetWindow() != mainWindow)
00087         glutSetWindow(mainWindow);
00088 
00089     appCore->tick();
00090 
00091     Display();
00092 }
00093 
00094 static void MouseDrag(int x, int y)
00095 {
00096     int buttons = 0;
00097     if (leftButton)
00098         buttons |= CelestiaCore::LeftButton;
00099     if (rightButton)
00100         buttons |= CelestiaCore::RightButton;
00101     if (middleButton)
00102         buttons |= CelestiaCore::MiddleButton;
00103 
00104     appCore->mouseMove(x - lastX, y - lastY, buttons);
00105 
00106     lastX = x;
00107     lastY = y;
00108 }
00109 
00110 static void MouseButton(int button, int state, int x, int y)
00111 {
00112 #ifdef MACOSX
00113     if (button == GLUT_LEFT_BUTTON) {
00114         UInt32 mods=GetCurrentKeyModifiers ();
00115         if      (mods & optionKey)  button=GLUT_MIDDLE_BUTTON;
00116         else if (mods & cmdKey)     button=GLUT_RIGHT_BUTTON;
00117     }
00118 #endif /* MACOSX */
00119     // On Linux, mouse wheel up and down are usually translated into
00120     // mouse button 4 and 5 down events.
00121     if (button == MOUSE_WHEEL_UP)
00122     {
00123         appCore->mouseWheel(-1.0f, 0);
00124     }
00125     else if (button == MOUSE_WHEEL_DOWN)
00126     {
00127         appCore->mouseWheel(1.0f, 0);
00128     }
00129     else if (button == GLUT_LEFT_BUTTON)
00130     {
00131         leftButton = (state == GLUT_DOWN);
00132         if (state == GLUT_DOWN)
00133             appCore->mouseButtonDown(x, y, CelestiaCore::LeftButton);
00134         else
00135             appCore->mouseButtonUp(x, y, CelestiaCore::LeftButton);
00136     }
00137     else if (button == GLUT_RIGHT_BUTTON)
00138     {
00139         rightButton = (state == GLUT_DOWN);
00140         if (state == GLUT_DOWN)
00141             appCore->mouseButtonDown(x, y, CelestiaCore::RightButton);
00142         else
00143             appCore->mouseButtonUp(x, y, CelestiaCore::RightButton);
00144     }
00145     else if (button == GLUT_MIDDLE_BUTTON)
00146     {
00147         middleButton = (state == GLUT_DOWN);
00148         if (state == GLUT_DOWN)
00149             appCore->mouseButtonDown(x, y, CelestiaCore::MiddleButton);
00150         else
00151             appCore->mouseButtonUp(x, y, CelestiaCore::MiddleButton);
00152     }
00153 
00154     lastX = x;
00155     lastY = y;
00156 }
00157 
00158 
00159 static void KeyPress(unsigned char c, int x, int y)
00160 {
00161     // Ctrl-Q exits
00162     if (c == '\021')
00163         exit(0);
00164 
00165     appCore->charEntered((char) c);
00166     //appCore->keyDown((int) c);
00167 }
00168 
00169 
00170 static void KeyUp(unsigned char c, int x, int y)
00171 {
00172     appCore->keyUp((int) c);
00173 }
00174 
00175 
00176 static void HandleSpecialKey(int key, bool down)
00177 {
00178     int k = -1;
00179     switch (key)
00180     {
00181     case GLUT_KEY_UP:
00182         k = CelestiaCore::Key_Up;
00183         break;
00184     case GLUT_KEY_DOWN:
00185         k = CelestiaCore::Key_Down;
00186         break;
00187     case GLUT_KEY_LEFT:
00188         k = CelestiaCore::Key_Left;
00189         break;
00190     case GLUT_KEY_RIGHT:
00191         k = CelestiaCore::Key_Right;
00192         break;
00193     case GLUT_KEY_HOME:
00194         k = CelestiaCore::Key_Home;
00195         break;
00196     case GLUT_KEY_END:
00197         k = CelestiaCore::Key_End;
00198         break;
00199     case GLUT_KEY_F1:
00200         k = CelestiaCore::Key_F1;
00201         break;
00202     case GLUT_KEY_F2:
00203         k = CelestiaCore::Key_F2;
00204         break;
00205     case GLUT_KEY_F3:
00206         k = CelestiaCore::Key_F3;
00207         break;
00208     case GLUT_KEY_F4:
00209         k = CelestiaCore::Key_F4;
00210         break;
00211     case GLUT_KEY_F5:
00212         k = CelestiaCore::Key_F5;
00213         break;
00214     case GLUT_KEY_F6:
00215         k = CelestiaCore::Key_F6;
00216         break;
00217     case GLUT_KEY_F7:
00218         k = CelestiaCore::Key_F7;
00219         break;
00220     case GLUT_KEY_F11:
00221         k = CelestiaCore::Key_F11;
00222         break;
00223     case GLUT_KEY_F12:
00224         k = CelestiaCore::Key_F12;
00225         break;
00226     }
00227     /* Glut doesn't seem to handle Keypad Keys, so we can't pass them on.
00228        They will be passed as the appropriate Special keys instead */
00229 
00230     if (k >= 0)
00231     {
00232         if (down)
00233             appCore->keyDown(k);
00234         else
00235             appCore->keyUp(k);
00236     }
00237 }
00238 
00239 
00240 static void SpecialKeyPress(int key, int x, int y)
00241 {
00242     HandleSpecialKey(key, true);
00243 }
00244 
00245 
00246 static void SpecialKeyUp(int key, int x, int y)
00247 {
00248     HandleSpecialKey(key, false);
00249 }
00250 
00251 #ifdef MACOSX
00252 static void menuCallback (int which);
00253 static void initMenus(void) {
00254     int gMain,gNavigation,gTime,gLabels,gRendering;
00255     int gViews,gSpaceflight,gNumber,gJoystick,gMouse;
00256     gMain=gNavigation=gTime=gLabels=gRendering=0;
00257     gViews=gSpaceflight=gNumber=gJoystick=gMouse=0;
00258     gNavigation=glutCreateMenu(menuCallback);
00259     glutAddMenuEntry("Center                      C",101);
00260     glutAddMenuEntry("Go closer                   G",102);
00261     glutAddMenuEntry("Follow                      F",103);
00262     glutAddMenuEntry("Orbit                       Y",104);
00263     glutAddMenuEntry("Track                       T",105);
00264     glutAddMenuEntry("Move closer              HOME",106);
00265     glutAddMenuEntry("Move farther              END",107);
00266     glutAddMenuEntry("Cancel motion             ESC",108);
00267     glutAddMenuEntry("*Roll Camera            <- ->",000);
00268     glutAddMenuEntry("*Camera Pitch         UP DOWN",000);
00269     gTime=glutCreateMenu(menuCallback);
00270     glutAddMenuEntry("10x faster                  L",201);
00271     glutAddMenuEntry("10x slower                  K",202);
00272     glutAddMenuEntry("Reverse time                J",203);
00273     gLabels=glutCreateMenu(menuCallback);
00274     glutAddMenuEntry("Toggle planet/moon          N",301);
00275     glutAddMenuEntry("Toggle star                 B",302);
00276     glutAddMenuEntry("Toggle constellation        =",303);
00277     glutAddMenuEntry("Toggle info text            V",304);
00278     gRendering=glutCreateMenu(menuCallback);
00279     glutAddMenuEntry("Wireframe                   W",401);
00280     glutAddMenuEntry("Per-pixel lighting     CTRL+P",402);
00281     glutAddMenuEntry("Vertex programs        CTRL+V",403);
00282     glutAddMenuEntry("Show FPS                    `",404);
00283     glutAddMenuEntry("*Limiting magnitude       ] [",000);
00284     glutAddMenuEntry("*Ambient illumination     } {",000);
00285     glutAddMenuEntry("*Narrow/Widen FOV         , .",000);
00286     gViews=glutCreateMenu(menuCallback);
00287     glutAddMenuEntry("Galaxies                    U",501);
00288     glutAddMenuEntry("Planet orbits               O",502);
00289     glutAddMenuEntry("Constellations              /",503);
00290     glutAddMenuEntry("Atmospheres            CTRL+A",504);
00291     glutAddMenuEntry("Cloud textures              I",505);
00292     glutAddMenuEntry("Night side planet maps CTRL+L",506);
00293     glutAddMenuEntry("Equatorial coordinates      ;",507);
00294     gSpaceflight=glutCreateMenu(menuCallback);
00295     glutAddMenuEntry("Stop                       F1",601);
00296     glutAddMenuEntry("Set velocity to 1 km/s     F2",602);
00297     glutAddMenuEntry("Set velocity to 1,000 km/s F3",603);
00298     glutAddMenuEntry("Set velocity to lightspeed F4",604);
00299     glutAddMenuEntry("Set velocity to 10^6 km/s  F5",605);
00300     glutAddMenuEntry("Set velocity to 1 AU/s     F6",606);
00301     glutAddMenuEntry("Set velocity to 1 ly/s     F7",607);
00302     glutAddMenuEntry("Increase velocity (exp)     A",608);
00303     glutAddMenuEntry("Decrease velocity (exp)     Z",609);
00304     glutAddMenuEntry("Reverse direction           Q",610);
00305     glutAddMenuEntry("Movement to screen origin   X",611);
00306     gNumber=glutCreateMenu(menuCallback);
00307     glutAddMenuEntry("Stop rotation               5",701);
00308     glutAddMenuEntry("*Yaw left/right           4 6",702);
00309     glutAddMenuEntry("*Pitch up/down            2 8",703);
00310     glutAddMenuEntry("*Roll left/right          7 9",704);
00311     gJoystick=glutCreateMenu(menuCallback);
00312     glutAddMenuEntry("Enable joystick            F8",801);
00313     glutAddMenuEntry("*Yaw                   X axis",000);
00314     glutAddMenuEntry("*Pitch                 Y axis",000);
00315     glutAddMenuEntry("*Roll             L,R trigger",000);
00316     glutAddMenuEntry("*Speed             Button 1,2",000);
00317     gMain=glutCreateMenu(menuCallback);
00318     glutAddMenuEntry("Select the sun (Home)    H",001);
00319 /*    glutAddMenuEntry("Select by name       ENTER",002); */
00320     glutAddMenuEntry("Run demo                         D",003);
00321 /*   
00322     gMouse=glutCreateMenu(menuCallback);
00323     glutAddSubMenu("*Orient camera    CLICK+DRAG",000);
00324     glutAddSubMenu("*Orbit object    RCLICK+DRAG",000);
00325 */
00326     glutAddSubMenu("Selected Object", gNavigation);
00327     glutAddSubMenu("Time",gTime);
00328     glutAddSubMenu("Labels",gLabels);
00329     glutAddSubMenu("Rendering",gRendering);
00330     glutAddSubMenu("Views",gViews);
00331     glutAddSubMenu("Spaceflight",gSpaceflight);
00332     glutAddSubMenu("Number Pad",gNumber);
00333     glutAddSubMenu("Joystick",gJoystick);
00334 /*
00335     glutAddSubMenu("Mouse",gMouse);
00336 */
00337     glutAttachMenu(GLUT_RIGHT_BUTTON);
00338 }
00339 
00340 #define CTRLKEY(KEY) (KEY-'a'+(char)1)
00341 #define caseKey(CASE,WHICH) \
00342     case (CASE): \
00343         appCore->charEntered((char)(WHICH)); \
00344         appCore->keyDown((int)(WHICH)); \
00345         appCore->keyUp((int)(WHICH)); \
00346         break
00347 #define caseKeySpecial(CASE,WHICH) \
00348     case (CASE): \
00349         appCore->keyDown(CelestiaCore::Key_##WHICH); \
00350         appCore->keyUp(CelestiaCore::Key_##WHICH); \
00351         break
00352 
00353 static void menuCallback (int which) {
00354     switch(which) {
00355         // main menu
00356         caseKey(1,'h');
00357         caseKey(2,0x13);
00358         caseKey(3,'d');
00359         // navigation
00360         caseKey(101,'c');
00361         caseKey(102,'g');
00362         caseKey(103,'f');
00363         caseKey(104,'y');
00364         caseKey(105,'t');
00365         caseKeySpecial(106,Home);
00366         caseKeySpecial(107,End);
00367         caseKey(108,0x27);
00368         // time
00369         caseKey(201,'l');
00370         caseKey(202,'k');
00371         caseKey(203,'j');
00372         // labels
00373         caseKey(301,'n');
00374         caseKey(302,'b');
00375         caseKey(303,'=');
00376         caseKey(304,'v');
00377         // rendering
00378         caseKey(401,'w');
00379         caseKey(402,CTRLKEY('p'));
00380         caseKey(403,CTRLKEY('v'));
00381         caseKey(404,'`');
00382         // views
00383         caseKey(501,'u');
00384         caseKey(502,'o');
00385         caseKey(503,'/');
00386         caseKey(504,CTRLKEY('a'));
00387         caseKey(505,'i');
00388         caseKey(506,CTRLKEY('l'));
00389         caseKey(507,';');
00390         // spaceflight
00391         caseKeySpecial(601,F1);
00392         caseKeySpecial(602,F2);
00393         caseKeySpecial(603,F3);
00394         caseKeySpecial(604,F4);
00395         caseKeySpecial(605,F5);
00396         caseKeySpecial(606,F6);
00397         caseKeySpecial(607,F7);
00398         caseKey(608,'a');
00399         caseKey(609,'z');
00400         caseKey(610,'q');
00401         caseKey(611,'x');
00402         // number pad
00403         caseKey(701,5);
00404         // joystick
00405         caseKeySpecial(801,F8);
00406     }
00407 }
00408 
00409 
00410 #endif
00411 
00412 #ifdef MACOSX
00413 static void killLastSlash(char *buf) {
00414   int i=strlen(buf);
00415   while (--i && buf[i]!='/') {}
00416   if (buf[i]=='/') buf[i]=0;
00417 }
00418 static void dirFixup(char *argv0) {
00419     char *myPath;
00420     assert(myPath=(char *)malloc(strlen(argv0)+128));
00421     strcpy(myPath,argv0);
00422     killLastSlash(myPath);
00423     killLastSlash(myPath);
00424     // BEWARE!  GLUT is going to put us here anyways, DO NOT TRY SOMEWHERE ELSE
00425     // or you will waste your goddamn time like I did
00426     // damn undocumented shit.
00427     strcat(myPath,"/Resources");
00428     chdir(myPath);
00429     free(myPath);
00430 }
00431 #endif /* MACOSX */
00432 
00433 int main(int argc, char* argv[])
00434 {
00435         setlocale(LC_ALL, "");
00436         setlocale(LC_NUMERIC, "C");
00437         bindtextdomain(PACKAGE, LOCALEDIR);
00438         bind_textdomain_codeset(PACKAGE, "UTF-8");
00439         textdomain(PACKAGE);
00440                         
00441    #ifdef MACOSX
00442    #define BUNDLEONLY 1
00443    #ifndef BUNDLEONLY
00444    // for bundles only!
00445    if (argc==2 && argv[1][0]=='-' && argv[1][1]=='p' && argv[1][2]=='s' && argv[1][3]=='n')
00446    {
00447    #endif /* !BUNDLEONLY */
00448         argc--;
00449         dirFixup(argv[0]);
00450     #ifndef BUNDLEONLY
00451     } else  
00452     /* BE REAL DAMN CAREFUL WITH THIS LINGERING IF! */
00453     #endif /* !BUNDLEONLY */
00454     #else /* MACOSX */
00455     if (chdir(CONFIG_DATA_DIR) == -1)
00456     {
00457         cerr << "Cannot chdir to '" << CONFIG_DATA_DIR <<
00458             "', probably due to improper installation\n";
00459     }
00460     #endif /* !MACOSX */
00461     // Not ready to render yet
00462     ready = false;
00463 
00464     char c;
00465         int startfile = 0;
00466     while ((c = getopt(argc, argv, "v::f")) > -1)
00467     {
00468         if (c == '?')
00469         {
00470             cout << "Usage: celestia [-v] [-f <filename>]\n";
00471             exit(1);
00472         }
00473         else if (c == 'v')
00474         {
00475             if(optarg)
00476                 SetDebugVerbosity(atoi(optarg));
00477             else
00478                 SetDebugVerbosity(0);
00479         }
00480                 else if (c == 'f') {
00481                         startfile = 1;
00482                 }
00483     }
00484 
00485     appCore = new CelestiaCore();
00486     if (appCore == NULL)
00487     {
00488         cerr << "Out of memory.\n";
00489         return 1;
00490     }
00491 
00492     if (!appCore->initSimulation())
00493     {
00494         return 1;
00495     }
00496 
00497     glutInit(&argc, argv);
00498     glutInitWindowSize(480, 360);
00499     glutInitWindowPosition(0, 0);
00500     glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH);
00501     mainWindow = glutCreateWindow("Celestia");
00502 
00503     Resize(480, 360);
00504     glutReshapeFunc(Resize);
00505     glutDisplayFunc(Display);
00506     glutIdleFunc(Idle);
00507     glutMouseFunc(MouseButton);
00508     glutMotionFunc(MouseDrag);
00509     glutKeyboardFunc(KeyPress);
00510     glutKeyboardUpFunc(KeyUp);
00511     glutSpecialFunc(SpecialKeyPress);
00512     glutSpecialUpFunc(SpecialKeyUp);
00513 
00514     #ifdef MACOSX
00515     initMenus();
00516     #endif
00517 
00518     // GL should be all set up, now initialize the renderer.
00519     appCore->initRenderer();
00520 
00521     // Set the simulation starting time to the current system time
00522     time_t curtime=time(NULL);
00523     appCore->start((double) curtime / 86400.0 + (double) astro::Date(1970, 1, 1));
00524     #ifdef MACOSX
00525     /* localtime in Darwin is is reentrant only
00526        equiv to Linux localtime_r()
00527        should probably port !MACOSX code to use this too, available since
00528        libc 5.2.5 according to manpage */
00529     struct tm *temptime=localtime(&curtime);
00530     appCore->setTimeZoneBias(temptime->tm_gmtoff);
00531     appCore->setTimeZoneName(temptime->tm_zone);
00532     #else
00533     localtime(&curtime); // Only doing this to set timezone as a side effect
00534     appCore->setTimeZoneBias(-timezone);
00535     appCore->setTimeZoneName(tzname[daylight?0:1]);
00536     #endif
00537 
00538         if (startfile == 1) {
00539                 if (argv[argc - 1][0] == '-') {
00540                         cout << "Missing Filename.\n";
00541                         return 1;
00542                 }
00543         
00544                 cout << "*** Using CEL File: " << argv[argc - 1] << endl;
00545                 appCore->runScript(argv[argc - 1]);
00546         }
00547 
00548     ready = true;
00549     glutMainLoop();
00550 
00551     return 0;
00552 }
00553 
00554 

Generated on Sat Jan 14 22:30:30 2006 for Celestia by  doxygen 1.4.1