main.cpp
上传用户:center1979
上传日期:2022-07-26
资源大小:50633k
文件大小:15k
源码类别:

OpenGL

开发平台:

Visual C++

  1. /*
  2.  *  Celestia GTK+ Front-End
  3.  *  Copyright (C) 2005 Pat Suwalski <pat@suwalski.net>
  4.  *
  5.  *  This program is free software; you can redistribute it and/or modify
  6.  *  it under the terms of the GNU General Public License as published by
  7.  *  the Free Software Foundation; either version 2 of the License, or
  8.  *  (at your option) any later version.
  9.  *
  10.  *  $Id: main.cpp,v 1.9 2008-01-21 04:55:19 suwalski Exp $
  11.  */
  12. #ifdef HAVE_CONFIG_H
  13. #include <config.h>
  14. #endif /* HAVE_CONFIG_H */
  15. #include <iostream>
  16. #include <fstream>
  17. #include <cstdlib>
  18. #include <cctype>
  19. #include <cstring>
  20. #include <time.h>
  21. #ifdef WIN32
  22. #include <direct.h>
  23. #else
  24. #include <unistd.h>
  25. #endif /* WIN32 */
  26. #include <gtk/gtk.h>
  27. #include <gtk/gtkgl.h>
  28. #include <celengine/astro.h>
  29. #include <celengine/celestia.h>
  30. #include <celengine/gl.h>
  31. #include <celengine/glext.h>
  32. #include <celengine/galaxy.h>
  33. #include <celengine/simulation.h>
  34. #include <celestia/celestiacore.h>
  35. #include <celutil/debug.h>
  36. /* Includes for the GNOME front-end */
  37. #ifdef GNOME
  38. #include <gnome.h>
  39. #include <libgnomeui/libgnomeui.h>
  40. #include <gconf/gconf-client.h>
  41. #endif /* GNOME */
  42. /* Includes for the GTK front-end */
  43. #include "common.h"
  44. #include "glwidget.h"
  45. #include "menu-context.h"
  46. #include "splash.h"
  47. #include "ui.h"
  48. /* Includes for the settings interface */
  49. #ifdef GNOME
  50. #include "settings-gconf.h"
  51. #else
  52. #include "settings-file.h"
  53. #endif /* GNOME */
  54. #ifndef DEBUG
  55. #define G_DISABLE_ASSERT
  56. #endif /* DEBUG */
  57. using namespace std;
  58. /* Function Definitions */
  59. static void createMainMenu(GtkWidget* window, AppData* app);
  60. static void initRealize(GtkWidget* widget, AppData* app);
  61. /* Command-Line Options */
  62. static gchar* configFile = NULL;
  63. static gchar* installDir = NULL;
  64. static gchar** extrasDir = NULL;
  65. static gboolean fullScreen = FALSE;
  66. static gboolean noSplash = FALSE;
  67. /* Command-Line Options specification */
  68. static GOptionEntry optionEntries[] =
  69. {
  70. { "conf", 'c', 0, G_OPTION_ARG_FILENAME, &configFile, "Alternate configuration file", "file" },
  71. { "dir", 'd', 0, G_OPTION_ARG_FILENAME, &installDir, "Alternate installation directory", "directory" },
  72. { "extrasdir", 'e', 0, G_OPTION_ARG_FILENAME_ARRAY, &extrasDir, "Additional "extras" directory", "directory" },
  73. { "fullscreen", 'f', 0, G_OPTION_ARG_NONE, &fullScreen, "Start full-screen", NULL },
  74. { "nosplash", 's', 0, G_OPTION_ARG_NONE, &noSplash, "Disable splash screen", NULL },
  75. { NULL },
  76. };
  77. /* Initializes GtkActions and creates main menu */
  78. static void createMainMenu(GtkWidget* window, AppData* app)
  79. {
  80. GtkUIManager *ui_manager;
  81. GtkAccelGroup *accel_group;
  82. GError *error;
  83. app->agMain = gtk_action_group_new ("MenuActions");
  84. app->agRender = gtk_action_group_new("RenderActions");
  85. app->agLabel = gtk_action_group_new("LabelActions");
  86. app->agOrbit = gtk_action_group_new("OrbitActions");
  87. app->agVerbosity = gtk_action_group_new("VerbosityActions");
  88. app->agStarStyle = gtk_action_group_new("StarStyleActions");
  89. app->agAmbient = gtk_action_group_new("AmbientActions");
  90. /* All actions have the AppData structure passed */
  91. gtk_action_group_add_actions(app->agMain, actionsPlain, G_N_ELEMENTS(actionsPlain), app);
  92. gtk_action_group_add_toggle_actions(app->agMain, actionsToggle, G_N_ELEMENTS(actionsToggle), app);
  93. gtk_action_group_add_radio_actions(app->agVerbosity, actionsVerbosity, G_N_ELEMENTS(actionsVerbosity), 0, G_CALLBACK(actionVerbosity), app);
  94. gtk_action_group_add_radio_actions(app->agStarStyle, actionsStarStyle, G_N_ELEMENTS(actionsStarStyle), 0, G_CALLBACK(actionStarStyle), app);
  95. gtk_action_group_add_radio_actions(app->agAmbient, actionsAmbientLight, G_N_ELEMENTS(actionsAmbientLight), 0, G_CALLBACK(actionAmbientLight), app);
  96. gtk_action_group_add_toggle_actions(app->agRender, actionsRenderFlags, G_N_ELEMENTS(actionsRenderFlags), app);
  97. gtk_action_group_add_toggle_actions(app->agLabel, actionsLabelFlags, G_N_ELEMENTS(actionsLabelFlags), app);
  98. gtk_action_group_add_toggle_actions(app->agOrbit, actionsOrbitFlags, G_N_ELEMENTS(actionsOrbitFlags), app);
  99. ui_manager = gtk_ui_manager_new();
  100. gtk_ui_manager_insert_action_group(ui_manager, app->agMain, 0);
  101. gtk_ui_manager_insert_action_group(ui_manager, app->agRender, 0);
  102. gtk_ui_manager_insert_action_group(ui_manager, app->agLabel, 0);
  103. gtk_ui_manager_insert_action_group(ui_manager, app->agOrbit, 0);
  104. gtk_ui_manager_insert_action_group(ui_manager, app->agStarStyle, 0);
  105. gtk_ui_manager_insert_action_group(ui_manager, app->agAmbient, 0);
  106. gtk_ui_manager_insert_action_group(ui_manager, app->agVerbosity, 0);
  107. accel_group = gtk_ui_manager_get_accel_group(ui_manager);
  108. gtk_window_add_accel_group(GTK_WINDOW (window), accel_group);
  109. error = NULL;
  110. if (!gtk_ui_manager_add_ui_from_file(ui_manager, "celestiaui.xml", &error))
  111. {
  112. g_message("Building menus failed: %s", error->message);
  113. g_error_free(error);
  114. exit(EXIT_FAILURE);
  115. }
  116. app->mainMenu = gtk_ui_manager_get_widget(ui_manager, "/MainMenu");
  117. }
  118. /* Our own watcher. Celestiacore will call notifyChange() to tell us
  119.  * we need to recheck the check menu items and option buttons. */
  120. class GtkWatcher : public CelestiaWatcher
  121. {
  122. public:
  123.     GtkWatcher(CelestiaCore*, AppData*);
  124.     virtual void notifyChange(CelestiaCore*, int);
  125. private:
  126. AppData* app;
  127. };
  128. GtkWatcher::GtkWatcher(CelestiaCore* _appCore, AppData* _app) :
  129.     CelestiaWatcher(*_appCore), app(_app)
  130. {
  131. }
  132. void GtkWatcher::notifyChange(CelestiaCore*, int property)
  133. {
  134. if (property & CelestiaCore::LabelFlagsChanged)
  135. resyncLabelActions(app);
  136. else if (property & CelestiaCore::RenderFlagsChanged)
  137. {
  138. resyncRenderActions(app);
  139. resyncOrbitActions(app);
  140. resyncStarStyleActions(app);
  141. resyncTextureResolutionActions(app);
  142. }
  143. else if (property & CelestiaCore::VerbosityLevelChanged)
  144. resyncVerbosityActions(app);
  145. else if (property & CelestiaCore::TimeZoneChanged)
  146. resyncTimeZoneAction(app);
  147. else if (property & CelestiaCore::AmbientLightChanged)
  148. resyncAmbientActions(app);
  149. /*
  150. else if (property & CelestiaCore::FaintestChanged) DEPRECATED?
  151. else if (property & CelestiaCore::HistoryChanged)
  152. */
  153. else if (property == CelestiaCore::TextEnterModeChanged)
  154. {
  155. if (app->core->getTextEnterMode() != 0)
  156. {
  157. /* Grey-out the menu */
  158. gtk_widget_set_sensitive(app->mainMenu, FALSE);
  159. /* Disable any actions that will interfere in typing and
  160.    autocomplete */
  161. gtk_action_group_set_sensitive(app->agMain, FALSE);
  162. gtk_action_group_set_sensitive(app->agRender, FALSE);
  163. gtk_action_group_set_sensitive(app->agLabel, FALSE);
  164. }
  165. else
  166. {
  167. /* Set the menu normal */
  168. gtk_widget_set_sensitive(app->mainMenu, TRUE);
  169. /* Re-enable action groups */
  170. gtk_action_group_set_sensitive(app->agMain, TRUE);
  171. gtk_action_group_set_sensitive(app->agRender, TRUE);
  172. gtk_action_group_set_sensitive(app->agLabel, TRUE);
  173. }
  174. }
  175. else if (property & CelestiaCore::GalaxyLightGainChanged)
  176. resyncGalaxyGainActions(app);
  177. }
  178. /* END Watcher */
  179. /* CALLBACK: Event "realize" on the main GL area. Things that go here are those
  180.  *           that require the glArea to be set up. */
  181. static void initRealize(GtkWidget* widget, AppData* app)
  182. {
  183. if (!app->core->initRenderer())
  184. {
  185. cerr << "Failed to initialize renderer.n";
  186. }
  187. /* Read/Apply Settings */
  188. #ifdef GNOME
  189. applySettingsGConfMain(app, app->client);
  190. #else
  191. applySettingsFileMain(app, app->settingsFile);
  192. #endif /* GNOME */
  193. /* Synchronize all actions with core settings */
  194. resyncLabelActions(app);
  195. resyncRenderActions(app);
  196. resyncOrbitActions(app);
  197. resyncVerbosityActions(app);
  198. resyncAmbientActions(app);
  199. resyncStarStyleActions(app);
  200. /* If full-screen at startup, make it so. */
  201. if (app->fullScreen)
  202. gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(gtk_action_group_get_action(app->agMain, "FullScreen")), TRUE);
  203. /* If framerate limiting is off, set it so. */
  204. if (!app->renderer->getVideoSync())
  205. gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(gtk_action_group_get_action(app->agMain, "VideoSync")), FALSE);
  206. /* If URL at startup, make it so. */
  207. if (app->startURL != NULL)
  208. app->core->setStartURL(app->startURL);
  209. /* Set simulation time */
  210. app->core->start((double)time(NULL) / 86400.0 + (double)astro::Date(1970, 1, 1));
  211. updateTimeZone(app, app->showLocalTime);
  212. /* Setting time zone name not very useful, but makes space for "LT" status in
  213.  * the top-right corner. Set to some default. */
  214. app->core->setTimeZoneName("UTC");
  215. /* Set the cursor to a crosshair */
  216. gdk_window_set_cursor(widget->window, gdk_cursor_new(GDK_CROSSHAIR));
  217. }
  218. /* MAIN */
  219. int main(int argc, char* argv[])
  220. {
  221. /* Initialize the structure that holds the application's vitals. */
  222. AppData* app = g_new0(AppData, 1);
  223. /* Not ready to render yet. */
  224. app->bReady = FALSE;
  225. /* Initialize variables in the AppData structure. */
  226. app->lastX = 0;
  227. app->lastY = 0;
  228. app->showLocalTime = FALSE;
  229. app->fullScreen = FALSE;
  230. app->startURL = NULL;
  231. /* Watcher enables sending signals from inside of core */
  232. GtkWatcher* gtkWatcher;
  233. /* Command line option parsing */
  234. GError *error = NULL;
  235. GOptionContext* context = g_option_context_new("");
  236. g_option_context_add_main_entries(context, optionEntries, NULL);
  237. g_option_context_add_group(context, gtk_get_option_group(TRUE));
  238. g_option_context_parse(context, &argc, &argv, &error);
  239. if (error != NULL)
  240. {
  241. g_print("Error in command line options. Use --help for full list.n");
  242. exit(1);
  243. }
  244. /* At this point, the argument count should be 1 or 2, with the lastX
  245.  * potentially being a cel:// URL. */
  246. /* If there's an argument left, assume it's a URL. This happens here
  247.  * because it's after the saved prefs are applied. The appCore gets
  248.  * initialized elsewhere. */
  249. if (argc > 1)
  250. app->startURL = argv[argc - 1];
  251. if (installDir == NULL)
  252. installDir = (gchar*)CONFIG_DATA_DIR;
  253. if (chdir(installDir) == -1)
  254. cerr << "Cannot chdir to '" << installDir << "', probably due to improper installation.n";
  255. #ifdef GNOME
  256. /* GNOME Initialization */
  257. GnomeProgram *program;
  258. program = gnome_program_init("Celestia", VERSION, LIBGNOMEUI_MODULE,
  259.                              argc, argv, GNOME_PARAM_NONE);
  260. #else
  261. /* GTK-Only Initialization */
  262. gtk_init(&argc, &argv);
  263. #endif
  264. /* Turn on the splash screen */
  265. SplashData* ss = splashStart(app, !noSplash);
  266. splashSetText(ss, "Initializing...");
  267. SetDebugVerbosity(0);
  268. /* Force number displays into C locale. */
  269. setlocale(LC_NUMERIC, "C");
  270. setlocale(LC_ALL, "");
  271. #ifndef WIN32
  272. bindtextdomain(PACKAGE, LOCALEDIR);
  273. bind_textdomain_codeset(PACKAGE, "UTF-8");
  274. textdomain(PACKAGE);
  275. #endif /* WIN32 */
  276. app->core = new CelestiaCore();
  277. if (app->core == NULL)
  278. {
  279. cerr << "Failed to initialize Celestia core.n";
  280. return 1;
  281. }
  282. app->renderer = app->core->getRenderer();
  283. g_assert(app->renderer);
  284. /* Parse simulation arguments */
  285. string cf;
  286. if (configFile != NULL)
  287. cf = string(configFile);
  288. string* altConfig = (configFile != NULL) ? &cf : NULL;
  289. vector<string> configDirs;
  290. if (extrasDir != NULL)
  291. {
  292. /* Add each extrasDir to the vector */
  293. int i = 0;
  294. while (extrasDir[i] != NULL)
  295. {
  296. configDirs.push_back(extrasDir[i]);
  297. i++;
  298. }
  299. }
  300. /* Initialize the simulation */
  301. if (!app->core->initSimulation(altConfig, &configDirs, ss->notifier))
  302. return 1;
  303. app->simulation = app->core->getSimulation();
  304. g_assert(app->simulation);
  305. #ifdef GNOME
  306. /* Create the main window (GNOME) */
  307. app->mainWindow = gnome_app_new("Celestia", "Celestia");
  308. #else
  309. /* Create the main window (GTK) */
  310. app->mainWindow = gtk_window_new(GTK_WINDOW_TOPLEVEL);
  311. gtk_window_set_title(GTK_WINDOW(app->mainWindow), "Celestia");
  312. #endif /* GNOME */
  313. /* Set pointer to AppData structure. This is for when a function is in a
  314.  * *real* bind to get at this structure. */
  315. g_object_set_data(G_OBJECT(app->mainWindow), "CelestiaData", app);
  316. GtkWidget* mainBox = GTK_WIDGET(gtk_vbox_new(FALSE, 0));
  317. gtk_container_set_border_width(GTK_CONTAINER(mainBox), 0);
  318. g_signal_connect(GTK_OBJECT(app->mainWindow), "destroy",
  319.                  G_CALLBACK(actionQuit), app);
  320. /* Initialize the OpenGL widget */
  321. gtk_gl_init (&argc, &argv);
  322. /* Configure OpenGL. Try double-buffered visual. */
  323. GdkGLConfig* glconfig = gdk_gl_config_new_by_mode(static_cast<GdkGLConfigMode>
  324.                                                   (GDK_GL_MODE_RGB | GDK_GL_MODE_DEPTH | GDK_GL_MODE_DOUBLE));
  325. if (glconfig == NULL)
  326. {
  327. g_print("*** Cannot find the double-buffered visual.n");
  328. g_print("*** Trying single-buffered visual.n");
  329. /* Try single-buffered visual */
  330. glconfig = gdk_gl_config_new_by_mode(static_cast<GdkGLConfigMode>
  331.                                      (GDK_GL_MODE_RGB | GDK_GL_MODE_DEPTH));
  332. if (glconfig == NULL)
  333. {
  334. g_print ("*** No appropriate OpenGL-capable visual found.n");
  335. exit(1);
  336. }
  337. }
  338. /* Initialize settings system */
  339. #ifdef GNOME
  340. initSettingsGConf(app);
  341. #else
  342. initSettingsFile(app);
  343. #endif /* GNOME */
  344. /* Create area to be used for OpenGL display */
  345. app->glArea = gtk_drawing_area_new();
  346. /* Set OpenGL-capability to the widget. */
  347. gtk_widget_set_gl_capability(app->glArea,
  348.                              glconfig,
  349.                              NULL,
  350.                              TRUE,
  351.                              GDK_GL_RGBA_TYPE);
  352. gtk_widget_set_events(GTK_WIDGET(app->glArea),
  353.                       GDK_EXPOSURE_MASK |
  354.                       GDK_KEY_PRESS_MASK |
  355.                       GDK_KEY_RELEASE_MASK |
  356.                       GDK_BUTTON_PRESS_MASK |
  357.                       GDK_BUTTON_RELEASE_MASK |
  358.                       GDK_POINTER_MOTION_MASK);
  359. /* Load settings the can be applied before the simulation is initialized */
  360. #ifdef GNOME
  361. applySettingsGConfPre(app, app->client);
  362. #else
  363. applySettingsFilePre(app, app->settingsFile);
  364. #endif /* GNOME */
  365. /* Full-Screen option from the command line (overrides above). */
  366. if (fullScreen)
  367. app->fullScreen = TRUE;
  368. /* Initialize handlers to all events in the glArea */
  369. initGLCallbacks(app);
  370. /* Handler than completes initialization when the glArea is realized */
  371. g_signal_connect(GTK_OBJECT(app->glArea), "realize",
  372.                  G_CALLBACK(initRealize), app);
  373. /* Create the main menu bar */
  374. createMainMenu(app->mainWindow, app);
  375. /* Initialize the context menu */
  376. initContext(app);
  377. /* Set context menu callback for the core */
  378. app->core->setContextMenuCallback(menuContext);
  379. #ifdef GNOME
  380. /* Set window contents (GNOME) */
  381. gnome_app_set_contents((GnomeApp *)app->mainWindow, GTK_WIDGET(mainBox));
  382. #else
  383. /* Set window contents (GTK) */
  384. gtk_container_add(GTK_CONTAINER(app->mainWindow), GTK_WIDGET(mainBox));
  385. #endif /* GNOME */
  386. gtk_box_pack_start(GTK_BOX(mainBox), app->mainMenu, FALSE, TRUE, 0);
  387. gtk_box_pack_start(GTK_BOX(mainBox), app->glArea, TRUE, TRUE, 0);
  388. gtk_window_set_default_icon_from_file("celestia-logo.png", NULL);
  389. /* Set focus to glArea widget */
  390. GTK_WIDGET_SET_FLAGS(app->glArea, GTK_CAN_FOCUS);
  391. gtk_widget_grab_focus(GTK_WIDGET(app->glArea));
  392. /* Initialize the Watcher */
  393. gtkWatcher = new GtkWatcher(app->core, app);
  394. /* Unload the splash screen */
  395. splashEnd(ss);
  396. gtk_widget_show_all(app->mainWindow);
  397. /* HACK: Now that window is drawn, set minimum window size */
  398. gtk_widget_set_size_request(app->glArea, 320, 240);
  399. #ifdef GNOME
  400. initSettingsGConfNotifiers(app);
  401. #endif /* GNOME */
  402. /* Set the ready flag */
  403. app->bReady = TRUE;
  404. /* Call Main GTK Loop */
  405. gtk_main();
  406.     
  407. g_free(app);
  408. return 0;
  409. }
  410. #ifdef WIN32
  411. int APIENTRY WinMain(HINSTANCE hInstance,
  412.                      HINSTANCE hPrevInstance,
  413.                      LPSTR lpCmdLine,
  414.                      int nCmdShow)
  415. {
  416. return main(__argc, __argv);
  417. }
  418. #endif /* WIN32 */