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