00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
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
00036
00037
00038
00039 using namespace std;
00040
00041
00042 char AppName[] = "Celestia";
00043
00044 static CelestiaCore* appCore = NULL;
00045
00046
00047 static bool ready = false;
00048
00049
00050
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
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
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
00119
00120
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
00162 if (c == '\021')
00163 exit(0);
00164
00165 appCore->charEntered((char) c);
00166
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
00228
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
00320 glutAddMenuEntry("Run demo D",003);
00321
00322
00323
00324
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
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
00356 caseKey(1,'h');
00357 caseKey(2,0x13);
00358 caseKey(3,'d');
00359
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
00369 caseKey(201,'l');
00370 caseKey(202,'k');
00371 caseKey(203,'j');
00372
00373 caseKey(301,'n');
00374 caseKey(302,'b');
00375 caseKey(303,'=');
00376 caseKey(304,'v');
00377
00378 caseKey(401,'w');
00379 caseKey(402,CTRLKEY('p'));
00380 caseKey(403,CTRLKEY('v'));
00381 caseKey(404,'`');
00382
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
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
00403 caseKey(701,5);
00404
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
00425
00426
00427 strcat(myPath,"/Resources");
00428 chdir(myPath);
00429 free(myPath);
00430 }
00431 #endif
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
00445 if (argc==2 && argv[1][0]=='-' && argv[1][1]=='p' && argv[1][2]=='s' && argv[1][3]=='n')
00446 {
00447 #endif
00448 argc--;
00449 dirFixup(argv[0]);
00450 #ifndef BUNDLEONLY
00451 } else
00452
00453 #endif
00454 #else
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
00461
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
00519 appCore->initRenderer();
00520
00521
00522 time_t curtime=time(NULL);
00523 appCore->start((double) curtime / 86400.0 + (double) astro::Date(1970, 1, 1));
00524 #ifdef MACOSX
00525
00526
00527
00528
00529 struct tm *temptime=localtime(&curtime);
00530 appCore->setTimeZoneBias(temptime->tm_gmtoff);
00531 appCore->setTimeZoneName(temptime->tm_zone);
00532 #else
00533 localtime(&curtime);
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