1 /*
2  * See Licensing and Copyright notice in naev.h
3  */
4 
5 
6 #include "map_overlay.h"
7 
8 #include "naev.h"
9 
10 #include "SDL.h"
11 
12 #include "log.h"
13 #include "opengl.h"
14 #include "font.h"
15 #include "gui.h"
16 #include "pilot.h"
17 #include "player.h"
18 #include "space.h"
19 #include "input.h"
20 #include "array.h"
21 
22 
23 /**
24  * @brief An overlay map marker.
25  */
26 typedef struct ovr_marker_s {
27    unsigned int id; /**< ID of the marker. */
28    char *text; /**< Marker display text. */
29    int type; /**< Marker type. */
30    union {
31       struct {
32          double x; /**< X center of point marker. */
33          double y; /**< Y center of point marker. */
34       } pt; /**< Point marker. */
35    } u; /**< Type data. */
36 } ovr_marker_t;
37 static unsigned int mrk_idgen = 0; /**< ID generator for markers. */
38 static ovr_marker_t *ovr_markers = NULL; /**< Overlay markers. */
39 
40 
41 static Uint32 ovr_opened = 0; /**< Time last opened. */
42 static int ovr_open = 0; /**< Is the overlay open? */
43 static double ovr_res = 10.; /**< Resolution. */
44 
45 
46 /*
47  * Prototypes
48  */
49 /* Markers. */
50 static void ovr_mrkRenderAll( double res );
51 static void ovr_mrkCleanup(  ovr_marker_t *mrk );
52 static ovr_marker_t *ovr_mrkNew (void);
53 
54 
55 /**
56  * @brief Check to see if the map overlay is open.
57  */
ovr_isOpen(void)58 int ovr_isOpen (void)
59 {
60    return !!ovr_open;
61 }
62 
63 
64 /**
65  * @brief Handles input to the map overlay.
66  */
ovr_input(SDL_Event * event)67 int ovr_input( SDL_Event *event )
68 {
69    int mx, my;
70    double x, y;
71 
72    /* We only want mouse events. */
73    if (event->type != SDL_MOUSEBUTTONDOWN)
74       return 0;
75 
76    /* Player must not be NULL. */
77    if (player_isFlag(PLAYER_DESTROYED) || (player.p == NULL))
78       return 0;
79 
80    /* Player must not be dead. */
81    if (pilot_isFlag(player.p, PILOT_DEAD))
82       return 0;
83 
84    /* Mouse targeting only uses left and right buttons. */
85    if (event->button.button != SDL_BUTTON_LEFT &&
86             event->button.button != SDL_BUTTON_RIGHT)
87       return 0;
88 
89    /* Translate from window to screen. */
90    mx = event->button.x;
91    my = event->button.y;
92    gl_windowToScreenPos( &mx, &my, mx, my );
93 
94    /* Translate to space coords. */
95    x  = ((double)mx - SCREEN_W/2.) * ovr_res;
96    y  = ((double)my - SCREEN_H/2.) * ovr_res;
97 
98    return input_clickPos( event, x, y, 1., 10. * ovr_res, 15. * ovr_res );
99 }
100 
101 
102 /**
103  * @brief Refreshes the map overlay recalculating the dimensions it should have.
104  *
105  * This should be called if the planets or the likes change at any given time.
106  */
ovr_refresh(void)107 void ovr_refresh (void)
108 {
109    double max_x, max_y;
110    int i;
111 
112    /* Must be open. */
113    if (!ovr_isOpen())
114       return;
115 
116    /* Calculate max size. */
117    max_x = 0.;
118    max_y = 0.;
119    for (i=0; i<cur_system->njumps; i++) {
120       max_x = MAX( max_x, ABS(cur_system->jumps[i].pos.x) );
121       max_y = MAX( max_y, ABS(cur_system->jumps[i].pos.y) );
122    }
123    for (i=0; i<cur_system->nplanets; i++) {
124       max_x = MAX( max_x, ABS(cur_system->planets[i]->pos.x) );
125       max_y = MAX( max_y, ABS(cur_system->planets[i]->pos.y) );
126    }
127 
128    /* We need to calculate the radius of the rendering. */
129    ovr_res = 2. * 1.2 * MAX( max_x / SCREEN_W, max_y / SCREEN_H );
130 }
131 
132 
133 /**
134  * @brief Properly opens or closes the overlay map.
135  *
136  *    @param open Whether or not to open it.
137  */
ovr_setOpen(int open)138 void ovr_setOpen( int open )
139 {
140    if (open && !ovr_open) {
141       ovr_open = 1;
142       input_mouseShow();
143    }
144    else if (ovr_open) {
145       ovr_open = 0;
146       input_mouseHide();
147    }
148 }
149 
150 
151 /**
152  * @brief Handles a keypress event.
153  *
154  *    @param type Type of event.
155  */
ovr_key(int type)156 void ovr_key( int type )
157 {
158    Uint32 t;
159 
160    t = SDL_GetTicks();
161 
162    if (type > 0) {
163       if (ovr_open)
164          ovr_setOpen(0);
165       else {
166          ovr_setOpen(1);
167          ovr_opened  = t;
168 
169          /* Refresh overlay size. */
170          ovr_refresh();
171       }
172    }
173    else if (type < 0) {
174       if (t - ovr_opened > 300)
175          ovr_setOpen(0);
176    }
177 }
178 
179 
180 /**
181  * @brief Renders the overlay map.
182  *
183  *    @param dt Current delta tick.
184  */
ovr_render(double dt)185 void ovr_render( double dt )
186 {
187    (void) dt;
188    int i, j;
189    Pilot **pstk;
190    AsteroidAnchor *ast;
191    int n;
192    double w, h, res;
193    double x,y;
194    glColour c = { .r=0., .g=0., .b=0., .a=0.5 };
195 
196    /* Must be open. */
197    if (!ovr_open)
198       return;
199 
200    /* Player must be alive. */
201    if (player_isFlag( PLAYER_DESTROYED ) || (player.p == NULL))
202       return;
203 
204    /* Default values. */
205    w     = SCREEN_W;
206    h     = SCREEN_H;
207    res   = ovr_res;
208 
209    /* First render the background overlay. */
210    gl_renderRect( 0., 0., w, h, &c );
211 
212    /* Render planets. */
213    for (i=0; i<cur_system->nplanets; i++)
214       if ((cur_system->planets[ i ]->real == ASSET_REAL) && (i != player.p->nav_planet))
215          gui_renderPlanet( i, RADAR_RECT, w, h, res, 1 );
216    if (player.p->nav_planet > -1)
217       gui_renderPlanet( player.p->nav_planet, RADAR_RECT, w, h, res, 1 );
218 
219    /* Render jump points. */
220    for (i=0; i<cur_system->njumps; i++)
221       if ((i != player.p->nav_hyperspace) && !jp_isFlag(&cur_system->jumps[i], JP_EXITONLY))
222          gui_renderJumpPoint( i, RADAR_RECT, w, h, res, 1 );
223    if (player.p->nav_hyperspace > -1)
224       gui_renderJumpPoint( player.p->nav_hyperspace, RADAR_RECT, w, h, res, 1 );
225 
226    /* Render pilots. */
227    pstk  = pilot_getAll( &n );
228    j     = 0;
229    for (i=0; i<n; i++) {
230       if (pstk[i]->id == PLAYER_ID) /* Skip player. */
231          continue;
232       if (pstk[i]->id == player.p->target)
233          j = i;
234       else
235          gui_renderPilot( pstk[i], RADAR_RECT, w, h, res, 1 );
236    }
237    /* Render the targeted pilot */
238    if (j!=0)
239       gui_renderPilot( pstk[j], RADAR_RECT, w, h, res, 1 );
240 
241    /* Check if player has goto target. */
242    if (player_isFlag(PLAYER_AUTONAV) && (player.autonav == AUTONAV_POS_APPROACH)) {
243       x = player.autonav_pos.x / res + w / 2.;
244       y = player.autonav_pos.y / res + h / 2.;
245       gl_renderCross( x, y, 5., &cRadar_hilight );
246       gl_printRaw( &gl_smallFont, x+10., y-gl_smallFont.h/2., &cRadar_hilight, "GOTO" );
247    }
248 
249    /* render the asteroids */
250    for (i=0; i<cur_system->nasteroids; i++) {
251       ast = &cur_system->asteroids[i];
252       for (j=0; j<ast->nb; j++)
253          gui_renderAsteroid( &ast->asteroids[j], w, h, res, 1 );
254    }
255 
256    /* Render the player. */
257    gui_renderPlayer( res, 1 );
258 
259    /* Render markers. */
260    ovr_mrkRenderAll( res );
261 }
262 
263 
264 /**
265  * @brief Renders all the markers.
266  *
267  *    @param res Resolution to render at.
268  */
ovr_mrkRenderAll(double res)269 static void ovr_mrkRenderAll( double res )
270 {
271    int i;
272    ovr_marker_t *mrk;
273    double x, y;
274 
275    if (ovr_markers == NULL)
276       return;
277 
278    for (i=0; i<array_size(ovr_markers); i++) {
279       mrk = &ovr_markers[i];
280 
281       x = mrk->u.pt.x / res + SCREEN_W / 2.;
282       y = mrk->u.pt.y / res + SCREEN_H / 2.;
283       gl_renderCross( x, y, 5., &cRadar_hilight );
284 
285       if (mrk->text != NULL)
286          gl_printRaw( &gl_smallFont, x+10., y-gl_smallFont.h/2., &cRadar_hilight, mrk->text );
287    }
288 }
289 
290 
291 /**
292  * @brief Frees up and clears all marker related stuff.
293  */
ovr_mrkFree(void)294 void ovr_mrkFree (void)
295 {
296    /* Clear markers. */
297    ovr_mrkClear();
298 
299    /* Free array. */
300    if (ovr_markers != NULL)
301       array_free( ovr_markers );
302    ovr_markers = NULL;
303 }
304 
305 
306 /**
307  * @brief Clears the current markers.
308  */
ovr_mrkClear(void)309 void ovr_mrkClear (void)
310 {
311    int i;
312    if (ovr_markers == NULL)
313       return;
314    for (i=0; i<array_size(ovr_markers); i++)
315       ovr_mrkCleanup( &ovr_markers[i] );
316    array_erase( &ovr_markers, ovr_markers, &ovr_markers[ array_size(ovr_markers) ] );
317 }
318 
319 
320 /**
321  * @brief Clears up after an individual marker.
322  *
323  *    @param mrk Marker to clean up after.
324  */
ovr_mrkCleanup(ovr_marker_t * mrk)325 static void ovr_mrkCleanup( ovr_marker_t *mrk )
326 {
327    if (mrk->text != NULL)
328       free( mrk->text );
329    mrk->text = NULL;
330 }
331 
332 
333 /**
334  * @brief Creates a new marker.
335  *
336  *    @return The newly created marker.
337  */
ovr_mrkNew(void)338 static ovr_marker_t *ovr_mrkNew (void)
339 {
340    ovr_marker_t *mrk;
341 
342    if (ovr_markers == NULL)
343       ovr_markers = array_create(  ovr_marker_t );
344 
345    mrk = &array_grow( &ovr_markers );
346    memset( mrk, 0, sizeof( ovr_marker_t ) );
347    mrk->id = ++mrk_idgen;
348    return mrk;
349 }
350 
351 
352 /**
353  * @brief Creates a new point marker.
354  *
355  *    @param text Text to display with the marker.
356  *    @param x X position of the marker.
357  *    @param y Y position of the marker.
358  *    @return The id of the newly created marker.
359  */
ovr_mrkAddPoint(const char * text,double x,double y)360 unsigned int ovr_mrkAddPoint( const char *text, double x, double y )
361 {
362    ovr_marker_t *mrk;
363 
364    mrk = ovr_mrkNew();
365    mrk->type = 0;
366    if (text != NULL)
367       mrk->text = strdup( text );
368    mrk->u.pt.x = x;
369    mrk->u.pt.y = y;
370 
371    return mrk->id;
372 }
373 
374 
375 /**
376  * @brief Removes a marker by id.
377  *
378  *    @param id ID of the marker to remove.
379  */
ovr_mrkRm(unsigned int id)380 void ovr_mrkRm( unsigned int id )
381 {
382    int i;
383    if (ovr_markers == NULL)
384       return;
385    for (i=0; i<array_size(ovr_markers); i++) {
386       if (id!=ovr_markers[i].id)
387          continue;
388       ovr_mrkCleanup( &ovr_markers[i] );
389       array_erase( &ovr_markers, &ovr_markers[i], &ovr_markers[i+1] );
390       break;
391    }
392 }
393 
394 
395