1 /*
2 * CRRCsim - the Charles River Radio Control Club Flight Simulator Project
3 *
4 * Copyright (C) 2005, 2008 Olivier Bordes (original author)
5 * Copyright (C) 2005 Lionel Cailler
6 * Copyright (C) 2005, 2009-2010 Jens Wilhelm Wulf
7 * Copyright (C) 2005-2009 Jan Reucker
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License version 2
11 * as published by the Free Software Foundation.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330,
21 * Boston, MA 02111-1307, USA.
22 *
23 */
24
25 /**
26 * \file handlerF3A.cpp
27 *
28 * Purpose: Add F3A functions to crrcsim.
29 * F3A is a FAI category which define aerobatics contest
30 */
31 #include "../../i18n.h"
32 #include "../../include_gl.h"
33
34 #include <stdlib.h>
35 #include <stdio.h>
36 #include <math.h>
37 #include <iostream>
38 #include "../../global.h"
39 #include "../../aircraft.h"
40 #include "../../crrc_soundserver.h"
41 #include "../../global_video.h"
42 #include "../../crrc_system.h"
43 #include "../../mod_misc/ls_constants.h"
44 #include "../../mod_misc/SimpleXMLTransfer.h"
45 #include "../../mod_misc/lib_conversions.h"
46 #include "../../mod_misc/filesystools.h"
47 #include "../../mod_landscape/crrc_scenery.h"
48 #include "../../record.h"
49 #include "../../robots.h"
50 #include "../../mod_robots/marker.h"
51 #include "../../mod_video/fonts.h"
52 #include "../../mod_video/gloverlay.h"
53 #include "../../SimStateHandler.h"
54 #include "handlerF3A.h"
55 using namespace std;
56
57 #ifndef TRUE
58 #define TRUE 1
59 #endif
60
61 #ifndef FALSE
62 #define FALSE 0
63 #endif
64
65 /** \brief The default constructor
66 *
67 * Creates an F3A game handler
68 */
HandlerF3A()69 HandlerF3A::HandlerF3A()
70 {
71 prepareConfigFile(cfgfile);
72 //retrieve information from config file
73 draw_grid = cfgfile->getInt("game.f3a.draw_grid");
74 draw_trajectory = cfgfile->getInt("game.f3a.draw_trajectory");
75 draw_indicators = cfgfile->getInt("game.f3a.draw_indicators");
76 persistence = cfgfile->getInt("game.f3a.trajectory_persistence");
77 tolerance = cfgfile->getInt("game.f3a.attitude_tolerance");
78
79 SimpleXMLTransfer* f3acfg = cfg->getCurLocCfgPtr(cfgfile)->getChild("game.f3a", true);
80 grid_size = f3acfg->getInt ("grid_size");
81 flight_height = f3acfg->getInt ("flight_height");
82 flight_distance = f3acfg->getInt ("flight_distance");
83 set_orientation(f3acfg->getInt("orientation") );
84 center_grid_position_north = f3acfg->getInt("position_north");
85 center_grid_position_east = f3acfg->getInt("position_east");
86 center_grid_position_elev = Global::scenery->getHeight(
87 center_grid_position_north,
88 center_grid_position_east);
89
90 window_xsize = 0;
91 window_ysize = 0;
92
93 // states for OpenGL rendering
94 trajectory_rendering_state = new ssgSimpleState();
95 trajectory_rendering_state->disable(GL_CULL_FACE);
96 trajectory_rendering_state->disable(GL_COLOR_MATERIAL);
97 trajectory_rendering_state->disable(GL_TEXTURE_2D);
98 trajectory_rendering_state->disable(GL_LIGHTING);
99 trajectory_rendering_state->enable(GL_BLEND);
100 trajectory_rendering_state->enable(GL_LINE_SMOOTH);
101
102 grid_rendering_state = new ssgSimpleState();
103 grid_rendering_state->disable(GL_CULL_FACE);
104 grid_rendering_state->disable(GL_COLOR_MATERIAL);
105 grid_rendering_state->disable(GL_TEXTURE_2D);
106 grid_rendering_state->disable(GL_LIGHTING);
107 grid_rendering_state->enable(GL_BLEND);
108 grid_rendering_state->enable(GL_LINE_SMOOTH);
109
110 text_rendering_state = new ssgSimpleState();
111 text_rendering_state->disable(GL_CULL_FACE);
112 text_rendering_state->disable(GL_COLOR_MATERIAL);
113 text_rendering_state->disable(GL_TEXTURE_2D);
114 text_rendering_state->disable(GL_LIGHTING);
115 text_rendering_state->enable(GL_BLEND);
116 text_rendering_state->setMaterial(GL_EMISSION, 0.0, 0.0, 0.0, 0.0);
117 text_rendering_state->setMaterial(GL_AMBIENT, 1.0, 1.0, 1.0, 1.0);
118 text_rendering_state->setMaterial(GL_DIFFUSE, 1.0, 1.0, 1.0, 1.0);
119 text_rendering_state->setMaterial(GL_SPECULAR, 0.0, 0.0, 0.0, 0.1);
120
121 reset();
122 }
123
124
125 /** \brief The destructor.
126 *
127 * Deletes an F3A game handler
128 */
~HandlerF3A()129 HandlerF3A::~HandlerF3A()
130 {
131 delete grid_rendering_state;
132 delete trajectory_rendering_state;
133 delete text_rendering_state;
134 }
135
136
137 /** \brief Render game-mode-specific details
138 *
139 * This method renders graphics objects that are specific to the
140 * F3F game mode, namely the base pylons.
141 */
draw()142 void HandlerF3A::draw()
143 {
144 if (Global::testmode)
145 return;
146
147 if (draw_grid)
148 {
149 grid_rendering_state->apply();
150 draw_f3a_grid();
151 }
152 if (draw_trajectory)
153 {
154 trajectory_rendering_state->apply();
155 draw_f3a_trajectory();
156 }
157 }
158
159
160 /** \brief Print the game-mode-specific text overlay
161 *
162 * This method renders the text overlay for the F3A mode.
163 *
164 * \todo This method should use PLIB instead of GLUT for font rendering.
165 *
166 * \param ww current OpenGL window width
167 * \param hh current OpenGL window height
168 */
display_infos(GLfloat ww,GLfloat hh)169 void HandlerF3A::display_infos(GLfloat ww, GLfloat hh)
170 {
171 int y_offset;
172 int lineheight = 35;
173 char astring[256];
174
175 window_xsize = ww;
176 window_ysize = hh;
177
178 if (draw_indicators)
179 {
180 // draw indicators overlay
181 GlOverlay::setupRenderingState(window_xsize, window_ysize);
182 draw_f3a_indicators(window_xsize, window_ysize);
183 GlOverlay::restoreRenderingState();
184 }
185
186 startTextRendering();
187 text_rendering_state->apply();
188
189 if (ww <= 800)
190 {
191 if (Video::textureFont)
192 {
193 fontRenderer.setFont(Video::textureFont);
194 fontRenderer.setPointSize(16);
195 }
196 else fontRenderer.setFont(fntGetBitmapFont(FNT_BITMAP_HELVETICA_18));
197 y_offset = 45;
198 lineheight = 27;
199 }
200 else
201 {
202 if (Video::textureFont)
203 {
204 fontRenderer.setFont(Video::textureFont);
205 fontRenderer.setPointSize(22);
206 }
207 else fontRenderer.setFont(fntGetBitmapFont(FNT_BITMAP_TIMES_ROMAN_24));
208 y_offset = 55;
209 lineheight = 36;
210 }
211
212 // debug string
213 sprintf(astring, "- F3A -");
214 output(window_xsize/2 - textLength(astring)/2,
215 window_ysize - y_offset - 0*lineheight,
216 astring);
217
218 finishTextRendering();
219 }
220
221
222 /** \brief Switch to a text rendering state/projection
223 *
224 * Sets up the OpenGL projection matrix for 2D text rendering.
225 */
startTextRendering() const226 void HandlerF3A::startTextRendering() const
227 {
228 glMatrixMode(GL_PROJECTION);
229 glPushMatrix();
230
231 glLoadIdentity();
232 gluOrtho2D(0, window_xsize, 0, window_ysize);
233 }
234
235
236 /** \brief Switch back to 3D rendering
237 *
238 * Revert the changes done in startTextRendering()
239 */
finishTextRendering() const240 void HandlerF3A::finishTextRendering() const
241 {
242 glPopMatrix();
243 glMatrixMode(GL_MODELVIEW);
244 }
245
246
247 /** \brief Render a text string
248 *
249 * This method renders a string at a given position using the
250 * specified font.
251 *
252 * \todo This method should use PLIB instead of GLUT for font rendering.
253 *
254 * \param x Horizontal start of text
255 * \param y Vertical start of text
256 * \param text the string to be displayed
257 */
output(GLfloat x,GLfloat y,const char * text)258 void HandlerF3A::output(GLfloat x, GLfloat y, const char *text)
259 {
260 fontRenderer.begin();
261 glColor4f(1, 0.3, 0.3, 0.7);
262 fontRenderer.start2f(x, y);
263 fontRenderer.puts(text);
264 fontRenderer.end();
265 }
266
267
268 /** \brief Calculate the length of a rendered text string
269 *
270 * This method calculates the length of a text string rendered
271 * in the current font.
272 *
273 * \param text pointer to the text to be rendered
274 * \return width of the rendered text string
275 */
textLength(const char * text) const276 GLfloat HandlerF3A::textLength(const char *text) const
277 {
278 float left, right;
279
280 fontRenderer.getFont()->getBBox(text,
281 fontRenderer.getPointSize(),
282 fontRenderer.getSlant(),
283 &left, &right,
284 NULL, NULL);
285 return (right - left);
286 }
287
288
289 /** \brief Reset the game handler.
290 *
291 * Everything will be reset to be ready for a new run.
292 */
reset()293 void HandlerF3A::reset()
294 {
295 // reset trajectory storage
296 traj_t0 = 0;
297 traj_first = MAX_TRAJ - 1;
298 traj_last = 0;
299
300 // reset trajectory slope angle
301 THETA_cg = 0.;
302 }
303
304
305 /** \brief Cyclic game-handler function for F3A
306 *
307 * Check if the model cross pylons A or pylons B.
308 * Increase BASE counter.
309 */
update(float a,float b,float c,FlightRecorder * recorder,Robots * robots)310 void HandlerF3A::update(float a, float b, float c, FlightRecorder* recorder, Robots* robots)
311 {
312 if (Global::testmode)
313 return;
314
315 // save previous cg coords
316 float xx_cg_old = XX_cg_grd;
317 float yy_cg_old = YY_cg_grd;
318 float zz_cg_old = ZZ_cg_grd;
319
320 //convert coords on F3A coords
321 float a0 = a - center_grid_position_north;
322 float b0 = b - center_grid_position_east;
323 float c0 = c - center_grid_position_elev;
324 XX_cg_grd = - b0 * cos_dir + a0 * sin_dir;
325 YY_cg_grd = + a0 * cos_dir + b0 * sin_dir;
326 ZZ_cg_grd = c0;
327
328 // compute cg trajectory slope angle
329 THETA_cg = 0.0;
330 if (traj_t0)
331 {
332 float dx = XX_cg_grd - xx_cg_old;
333 float dy = YY_cg_grd - yy_cg_old;
334 float dz = ZZ_cg_grd - zz_cg_old;
335 float dl = sqrt(dx*dx + dy*dy + dz*dz);
336 if (dl > 0.1)
337 {
338 float dd = sqrt(dx*dx + dy*dy);
339 THETA_cg = atan2(dz,dd);
340 }
341 }
342
343 // advance buffer index, avoid overwriting
344 if (++traj_first == MAX_TRAJ)
345 traj_first = 0;
346 if (traj_t0 && (traj_first == traj_last))
347 {
348 if (++traj_last == MAX_TRAJ)
349 traj_last = 0;
350 }
351
352 // save trajectory in circular buffer
353 traj_x[traj_first] = a;
354 traj_y[traj_first] = b;
355 traj_z[traj_first] = c;
356 traj_t[traj_first] = Global::Simulation->getSimulationTimeSinceReset();
357 traj_CL[traj_first] = Global::aircraft->getFDM()->getFlightCL();
358 if (!traj_t0)
359 traj_t0 = traj_t[traj_first];
360
361 // identify last time sample
362 int t_last = traj_t[traj_first] - persistence*1000;
363 if (t_last < traj_t0)
364 t_last = traj_t0;
365 while (traj_t[traj_last] < t_last)
366 {
367 if (++traj_last == MAX_TRAJ)
368 traj_last = 0;
369 }
370 }
371
372 /** \brief Prepare the config file
373 *
374 * This function checks if the config file contains all tags needed
375 * to store the F3A configuration. If a tag is missing, it is
376 * created and filled with a sensible default value.
377 *
378 * \param cfgfile Pointer to the config file
379 */
prepareConfigFile(SimpleXMLTransfer * cfgfile)380 void HandlerF3A::prepareConfigFile(SimpleXMLTransfer *cfgfile)
381 {
382 int grid_size, flight_height, flight_distance, orientation, position_north, position_east;
383
384 //general F3A-options
385 cfgfile->makeSureAttributeExists("game.f3a.enabled", "0");
386 cfgfile->makeSureAttributeExists("game.f3a.draw_grid", "0");
387 cfgfile->makeSureAttributeExists("game.f3a.draw_trajectory", "0");
388 cfgfile->makeSureAttributeExists("game.f3a.draw_indicators", "0");
389 cfgfile->makeSureAttributeExists("game.f3a.trajectory_persistence", "30");
390 cfgfile->makeSureAttributeExists("game.f3a.attitude_tolerance", "2");
391
392 //location specifics parameters
393 SimpleXMLTransfer *xml_scenery = Global::scenery->getXMLsection("F3A");
394 if (!xml_scenery) xml_scenery = Global::scenery->getXMLsection("f3a");
395 if (xml_scenery)
396 {
397 //retrieve information from scenery file description
398 grid_size = xml_scenery->attributeAsInt("grid_size", 100);
399 flight_height = xml_scenery->attributeAsInt("flight_height", 100);
400 flight_distance = xml_scenery->attributeAsInt("flight_distance", 500);
401 orientation = xml_scenery->attributeAsInt("orientation", 0);
402 position_north = xml_scenery->attributeAsInt("position_north", 0);
403 position_east = xml_scenery->attributeAsInt("position_east", 0);
404 }
405 else
406 {
407 //default value
408 grid_size = 100;
409 flight_height = 100;
410 flight_distance = 500;
411 orientation = 0;
412 position_north = 0;
413 position_east = 0;
414 }
415 //put on location section on configfile
416 SimpleXMLTransfer* f3acfg = cfg->getCurLocCfgPtr(cfgfile)->getChild("game.f3a", true);
417 char buf[100];
418 sprintf(buf,"%d",grid_size);
419 f3acfg->makeSureAttributeExists("grid_size", buf);
420 sprintf(buf,"%d",flight_height);
421 f3acfg->makeSureAttributeExists("flight_height", buf);
422 sprintf(buf,"%d",flight_distance);
423 f3acfg->makeSureAttributeExists("flight_distance", buf);
424 sprintf(buf,"%d",orientation);
425 f3acfg->makeSureAttributeExists("orientation", buf);
426 sprintf(buf,"%d",position_north);
427 f3acfg->makeSureAttributeExists("position_north",buf);
428 sprintf(buf,"%d",position_east);
429 f3acfg->makeSureAttributeExists("position_east",buf);
430 }
431
432
GetRecordHeader()433 SimpleXMLTransfer* HandlerF3A::GetRecordHeader()
434 {
435 SimpleXMLTransfer* header = new SimpleXMLTransfer();
436 header->setAttribute("mode", "F3A");
437 return(header);
438 }
439
440
draw_f3a_grid() const441 void HandlerF3A::draw_f3a_grid() const
442 {
443 GLfloat htan = tan(H_ANGLE*M_PI/180.);
444 GLfloat vtan = tan(V_ANGLE*M_PI/180.);
445 GLfloat xl, xr, y, zb, zt;
446
447 // grid plane dimensions, relative to base center
448 // y positive to the front, x positive to the left
449 y = flight_distance;
450 xr = y*htan;
451 xl = - xr;
452 zb = flight_height;
453 zt = y*vtan;
454
455 draw_f3a_grid_plane(xl, xr, y, zb, zt);
456 }
457
458
draw_f3a_grid_plane(GLfloat xl,GLfloat xr,GLfloat y,GLfloat zb,GLfloat zt) const459 void HandlerF3A::draw_f3a_grid_plane(GLfloat xl, GLfloat xr, GLfloat y, GLfloat zb, GLfloat zt) const
460 {
461 GLfloat ln, le, cn, ce, rn, re, z1, z2;
462 GLfloat x, z;
463 GLfloat alpha0 = 0.5;
464 GLfloat color_alpha[] = {1,0,0, alpha0};
465
466 // grid plane world coords
467 ln = center_grid_position_north + y * cos_dir - xl * sin_dir;
468 cn = center_grid_position_north + y * cos_dir;
469 rn = center_grid_position_north + y * cos_dir - xr * sin_dir;
470 le = center_grid_position_east + y * sin_dir + xl * cos_dir;
471 ce = center_grid_position_east + y * sin_dir;
472 re = center_grid_position_east + y * sin_dir + xr * cos_dir;
473 z1 = center_grid_position_elev + zb;
474 z2 = center_grid_position_elev + zt;
475
476 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
477 glColor4fv(color_alpha);
478
479 // draw grid bottom and center line
480 glLineWidth(4.0);
481 glBegin(GL_LINES);
482 glVertex3f(le, z1, -ln);
483 glVertex3f(re, z1, -rn);
484 glEnd();
485
486 glBegin(GL_LINES);
487 glVertex3f(ce, z1, -cn);
488 glVertex3f(ce, z2, -cn);
489 glEnd();
490
491 // draw grid perimeter
492 color_alpha[3] = alpha0*0.2;
493 glColor4fv(color_alpha);
494 glLineWidth(4.0);
495 glBegin(GL_LINE_STRIP);
496 glVertex3f(le, z1, -ln);
497 glVertex3f(le, z2, -ln);
498 glVertex3f(re, z2, -rn);
499 glVertex3f(re, z1, -rn);
500 glEnd();
501
502 // draw vertical grid lines
503 glLineWidth(1.0);
504 x = 0.0 + grid_size;
505 while (x < xr)
506 {
507 color_alpha[3] = alpha0*(0.8*(1. - x/xr) + 0.2);
508 glColor4fv(color_alpha);
509 glBegin(GL_LINES);
510 glVertex3f(ce - x*cos_dir, z1, -(cn + x*sin_dir));
511 glVertex3f(ce - x*cos_dir, z2, -(cn + x*sin_dir));
512 glVertex3f(ce + x*cos_dir, z1, -(cn - x*sin_dir));
513 glVertex3f(ce + x*cos_dir, z2, -(cn - x*sin_dir));
514 glEnd();
515
516 x += grid_size;
517 }
518
519 // draw horizontal grid lines
520 glLineWidth(1.0);
521 z = z1 + grid_size;
522 while (z < z2)
523 {
524 color_alpha[3] = alpha0*(0.8*(1. - (z - z1)/(z2 - z1)) + 0.2);
525 glColor4fv(color_alpha);
526 glBegin(GL_LINES);
527 glVertex3f(le, z, -ln);
528 glVertex3f(re, z, -rn);
529 glEnd();
530
531 z += grid_size;
532 }
533
534 glLineWidth(1.0);
535 }
536
537
draw_f3a_trajectory() const538 void HandlerF3A::draw_f3a_trajectory() const
539 {
540 GLfloat alpha0 = 0.4;
541 GLfloat a, b, x, y, north, east;
542 GLfloat color1_alpha[] = {0,0,0, alpha0};
543 GLfloat color2_alpha[] = {1,0,0, alpha0};
544
545 if (traj_t0)
546 {
547 int t_blur = traj_t[traj_last] + 1000;
548
549 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
550 glLineStipple(2, 0x0F0F); // dashed line pattern
551
552 // draw 3D trajectory line
553 int segment = 0;
554 int i = traj_last;
555 int n = traj_first;
556 if (++n == MAX_TRAJ)
557 n = 0;
558
559 glLineWidth(3.0);
560 while (i != n)
561 {
562 if (traj_t[i] < t_blur)
563 color1_alpha[3] = alpha0*(1. - (t_blur - traj_t[i])/1000.);
564 else
565 color1_alpha[3] = alpha0;
566
567 if (!segment)
568 {
569 if (traj_CL[i] >= 0.0)
570 {
571 segment = 1;
572 glDisable(GL_LINE_STIPPLE);
573 glBegin(GL_LINE_STRIP);
574 }
575 else
576 {
577 segment = -1;
578 glEnable(GL_LINE_STIPPLE);
579 glBegin(GL_LINE_STRIP);
580 }
581 }
582 glColor4fv(color1_alpha);
583 glVertex3f(traj_y[i], traj_z[i], -traj_x[i]);
584
585 if (segment*traj_CL[i] > 0.0)
586 {
587 if (++i == MAX_TRAJ)
588 i = 0;
589 }
590 else
591 {
592 glEnd();
593 segment = 0;
594 }
595 }
596 glEnd();
597 glDisable(GL_LINE_STIPPLE);
598
599 // draw 2D trajectory line on grid plane
600 if (draw_grid)
601 {
602 int segment = 0;
603 int i = traj_last;
604 int n = traj_first;
605 if (++n == MAX_TRAJ)
606 n = 0;
607
608 glLineWidth(3.0);
609 while (i != n)
610 {
611 //convert world coords to F3A grid coords
612 a = traj_x[i] - center_grid_position_north;
613 b = traj_y[i] - center_grid_position_east;
614 x = b * cos_dir - a * sin_dir;
615 y = a * cos_dir + b * sin_dir;
616 // project to grid plane
617 y = flight_distance;
618 // convert back to world coords
619 north = center_grid_position_north + y * cos_dir - x * sin_dir;
620 east = center_grid_position_east + y * sin_dir + x * cos_dir;
621
622 if (traj_t[i] < t_blur)
623 color2_alpha[3] = alpha0*(1. - (t_blur - traj_t[i])/1000.);
624 else
625 color2_alpha[3] = alpha0;
626
627 if (!segment)
628 {
629 if (traj_CL[i] >= 0.0)
630 {
631 segment = 1;
632 glDisable(GL_LINE_STIPPLE);
633 glBegin(GL_LINE_STRIP);
634 }
635 else
636 {
637 segment = -1;
638 glEnable(GL_LINE_STIPPLE);
639 glBegin(GL_LINE_STRIP);
640 }
641 }
642 glColor4fv(color2_alpha);
643 glVertex3f(east, traj_z[i], -north);
644
645 if (segment*traj_CL[i] > 0.0)
646 {
647 if (++i == MAX_TRAJ)
648 i = 0;
649 }
650 else
651 {
652 glEnd();
653 segment = 0;
654 }
655 }
656 glEnd();
657 glDisable(GL_LINE_STIPPLE);
658 }
659
660 glLineWidth(1.0);
661 }
662 }
663
664
draw_f3a_indicators(int window_xsize,int window_ysize) const665 void HandlerF3A::draw_f3a_indicators(int window_xsize, int window_ysize) const
666 {
667 // pitch from aircraft attitude
668 //GLfloat pitch = Global::aircraft->getFDM()->getTheta() * SG_RADIANS_TO_DEGREES;
669 //draw_f3a_horizon(window_xsize, window_ysize, 0, pitch);
670
671 // pitch from cg trajectory slope
672 GLfloat pitch = THETA_cg * SG_RADIANS_TO_DEGREES;
673 draw_f3a_horizon(window_xsize, window_ysize, 0, pitch);
674
675 GLfloat roll = Global::aircraft->getFDM()->getPhi() * SG_RADIANS_TO_DEGREES;
676 draw_f3a_horizon(window_xsize, window_ysize, 1, -roll);
677 }
678
679
draw_f3a_horizon(int window_xsize,int window_ysize,int position,GLfloat angle) const680 void HandlerF3A::draw_f3a_horizon(int window_xsize, int window_ysize, int position, GLfloat angle) const
681 {
682 int basex = 1.5*(window_ysize >> 5);
683 int basey = 2.0*(window_ysize >> 5);
684 int r = window_ysize >> 4;
685 int gap = r >> 3;
686 int tic = 0.5*gap;
687 int w = 2*(r + gap);
688 int h = 2*gap;
689 int i;
690
691 GLfloat alpha = 0.6;
692 GLfloat white[] = {1,1,1};
693 GLfloat black[] = {0,0,0};
694 GLfloat red[] = {1,0,0};
695 GLfloat white_alpha[] = {1,1,1, alpha};
696 GLfloat black_alpha[] = {0,0,0, alpha};
697 GLfloat ground_alpha[] = {.375,.275,0, alpha};
698 GLfloat sky_alpha[] = {0,.75,1, alpha};
699
700 GLUquadricObj *quadric;
701 quadric = gluNewQuadric();
702
703 // draw pitch or roll indicator
704
705 basey += position*w; // stack indicators on top of previous
706
707 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
708 glPushMatrix();
709 glTranslatef(basex + w/2, basey + w/2, 0);
710
711 // horizon
712 glColor4fv(black);
713 gluDisk(quadric, r, r+2, 32, 1);
714 //glRecti(-w/2, -w/2, w/2, w/2);
715 glColor4fv(ground_alpha);
716 gluPartialDisk(quadric, 0, r, 32, 1, 90 + angle, 180);
717 glColor4fv(sky_alpha);
718 gluPartialDisk(quadric, 0, r, 32, 1, 270 + angle, 180);
719
720 // marks
721 glColor3fv(white);
722 for (i = 0; i < 24; i++)
723 {
724 if (i % 3)
725 {
726 glLineWidth(1.0);
727 glBegin(GL_LINES);
728 glVertex2i( r, 0);
729 glVertex2i(r - tic, 0);
730 glEnd();
731 }
732 else
733 {
734 glLineWidth(2.0);
735 glBegin(GL_LINES);
736 glVertex2i( r, 0);
737 glVertex2i(r - gap, 0);
738 glEnd();
739 }
740 glRotatef(15, 0, 0, 1);
741 }
742
743 // airplane silouette
744 if (fabs(angle - 45.0*floor((angle + 0.5)/45.0)) <= tolerance)
745 glColor3fv(red);
746 else
747 glColor3fv(black);
748 glLineWidth(2.0);
749 glBegin(GL_LINES);
750 glVertex2i(-(r - gap), 0);
751 glVertex2i( r - gap, 0);
752 glEnd();
753 if (position == 0)
754 {
755 // pitch indicator
756 glBegin(GL_TRIANGLES);
757 glVertex2i( r - gap, 0);
758 glVertex2i(r - gap - h, h/2);
759 glVertex2i(r - gap - h, -h/2);
760 glEnd();
761
762 glColor4fv(black_alpha);
763 gluPartialDisk(quadric, 0, h, 16, 1, 0, 90);
764 gluPartialDisk(quadric, 0, h, 16, 1, 180, 90);
765 glColor4fv(white_alpha);
766 gluPartialDisk(quadric, 0, h, 16, 1, 90, 90);
767 gluPartialDisk(quadric, 0, h, 16, 1, 270, 90);
768 }
769 else
770 {
771 // roll indicator
772 glBegin(GL_TRIANGLES);
773 glVertex2i(-h/2, 0);
774 glVertex2i( 0, h);
775 glVertex2i( h/2, 0);
776 glEnd();
777 }
778 glLineWidth(1.0);
779 glPopMatrix();
780
781 gluDeleteQuadric(quadric);
782 }
783