1 /*
2 * See Licensing and Copyright notice in naev.h
3 */
4
5 /**
6 * @file gui.c
7 *
8 * @brief Contains the GUI stuff for the player.
9 */
10
11
12 #include "gui.h"
13
14 #include "naev.h"
15
16 #include <stdlib.h>
17
18 #include "player.h"
19 #include "nxml.h"
20 #include "pilot.h"
21 #include "log.h"
22 #include "opengl.h"
23 #include "font.h"
24 #include "ndata.h"
25 #include "space.h"
26 #include "rng.h"
27 #include "land.h"
28 #include "sound.h"
29 #include "economy.h"
30 #include "pause.h"
31 #include "menu.h"
32 #include "toolkit.h"
33 #include "dialogue.h"
34 #include "mission.h"
35 #include "nlua_misn.h"
36 #include "ntime.h"
37 #include "hook.h"
38 #include "map.h"
39 #include "nfile.h"
40 #include "spfx.h"
41 #include "unidiff.h"
42 #include "comm.h"
43 #include "intro.h"
44 #include "perlin.h"
45 #include "ai.h"
46 #include "music.h"
47 #include "nmath.h"
48 #include "gui_osd.h"
49 #include "conf.h"
50 #include "nebula.h"
51 #include "camera.h"
52 #include "pilot.h"
53 #include "nlua.h"
54 #include "nluadef.h"
55 #include "nlua_gfx.h"
56 #include "nlua_gui.h"
57 #include "nlua_tex.h"
58 #include "gui_omsg.h"
59 #include "nstring.h"
60
61
62 #define XML_GUI_ID "GUIs" /**< XML section identifier for GUI document. */
63 #define XML_GUI_TAG "gui" /**< XML Section identifier for GUI tags. */
64
65 #define INTERFERENCE_LAYERS 16 /**< Number of interference layers. */
66 #define INTERFERENCE_CHANGE_DT 0.1 /**< Speed to change at. */
67
68 #define RADAR_BLINK_PILOT 1. /**< Blink rate of the pilot target on radar. */
69 #define RADAR_BLINK_PLANET 1. /**< Blink rate of the planet target on radar. */
70
71
72 /* for interference. */
73 static int interference_layer = 0; /**< Layer of the current interference. */
74 double interference_alpha = 0.; /**< Alpha of the current interference layer. */
75 static double interference_t = 0.; /**< Interference timer to control transitions. */
76
77 /* some blinking stuff. */
78 static double blink_pilot = 0.; /**< Timer on target blinking on radar. */
79 static double blink_planet = 0.; /**< Timer on planet blinking on radar. */
80
81 /* for VBO. */
82 static gl_vbo *gui_vbo = NULL; /**< GUI VBO. */
83 static GLsizei gui_vboColourOffset = 0; /**< Offset of colour pixels. */
84
85 static int gui_getMessage = 1; /**< Whether or not the player should receive messages. */
86
87 /*
88 * pilot stuff for GUI
89 */
90 extern Pilot** pilot_stack; /**< @todo remove */
91 extern int pilot_nstack; /**< @todo remove */
92
93
94 extern int land_wid; /**< From land.c */
95
96
97 /**
98 * GUI Lua stuff.
99 */
100 static nlua_env gui_env = LUA_NOREF; /**< Current GUI Lua environment. */
101 static int gui_L_mclick = 0; /**< Use mouse click callback. */
102 static int gui_L_mmove = 0; /**< Use mouse movement callback. */
103
104
105 /**
106 * Cropping.
107 */
108 static double gui_viewport_x = 0.; /**< GUI Viewport X offset. */
109 static double gui_viewport_y = 0.; /**< GUI Viewport Y offset. */
110 static double gui_viewport_w = 0.; /**< GUI Viewport width. */
111 static double gui_viewport_h = 0.; /**< GUI Viewport height. */
112
113
114 /**
115 * @struct Radar
116 *
117 * @brief Represents the player's radar.
118 */
119 typedef struct Radar_ {
120 double w; /**< Width. */
121 double h; /**< Height. */
122 double x; /**< X position. */
123 double y; /**< Y position. */
124 RadarShape shape; /**< Shape */
125 double res; /**< Resolution */
126 glTexture *interference[INTERFERENCE_LAYERS]; /**< Interference texture. */
127 } Radar;
128 /* radar resolutions */
129 #define RADAR_RES_MAX 100. /**< Maximum radar resolution. */
130 #define RADAR_RES_MIN 10. /**< Minimum radar resolution. */
131 #define RADAR_RES_INTERVAL 10. /**< Steps used to increase/decrease resolution. */
132 #define RADAR_RES_DEFAULT 50. /**< Default resolution. */
133 static Radar gui_radar;
134
135 /* needed to render properly */
136 static double gui_xoff = 0.; /**< X Offset that GUI introduces. */
137 static double gui_yoff = 0.; /**< Y offset that GUI introduces. */
138
139 /* messages */
140 #define MESG_SIZE_MAX 256 /**< Maxmimu message length. */
141 static int mesg_max = 128; /**< Maximum messages onscreen */
142 static int mesg_pointer = 0; /**< Current pointer message is at (for when scrolling. */
143 static int mesg_viewpoint = -1; /**< Position of viewing. */
144 static double mesg_timeout = 15.; /**< Timeout length. */
145 static double mesg_fade = 5.; /**< Fade length. */
146 /**
147 * @struct Mesg
148 *
149 * @brief On screen player message.
150 */
151 typedef struct Mesg_ {
152 char str[MESG_SIZE_MAX]; /**< The message. */
153 double t; /**< Time to live for the message. */
154 glFontRestore restore; /**< Hack for font restoration. */
155 } Mesg;
156 static Mesg* mesg_stack = NULL; /**< Stack of messages, will be of mesg_max size. */
157 static int gui_mesg_w = 0; /**< Width of messages. */
158 static int gui_mesg_x = 0; /**< X positioning of messages. */
159 static int gui_mesg_y = 0; /**< Y positioning of messages. */
160
161 /* Calculations to speed up borders. */
162 static double gui_tr = 0.; /**< Border top-right. */
163 static double gui_br = 0.; /**< Border bottom-right. */
164 static double gui_tl = 0.; /**< Border top-left. */
165 static double gui_bl = 0.; /**< Border bottom-left. */
166
167 /* Intrinsic graphical stuff. */
168 static glTexture *gui_ico_hail = NULL; /**< Hailing icon. */
169 static glTexture *gui_target_planet = NULL; /**< Planet targeting icon. */
170 static glTexture *gui_target_pilot = NULL; /**< Pilot targeting icon. */
171
172
173 /*
174 * prototypes
175 */
176 /*
177 * external
178 */
179 extern void weapon_minimap( const double res, const double w, const double h,
180 const RadarShape shape, double alpha ); /**< from weapon.c */
181 /*
182 * internal
183 */
184 /* gui */
185 static void gui_createInterference( Radar *radar );
186 static void gui_borderIntersection( double *cx, double *cy, double rx, double ry, double hw, double hh );
187 /* Render GUI. */
188 static void gui_renderPilotTarget( double dt );
189 static void gui_renderPlanetTarget( double dt );
190 static void gui_renderBorder( double dt );
191 static void gui_renderMessages( double dt );
192 static const glColour *gui_getPlanetColour( int i );
193 static void gui_renderRadarOutOfRange( RadarShape sh, int w, int h, int cx, int cy, const glColour *col );
194 static void gui_planetBlink( int w, int h, int rc, int cx, int cy, GLfloat vr, RadarShape shape );
195 static const glColour* gui_getPilotColour( const Pilot* p );
196 static void gui_renderInterference (void);
197 static void gui_calcBorders (void);
198 /* Lua GUI. */
199 static int gui_doFunc( const char* func );
200 static int gui_prepFunc( const char* func );
201 static int gui_runFunc( const char* func, int nargs, int nret );
202
203
204
205 /**
206 * Sets the GUI to defaults.
207 */
gui_setDefaults(void)208 void gui_setDefaults (void)
209 {
210 gui_radar.res = RADAR_RES_DEFAULT;
211 memset( mesg_stack, 0, sizeof(Mesg)*mesg_max );
212 }
213
214
215 /**
216 * @brief Initializes the message system.
217 *
218 * @param x X position to set at.
219 * @param y Y position to set at.
220 */
gui_messageInit(int width,int x,int y)221 void gui_messageInit( int width, int x, int y )
222 {
223 gui_mesg_w = width;
224 gui_mesg_x = x;
225 gui_mesg_y = y;
226 }
227
228
229 /**
230 * @brief Scrolls up the message box.
231 *
232 * @param lines Number of lines to scroll up.
233 */
gui_messageScrollUp(int lines)234 void gui_messageScrollUp( int lines )
235 {
236 int o;
237
238 /* Handle hacks. */
239 if (mesg_viewpoint == -1) {
240 mesg_viewpoint = mesg_pointer;
241 return;
242 }
243
244 /* Get offset. */
245 o = mesg_pointer - mesg_viewpoint;
246 if (o < 0)
247 o += mesg_max;
248 o = mesg_max - 2*conf.mesg_visible - o;
249
250
251 /* Calculate max line movement. */
252 if (lines > o)
253 lines = o;
254
255 /* Move viewpoint. */
256 mesg_viewpoint = (mesg_viewpoint - lines) % mesg_max;
257 }
258
259
260 /**
261 * @brief Scrolls up the message box.
262 *
263 * @param lines Number of lines to scroll up.
264 */
gui_messageScrollDown(int lines)265 void gui_messageScrollDown( int lines )
266 {
267 int o;
268
269 /* Handle hacks. */
270 if (mesg_viewpoint == mesg_pointer) {
271 mesg_viewpoint = -1;
272 return;
273 }
274 else if (mesg_viewpoint == -1)
275 return;
276
277 /* Get offset. */
278 o = mesg_pointer - mesg_viewpoint;
279 if (o < 0)
280 o += mesg_max;
281
282 /* Calculate max line movement. */
283 if (lines > o)
284 lines = o;
285
286 /* Move viewpoint. */
287 mesg_viewpoint = (mesg_viewpoint + lines) % mesg_max;
288 }
289
290
291 /**
292 * @brief Toggles if player should receive messages.
293 *
294 * @param enable Whether or not to enable player receiving messages.
295 */
player_messageToggle(int enable)296 void player_messageToggle( int enable )
297 {
298 gui_getMessage = enable;
299 }
300
301
302 /**
303 * @brief Adds a mesg to the queue to be displayed on screen.
304 *
305 * @param str Message to add.
306 */
player_messageRaw(const char * str)307 void player_messageRaw( const char *str )
308 {
309 int i, p, l;
310
311 /* Must be receiving messages. */
312 if (!gui_getMessage)
313 return;
314
315 /* Must be non-null. */
316 if (str == NULL)
317 return;
318
319 /* Get length. */
320 l = strlen(str);
321 i = gl_printWidthForText( NULL, str, gui_mesg_w - ((str[0] == '\t') ? 45. : 15.) );
322 p = 0;
323 while (p < l) {
324 /* Move pointer. */
325 mesg_pointer = (mesg_pointer + 1) % mesg_max;
326 if (mesg_viewpoint != -1)
327 mesg_viewpoint++;
328
329 /* Buffer overrun safety. */
330 if (i > MESG_SIZE_MAX-1)
331 i = MESG_SIZE_MAX-1;
332
333 /* Add the new one */
334 if (p == 0) {
335 nsnprintf( mesg_stack[mesg_pointer].str, i+1, "%s", &str[p] );
336 gl_printRestoreInit( &mesg_stack[mesg_pointer].restore );
337 }
338 else {
339 mesg_stack[mesg_pointer].str[0] = '\t'; /* Hack to indent. */
340 nsnprintf( &mesg_stack[mesg_pointer].str[1], i+1, "%s", &str[p] );
341 gl_printStoreMax( &mesg_stack[mesg_pointer].restore, str, p );
342 }
343 mesg_stack[mesg_pointer].t = mesg_timeout;
344
345 /* Get length. */
346 p += i;
347 if ((str[p] == '\n') || (str[p] == ' '))
348 p++; /* Skip "empty char". */
349 i = gl_printWidthForText( NULL, &str[p], gui_mesg_w - 45. ); /* They're tabbed so it's shorter. */
350 }
351 }
352
353 /**
354 * @brief Adds a mesg to the queue to be displayed on screen.
355 *
356 * @param fmt String with formatting like printf.
357 */
player_message(const char * fmt,...)358 void player_message( const char *fmt, ... )
359 {
360 va_list ap;
361 char buf[1024];
362
363 /* Must be receiving messages. */
364 if (!gui_getMessage)
365 return;
366
367 /* Must be non-null. */
368 if (fmt == NULL)
369 return;
370
371 /* Add the new one */
372 va_start(ap, fmt);
373 vsnprintf( buf, sizeof(buf), fmt, ap );
374 va_end(ap);
375
376 /* Add the message. */
377 player_messageRaw( buf );
378 }
379
380
381 /**
382 * @brief Sets up rendering of planet and jump point targeting reticles.
383 *
384 * @param dt Current delta tick.
385 */
gui_renderPlanetTarget(double dt)386 static void gui_renderPlanetTarget( double dt )
387 {
388 (void) dt;
389 double x,y, w,h;
390 const glColour *c;
391 Planet *planet;
392 JumpPoint *jp;
393
394 /* no need to draw if pilot is dead */
395 if (player_isFlag(PLAYER_DESTROYED) || player_isFlag(PLAYER_CREATING) ||
396 (player.p == NULL) || pilot_isFlag(player.p,PILOT_DEAD))
397 return;
398
399 /* Make sure target exists. */
400 if ((player.p->nav_planet < 0) && (player.p->nav_hyperspace < 0))
401 return;
402
403 /* Make sure targets are still in range. */
404 #if 0
405 if (!pilot_inRangePlanet( player.p, player.p->nav_planet )) {
406 player_targetPlanetSet( -1 );
407 return;
408 }
409 #endif
410
411 /* Draw planet and jump point target graphics. */
412 if (player.p->nav_hyperspace >= 0) {
413 jp = &cur_system->jumps[player.p->nav_hyperspace];
414
415 c = &cGreen;
416
417 x = jp->pos.x - jumppoint_gfx->sw/2.;
418 y = jp->pos.y + jumppoint_gfx->sh/2.;
419 w = jumppoint_gfx->sw;
420 h = jumppoint_gfx->sh;
421 gui_renderTargetReticles( x, y, w, h, c );
422 }
423 if (player.p->nav_planet >= 0) {
424 planet = cur_system->planets[player.p->nav_planet];
425 c = planet_getColour( planet );
426
427 x = planet->pos.x - planet->gfx_space->w / 2.;
428 y = planet->pos.y + planet->gfx_space->h / 2.;
429 w = planet->gfx_space->w;
430 h = planet->gfx_space->h;
431 gui_renderTargetReticles( x, y, w, h, c );
432 }
433 }
434
435
436 /**
437 * @brief Renders planet and jump point targeting reticles.
438 *
439 * @param x X position of reticle segment.
440 * @param y Y position of reticle segment.
441 * @param w Width.
442 * @param h Height.
443 * @param c Colour.
444 */
gui_renderTargetReticles(int x,int y,int w,int h,const glColour * c)445 void gui_renderTargetReticles( int x, int y, int w, int h, const glColour* c )
446 {
447 /* Must not be NULL. */
448 if (gui_target_planet == NULL)
449 return;
450
451 gl_blitSprite( gui_target_planet, x, y, 0, 0, c ); /* top left */
452
453 x += w;
454 gl_blitSprite( gui_target_planet, x, y, 1, 0, c ); /* top right */
455
456 y -= h;
457 gl_blitSprite( gui_target_planet, x, y, 1, 1, c ); /* bottom right */
458
459 x -= w;
460 gl_blitSprite( gui_target_planet, x, y, 0, 1, c ); /* bottom left */
461 }
462
463
464 /**
465 * @brief Renders the players pilot target.
466 *
467 * @double dt Current delta tick.
468 */
gui_renderPilotTarget(double dt)469 static void gui_renderPilotTarget( double dt )
470 {
471 (void) dt;
472 Pilot *p;
473 const glColour *c;
474 double x, y;
475
476 /* Player is most likely dead. */
477 if (gui_target_pilot == NULL)
478 return;
479
480 /* Get the target. */
481 if (player.p->target != PLAYER_ID)
482 p = pilot_get(player.p->target);
483 else p = NULL;
484
485 /* Make sure pilot exists and is still alive. */
486 if ((p==NULL) || pilot_isFlag(p,PILOT_DEAD)) {
487 pilot_setTarget( player.p, player.p->id );
488 gui_setTarget();
489 return;
490 }
491
492 /* Make sure target is still in range. */
493 if (!pilot_inRangePilot( player.p, p )) {
494 pilot_setTarget( player.p, player.p->id );
495 gui_setTarget();
496 return;
497 }
498
499 /* Draw the pilot target. */
500 if (pilot_isDisabled(p))
501 c = &cInert;
502 else if (pilot_isFlag(p,PILOT_BRIBED))
503 c = &cNeutral;
504 else if (pilot_isHostile(p))
505 c = &cHostile;
506 else if (pilot_isFriendly(p))
507 c = &cFriend;
508 else
509 c = faction_getColour(p->faction);
510
511 x = p->solid->pos.x - p->ship->gfx_space->sw * PILOT_SIZE_APROX/2.;
512 y = p->solid->pos.y + p->ship->gfx_space->sh * PILOT_SIZE_APROX/2.;
513 gl_blitSprite( gui_target_pilot, x, y, 0, 0, c ); /* top left */
514
515 x += p->ship->gfx_space->sw * PILOT_SIZE_APROX;
516 gl_blitSprite( gui_target_pilot, x, y, 1, 0, c ); /* top right */
517
518 y -= p->ship->gfx_space->sh * PILOT_SIZE_APROX;
519 gl_blitSprite( gui_target_pilot, x, y, 1, 1, c ); /* bottom right */
520
521 x -= p->ship->gfx_space->sw * PILOT_SIZE_APROX;
522 gl_blitSprite( gui_target_pilot, x, y, 0, 1, c ); /* bottom left */
523 }
524
525
526 /**
527 * @brief Gets the intersection with the border.
528 *
529 * http://en.wikipedia.org/wiki/Intercept_theorem
530 *
531 * @param[out] cx X intersection.
532 * @param[out] cy Y intersection.
533 * @param rx Center X position of intersection.
534 * @param ry Center Y position of intersection.
535 * @param hw Screen half-width.
536 * @param hh Screen half-height.
537 */
gui_borderIntersection(double * cx,double * cy,double rx,double ry,double hw,double hh)538 static void gui_borderIntersection( double *cx, double *cy, double rx, double ry, double hw, double hh )
539 {
540 double a;
541 double w, h;
542
543 /* Get angle. */
544 a = atan2( ry, rx );
545 if (a < 0.)
546 a += 2.*M_PI;
547
548 /* Helpers. */
549 w = hw-7.;
550 h = hh-7.;
551
552 /* Handle by quadrant. */
553 if ((a > gui_tr) && (a < gui_tl)) { /* Top. */
554 *cx = h * (rx/ry);
555 *cy = h;
556 }
557 else if ((a > gui_tl) && (a < gui_bl)) { /* Left. */
558 *cx = -w;
559 *cy = -w * (ry/rx);
560 }
561 else if ((a > gui_bl) && (a < gui_br)) { /* Bottom. */
562 *cx = -h * (rx/ry);
563 *cy = -h;
564 }
565 else { /* Right. */
566 *cx = w;
567 *cy = w * (ry/rx);
568 }
569
570 /* Translate. */
571 *cx += hw;
572 *cy += hh;
573 }
574
575
576 /**
577 * @brief Renders the ships/planets in the border.
578 *
579 * @param dt Current delta tick.
580 */
gui_renderBorder(double dt)581 static void gui_renderBorder( double dt )
582 {
583 (void) dt;
584 int i, j;
585 Pilot *plt;
586 Planet *pnt;
587 JumpPoint *jp;
588 int hw, hh;
589 double rx,ry;
590 double cx,cy;
591 const glColour *col;
592 double int_a;
593 GLfloat vertex[5*2], colours[5*4];
594
595 /* Get player position. */
596 hw = SCREEN_W/2;
597 hh = SCREEN_H/2;
598
599 /* Interference. */
600 int_a = 1. - interference_alpha;
601
602 /* Render borders to enhance contrast. */
603 gl_renderRect( 0., 0., 15., SCREEN_H, &cBlackHilight );
604 gl_renderRect( SCREEN_W - 15., 0., 15., SCREEN_H, &cBlackHilight );
605 gl_renderRect( 15., 0., SCREEN_W - 30., 15., &cBlackHilight );
606 gl_renderRect( 15., SCREEN_H - 15., SCREEN_W - 30., 15., &cBlackHilight );
607
608 /* Draw planets. */
609 for (i=0; i<cur_system->nplanets; i++) {
610 /* Check that it's real. */
611 if(cur_system->planets[i]->real != ASSET_REAL)
612 continue;
613
614 pnt = cur_system->planets[i];
615
616 /* Skip if unknown. */
617 if (!planet_isKnown( pnt ))
618 continue;
619
620 /* Check if out of range. */
621 if (!gui_onScreenAsset( &rx, &ry, NULL, pnt )) {
622
623 /* Get border intersection. */
624 gui_borderIntersection( &cx, &cy, rx, ry, hw, hh );
625
626 /* Set up colours. */
627 col = gui_getPlanetColour(i);
628 for (j=0; j<5; j++) {
629 colours[4*j + 0] = col->r;
630 colours[4*j + 1] = col->g;
631 colours[4*j + 2] = col->b;
632 colours[4*j + 3] = 1;
633 }
634 gl_vboSubData( gui_vbo, gui_vboColourOffset,
635 sizeof(GLfloat) * 5*4, colours );
636 /* Set up vertex. */
637 vertex[0] = cx-5.;
638 vertex[1] = cy-5.;
639 vertex[2] = cx-5.;
640 vertex[3] = cy+5.;
641 vertex[4] = cx+5.;
642 vertex[5] = cy+5.;
643 vertex[6] = cx+5.;
644 vertex[7] = cy-5.;
645 vertex[8] = cx-5.;
646 vertex[9] = cy-5.;
647 gl_vboSubData( gui_vbo, 0, sizeof(GLfloat) * 5*2, vertex );
648 /* Draw tho VBO. */
649 gl_vboActivateOffset( gui_vbo, GL_VERTEX_ARRAY, 0, 2, GL_FLOAT, 0 );
650 gl_vboActivateOffset( gui_vbo, GL_COLOR_ARRAY,
651 gui_vboColourOffset, 4, GL_FLOAT, 0 );
652 glDrawArrays( GL_LINE_STRIP, 0, 5 );
653 }
654 }
655
656 /* Draw jump routes. */
657 for (i=0; i<cur_system->njumps; i++) {
658 jp = &cur_system->jumps[i];
659
660 /* Skip if unknown or exit-only. */
661 if (!jp_isKnown( jp ) || jp_isFlag( jp, JP_EXITONLY ))
662 continue;
663
664 /* Check if out of range. */
665 if (!gui_onScreenAsset( &rx, &ry, jp, NULL )) {
666
667 /* Get border intersection. */
668 gui_borderIntersection( &cx, &cy, rx, ry, hw, hh );
669
670 /* Set up colours. */
671 if (i==player.p->nav_hyperspace)
672 col = &cGreen;
673 else
674 col = &cWhite;
675 for (j=0; j<4; j++) {
676 colours[4*j + 0] = col->r;
677 colours[4*j + 1] = col->g;
678 colours[4*j + 2] = col->b;
679 colours[4*j + 3] = 1;
680 }
681 gl_vboSubData( gui_vbo, gui_vboColourOffset,
682 sizeof(GLfloat) * 4*4, colours );
683 /* Set up vertex. */
684 vertex[0] = cx-5.;
685 vertex[1] = cy-5.;
686 vertex[2] = cx+5.;
687 vertex[3] = cy-5.;
688 vertex[4] = cx;
689 vertex[5] = cy+5.;
690 vertex[6] = cx-5.;
691 vertex[7] = cy-5.;
692 gl_vboSubData( gui_vbo, 0, sizeof(GLfloat) * 4*2, vertex );
693 /* Draw tho VBO. */
694 gl_vboActivateOffset( gui_vbo, GL_VERTEX_ARRAY, 0, 2, GL_FLOAT, 0 );
695 gl_vboActivateOffset( gui_vbo, GL_COLOR_ARRAY,
696 gui_vboColourOffset, 4, GL_FLOAT, 0 );
697 glDrawArrays( GL_LINE_STRIP, 0, 4 );
698 }
699 }
700
701 /* Draw pilots. */
702 for (i=1; i<pilot_nstack; i++) { /* skip the player */
703 plt = pilot_stack[i];
704
705 /* See if in sensor range. */
706 if (!pilot_inRangePilot(player.p, plt))
707 continue;
708
709 /* Check if out of range. */
710 if (!gui_onScreenPilot( &rx, &ry, plt )) {
711
712 /* Get border intersection. */
713 gui_borderIntersection( &cx, &cy, rx, ry, hw, hh );
714
715 /* Set up colours. */
716 col = gui_getPilotColour(plt);
717 for (j=0; j<4; j++) {
718 colours[4*j + 0] = col->r;
719 colours[4*j + 1] = col->g;
720 colours[4*j + 2] = col->b;
721 colours[4*j + 3] = int_a;
722 }
723 gl_vboSubData( gui_vbo, gui_vboColourOffset,
724 sizeof(GLfloat) * 4*4, colours );
725 /* Set up vertex. */
726 vertex[0] = cx-5.;
727 vertex[1] = cy-5.;
728 vertex[2] = cx+5.;
729 vertex[3] = cy+5.;
730 vertex[4] = cx+5.;
731 vertex[5] = cy-5.;
732 vertex[6] = cx-5.;
733 vertex[7] = cy+5.;
734 gl_vboSubData( gui_vbo, 0, sizeof(GLfloat) * 4*2, vertex );
735 /* Draw tho VBO. */
736 gl_vboActivateOffset( gui_vbo, GL_VERTEX_ARRAY, 0, 2, GL_FLOAT, 0 );
737 gl_vboActivateOffset( gui_vbo, GL_COLOR_ARRAY,
738 gui_vboColourOffset, 4, GL_FLOAT, 0 );
739 glDrawArrays( GL_LINES, 0, 4 );
740 }
741 }
742
743 /* Deactivate the VBO. */
744 gl_vboDeactivate();
745 }
746
747
748 /**
749 * @brief Takes a pilot and returns whether it's on screen, plus its relative position.
750 *
751 * @param[out] rx Relative X position (factoring in viewport offset)
752 * @param[out] ry Relative Y position (factoring in viewport offset)
753 * @param pilot Pilot to determine the visibility and position of
754 * @return Whether or not the pilot is on-screen.
755 */
gui_onScreenPilot(double * rx,double * ry,Pilot * pilot)756 int gui_onScreenPilot( double *rx, double *ry, Pilot *pilot )
757 {
758 double z;
759 int cw, ch;
760 glTexture *tex;
761
762 z = cam_getZoom();
763
764 tex = pilot->ship->gfx_space;
765
766 /* Get relative positions. */
767 *rx = (pilot->solid->pos.x - player.p->solid->pos.x)*z;
768 *ry = (pilot->solid->pos.y - player.p->solid->pos.y)*z;
769
770 /* Correct for offset. */
771 *rx -= gui_xoff;
772 *ry -= gui_yoff;
773
774 /* Compare dimensions. */
775 cw = SCREEN_W/2 + tex->sw/2;
776 ch = SCREEN_H/2 + tex->sh/2;
777
778 if ((ABS(*rx) > cw) || (ABS(*ry) > ch))
779 return 0;
780
781 return 1;
782 }
783
784
785 /**
786 * @brief Takes a planet or jump point and returns whether it's on screen, plus its relative position.
787 *
788 * @param[out] rx Relative X position (factoring in viewport offset)
789 * @param[out] ry Relative Y position (factoring in viewport offset)
790 * @param jp Jump point to determine the visibility and position of
791 * @param pnt Planet to determine the visibility and position of
792 * @return Whether or not the given asset is on-screen.
793 */
gui_onScreenAsset(double * rx,double * ry,JumpPoint * jp,Planet * pnt)794 int gui_onScreenAsset( double *rx, double *ry, JumpPoint *jp, Planet *pnt )
795 {
796 double z;
797 int cw, ch;
798 glTexture *tex;
799
800 z = cam_getZoom();
801
802 if (jp == NULL) {
803 tex = pnt->gfx_space;
804 *rx = (pnt->pos.x - player.p->solid->pos.x)*z;
805 *ry = (pnt->pos.y - player.p->solid->pos.y)*z;
806 }
807 else {
808 tex = jumppoint_gfx;
809 *rx = (jp->pos.x - player.p->solid->pos.x)*z;
810 *ry = (jp->pos.y - player.p->solid->pos.y)*z;
811 }
812
813 /* Correct for offset. */
814 *rx -= gui_xoff;
815 *ry -= gui_yoff;
816
817 /* Compare dimensions. */
818 cw = SCREEN_W/2 + tex->sw/2;
819 ch = SCREEN_H/2 + tex->sh/2;
820
821 if ((ABS(*rx) > cw) || (ABS(*ry) > ch))
822 return 0;
823
824 return 1;
825 }
826
827
828 /**
829 * @brief Renders the gui targeting reticles.
830 *
831 * @param dt Current deltatick.
832 */
gui_renderReticles(double dt)833 void gui_renderReticles( double dt )
834 {
835 /* Player must be alive. */
836 if (player.p == NULL)
837 return;
838
839 gui_renderPlanetTarget(dt);
840 gui_renderPilotTarget(dt);
841 }
842
843
844 static int can_jump = 0; /**< Stores whether or not the player is able to jump. */
845 /**
846 * @brief Renders the player's GUI.
847 *
848 * @param dt Current delta tick.
849 */
gui_render(double dt)850 void gui_render( double dt )
851 {
852 int i;
853 double x;
854 glColour col;
855
856 /* If player is dead just render the cinematic mode. */
857 if (!menu_isOpen(MENU_MAIN) &&
858 (player_isFlag(PLAYER_DESTROYED) || player_isFlag(PLAYER_CREATING) ||
859 ((player.p != NULL) && pilot_isFlag(player.p,PILOT_DEAD)))) {
860 spfx_cinematic();
861 return;
862 }
863
864 /* Make sure player is valid. */
865 if (player.p == NULL)
866 return;
867
868 /* Cinematics mode. */
869 if (player_isFlag( PLAYER_CINEMATICS_GUI ))
870 return;
871
872 /*
873 * Countdown timers.
874 */
875 blink_pilot -= dt / dt_mod;
876 if (blink_pilot < 0.)
877 blink_pilot += RADAR_BLINK_PILOT;
878 blink_planet -= dt / dt_mod;
879 if (blink_planet < 0.)
880 blink_planet += RADAR_BLINK_PLANET;
881 if (interference_alpha > 0.)
882 interference_t += dt;
883
884 /* Render the border ships and targets. */
885 gui_renderBorder(dt);
886
887 /* Set viewport. */
888 gl_viewport( 0., 0., gl_screen.rw, gl_screen.rh );
889
890 /* Run Lua. */
891 if (gui_env != LUA_NOREF) {
892 gui_prepFunc( "render" );
893 lua_pushnumber( naevL, dt );
894 lua_pushnumber( naevL, dt_mod );
895 gui_runFunc( "render", 2, 0 );
896 if (pilot_isFlag(player.p, PILOT_COOLDOWN)) {
897 gui_prepFunc( "render_cooldown" );
898 lua_pushnumber( naevL, player.p->ctimer / player.p->cdelay );
899 lua_pushnumber( naevL, player.p->ctimer );
900 gui_runFunc( "render_cooldown", 2, 0 );
901 }
902 }
903
904 /* Messages. */
905 gui_renderMessages(dt);
906
907
908 /* OSD. */
909 osd_render();
910
911 /* Noise when getting near a jump. */
912 if (player.p->nav_hyperspace >= 0) { /* hyperspace target */
913
914 /* Determine if we have to play the "enter hyperspace range" sound. */
915 i = space_canHyperspace(player.p);
916 if ((i != 0) && (i != can_jump))
917 if (!pilot_isFlag(player.p, PILOT_HYPERSPACE))
918 player_soundPlayGUI(snd_jump, 1);
919 can_jump = i;
920 }
921
922 /* Hyperspace. */
923 if (pilot_isFlag(player.p, PILOT_HYPERSPACE) &&
924 (player.p->ptimer < HYPERSPACE_FADEOUT)) {
925 x = (HYPERSPACE_FADEOUT-player.p->ptimer) / HYPERSPACE_FADEOUT;
926 col.r = 1.;
927 col.g = 1.;
928 col.b = 1.;
929 col.a = x;
930 gl_renderRect( 0., 0., SCREEN_W, SCREEN_H, &col );
931 }
932
933 /* Reset viewport. */
934 gl_defViewport();
935
936 /* Render messages. */
937 omsg_render( dt );
938 }
939
940
941 /**
942 * @brief Initializes the radar.
943 *
944 * @param circle Whether or not the radar is circular.
945 */
gui_radarInit(int circle,int w,int h)946 int gui_radarInit( int circle, int w, int h )
947 {
948 gui_radar.shape = circle ? RADAR_CIRCLE : RADAR_RECT;
949 gui_radar.res = RADAR_RES_DEFAULT;
950 gui_radar.w = w;
951 gui_radar.h = h;
952 gui_createInterference( &gui_radar );
953 return 0;
954 }
955
956
957 /**
958 * @brief Renders the GUI radar.
959 *
960 * @param x X position to render at.
961 * @param y Y position to render at.
962 */
gui_radarRender(double x,double y)963 void gui_radarRender( double x, double y )
964 {
965 int i, j;
966 Radar *radar;
967 AsteroidAnchor *ast;
968
969 /* The global radar. */
970 radar = &gui_radar;
971 gui_radar.x = x;
972 gui_radar.y = y;
973
974 gl_matrixPush();
975 if (radar->shape==RADAR_RECT) {
976 gl_clipRect( x, y, radar->w, radar->h );
977 gl_matrixTranslate( x + radar->w/2., y + radar->h/2. );
978 }
979 else if (radar->shape==RADAR_CIRCLE)
980 gl_matrixTranslate( x, y );
981
982 /*
983 * planets
984 */
985 for (i=0; i<cur_system->nplanets; i++)
986 if ((cur_system->planets[ i ]->real == ASSET_REAL) && (i != player.p->nav_planet))
987 gui_renderPlanet( i, radar->shape, radar->w, radar->h, radar->res, 0 );
988 if (player.p->nav_planet > -1)
989 gui_renderPlanet( player.p->nav_planet, radar->shape, radar->w, radar->h, radar->res, 0 );
990
991 /*
992 * Jump points.
993 */
994 for (i=0; i<cur_system->njumps; i++)
995 if (i != player.p->nav_hyperspace && jp_isUsable(&cur_system->jumps[i]))
996 gui_renderJumpPoint( i, radar->shape, radar->w, radar->h, radar->res, 0 );
997 if (player.p->nav_hyperspace > -1)
998 gui_renderJumpPoint( player.p->nav_hyperspace, radar->shape, radar->w, radar->h, radar->res, 0 );
999
1000 /*
1001 * weapons
1002 */
1003 weapon_minimap( radar->res, radar->w, radar->h,
1004 radar->shape, 1.-interference_alpha );
1005
1006
1007 /* render the pilot_nstack */
1008 j = 0;
1009 for (i=1; i<pilot_nstack; i++) { /* skip the player */
1010 if (pilot_stack[i]->id == player.p->target)
1011 j = i;
1012 else
1013 gui_renderPilot( pilot_stack[i], radar->shape, radar->w, radar->h, radar->res, 0 );
1014 }
1015 /* render the targeted pilot */
1016 if (j!=0)
1017 gui_renderPilot( pilot_stack[j], radar->shape, radar->w, radar->h, radar->res, 0 );
1018
1019 /* render the asteroids */
1020 for (i=0; i<cur_system->nasteroids; i++) {
1021 ast = &cur_system->asteroids[i];
1022 for (j=0; j<ast->nb; j++)
1023 gui_renderAsteroid( &ast->asteroids[j], radar->w, radar->h, radar->res, 0 );
1024 }
1025
1026 /* Interference. */
1027 gui_renderInterference();
1028
1029 /* Render the player cross. */
1030 gui_renderPlayer( radar->res, 0 );
1031
1032 gl_matrixPop();
1033 if (radar->shape==RADAR_RECT)
1034 gl_unclipRect();
1035 }
1036
1037
1038 /**
1039 * @brief Gets the radar's position.
1040 *
1041 * @param[out] x X position.
1042 * @param[out] y Y position.
1043 */
gui_radarGetPos(int * x,int * y)1044 void gui_radarGetPos( int *x, int *y )
1045 {
1046 *x = gui_radar.x;
1047 *y = gui_radar.y;
1048 }
1049
1050
1051 /**
1052 * @brief Gets the radar's dimensions.
1053 *
1054 * @param[out] w Width.
1055 * @param[out] h Height.
1056 */
gui_radarGetDim(int * w,int * h)1057 void gui_radarGetDim( int *w, int *h )
1058 {
1059 *w = gui_radar.w;
1060 *h = gui_radar.h;
1061 }
1062
1063
1064 /**
1065 * @brief Outputs the radar's resolution.
1066 *
1067 * @param[out] res Current zoom ratio.
1068 */
gui_radarGetRes(int * res)1069 void gui_radarGetRes( int *res )
1070 {
1071 *res = gui_radar.res;
1072 }
1073
1074
1075 /**
1076 * @brief Clears the GUI messages.
1077 */
gui_clearMessages(void)1078 void gui_clearMessages (void)
1079 {
1080 memset( mesg_stack, 0, sizeof(Mesg)*mesg_max );
1081 }
1082
1083
1084 /**
1085 * @brief Renders the player's messages on screen.
1086 *
1087 * @param dt Current delta tick.
1088 */
gui_renderMessages(double dt)1089 static void gui_renderMessages( double dt )
1090 {
1091 double x, y, h, hs, vx, vy;
1092 int v, i, m, o;
1093 glColour c;
1094
1095 /* Coordinate translation. */
1096 x = gui_mesg_x;
1097 y = gui_mesg_y;
1098
1099 /* Handle viewpoint hacks. */
1100 v = mesg_viewpoint;
1101 if (v == -1)
1102 v = mesg_pointer;
1103
1104 /* Colour. */
1105 c.r = 1.;
1106 c.g = 1.;
1107 c.b = 1.;
1108
1109 /* Render background. */
1110 h = conf.mesg_visible*gl_defFont.h*1.2;
1111 gl_renderRect( x-2., y-2., gui_mesg_w-13., h+4., &cBlackHilight );
1112
1113 /* Set up position. */
1114 vx = x;
1115 vy = y;
1116
1117 /* Must be run here. */
1118 if (mesg_viewpoint != -1) {
1119 /* Data. */
1120 hs = h*(double)conf.mesg_visible/(double)mesg_max;
1121 o = mesg_pointer - mesg_viewpoint;
1122 if (o < 0)
1123 o += mesg_max;
1124 }
1125
1126 /* Render text. */
1127 for (i=0; i<conf.mesg_visible; i++) {
1128 /* Reference translation. */
1129 m = (v - i) % mesg_max;
1130 if (m < 0)
1131 m += mesg_max;
1132
1133 /* Timer handling. */
1134 if ((mesg_viewpoint != -1) || (mesg_stack[m].t >= 0.)) {
1135 /* Decrement timer. */
1136 if (mesg_viewpoint == -1) {
1137 mesg_stack[m].t -= dt / dt_mod;
1138
1139 /* Handle fading out. */
1140 if (mesg_stack[m].t - mesg_fade < 0.)
1141 c.a = mesg_stack[m].t / mesg_fade;
1142 else
1143 c.a = 1.;
1144 }
1145 else
1146 c.a = 1.;
1147
1148 /* Only handle non-NULL messages. */
1149 if (mesg_stack[m].str[0] != '\0') {
1150 if (mesg_stack[m].str[0] == '\t') {
1151 gl_printRestore( &mesg_stack[m].restore );
1152 gl_printMaxRaw( NULL, gui_mesg_w - 45., x + 30, y, &c, &mesg_stack[m].str[1] );
1153 }
1154 else
1155 gl_printMaxRaw( NULL, gui_mesg_w - 15., x, y, &c, mesg_stack[m].str );
1156 }
1157 }
1158
1159 /* Increase position. */
1160 y += (double)gl_defFont.h*1.2;
1161 }
1162
1163 /* Render position. */
1164 if (mesg_viewpoint != -1) {
1165 /* Border. */
1166 c.a = 0.2;
1167 gl_renderRect( vx + gui_mesg_w-10., vy, 10, h, &c );
1168
1169 /* Inside. */
1170 c.a = 0.5;
1171 gl_renderRect( vx + gui_mesg_w-10., vy + hs/2. + (h-hs)*((double)o/(double)(mesg_max-conf.mesg_visible)), 10, hs, &c );
1172 }
1173 }
1174
1175
1176 /**
1177 * @brief Renders interference if needed.
1178 */
gui_renderInterference(void)1179 static void gui_renderInterference (void)
1180 {
1181 glColour c;
1182 glTexture *tex;
1183 int t;
1184
1185 /* Must be displaying interference. */
1186 if (interference_alpha <= 0.)
1187 return;
1188
1189 /* Calculate frame to draw. */
1190 if (interference_t > INTERFERENCE_CHANGE_DT) { /* Time to change */
1191 t = RNG(0, INTERFERENCE_LAYERS-1);
1192 if (t != interference_layer)
1193 interference_layer = t;
1194 else
1195 interference_layer = (interference_layer == INTERFERENCE_LAYERS-1) ?
1196 0 : interference_layer+1;
1197 interference_t -= INTERFERENCE_CHANGE_DT;
1198 }
1199
1200 /* Render the interference. */
1201 c.r = c.g = c.b = 1.;
1202 c.a = interference_alpha;
1203 tex = gui_radar.interference[interference_layer];
1204 if (gui_radar.shape == RADAR_CIRCLE)
1205 gl_blitStatic( tex, -gui_radar.w, -gui_radar.w, &c );
1206 else if (gui_radar.shape == RADAR_RECT)
1207 gl_blitStatic( tex, -gui_radar.w, -gui_radar.h, &c );
1208 }
1209
1210
1211 /**
1212 * @brief Gets a pilot's colour, with a special colour for targets.
1213 *
1214 * @param p Pilot to get colour of.
1215 * @return The colour of the pilot.
1216 *
1217 * @sa pilot_getColour
1218 */
gui_getPilotColour(const Pilot * p)1219 static const glColour* gui_getPilotColour( const Pilot* p )
1220 {
1221 const glColour *col;
1222
1223 if (p->id == player.p->target)
1224 col = &cRadar_tPilot;
1225 else
1226 col = pilot_getColour(p);
1227
1228 return col;
1229 }
1230
1231
1232 /**
1233 * @brief Renders a pilot in the GUI radar.
1234 *
1235 * @param p Pilot to render.
1236 */
1237 #define CHECK_PIXEL(x,y) \
1238 (shape==RADAR_RECT && ABS(x)<w/2. && ABS(y)<h/2.) || \
1239 (shape==RADAR_CIRCLE && (((x)*(x)+(y)*(y)) < rc))
gui_renderPilot(const Pilot * p,RadarShape shape,double w,double h,double res,int overlay)1240 void gui_renderPilot( const Pilot* p, RadarShape shape, double w, double h, double res, int overlay )
1241 {
1242 int i, curs;
1243 int x, y, sx, sy;
1244 double px, py;
1245 const glColour *col;
1246 glColour ccol;
1247 GLfloat vertex[2*8], colours[4*8];
1248 GLfloat cx, cy;
1249 int rc;
1250
1251 /* Make sure is in range. */
1252 if (!pilot_inRangePilot( player.p, p ))
1253 return;
1254
1255 /* Get position. */
1256 if (overlay) {
1257 x = (int)(p->solid->pos.x / res);
1258 y = (int)(p->solid->pos.y / res);
1259 }
1260 else {
1261 x = (int)((p->solid->pos.x - player.p->solid->pos.x) / res);
1262 y = (int)((p->solid->pos.y - player.p->solid->pos.y) / res);
1263 }
1264 /* Get size. */
1265 sx = (int)(PILOT_SIZE_APROX/2. * p->ship->gfx_space->sw / res);
1266 sy = (int)(PILOT_SIZE_APROX/2. * p->ship->gfx_space->sh / res);
1267 if (sx < 1.)
1268 sx = 1.;
1269 if (sy < 1.)
1270 sy = 1.;
1271
1272 /* Check if pilot in range. */
1273 if ( ((shape==RADAR_RECT) &&
1274 ((ABS(x) > w/2+sx) || (ABS(y) > h/2.+sy)) ) ||
1275 ((shape==RADAR_CIRCLE) &&
1276 ((x*x+y*y) > (int)(w*w))) ) {
1277
1278 /* Draw little targeted symbol. */
1279 if (p->id == player.p->target && !overlay)
1280 gui_renderRadarOutOfRange( shape, w, h, x, y, &cRadar_tPilot );
1281 return;
1282 }
1283
1284 /* Transform coordinates into the 0,0 -> SCREEN_W, SCREEN_H range. */
1285 if (overlay) {
1286 x += SCREEN_W / 2;
1287 y += SCREEN_H / 2;
1288 w *= 2.;
1289 h *= 2.;
1290 }
1291
1292 if (shape==RADAR_RECT)
1293 rc = 0;
1294 else if (shape==RADAR_CIRCLE)
1295 rc = (int)(w*w);
1296 else
1297 return;
1298
1299 /* Draw selection if targeted. */
1300 if (p->id == player.p->target) {
1301 if (blink_pilot < RADAR_BLINK_PILOT/2.) {
1302 /* Set up colours. */
1303 for (i=0; i<8; i++) {
1304 colours[4*i + 0] = cRadar_tPilot.r;
1305 colours[4*i + 1] = cRadar_tPilot.g;
1306 colours[4*i + 2] = cRadar_tPilot.b;
1307 colours[4*i + 3] = 1.-interference_alpha;
1308 }
1309 gl_vboSubData( gui_vbo, gui_vboColourOffset,
1310 sizeof(GLfloat) * 8*4, colours );
1311 /* Set up vertex. */
1312 curs = 0;
1313 cx = x-sx;
1314 cy = y+sy;
1315 if (CHECK_PIXEL(cx-3.3,cy+3.3)) {
1316 vertex[curs++] = cx-1.5;
1317 vertex[curs++] = cy+1.5;
1318 vertex[curs++] = cx-3.3;
1319 vertex[curs++] = cy+3.3;
1320 }
1321 cx = x+sx;
1322 if (CHECK_PIXEL(cx+3.3,cy+3.3)) {
1323 vertex[curs++] = cx+1.5;
1324 vertex[curs++] = cy+1.5;
1325 vertex[curs++] = cx+3.3;
1326 vertex[curs++] = cy+3.3;
1327 }
1328 cy = y-sy;
1329 if (CHECK_PIXEL(cx+3.3,cy-3.3)) {
1330 vertex[curs++] = cx+1.5;
1331 vertex[curs++] = cy-1.5;
1332 vertex[curs++] = cx+3.3;
1333 vertex[curs++] = cy-3.3;
1334 }
1335 cx = x-sx;
1336 if (CHECK_PIXEL(cx-3.3,cy-3.3)) {
1337 vertex[curs++] = cx-1.5;
1338 vertex[curs++] = cy-1.5;
1339 vertex[curs++] = cx-3.3;
1340 vertex[curs++] = cy-3.3;
1341 }
1342 gl_vboSubData( gui_vbo, 0, sizeof(GLfloat) * (curs/2)*2, vertex );
1343 /* Draw tho VBO. */
1344 gl_vboActivateOffset( gui_vbo, GL_VERTEX_ARRAY, 0, 2, GL_FLOAT, 0 );
1345 gl_vboActivateOffset( gui_vbo, GL_COLOR_ARRAY,
1346 gui_vboColourOffset, 4, GL_FLOAT, 0 );
1347 glDrawArrays( GL_LINES, 0, curs/2 );
1348 }
1349 }
1350
1351 /* Deactivate VBO. */
1352 gl_vboDeactivate();
1353
1354 /* Draw square. */
1355 px = MAX(x-sx,-w);
1356 py = MAX(y-sy, -h);
1357 if (pilot_isFlag(p, PILOT_HILIGHT) && (blink_pilot < RADAR_BLINK_PILOT/2.))
1358 col = &cRadar_hilight;
1359 else
1360 col = gui_getPilotColour(p);
1361 ccol.r = col->r;
1362 ccol.g = col->g;
1363 ccol.b = col->b;
1364 ccol.a = 1.-interference_alpha;
1365 gl_renderRect( px, py, MIN( 2*sx, w-px ), MIN( 2*sy, h-py ), &ccol );
1366
1367 /* Draw name. */
1368 if (overlay && pilot_isFlag(p, PILOT_HILIGHT))
1369 gl_printRaw( &gl_smallFont, x+2*sx+5., y-gl_smallFont.h/2., col, p->name );
1370 }
1371
1372
1373 /**
1374 * @brief Renders an asteroid in the GUI radar.
1375 *
1376 * @param a Asteroid to render.
1377 */
gui_renderAsteroid(const Asteroid * a,double w,double h,double res,int overlay)1378 void gui_renderAsteroid( const Asteroid* a, double w, double h, double res, int overlay )
1379 {
1380 int x, y, sx, sy;
1381 double px, py;
1382 const glColour *col;
1383 glColour ccol;
1384
1385 /* Make sure is in range. TODO: real detection system for asteroids */
1386 if ( MOD( a->pos.x - player.p->solid->pos.x,
1387 a->pos.y - player.p->solid->pos.y ) > 4000. )
1388 return;
1389
1390 /* Get position. */
1391 if (overlay) {
1392 x = (int)(a->pos.x / res);
1393 y = (int)(a->pos.y / res);
1394 }
1395 else {
1396 x = (int)((a->pos.x - player.p->solid->pos.x) / res);
1397 y = (int)((a->pos.y - player.p->solid->pos.y) / res);
1398 }
1399 /* Get size. */
1400 sx = 1.;
1401 sy = 1.;
1402
1403 /* Transform coordinates into the 0,0 -> SCREEN_W, SCREEN_H range. */
1404 if (overlay) {
1405 x += SCREEN_W / 2;
1406 y += SCREEN_H / 2;
1407 w *= 2.;
1408 h *= 2.;
1409 }
1410
1411 /* Deactivate VBO. */
1412 gl_vboDeactivate();
1413
1414 /* Draw square. */
1415 px = MAX(x-sx,-w);
1416 py = MAX(y-sy, -h);
1417
1418 col = &cWhite;
1419 ccol.r = col->r;
1420 ccol.g = col->g;
1421 ccol.b = col->b;
1422 ccol.a = 1.-interference_alpha;
1423 gl_renderRect( px, py, MIN( 2*sx, w-px ), MIN( 2*sy, h-py ), &ccol );
1424 }
1425
1426
1427 /**
1428 * @brief Renders the player cross on the radar or whatever.
1429 */
gui_renderPlayer(double res,int overlay)1430 void gui_renderPlayer( double res, int overlay )
1431 {
1432 double x, y, r;
1433
1434 if (overlay) {
1435 x = player.p->solid->pos.x / res + SCREEN_W / 2;
1436 y = player.p->solid->pos.y / res + SCREEN_H / 2;
1437 r = 5.;
1438 }
1439 else {
1440 x = 0.;
1441 y = 0.;
1442 r = 3.;
1443 }
1444
1445 /* Render the cross. */
1446 gl_renderCross( x, y, r, &cRadar_player );
1447
1448 if (overlay)
1449 gl_printRaw( &gl_smallFont, x+r+5., y-gl_smallFont.h/2., &cRadar_player, "You" );
1450 }
1451
1452
1453 /**
1454 * @brief Gets the colour of a planet.
1455 *
1456 * @param i Index of the planet to get colour of.
1457 * @return Colour of the planet.
1458 */
gui_getPlanetColour(int i)1459 static const glColour *gui_getPlanetColour( int i )
1460 {
1461 const glColour *col;
1462 Planet *planet;
1463
1464 planet = cur_system->planets[i];
1465
1466 if (i == player.p->nav_planet)
1467 col = &cRadar_tPlanet;
1468 else
1469 col = planet_getColour( planet );
1470
1471 return col;
1472 }
1473
1474
1475 /**
1476 * @brief Force sets the planet and pilot radar blink.
1477 */
gui_forceBlink(void)1478 void gui_forceBlink (void)
1479 {
1480 blink_pilot = 0.;
1481 blink_planet = 0.;
1482 }
1483
1484
1485 /**
1486 * @brief Renders the planet blink around a position on the minimap.
1487 */
gui_planetBlink(int w,int h,int rc,int cx,int cy,GLfloat vr,RadarShape shape)1488 static void gui_planetBlink( int w, int h, int rc, int cx, int cy, GLfloat vr, RadarShape shape )
1489 {
1490 GLfloat vx, vy;
1491 GLfloat vertex[8*2], colours[8*4];
1492 int i, curs;
1493
1494 if (blink_planet < RADAR_BLINK_PLANET/2.) {
1495 curs = 0;
1496 vx = cx-vr;
1497 vy = cy+vr;
1498 if (CHECK_PIXEL(vx-3.3, vy+3.3)) {
1499 vertex[curs++] = vx-1.5;
1500 vertex[curs++] = vy+1.5;
1501 vertex[curs++] = vx-3.3;
1502 vertex[curs++] = vy+3.3;
1503 }
1504 vx = cx+vr;
1505 if (CHECK_PIXEL(vx+3.3, vy+3.3)) {
1506 vertex[curs++] = vx+1.5;
1507 vertex[curs++] = vy+1.5;
1508 vertex[curs++] = vx+3.3;
1509 vertex[curs++] = vy+3.3;
1510 }
1511 vy = cy-vr;
1512 if (CHECK_PIXEL(vx+3.3, vy-3.3)) {
1513 vertex[curs++] = vx+1.5;
1514 vertex[curs++] = vy-1.5;
1515 vertex[curs++] = vx+3.3;
1516 vertex[curs++] = vy-3.3;
1517 }
1518 vx = cx-vr;
1519 if (CHECK_PIXEL(vx-3.3, vy-3.3)) {
1520 vertex[curs++] = vx-1.5;
1521 vertex[curs++] = vy-1.5;
1522 vertex[curs++] = vx-3.3;
1523 vertex[curs++] = vy-3.3;
1524 }
1525 gl_vboSubData( gui_vbo, 0, sizeof(GLfloat) * (curs/2)*2, vertex );
1526 /* Set the colours. */
1527 for (i=0; i<curs/2; i++) {
1528 colours[4*i + 0] = cRadar_tPlanet.r;
1529 colours[4*i + 1] = cRadar_tPlanet.g;
1530 colours[4*i + 2] = cRadar_tPlanet.b;
1531 colours[4*i + 3] = 1.-interference_alpha;
1532 }
1533 gl_vboSubData( gui_vbo, gui_vboColourOffset,
1534 sizeof(GLfloat) * (curs/2)*4, colours );
1535 /* Draw tho VBO. */
1536 gl_vboActivateOffset( gui_vbo, GL_VERTEX_ARRAY, 0, 2, GL_FLOAT, 0 );
1537 gl_vboActivateOffset( gui_vbo, GL_COLOR_ARRAY,
1538 gui_vboColourOffset, 4, GL_FLOAT, 0 );
1539 glDrawArrays( GL_LINES, 0, curs/2 );
1540 }
1541
1542 /* Deactivate the VBO. */
1543 gl_vboDeactivate();
1544 }
1545
1546
1547 /**
1548 * @brief Renders an out of range marker for the planet.
1549 */
gui_renderRadarOutOfRange(RadarShape sh,int w,int h,int cx,int cy,const glColour * col)1550 static void gui_renderRadarOutOfRange( RadarShape sh, int w, int h, int cx, int cy, const glColour *col )
1551 {
1552 GLfloat vertex[2*2], colours[8*2];
1553 double a;
1554 int i;
1555
1556 /* Set the colour. */
1557 for (i=0; i<2; i++) {
1558 colours[4*i + 0] = col->r;
1559 colours[4*i + 1] = col->g;
1560 colours[4*i + 2] = col->b;
1561 colours[4*i + 3] = 1.-interference_alpha;
1562 }
1563 gl_vboSubData( gui_vbo, gui_vboColourOffset,
1564 sizeof(GLfloat) * 2*4, colours );
1565
1566 /* Draw a line like for pilots. */
1567 a = ANGLE(cx,cy);
1568 if (sh == RADAR_CIRCLE) {
1569 vertex[0] = w*cos(a);
1570 vertex[1] = w*sin(a);
1571 vertex[2] = 0.85*vertex[0];
1572 vertex[3] = 0.85*vertex[1];
1573 }
1574 else {
1575 int cxa, cya;
1576 cxa = ABS(cx);
1577 cya = ABS(cy);
1578 /* Determine position. */
1579 if (cy >= cxa) { /* Bottom */
1580 vertex[0] = w/2. * (cx*1./cy);
1581 vertex[1] = h/2.;
1582 } else if (cx >= cya) { /* Left */
1583 vertex[0] = w/2.;
1584 vertex[1] = h/2. * (cy*1./cx);
1585 } else if (cya >= cxa) { /* Top */
1586 vertex[0] = -w/2. * (cx*1./cy);
1587 vertex[1] = -h/2.;
1588 } else { /* Right */
1589 vertex[0] = -w/2.;
1590 vertex[1] = -h/2. * (cy*1./cx);
1591 }
1592 /* Calculate rest. */
1593 vertex[2] = vertex[0] - 0.15*w*cos(a);
1594 vertex[3] = vertex[1] - 0.15*w*sin(a);
1595 }
1596 /* Set the vertex. */
1597 gl_vboSubData( gui_vbo, 0, sizeof(GLfloat) * 2*2, vertex );
1598 /* Draw tho VBO. */
1599 gl_vboActivateOffset( gui_vbo, GL_VERTEX_ARRAY, 0, 2, GL_FLOAT, 0 );
1600 gl_vboActivateOffset( gui_vbo, GL_COLOR_ARRAY,
1601 gui_vboColourOffset, 4, GL_FLOAT, 0 );
1602 glDrawArrays( GL_LINES, 0, 2 );
1603
1604 /* Deactivate the VBO. */
1605 gl_vboDeactivate();
1606 }
1607
1608
1609 /**
1610 * @brief Draws the planets in the minimap.
1611 *
1612 * Matrix mode is already displaced to center of the minimap.
1613 */
gui_renderPlanet(int ind,RadarShape shape,double w,double h,double res,int overlay)1614 void gui_renderPlanet( int ind, RadarShape shape, double w, double h, double res, int overlay )
1615 {
1616 int i;
1617 int x, y;
1618 int cx, cy, r, rc;
1619 GLfloat vx, vy, vr;
1620 GLfloat a;
1621 const glColour *col;
1622 Planet *planet;
1623 GLfloat vertex[5*2], colours[5*4];
1624
1625 /* Make sure is known. */
1626 if ( !planet_isKnown( cur_system->planets[ind] ))
1627 return;
1628
1629 /* Default values. */
1630 planet = cur_system->planets[ind];
1631 r = (int)(planet->radius*2. / res);
1632 vr = MAX( r, 3. ); /* Make sure it's visible. */
1633 if (overlay) {
1634 cx = (int)(planet->pos.x / res);
1635 cy = (int)(planet->pos.y / res);
1636 }
1637 else {
1638 cx = (int)((planet->pos.x - player.p->solid->pos.x) / res);
1639 cy = (int)((planet->pos.y - player.p->solid->pos.y) / res);
1640 }
1641 if (shape==RADAR_CIRCLE)
1642 rc = (int)(w*w);
1643 else
1644 rc = 0;
1645
1646 /* Check if in range. */
1647 if (shape == RADAR_RECT) {
1648 /* Out of range. */
1649 if ((ABS(cx) - r > w/2.) || (ABS(cy) - r > h/2.)) {
1650 if ((player.p->nav_planet == ind) && !overlay)
1651 gui_renderRadarOutOfRange( RADAR_RECT, w, h, cx, cy, &cRadar_tPlanet );
1652 return;
1653 }
1654 }
1655 else if (shape == RADAR_CIRCLE) {
1656 x = ABS(cx)-r;
1657 y = ABS(cy)-r;
1658 /* Out of range. */
1659 if (x*x + y*y > pow2(w-r)) {
1660 if ((player.p->nav_planet == ind) && !overlay)
1661 gui_renderRadarOutOfRange( RADAR_CIRCLE, w, w, cx, cy, &cRadar_tPlanet );
1662 return;
1663 }
1664 }
1665
1666 if (overlay) {
1667 /* Transform coordinates. */
1668 cx += SCREEN_W / 2;
1669 cy += SCREEN_H / 2;
1670 w *= 2.;
1671 h *= 2.;
1672 }
1673
1674 /* Do the blink. */
1675 if (ind == player.p->nav_planet)
1676 gui_planetBlink( w, h, rc, cx, cy, vr, shape );
1677
1678 /* Get the colour. */
1679 col = gui_getPlanetColour(ind);
1680 if (overlay)
1681 a = 1.;
1682 else
1683 a = 1.-interference_alpha;
1684 for (i=0; i<5; i++) {
1685 colours[4*i + 0] = col->r;
1686 colours[4*i + 1] = col->g;
1687 colours[4*i + 2] = col->b;
1688 colours[4*i + 3] = a;
1689 }
1690 gl_vboSubData( gui_vbo, gui_vboColourOffset,
1691 sizeof(GLfloat) * 5*4, colours );
1692 /* Now load the data. */
1693 vx = cx;
1694 vy = cy;
1695 vertex[0] = vx;
1696 vertex[1] = vy + vr;
1697 vertex[2] = vx + vr;
1698 vertex[3] = vy;
1699 vertex[4] = vx;
1700 vertex[5] = vy - vr;
1701 vertex[6] = vx - vr;
1702 vertex[7] = vy;
1703 vertex[8] = vertex[0];
1704 vertex[9] = vertex[1];
1705 gl_vboSubData( gui_vbo, 0, sizeof(GLfloat) * 5*2, vertex );
1706 /* Draw tho VBO. */
1707 gl_vboActivateOffset( gui_vbo, GL_VERTEX_ARRAY, 0, 2, GL_FLOAT, 0 );
1708 gl_vboActivateOffset( gui_vbo, GL_COLOR_ARRAY,
1709 gui_vboColourOffset, 4, GL_FLOAT, 0 );
1710 glDrawArrays( GL_LINE_STRIP, 0, 5 );
1711
1712 /* Deactivate the VBO. */
1713 gl_vboDeactivate();
1714
1715 /* Render name. */
1716 if (overlay)
1717 gl_printRaw( &gl_smallFont, cx+vr+5., cy, col, planet->name );
1718 }
1719
1720
1721 /**
1722 * @brief Renders a jump point on the minimap.
1723 *
1724 * @param i Jump point to render.
1725 */
gui_renderJumpPoint(int ind,RadarShape shape,double w,double h,double res,int overlay)1726 void gui_renderJumpPoint( int ind, RadarShape shape, double w, double h, double res, int overlay )
1727 {
1728 int i;
1729 int cx, cy, x, y, r, rc;
1730 GLfloat a;
1731 GLfloat ca, sa;
1732 GLfloat vx, vy, vr;
1733 const glColour *col;
1734 GLfloat vertex[4*2], colours[4*4];
1735 JumpPoint *jp;
1736
1737 /* Default values. */
1738 jp = &cur_system->jumps[ind];
1739 r = (int)(jumppoint_gfx->sw / res);
1740 vr = MAX( r, 3. ); /* Make sure it's visible. */
1741 if (overlay) {
1742 cx = (int)(jp->pos.x / res);
1743 cy = (int)(jp->pos.y / res);
1744 }
1745 else {
1746 cx = (int)((jp->pos.x - player.p->solid->pos.x) / res);
1747 cy = (int)((jp->pos.y - player.p->solid->pos.y) / res);
1748 }
1749 if (shape==RADAR_CIRCLE)
1750 rc = (int)(w*w);
1751 else
1752 rc = 0;
1753
1754 /* Check if known */
1755 if (!jp_isKnown(jp))
1756 return;
1757
1758 /* Check if in range. */
1759 if (shape == RADAR_RECT) {
1760 /* Out of range. */
1761 if ((ABS(cx) - r > w/2.) || (ABS(cy) - r > h/2.)) {
1762 if ((player.p->nav_hyperspace == ind) && !overlay)
1763 gui_renderRadarOutOfRange( RADAR_RECT, w, h, cx, cy, &cRadar_tPlanet );
1764 return;
1765 }
1766 }
1767 else if (shape == RADAR_CIRCLE) {
1768 x = ABS(cx)-r;
1769 y = ABS(cy)-r;
1770 /* Out of range. */
1771 if (x*x + y*y > pow2(w-r)) {
1772 if ((player.p->nav_hyperspace == ind) && !overlay)
1773 gui_renderRadarOutOfRange( RADAR_CIRCLE, w, w, cx, cy, &cRadar_tPlanet );
1774 return;
1775 }
1776 }
1777
1778 if (overlay) {
1779 /* Transform coordinates. */
1780 cx += SCREEN_W / 2;
1781 cy += SCREEN_H / 2;
1782 w *= 2.;
1783 h *= 2.;
1784 }
1785
1786 /* Do the blink. */
1787 if (ind == player.p->nav_hyperspace) {
1788 gui_planetBlink( w, h, rc, cx, cy, vr, shape );
1789 col = &cGreen;
1790 }
1791 else if (jp_isFlag(jp, JP_HIDDEN))
1792 col = &cRed;
1793 else
1794 col = &cWhite;
1795
1796 if (overlay)
1797 a = 1.;
1798 else
1799 a = 1.-interference_alpha;
1800
1801 /* Get the colour. */
1802 for (i=0; i<4; i++) {
1803 colours[4*i + 0] = col->r;
1804 colours[4*i + 1] = col->g;
1805 colours[4*i + 2] = col->b;
1806 colours[4*i + 3] = a;
1807 }
1808 gl_vboSubData( gui_vbo, gui_vboColourOffset,
1809 sizeof(GLfloat) * 5*4, colours );
1810 /* Now load the data. */
1811 vx = cx;
1812 vy = cy;
1813 ca = jp->cosa;
1814 sa = jp->sina;
1815 /* Must rotate around triangle center which with our calculations is shifted vr/3 to the left. */
1816 vertex[0] = vx + (4./3.*vr)*ca;
1817 vertex[1] = vy - (4./3.*vr)*sa;
1818 vertex[2] = vx - (2./3.*vr)*ca + vr*sa;
1819 vertex[3] = vy + (2./3.*vr)*sa + vr*ca;
1820 vertex[4] = vx - (2./3.*vr)*ca - vr*sa;
1821 vertex[5] = vy + (2./3.*vr)*sa - vr*ca;
1822 vertex[6] = vertex[0];
1823 vertex[7] = vertex[1];
1824 gl_vboSubData( gui_vbo, 0, sizeof(GLfloat) * 4*2, vertex );
1825 /* Draw tho VBO. */
1826 gl_vboActivateOffset( gui_vbo, GL_VERTEX_ARRAY, 0, 2, GL_FLOAT, 0 );
1827 gl_vboActivateOffset( gui_vbo, GL_COLOR_ARRAY,
1828 gui_vboColourOffset, 4, GL_FLOAT, 0 );
1829 glDrawArrays( GL_LINE_STRIP, 0, 4 );
1830
1831 /* Deactivate the VBO. */
1832 gl_vboDeactivate();
1833
1834 /* Render name. */
1835 if (overlay)
1836 gl_printRaw( &gl_smallFont, cx+vr+5., cy, col, sys_isKnown(jp->target) ? jp->target->name : "Unknown" );
1837 }
1838 #undef CHECK_PIXEL
1839
1840
1841 /**
1842 * @brief Sets the viewport.
1843 */
gui_setViewport(double x,double y,double w,double h)1844 void gui_setViewport( double x, double y, double w, double h )
1845 {
1846 gui_viewport_x = x;
1847 gui_viewport_y = y;
1848 gui_viewport_w = w;
1849 gui_viewport_h = h;
1850
1851 /* We now set the viewport. */
1852 gl_setDefViewport( gui_viewport_x, gui_viewport_y, gui_viewport_w, gui_viewport_h );
1853 gl_defViewport();
1854
1855 /* Run border calculations. */
1856 gui_calcBorders();
1857
1858 /* Regenerate the Nebula stuff. */
1859 if ((cur_system != NULL) && (cur_system->nebu_density > 0.))
1860 nebu_genOverlay();
1861 }
1862
1863
1864 /**
1865 * @brief Resets the viewport.
1866 */
gui_clearViewport(void)1867 void gui_clearViewport (void)
1868 {
1869 gl_setDefViewport( 0., 0., gl_screen.nw, gl_screen.nh );
1870 gl_defViewport();
1871 }
1872
1873
1874 /**
1875 * @brief Calculates and sets the GUI borders.
1876 */
gui_calcBorders(void)1877 static void gui_calcBorders (void)
1878 {
1879 double w,h;
1880
1881 /* Precalculations. */
1882 w = SCREEN_W/2.;
1883 h = SCREEN_H/2.;
1884
1885 /*
1886 * Borders.
1887 */
1888 gui_tl = atan2( +h, -w );
1889 if (gui_tl < 0.)
1890 gui_tl += 2*M_PI;
1891 gui_tr = atan2( +h, +w );
1892 if (gui_tr < 0.)
1893 gui_tr += 2*M_PI;
1894 gui_bl = atan2( -h, -w );
1895 if (gui_bl < 0.)
1896 gui_bl += 2*M_PI;
1897 gui_br = atan2( -h, +w );
1898 if (gui_br < 0.)
1899 gui_br += 2*M_PI;
1900 }
1901
1902
1903 /**
1904 * @brief Initializes the GUI system.
1905 *
1906 * @return 0 on success;
1907 */
gui_init(void)1908 int gui_init (void)
1909 {
1910 /*
1911 * radar
1912 */
1913 gui_radar.res = RADAR_RES_DEFAULT;
1914
1915 /*
1916 * messages
1917 */
1918 gui_mesg_x = 20;
1919 gui_mesg_y = 30;
1920 gui_mesg_w = SCREEN_W - 400;
1921 if (mesg_stack == NULL) {
1922 mesg_stack = calloc(mesg_max, sizeof(Mesg));
1923 if (mesg_stack == NULL) {
1924 ERR("Out of memory!");
1925 return -1;
1926 }
1927 }
1928
1929 /*
1930 * VBO.
1931 */
1932 if (gui_vbo == NULL) {
1933 gui_vbo = gl_vboCreateStream( sizeof(GLfloat) * 8*(2+4), NULL );
1934 gui_vboColourOffset = sizeof(GLfloat) * 8*2;
1935 }
1936
1937 /*
1938 * OSD
1939 */
1940 osd_setup( 30., SCREEN_H-90., 150., 300. );
1941
1942 /*
1943 * Set viewport.
1944 */
1945 gui_setViewport( 0., 0., gl_screen.w, gl_screen.h );
1946
1947 /*
1948 * Icons.
1949 */
1950 gui_ico_hail = gl_newSprite( GUI_GFX_PATH"hail.png", 5, 2, 0 );
1951
1952 return 0;
1953 }
1954
1955
1956 /**
1957 * @brief Runs a GUI Lua function.
1958 *
1959 * @param func Name of the function to run.
1960 * @return 0 on success.
1961 */
gui_doFunc(const char * func)1962 static int gui_doFunc( const char* func )
1963 {
1964 gui_prepFunc( func );
1965 return gui_runFunc( func, 0, 0 );
1966 }
1967
1968
1969 /**
1970 * @brief Prepares to run a function.
1971 */
gui_prepFunc(const char * func)1972 static int gui_prepFunc( const char* func )
1973 {
1974 #if DEBUGGING
1975 if (gui_env == LUA_NOREF) {
1976 WARN( "Trying to run GUI func '%s' but no GUI is loaded!", func );
1977 return -1;
1978 }
1979 #endif /* DEBUGGING */
1980
1981 /* Set up function. */
1982 nlua_getenv( gui_env, func );
1983 return 0;
1984 }
1985
1986
1987 /**
1988 * @brief Runs a function.
1989 * @note Function must be prepared beforehand.
1990 * @param func Name of the function to run.
1991 * @param nargs Arguments to the function.
1992 * @param nret Parameters to get returned from the function.
1993 */
gui_runFunc(const char * func,int nargs,int nret)1994 static int gui_runFunc( const char* func, int nargs, int nret )
1995 {
1996 int ret;
1997 const char* err;
1998
1999 /* Run the function. */
2000 ret = nlua_pcall( gui_env, nargs, nret );
2001 if (ret != 0) { /* error has occurred */
2002 err = (lua_isstring(naevL,-1)) ? lua_tostring(naevL,-1) : NULL;
2003 WARN("GUI Lua -> '%s': %s",
2004 func, (err) ? err : "unknown error");
2005 lua_pop(naevL,2);
2006 return ret;
2007 }
2008
2009 return ret;
2010 }
2011
2012
2013 /**
2014 * @brief Reloads the GUI.
2015 */
gui_reload(void)2016 void gui_reload (void)
2017 {
2018 if (gui_env == LUA_NOREF)
2019 return;
2020
2021 gui_load( gui_pick() );
2022 }
2023
2024
2025 /**
2026 * @brief Player just changed their cargo.
2027 */
gui_setCargo(void)2028 void gui_setCargo (void)
2029 {
2030 if (gui_env != LUA_NOREF)
2031 gui_doFunc( "update_cargo" );
2032 }
2033
2034
2035 /**
2036 * @brief PlNULLayer just changed their nav computer target.
2037 */
gui_setNav(void)2038 void gui_setNav (void)
2039 {
2040 if (gui_env != LUA_NOREF)
2041 gui_doFunc( "update_nav" );
2042 }
2043
2044
2045 /**
2046 * @brief Player just changed their pilot target.
2047 */
gui_setTarget(void)2048 void gui_setTarget (void)
2049 {
2050 if (gui_env != LUA_NOREF)
2051 gui_doFunc( "update_target" );
2052 }
2053
2054
2055 /**
2056 * @brief Player just upgraded their ship or modified it.
2057 */
gui_setShip(void)2058 void gui_setShip (void)
2059 {
2060 if (gui_env != LUA_NOREF)
2061 gui_doFunc( "update_ship" );
2062 }
2063
2064
2065 /**
2066 * @brief Player just changed their system.
2067 */
gui_setSystem(void)2068 void gui_setSystem (void)
2069 {
2070 if (gui_env != LUA_NOREF)
2071 gui_doFunc( "update_system" );
2072 }
2073
2074
2075 /**
2076 * @brief Player's relationship with a faction was modified.
2077 */
gui_updateFaction(void)2078 void gui_updateFaction (void)
2079 {
2080 if (gui_env != LUA_NOREF && player.p->nav_planet != -1)
2081 gui_doFunc( "update_faction" );
2082 }
2083
2084
2085 /**
2086 * @brief Calls trigger functions depending on who the pilot is.
2087 *
2088 * @param The pilot to act based upon.
2089 */
gui_setGeneric(Pilot * pilot)2090 void gui_setGeneric( Pilot* pilot )
2091 {
2092 if (gui_env == LUA_NOREF)
2093 return;
2094
2095 if ((player.p->target != PLAYER_ID) && (pilot->id == player.p->target))
2096 gui_setTarget();
2097 else if (pilot_isPlayer(pilot)) {
2098 gui_setCargo();
2099 gui_setShip();
2100 }
2101 }
2102
2103
2104 /**
2105 * @brief Determines which GUI should be used.
2106 */
gui_pick(void)2107 char* gui_pick (void)
2108 {
2109 char* gui;
2110
2111 if (player.gui && (player.guiOverride == 1 || strcmp(player.p->ship->gui,"default")==0))
2112 gui = player.gui;
2113 else
2114 gui = player.p->ship->gui;
2115 return gui;
2116 }
2117
2118
2119 /**
2120 * @brief Attempts to load the actual GUI.
2121 *
2122 * @param name Name of the GUI to load.
2123 * @return 0 on success.
2124 */
gui_load(const char * name)2125 int gui_load( const char* name )
2126 {
2127 (void) name;
2128 char *buf, path[PATH_MAX];
2129 uint32_t bufsize;
2130
2131 /* Set defaults. */
2132 gui_cleanup();
2133
2134 /* Open file. */
2135 nsnprintf( path, sizeof(path), "dat/gui/%s.lua", name );
2136 buf = ndata_read( path, &bufsize );
2137 if (buf == NULL) {
2138 WARN("Unable to find GUI '%s'.", path );
2139 return -1;
2140 }
2141
2142 /* Clean up. */
2143 if (gui_env != LUA_NOREF) {
2144 nlua_freeEnv(gui_env);
2145 gui_env = LUA_NOREF;
2146 }
2147
2148 /* Create Lua state. */
2149 gui_env = nlua_newEnv(1);
2150 if (nlua_dobufenv( gui_env, buf, bufsize, path ) != 0) {
2151 WARN("Failed to load GUI Lua: %s\n"
2152 "%s\n"
2153 "Most likely Lua file has improper syntax, please check",
2154 path, lua_tostring(naevL,-1));
2155 nlua_freeEnv( gui_env );
2156 gui_env = LUA_NOREF;
2157 free(buf);
2158 return -1;
2159 }
2160 free(buf);
2161 nlua_loadStandard( gui_env );
2162 nlua_loadGFX( gui_env );
2163 nlua_loadGUI( gui_env );
2164
2165 /* Run create function. */
2166 if (gui_doFunc( "create" )) {
2167 nlua_freeEnv( gui_env );
2168 gui_env = LUA_NOREF;
2169 }
2170
2171 /* Recreate land window if landed. */
2172 if (landed) {
2173 land_genWindows( 0, 1 );
2174 window_lower( land_wid );
2175 }
2176
2177 return 0;
2178 }
2179
2180
2181 /**
2182 * @brief Creates the interference map for the current gui.
2183 */
gui_createInterference(Radar * radar)2184 static void gui_createInterference( Radar *radar )
2185 {
2186 uint8_t raw;
2187 int i, j, k;
2188 float *map;
2189 uint32_t *pix;
2190 SDL_Surface *sur;
2191 int w,h, hw,hh;
2192 float c;
2193 int r;
2194
2195 /* Dimension shortcuts. */
2196 if (radar->shape == RADAR_CIRCLE) {
2197 w = radar->w*2.;
2198 h = w;
2199 }
2200 else if (radar->shape == RADAR_RECT) {
2201 w = radar->w*2.;
2202 h = radar->h*2.;
2203 }
2204 else {
2205 WARN("Radar shape is invalid.");
2206 return;
2207 }
2208
2209 for (k=0; k<INTERFERENCE_LAYERS; k++) {
2210
2211 /* Free the old texture. */
2212 if (radar->interference[k] != NULL)
2213 gl_freeTexture(radar->interference[k]);
2214
2215 /* Create the temporary surface. */
2216 sur = SDL_CreateRGBSurface( SDL_SWSURFACE, w, h, 32, RGBAMASK );
2217 pix = sur->pixels;
2218
2219 /* Clear pixels. */
2220 memset( pix, 0, sizeof(uint32_t)*w*h );
2221
2222 /* Load the interference map. */
2223 map = noise_genRadarInt( w, h, (w+h)/2*1.2 );
2224
2225 /* Create the texture. */
2226 SDL_LockSurface( sur );
2227 if (radar->shape == RADAR_CIRCLE) {
2228 r = pow2((int)radar->w);
2229 hw = w/2;
2230 hh = h/2;
2231 for (i=0; i<h; i++) {
2232 for (j=0; j<w; j++) {
2233 /* Must be in circle. */
2234 if (pow2(i-hh) + pow2(j-hw) > r)
2235 continue;
2236 c = map[i*w + j];
2237 raw = 0xff & (uint8_t)((float)0xff * c);
2238 memset( &pix[i*w + j], raw, sizeof(uint32_t) );
2239 pix[i*w + j] |= AMASK;
2240 }
2241 }
2242 }
2243 else if (radar->shape == RADAR_RECT) {
2244 for (i=0; i<h*w; i++) {
2245 /* Process pixels. */
2246 c = map[i];
2247 raw = 0xff & (uint8_t)((float)0xff * c);
2248 memset( &pix[i], raw, sizeof(uint32_t) );
2249 pix[i] |= AMASK;
2250 }
2251 }
2252 SDL_UnlockSurface( sur );
2253
2254 /* Set the interference. */
2255 radar->interference[k] = gl_loadImage( sur, 0 );
2256
2257 /* Clean up. */
2258 free(map);
2259 }
2260 }
2261
2262
2263 /**
2264 * @brief Cleans up the GUI.
2265 */
gui_cleanup(void)2266 void gui_cleanup (void)
2267 {
2268 int i;
2269
2270 /* Disable mouse voodoo. */
2271 gui_mouseClickEnable( 0 );
2272 gui_mouseMoveEnable( 0 );
2273
2274 /* Interference. */
2275 for (i=0; i<INTERFERENCE_LAYERS; i++) {
2276 if (gui_radar.interference[i] != NULL) {
2277 gl_freeTexture(gui_radar.interference[i]);
2278 gui_radar.interference[i] = NULL;
2279 }
2280 }
2281
2282 /* Set the viewport. */
2283 gui_clearViewport();
2284
2285 /* Reset FPS. */
2286 fps_setPos( 15., (double)(gl_screen.h-15-gl_defFont.h) );
2287
2288 /* Clean up interference. */
2289 interference_alpha = 0.;
2290 interference_layer = 0;
2291 interference_t = 0.;
2292
2293 /* Destroy offset. */
2294 gui_xoff = 0.;
2295 gui_yoff = 0.;
2296
2297 /* Destroy lua. */
2298 if (gui_env != LUA_NOREF) {
2299 nlua_freeEnv( gui_env );
2300 gui_env = LUA_NOREF;
2301 }
2302
2303 /* OMSG */
2304 omsg_position( SCREEN_W/2., SCREEN_H*2./3., SCREEN_W*2./3. );
2305 }
2306
2307
2308 /**
2309 * @brief Frees the gui stuff.
2310 */
gui_free(void)2311 void gui_free (void)
2312 {
2313 /* Clean up gui. */
2314 gui_cleanup();
2315
2316 /* Free messages. */
2317 if (mesg_stack != NULL) {
2318 free(mesg_stack);
2319 mesg_stack = NULL;
2320 }
2321
2322 /* Free VBO. */
2323 if (gui_vbo != NULL) {
2324 gl_vboDestroy( gui_vbo );
2325 gui_vbo = NULL;
2326 }
2327
2328 /* Clean up the osd. */
2329 osd_exit();
2330
2331 /* Free icons. */
2332 if (gui_ico_hail != NULL)
2333 gl_freeTexture( gui_ico_hail );
2334 gui_ico_hail = NULL;
2335 if (gui_target_planet != NULL)
2336 gl_freeTexture( gui_target_planet );
2337 gui_target_planet = NULL;
2338 if (gui_target_pilot != NULL)
2339 gl_freeTexture( gui_target_pilot );
2340 gui_target_pilot = NULL;
2341
2342 /* Free overlay messages. */
2343 omsg_cleanup();
2344 }
2345
2346
2347 /**
2348 * @brief Modifies the radar resolution.
2349 *
2350 * @param mod Number of intervals to jump (up or down).
2351 */
gui_setRadarRel(int mod)2352 void gui_setRadarRel( int mod )
2353 {
2354 gui_radar.res += mod * RADAR_RES_INTERVAL;
2355 gui_radar.res = CLAMP( RADAR_RES_MIN, RADAR_RES_MAX, gui_radar.res );
2356
2357 player_message( "\epRadar set to %dx.", (int)gui_radar.res );
2358 }
2359
2360
2361 /**
2362 * @brief Gets the GUI offset.
2363 *
2364 * @param x X offset.
2365 * @param y Y offset.
2366 */
gui_getOffset(double * x,double * y)2367 void gui_getOffset( double *x, double *y )
2368 {
2369 *x = gui_xoff;
2370 *y = gui_yoff;
2371 }
2372
2373
2374 /**
2375 * @brief Gets the hail icon texture.
2376 */
gui_hailIcon(void)2377 glTexture* gui_hailIcon (void)
2378 {
2379 return gui_ico_hail;
2380 }
2381
2382
2383 /**
2384 * @brief Sets the planet target GFX.
2385 */
gui_targetPlanetGFX(glTexture * gfx)2386 void gui_targetPlanetGFX( glTexture *gfx )
2387 {
2388 if (gui_target_planet != NULL)
2389 gl_freeTexture( gui_target_planet );
2390 gui_target_planet = gl_dupTexture( gfx );
2391 }
2392
2393
2394 /**
2395 * @brief Sets the pilot target GFX.
2396 */
gui_targetPilotGFX(glTexture * gfx)2397 void gui_targetPilotGFX( glTexture *gfx )
2398 {
2399 if (gui_target_pilot != NULL)
2400 gl_freeTexture( gui_target_pilot );
2401 gui_target_pilot = gl_dupTexture( gfx );
2402 }
2403
2404
2405 /**
2406 * @brief Handles GUI events.
2407 */
gui_handleEvent(SDL_Event * evt)2408 int gui_handleEvent( SDL_Event *evt )
2409 {
2410 int ret;
2411 int x, y;
2412
2413 if (player.p == NULL)
2414 return 0;
2415 if ((evt->type == SDL_MOUSEBUTTONDOWN) &&
2416 (pilot_isFlag(player.p,PILOT_HYP_PREP) ||
2417 pilot_isFlag(player.p,PILOT_HYP_BEGIN) ||
2418 pilot_isFlag(player.p,PILOT_HYPERSPACE)))
2419 return 0;
2420
2421 ret = 0;
2422 switch (evt->type) {
2423 /* Mouse motion. */
2424 case SDL_MOUSEMOTION:
2425 if (!gui_L_mmove)
2426 break;
2427 gui_prepFunc( "mouse_move" );
2428 gl_windowToScreenPos( &x, &y, evt->motion.x, evt->motion.y );
2429 lua_pushnumber( naevL, x );
2430 lua_pushnumber( naevL, y );
2431 gui_runFunc( "mouse_move", 2, 0 );
2432 break;
2433
2434 /* Mouse click. */
2435 case SDL_MOUSEBUTTONDOWN:
2436 case SDL_MOUSEBUTTONUP:
2437 if (!gui_L_mclick)
2438 break;
2439 gui_prepFunc( "mouse_click" );
2440 lua_pushnumber( naevL, evt->button.button+1 );
2441 gl_windowToScreenPos( &x, &y, evt->button.x, evt->button.y );
2442 lua_pushnumber( naevL, x );
2443 lua_pushnumber( naevL, y );
2444 lua_pushboolean( naevL, (evt->type==SDL_MOUSEBUTTONDOWN) );
2445 gui_runFunc( "mouse_click", 4, 1 );
2446 ret = lua_toboolean( naevL, -1 );
2447 lua_pop( naevL, 1 );
2448 break;
2449
2450 /* Not interested in the rest. */
2451 default:
2452 break;
2453 }
2454 return ret;
2455 }
2456
2457
2458 /**
2459 * @brief Enables the mouse click callback.
2460 */
gui_mouseClickEnable(int enable)2461 void gui_mouseClickEnable( int enable )
2462 {
2463 gui_L_mclick = enable;
2464 }
2465
2466
2467 /**
2468 * @brief Enables the mouse movement callback.
2469 */
gui_mouseMoveEnable(int enable)2470 void gui_mouseMoveEnable( int enable )
2471 {
2472 gui_L_mmove = enable;
2473 }
2474