1 /*
2     OpenUniverse 1.0
3     Copyright (C) 2000  Raul Alonso <amil@las.es>
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     This program is distributed in the hope that it will be useful,
11     but WITHOUT ANY WARRANTY; without even the implied warranty of
12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13     GNU General Public License for more details.
14 
15     You should have received a copy of the GNU General Public License
16     along with this program; if not, write to the Free Software
17     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 */
19 
20 #include "ou.h"
21 #include "gui.h"
22 
23 #ifdef HAVE_GLUI
24 
25 GLUI *glui_rwin = NULL, *glui_trailwin, *glui_optwin = NULL;
26 GLUI_Listbox *list_source, *list_target;
27 GLUI_Panel *control_panel;
28 GLUI_Translation *head_trans, *roll_trans;
29 GLUI_Checkbox *glui_follow;
30 GLUI_RadioGroup *radio;
31 GLUI_RadioButton *cam1, *cam2, *cam3, *cam4;
32 GLUI_Translation *trans_zoom;
33 int fullscreeninGUI = 0, rebuildStarsDL = 0;
34 
35 /*
36     GLUI callback
37 */
38 
update_cmode(void)39 void update_cmode(void)
40 {
41 	int type;
42 
43 
44 	type = ISASPACECRAFT(currtarget);
45 
46 	if (type)
47 		glui_follow->enable();
48 	else
49 		glui_follow->disable();
50 
51 
52 	if (follow && type) {
53 		cam1->set_name("Behind");
54 		cam2->set_name("Top");
55 		cam3->set_name("Right");
56 		cam4->set_name("Left");
57 		list_target->enable();
58 		trans_zoom->enable();
59 		head_trans->enable();
60 		roll_trans->enable();
61 	} else {
62 		cam1->set_name("Free");
63 		cam2->set_name("Linked");
64 		cam3->set_name("Body to Body");
65 		cam4->set_name("Orbiter");
66 		switch (cmode) {
67 		case 0:
68 		case 1:
69 			trans_zoom->disable();
70 			head_trans->disable();
71 			roll_trans->disable();
72 			break;
73 		case 2:
74 		case 3:
75 			trans_zoom->enable();
76 			break;
77 		}
78 	}
79 
80 
81 }
82 
glui_callback(int cmd)83 void glui_callback(int cmd)
84 {
85 
86 #define CX(s) (s->ball->down_pt[0]-s->ball->center[0])
87 #define CY(s) (s->ball->down_pt[1]-s->ball->center[1])
88 
89 	static GLUI_Spinner *spinner;
90 	static int i;
91 
92 	switch (cmd) {
93 	case OPT_OPEN:
94 		if (glui_optwin) {
95 			glui_optwin->show();
96 		} else {
97 			glui_optwin = GLUI_Master.create_glui("Options");
98 			glui_optwin->add_checkbox("Demo", &demomode);
99 			glui_optwin->add_checkbox("Pause", &paused);
100 			glui_optwin->add_separator();
101 			glui_optwin->add_checkbox("Atmosphere", &atmospheres);
102 			glui_optwin->add_checkbox("Lighting", &lighting);
103 			glui_optwin->add_checkbox("Textures", &texture);
104 			glui_optwin->add_checkbox("Stars", &drawstars);
105 			glui_optwin->add_checkbox("Milky Way", &milkyway);
106 			glui_optwin->add_checkbox("Messier Objects", &messier);
107 			glui_optwin->add_separator();
108 			glui_optwin->add_checkbox("Info", &info);
109 			glui_optwin->add_checkbox("Top View Map", &radar);
110 			glui_optwin->add_checkbox("Stars labels", &slabels);
111 			glui_optwin->add_checkbox("Bodies labels", &plabels);
112 			glui_optwin->add_separator();
113 			glui_optwin->add_checkbox("Joystick", &joyactive);
114 			glui_optwin->add_separator();
115 			glui_optwin->add_checkbox("Real time", &realtime);
116 			glui_optwin->add_separator();
117 			spinner =
118 				glui_optwin->add_spinner("Star brightness:",
119 										 GLUI_SPINNER_FLOAT, &star_mag,
120 										 OPT_STARMAG,
121 										 (GLUI_Update_CB) glui_callback);
122 			spinner->set_float_limits(0.0, 10.0);
123 			glui_optwin->add_button("Trails", TRAILS_OPEN,
124 									(GLUI_Update_CB) glui_callback);
125 			glui_optwin->add_button("Close", OPT_HIDE,
126 									(GLUI_Update_CB) glui_callback);
127 		}
128 		break;
129 	case OPT_HIDE:
130 		glui_optwin->hide();
131 		break;
132 	case TRAILS_OPEN:
133 		if (glui_trailwin) {
134 			glui_trailwin->show();
135 		} else {
136 			glui_trailwin = GLUI_Master.create_glui("Trails");
137 			for (i = 0; i < NUMBODIES; i++)
138 				if ((planets[i].Type == PLANET) ||
139 					(planets[i].Type == ASTEROID) ||
140 					(planets[i].Type == COMET))
141 						glui_trailwin->add_checkbox(planets[i].Name,
142 													&planets[i].
143 													TrailEnabled);
144 			glui_trailwin->add_button("Close", TRAILS_HIDE,
145 									  (GLUI_Update_CB) glui_callback);
146 		}
147 		break;
148 	case TRAILS_HIDE:
149 		glui_trailwin->hide();
150 		break;
151 	case CAM_NEAR:
152 		Key('n', 0, 0);
153 		break;
154 	case CAM_CMODE:
155 		i = follow && ISASPACECRAFT(currtarget);
156 		switch (cmode) {
157 		case 0:
158 			list_target->disable();
159 			control_panel->enable();
160 			trans_zoom->disable();
161 			break;
162 		case 1:
163 			transition = 1;
164 			if (!i) {
165 				list_target->enable();
166 				control_panel->disable();
167 			}
168 			break;
169 		case 2:
170 			transition = 1;
171 			if (!i) {
172 				list_target->enable();
173 				control_panel->disable();
174 			}
175 			break;
176 		case 3:
177 			transition = 1;
178 			if (!i) {
179 				list_target->enable();
180 				control_panel->disable();
181 			}
182 			break;
183 		default:
184 			break;
185 		}
186 		update_cmode();
187 		break;
188 	case CAM_FOLLOW:
189 		update_cmode();
190 		break;
191 	case CAM_SOURCE:
192 		if (currsource == currtarget) {
193 			currsource = (currsource + 1) % NUMBODIES;
194 			while (planets[currsource].Type >= RING)
195 				currsource = (currsource + 1) % NUMBODIES;
196 		}
197 		transition = 1;
198 		break;
199 	case CAM_TARGET:
200 		if (currsource == currtarget) {
201 			currtarget = (currtarget + 1) % NUMBODIES;
202 			while (planets[currtarget].Type >= RING)
203 				currtarget = (currtarget + 1) % NUMBODIES;
204 		}
205 		update_cmode();
206 		transition = 1;
207 		break;
208 	case CAM_HEADING:
209 		if (ISASPACECRAFT(currtarget)) {
210 			planets[currtarget].rot[X] = (int) head_trans->get_x();
211 			planets[currtarget].rot[Y] = (int) head_trans->get_y();
212 			CLAMP_SELF(planets[currtarget].rot[X], -64, 64);
213 			CLAMP_SELF(planets[currtarget].rot[Y], -64, 64);
214 			head_trans->set_x((float) planets[currtarget].rot[X]);
215 			head_trans->set_y((float) planets[currtarget].rot[Y]);
216 		} else {
217 			camrot[X] = (int) head_trans->get_x();
218 			camrot[Y] = (int) head_trans->get_y();
219 			CLAMP_SELF(camrot[X], -64, 64);
220 			CLAMP_SELF(camrot[Y], -64, 64);
221 			head_trans->set_x((float) camrot[X]);
222 			head_trans->set_y((float) camrot[Y]);
223 		}
224 		break;
225 	case CAM_ROLL:
226 		if (ISASPACECRAFT(currtarget)) {
227 			planets[currtarget].rot[Z] = (int) roll_trans->get_x();
228 			CLAMP_SELF(planets[currtarget].rot[Z], -64, 64);
229 			roll_trans->set_x((float) planets[currtarget].rot[Z]);
230 		} else {
231 			camrot[Z] = (int) roll_trans->get_x();
232 			CLAMP_SELF(camrot[Z], -64, 64);
233 			roll_trans->set_x((float) camrot[Z]);
234 		}
235 		if (roll_trans->get_y() > 0.0)
236 			Special(GLUT_KEY_PAGE_UP, 0, 0);
237 		if (roll_trans->get_y() < 0.0)
238 			Special(GLUT_KEY_PAGE_DOWN, 0, 0);
239 		roll_trans->set_y(0.0);
240 		break;
241 	case GUI_HIDE:
242 		glui_rwin->hide();
243 		fullscreeninGUI = 1;
244 		Reshape(glutGet((GLenum) GLUT_WINDOW_WIDTH),
245 				glutGet((GLenum) GLUT_WINDOW_HEIGHT));
246 		break;
247 	case GUI_QUIT:
248 		Key(27, 0, 0);
249 		break;
250 	case OPT_STARMAG:
251 		rebuildStarsDL = 1;
252 		break;
253 	default:
254 		break;
255 	}
256 }
257 
258 
259 #endif
260 
261 
GUI_Viewport(int * width,int * height)262 void GUI_Viewport(int *width, int *height)
263 {
264 #ifdef HAVE_GLUI
265 	int tx, ty, tw, th;
266 
267 	if (fullscreeninGUI)
268 		glViewport(0, 0, *width, *height);
269 	else {
270 
271 		GLUI_Master.get_viewport_area(&tx, &ty, &tw, &th);
272 		GLUI_Master.auto_set_viewport();
273 		*width = tw;
274 		*height = th;
275 	}
276 #else
277 	glViewport(0, 0, *width, *height);
278 #endif
279 
280 }
281 
282 
GUI_Init(void)283 void GUI_Init(void)
284 {
285 #ifdef HAVE_GLUI
286 	int i;
287 	char sbuf[80];
288 
289 	if (fullscreen)
290 		return;
291 
292 	GLUI_Master.set_glutKeyboardFunc(Key);
293 	GLUI_Master.set_glutSpecialFunc(Special);
294 	GLUI_Master.set_glutMouseFunc(Mouse);
295 	glutIdleFunc(NULL);
296 	GLUI_Master.set_glutIdleFunc(Idle);
297 
298 	glui_rwin =
299 		GLUI_Master.create_glui_subwindow(main_window,
300 										  GLUI_SUBWINDOW_RIGHT);
301 	glui_rwin->set_main_gfx_window(main_window);
302 
303 
304 	list_source =
305 		glui_rwin->add_listbox("Source:", &currsource, CAM_SOURCE,
306 							   (GLUI_Update_CB) glui_callback);
307 	for (i = 0; i < NUMBODIES; i++)
308 		switch (planets[i].Type) {
309 		case RING:
310 		case ATMOSPHERE:
311 			break;
312 		case SATELLITE:
313 		case ORBITER:
314 			sprintf(sbuf, "  %s", planets[i].Name);
315 			list_source->add_item(i, sbuf);
316 			break;
317 		default:
318 			list_source->add_item(i, planets[i].Name);
319 			break;
320 
321 		}
322 	list_source->enabled = true;
323 
324 
325 	list_target =
326 		glui_rwin->add_listbox("Target:", &currtarget, CAM_TARGET,
327 							   (GLUI_Update_CB) glui_callback);
328 	for (i = 0; i < NUMBODIES; i++)
329 		switch (planets[i].Type) {
330 		case RING:
331 		case ATMOSPHERE:
332 			break;
333 		case SATELLITE:
334 		case ORBITER:
335 			sprintf(sbuf, "  %s", planets[i].Name);
336 			list_target->add_item(i, sbuf);
337 			break;
338 		default:
339 			list_target->add_item(i, planets[i].Name);
340 			break;
341 
342 		}
343 
344 	glui_rwin->add_button("Go there!", CAM_NEAR,
345 						  (GLUI_Update_CB) glui_callback);
346 
347 	GLUI_Panel *camera_panel = glui_rwin->add_panel("Camera Mode");
348 	radio =
349 		glui_rwin->add_radiogroup_to_panel(camera_panel, &cmode, CAM_CMODE,
350 										   (GLUI_Update_CB) glui_callback);
351 	cam1 = glui_rwin->add_radiobutton_to_group(radio, "Free");
352 	cam2 = glui_rwin->add_radiobutton_to_group(radio, "Linked");
353 	cam3 = glui_rwin->add_radiobutton_to_group(radio, "Body to Body");
354 	cam4 = glui_rwin->add_radiobutton_to_group(radio, "Orbiter");
355 	glui_follow =
356 		glui_rwin->add_checkbox_to_panel(camera_panel, "Follow", &follow,
357 										 CAM_FOLLOW,
358 										 (GLUI_Update_CB) glui_callback);
359 	if (ISASPACECRAFT(currtarget))
360 		glui_follow->disable();
361 
362 	control_panel = glui_rwin->add_panel("", GLUI_PANEL_NONE);
363 
364 	head_trans =
365 		glui_rwin->add_translation_to_panel(control_panel, "Heading",
366 											GLUI_TRANSLATION_XY, NULL,
367 											CAM_HEADING,
368 											(GLUI_Update_CB)
369 											glui_callback);
370 
371 	glui_rwin->add_column_to_panel(control_panel, false);
372 
373 
374 	roll_trans =
375 		glui_rwin->add_translation_to_panel(control_panel, "Roll/Speed",
376 											GLUI_TRANSLATION_XY, NULL,
377 											CAM_ROLL,
378 											(GLUI_Update_CB)
379 											glui_callback);
380 
381 	GLUI_Panel *lens_panel = glui_rwin->add_panel("", GLUI_PANEL_NONE);
382 
383 /* Insert extra blank spaces to  avoid misalignment */
384 	GLUI_Translation *trans_fov =
385 		glui_rwin->add_translation_to_panel(lens_panel, "  FOV  ",
386 											GLUI_TRANSLATION_Z, &fov);
387 	trans_fov->set_speed(0.1);
388 	trans_fov->set_z(fov);
389 
390 	glui_rwin->add_column_to_panel(lens_panel, false);
391 
392 	trans_zoom =
393 		glui_rwin->add_translation_to_panel(lens_panel, "   ZOOM   ",
394 											GLUI_TRANSLATION_Z, &zoom);
395 	trans_zoom->set_speed(0.1);
396 	trans_zoom->set_z(zoom);
397 
398 	GLUI_Spinner *glui_tf =
399 		glui_rwin->add_spinner("Timefactor:", GLUI_SPINNER_INT,
400 							   &timefactor);
401 
402 	glui_tf->set_int_limits(-5000, 5000);
403 	glui_tf->set_speed(0.001);
404 
405 	glui_rwin->add_button("Options", OPT_OPEN,
406 						  (GLUI_Update_CB) glui_callback);
407 	glui_rwin->add_button("Hide GUI", GUI_HIDE,
408 						  (GLUI_Update_CB) glui_callback);
409 	glui_rwin->add_button("Quit", GUI_QUIT,
410 						  (GLUI_Update_CB) glui_callback);
411 	if (!cmode)
412 		control_panel->disable();
413 
414 	update_cmode();
415 #endif
416 }
417