9#include "map_overlay.h"
25const double OVERLAY_FADEIN = 1.0/3.0;
30typedef struct MapOverlayRadiusConstraint_ {
36typedef enum ovr_marker_type_e {
44typedef struct ovr_marker_s {
57static unsigned int mrk_idgen = 0;
60static SafeLane* ovr_render_safelanes = NULL;
62static Uint32 ovr_opened = 0;
63static int ovr_open = 0;
64static double ovr_res = 10.;
65static double ovr_dt = 0.;
66static const double ovr_text_pixbuf = 5.;
68typedef struct OverlayBounds_s {
83static void force_collision(
float *ox,
float *oy,
84 float x,
float y,
float w,
float h,
85 float mx,
float my,
float mw,
float mh );
86static void ovr_optimizeLayout(
int items,
const vec2** pos,
88static void ovr_refresh_uzawa_overlap(
float *forces_x,
float *forces_y,
89 float x,
float y,
float w,
float h,
const vec2** pos,
91 float *offx,
float *offy,
float *offdx,
float *offdy );
93static int ovr_safelaneKnown(
SafeLane *sf,
vec2 *posns[2] );
94static void map_overlayToScreenPos(
double *ox,
double *oy,
double x,
double y );
96static void ovr_mrkRenderAll(
double res,
int fg );
111static void ovr_boundsUpdate (
void)
113 ovr_bounds.w = SCREEN_W - ovr_bounds.l - ovr_bounds.r;
114 ovr_bounds.h = SCREEN_H - ovr_bounds.t - ovr_bounds.b;
115 ovr_bounds.x = ovr_bounds.w / 2. + ovr_bounds.l;
116 ovr_bounds.y = ovr_bounds.h / 2. + ovr_bounds.b;
127void ovr_boundsSet(
double top,
double right,
double bottom,
double left )
130 ovr_bounds.r = right;
131 ovr_bounds.b = bottom;
142void ovr_center(
double *x,
double *y )
151static void map_overlayToScreenPos(
double *ox,
double *oy,
double x,
double y )
153 *ox = ovr_bounds.x + x / ovr_res;
154 *oy = ovr_bounds.y + y / ovr_res;
160int ovr_input( SDL_Event *event )
166 if (event->type != SDL_MOUSEBUTTONDOWN)
170 if (player_isFlag(PLAYER_DESTROYED) || (
player.
p == NULL))
174 if (pilot_isFlag(
player.
p, PILOT_DEAD))
178 if (event->button.button != SDL_BUTTON_LEFT &&
179 event->button.button != SDL_BUTTON_RIGHT)
183 mx =
event->button.x;
184 my =
event->button.y;
188 x = ((double)mx - ovr_bounds.x) * ovr_res;
189 y = ((double)my - ovr_bounds.y) * ovr_res;
191 return input_clickPos( event, x, y, 1., 10. * ovr_res, 15. * ovr_res );
199void ovr_refresh (
void)
202 int items, jumpitems;
205 char buf[STRMAX_SHORT];
222 max_x =
MAX( max_x,
ABS(jp->pos.x) );
223 max_y =
MAX( max_y,
ABS(jp->pos.y) );
224 if (!jp_isUsable(jp))
227 snprintf( buf,
sizeof(buf),
"%s%s",
jump_getSymbol(jp), sys_isKnown(jp->target) ? _(jp->target->name) : _(
"Unknown") );
228 pos[items] = &jp->pos;
239 if (!spob_isKnown(pnt))
243 pos[items] = &pnt->
pos;
244 mo[items] = &pnt->
mo;
252 ovr_res = 2. * 1.2 *
MAX( max_x / ovr_bounds.w, max_y / ovr_bounds.h );
253 ovr_res =
MAX( ovr_res, 25. );
254 for (
int i=0; i<items; i++)
255 mo[i]->radius =
MAX( 2.+mo[i]->radius / ovr_res, i<jumpitems ? 5. : 7.5 );
258 ovr_optimizeLayout( items, pos, mo );
270 float cx, cy, r, sx, sy;
271 float x, y, w, h, mx, my, mw, mh;
272 float fx, fy, best, bx, by;
273 float *forces_xa, *forces_ya, *off_buffx, *off_buffy, *off_0x, *off_0y, old_bx, old_by, *off_dx, *off_dy;
276 const int max_iters = 15;
277 const float kx = 0.015;
278 const float ky = 0.045;
279 const float eps_con = 1.3;
286 uint8_t *must_shrink = malloc( items );
287 for (cur.
i=0; cur.
i<items; cur.
i++)
288 for (cur.
j=cur.
i+1; cur.
j<items; cur.
j++) {
289 cur.
dist = hypot( pos[cur.
i]->x - pos[cur.
j]->x, pos[cur.
i]->y - pos[cur.
j]->y ) / ovr_res;
290 if (cur.
dist < mo[cur.
i]->radius + mo[cur.
j]->radius)
294 float shrink_factor = 0.;
295 memset( must_shrink, 0, items );
301 shrink_factor =
MAX( shrink_factor, r - FLT_EPSILON );
302 must_shrink[fits[i].
i] = must_shrink[fits[i].j] = 1;
305 for (
int i=0; i<items; i++)
307 mo[i]->
radius *= shrink_factor;
313 for (
int i=0; i<items; i++)
314 mo[i]->radius =
MAX( mo[i]->radius, 4. );
317 off_0x = calloc( items,
sizeof(
float) );
318 off_0y = calloc( items,
sizeof(
float) );
321 for (
int i=0; i<items; i++) {
326 x = pos[i]->
x/ovr_res - ovr_text_pixbuf;
327 y = pos[i]->
y/ovr_res - ovr_text_pixbuf;
338 for (
int k=0; k<4; k++) {
342 for (
int j=0; j<items; j++) {
346 mx = pos[j]->
x/ovr_res - mw/2.;
347 my = pos[j]->
y/ovr_res - mh/2.;
349 force_collision( &fx, &fy, x+tx[k], y+ty[k], w, h, mx, my, mw, mh );
354 if (k == 0 || val < best) {
379 forces_xa = calloc( 2*items*items,
sizeof(
float) );
380 forces_ya = calloc( 2*items*items,
sizeof(
float) );
383 off_buffx = calloc( items,
sizeof(
float) );
384 off_buffy = calloc( items,
sizeof(
float) );
385 off_dx = calloc( items,
sizeof(
float) );
386 off_dy = calloc( items,
sizeof(
float) );
389 for (
int iter=0; iter<max_iters; iter++) {
391 for (
int i=0; i<items; i++) {
392 cx = pos[i]->
x / ovr_res;
393 cy = pos[i]->
y / ovr_res;
395 ovr_refresh_uzawa_overlap(
396 forces_xa, forces_ya,
397 cx + off_dx[i] + off_0x[i] - ovr_text_pixbuf,
398 cy + off_dy[i] + off_0y[i] - ovr_text_pixbuf,
399 mo[i]->text_width + 2*ovr_text_pixbuf,
401 pos, mo, items, i, off_0x, off_0y, off_dx, off_dy );
405 for (
int j=0; j<2*items; j++) {
406 sx += forces_xa[2*items*i+j];
407 sy += forces_ya[2*items*i+j];
411 old_bx = off_buffx[i];
412 old_by = off_buffy[i];
415 off_buffx[i] = kx * sx;
416 off_buffy[i] = ky * sy;
418 val =
MAX( val,
ABS(old_bx-off_buffx[i]) +
ABS(old_by-off_buffy[i]) );
422 for (
int i=0; i<items; i++) {
423 off_dx[i] = off_buffx[i];
424 off_dy[i] = off_buffy[i];
433 for (
int i=0; i<items; i++) {
434 mo[i]->
text_offx = off_dx[i] + off_0x[i];
435 mo[i]->
text_offy = off_dy[i] + off_0y[i];
452static void force_collision(
float *ox,
float *oy,
453 float x,
float y,
float w,
float h,
454 float mx,
float my,
float mw,
float mh )
457 if ((y+h < my+ovr_text_pixbuf) || (y+ovr_text_pixbuf > my+mh))
461 if (x+0.5*w < mx+0.5*mw) {
473 if ((x+w < mx+ovr_text_pixbuf) || (x+ovr_text_pixbuf > mx+mw))
477 if (y+0.5*h < my+0.5*mh) {
492static void ovr_refresh_uzawa_overlap(
float *forces_x,
float *forces_y,
493 float x,
float y,
float w,
float h,
const vec2** pos,
495 float *offx,
float *offy,
float *offdx,
float *offdy )
497 for (
int i=0; i<items; i++) {
498 float mx, my, mw, mh;
499 const float pb2 = ovr_text_pixbuf*2.;
504 mx = pos[i]->
x/ovr_res - mw/2.;
505 my = pos[i]->
y/ovr_res - mh/2.;
506 force_collision( &forces_x[2*items*self+2*i+1], &forces_y[2*items*self+2*i+1], x, y, w, h, mx, my, mw, mh );
514 mx = pos[i]->
x/ovr_res + offdx[i] + offx[i] - ovr_text_pixbuf;
515 my = pos[i]->
y/ovr_res + offdy[i] + offy[i] - ovr_text_pixbuf;
516 force_collision( &forces_x[2*items*self+2*i], &forces_y[2*items*self+2*i], x, y, w, h, mx, my, mw, mh );
520void ovr_initAlpha (
void)
525 if (!jp_isUsable(jp))
532 if (!spob_isKnown(pnt))
541 if (!ovr_safelaneKnown( &safelanes[i], posns ))
542 safelanes[i].map_alpha = 0.;
547 ovr_render_safelanes = safelanes;
557void ovr_setOpen(
int open )
559 if (open && !ovr_open) {
568 ovr_render_safelanes = NULL;
577void ovr_key(
int type )
587 ovr_opened = SDL_GetTicks();
591 if (SDL_GetTicks() - ovr_opened > 300)
596static int ovr_safelaneKnown(
SafeLane *sf,
vec2 *posns[2] )
601 for (
int j=0; j<2; j++) {
605 case SAFELANE_LOC_SPOB:
607 posns[j] = &pnt->
pos;
608 if (!spob_isKnown( pnt ))
611 case SAFELANE_LOC_DEST_SYS:
614 if (!jp_isKnown( jp ))
618 ERR( _(
"Invalid vertex type.") );
629void ovr_render(
double dt )
634 double rx,ry, x2,y2, rw,rh;
641 if (player_isFlag( PLAYER_DESTROYED ) || (
player.
p == NULL))
645 glClear(GL_DEPTH_BUFFER_BIT);
663 if (!ovr_safelaneKnown( &safelanes[i], posns ))
669 safelanes[i].map_alpha = ovr_render_safelanes[i].map_alpha;
671 if (safelanes[i].map_alpha < 1.0)
672 safelanes[i].
map_alpha =
MIN( safelanes[i].map_alpha+OVERLAY_FADEIN*dt, 1.0 );
680 col.a = 0.15 *
MIN( safelanes[i].map_alpha, 1.0 );
683 map_overlayToScreenPos( &x, &y, posns[0]->x, posns[0]->y );
684 map_overlayToScreenPos( &x2, &y2, posns[1]->x, posns[1]->y );
692 glUseProgram(shaders.safelane.program);
693 gl_renderShader( x+rx/2., y+ry/2., rw, rh, r, &shaders.safelane, &col, 1 );
696 ovr_render_safelanes = safelanes;
699 ovr_mrkRenderAll( res, 0 );
702 if (player_isFlag(PLAYER_AUTONAV) && (
player.
autonav == AUTONAV_POS_APPROACH)) {
703 glColour col = cRadar_hilight;
706 glUseProgram( shaders.selectposition.program );
725 if (jp->map_alpha < 1.0)
726 jp->map_alpha =
MIN( jp->map_alpha+OVERLAY_FADEIN*dt, 1.0 );
736 for (
int j=0; j<ast->
nb; j++)
744 if (pstk[i]->
id == PLAYER_ID)
753 if (pilot_isFlag(
player.
p, PILOT_STEALTH )) {
755 glColour col = {0., 0., 1., 1.};
758 glClearColor( 0., 0., 0., 0. );
759 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
760 glBlendEquation( GL_FUNC_ADD );
761 glBlendFuncSeparate( GL_SRC_ALPHA, GL_ONE, GL_ONE, GL_ONE );
767 map_overlayToScreenPos( &x, &y, ast->
pos.
x, ast->
pos.
y );
769 glUseProgram( shaders.astaura.program );
774 glBlendEquation( GL_FUNC_REVERSE_SUBTRACT );
775 glBlendFuncSeparate( GL_SRC_ALPHA, GL_ONE, GL_ONE, GL_ONE );
779 map_overlayToScreenPos( &x, &y, aexcl->
pos.
x, aexcl->
pos.
y );
781 glUseProgram( shaders.astaura.program );
785 glBlendEquation( GL_MAX );
789 if (!jp_isUsable(jp) || jp_isFlag(jp,JP_HIDDEN))
791 map_overlayToScreenPos( &x, &y, jp->pos.x, jp->pos.y );
792 r = EW_JUMP_BONUS_RANGE / res;
793 glUseProgram( shaders.astaura.program );
803 if (pilot_isDisabled(pstk[i]))
810 map_overlayToScreenPos( &x, &y, pstk[i]->solid->pos.x, pstk[i]->solid->pos.y );
813 glUseProgram( shaders.stealthaura.program );
818 glBlendEquation( GL_FUNC_ADD );
819 glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
821 glClearColor( 0., 0., 0., 1. );
823 glUseProgram(shaders.stealthoverlay.program);
826 glEnableVertexAttribArray( shaders.stealthoverlay.vertex );
831 gl_uniformColor(shaders.stealthoverlay.color, &cWhite);
834 gl_uniformMat4(shaders.stealthoverlay.projection, &ortho );
835 gl_uniformMat4(shaders.stealthoverlay.tex_mat, &I );
838 glDrawArrays( GL_TRIANGLE_STRIP, 0, 4 );
841 glDisableVertexAttribArray( shaders.stealthoverlay.vertex );
845 ovr_mrkRenderAll( res, 1 );
860static void ovr_mrkRenderAll(
double res,
int fg )
862 for (
int i=0; i<
array_size(ovr_markers); i++) {
865 map_overlayToScreenPos( &x, &y, mrk->
x, mrk->
y );
869 const glColour highlighted = COL_ALPHA( cRadar_hilight, 0.3 );
872 case OVR_MARKER_POINT:
873 glUseProgram( shaders.hilight.program );
874 glUniform1f( shaders.hilight.dt, ovr_dt );
875 gl_renderShader( x, y, 13., 13., 0., &shaders.hilight, &highlighted, 1 );
878 case OVR_MARKER_CIRCLE:
879 r =
MAX( mrk->
u.circle.r / res, 13. );
880 glUseProgram( shaders.hilight_circle.program );
881 glUniform1f( shaders.hilight_circle.dt, ovr_dt );
882 gl_renderShader( x, y, r, r, 0., &shaders.hilight_circle, &highlighted, 1 );
887 if (fg && mrk->
text != NULL) {
890 case OVR_MARKER_POINT:
894 case OVR_MARKER_CIRCLE:
895 r =
MAX( mrk->
u.circle.r / res, 13. );
906void ovr_mrkFree (
void)
915 ovr_render_safelanes = NULL;
921void ovr_mrkClear (
void)
924 ovr_mrkCleanup( &ovr_markers[i] );
948 if (ovr_markers == NULL)
953 mrk->
id = ++mrk_idgen;
966unsigned int ovr_mrkAddPoint(
const char *text,
double x,
double y )
971 for (
int i=0; i<
array_size(ovr_markers); i++) {
972 mrk = &ovr_markers[i];
974 if (mrk->
type != OVR_MARKER_POINT)
977 if (((text==NULL) && (mrk->
text!=NULL)) ||
978 ((text!=NULL) && ((mrk->
text==NULL) || strcmp(text,mrk->
text)!=0)))
981 if (hypotf( x-mrk->
x, y-mrk->
y ) > 1e-3)
991 mrk->
type = OVR_MARKER_POINT;
993 mrk->
text = strdup( text );
1009unsigned int ovr_mrkAddCircle(
const char *text,
double x,
double y,
double r )
1014 for (
int i=0; i<
array_size(ovr_markers); i++) {
1015 mrk = &ovr_markers[i];
1017 if (mrk->
type != OVR_MARKER_CIRCLE)
1020 if (((text==NULL) && (mrk->
text!=NULL)) ||
1021 ((text!=NULL) && ((mrk->
text==NULL) || strcmp(text,mrk->
text)!=0)))
1024 if ((mrk->
u.circle.r-r) > 1e-3 || hypotf( x-mrk->
x, y-mrk->
y ) > 1e-3)
1034 mrk->
type = OVR_MARKER_CIRCLE;
1036 mrk->
text = strdup( text );
1039 mrk->
u.circle.r = r;
1049void ovr_mrkRm(
unsigned int id )
1051 for (
int i=0; i<
array_size(ovr_markers); i++) {
1060 ovr_mrkCleanup( m );
Provides macros to work with dynamic arrays.
#define array_free(ptr_array)
Frees memory allocated and sets array to NULL.
#define array_end(array)
Returns a pointer to the end of the reserved memory space.
#define array_erase(ptr_array, first, last)
Erases elements in interval [first, last).
static ALWAYS_INLINE int array_size(const void *array)
Returns number of elements in the array.
#define array_grow(ptr_array)
Increases the number of elements by one and returns the last element.
#define array_push_back(ptr_array, element)
Adds a new element at the end of the array.
#define array_begin(array)
Returns a pointer to the beginning of the reserved memory space.
#define array_create(basic_type)
Creates a new dynamic array of ‘basic_type’.
int faction_isPlayerEnemy(int f)
Gets whether or not the player is an enemy of the faction.
int faction_isPlayerFriend(int f)
Gets whether or not the player is a friend of the faction.
int areAllies(int a, int b)
Checks whether two factions are allies or not.
int gl_printWidthRaw(const glFont *ft_font, const char *text)
Gets the width that it would take to print some text.
void gl_printMarkerRaw(const glFont *ft_font, double x, double y, const glColour *c, const char *text)
Wrapper for gl_printRaw for map overlay markers.
void gui_renderSpob(int ind, RadarShape shape, double w, double h, double res, double alpha, int overlay)
Draws the spobs in the minimap.
void gui_renderPlayer(double res, int overlay)
Renders the player cross on the radar or whatever.
void gui_renderAsteroid(const Asteroid *a, double w, double h, double res, int overlay)
Renders an asteroid in the GUI radar.
void gui_renderJumpPoint(int ind, RadarShape shape, double w, double h, double res, double alpha, int overlay)
Renders a jump point on the minimap.
void gui_renderPilot(const Pilot *p, RadarShape shape, double w, double h, double res, int overlay)
Renders a pilot in the GUI radar.
mat4 mat4_identity(void)
Creates an identity matrix.
mat4 mat4_ortho(double left, double right, double bottom, double top, double nearVal, double farVal)
Creates an orthographic projection matrix.
Header file with generic functions and naev-specifics.
void gl_windowToScreenPos(int *sx, int *sy, int wx, int wy)
Translates the window position to screen position.
void gl_renderShader(double x, double y, double w, double h, double r, const SimpleShader *shd, const glColour *c, int center)
Renders a simple shader.
void gl_renderRect(double x, double y, double w, double h, const glColour *c)
Renders a rectangle.
void gl_vboActivateAttribOffset(gl_vbo *vbo, GLuint index, GLuint offset, GLint size, GLenum type, GLsizei stride)
Activates a VBO's offset.
int pilot_validTarget(const Pilot *p, const Pilot *target)
Checks to see if a pilot is a valid target for another pilot.
int pilot_isFriendly(const Pilot *p)
Checks to see if pilot is friendly to the player.
Pilot *const * pilot_getAll(void)
Gets the pilot stack.
double pilot_sensorRange(void)
Returns the default sensor range for the current system.
SafeLane * safelanes_get(int faction, int standing, const StarSystem *system)
Gets a set of safelanes for a faction and system.
StarSystem * system_getIndex(int id)
Get the system by its index.
const char * jump_getSymbol(const JumpPoint *jp)
Gets the jump point symbol.
const char * spob_getSymbol(const Spob *p)
Gets the spob symbol.
JumpPoint * jump_getTarget(const StarSystem *target, const StarSystem *sys)
Less safe version of jump_get that works with pointers.
Spob * spob_getIndex(int ind)
Gets spob by index.
const char * spob_name(const Spob *p)
Gets the translated name of a spob.
glTexture * jumppoint_gfx
Represents an asteroid field anchor.
Represents an asteroid exclusion zone.
Saves the layout decisions from positioning labeled objects on the overlay.
The representation of an in-game pilot.
double map_overlay_opacity
Describes a safe lane, patrolled by a faction, within a system.
SafeLaneLocType point_type[2]
Represents a Space Object (SPOB), including and not limited to planets, stations, wormholes,...
GLuint fbo_tex[OPENGL_NUM_FBOS]
GLuint fbo[OPENGL_NUM_FBOS]
union ovr_marker_t::@16 u