1 /*
2  * XPilotNG/SDL, an SDL/OpenGL XPilot client.
3  *
4  * Copyright (C) 2003-2004 by
5  *
6  *      Juha Lindstr�m       <juhal@users.sourceforge.net>
7  *      Erik Andersson       <deity_at_home.se>
8  *
9  * Copyright (C) 1991-2002 by
10  *
11  *      Bj�rn Stabell        <bjoern@xpilot.org>
12  *      Ken Ronny Schouten   <ken@xpilot.org>
13  *      Bert Gijsbers        <bert@xpilot.org>
14  *      Dick Balaska         <dick@xpilot.org>
15  *
16  * This program is free software; you can redistribute it and/or modify
17  * it under the terms of the GNU General Public License as published by
18  * the Free Software Foundation; either version 2 of the License, or
19  * (at your option) any later version.
20  *
21  * This program is distributed in the hope that it will be useful,
22  * but WITHOUT ANY WARRANTY; without even the implied warranty of
23  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
24  * GNU General Public License for more details.
25  *
26  * You should have received a copy of the GNU General Public License
27  * along with this program; if not, write to the Free Software
28  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
29  */
30 
31 #include "xpclient_sdl.h"
32 
33 #include "sdlpaint.h"
34 #include "images.h"
35 #include "glwidgets.h"
36 #include "text.h"
37 #include "asteroid_data.h"
38 
39 Uint32 nullRGBA     = 0x00000000;
40 Uint32 blackRGBA    = 0x000000ff;
41 Uint32 whiteRGBA    = 0xffffffff;
42 Uint32 blueRGBA     = 0x0000ffff;
43 Uint32 redRGBA	    = 0xff0000ff;
44 Uint32 greenRGBA    = 0x00ff00ff;
45 Uint32 yellowRGBA   = 0xffff00ff;
46 
47 Uint32 wallColorRGBA;
48 Uint32 decorColorRGBA;
49 Uint32 hudColorRGBA;
50 Uint32 connColorRGBA;
51 Uint32 scoreObjectColorRGBA;
52 Uint32 fuelColorRGBA;
53 Uint32 messagesColorRGBA;
54 Uint32 oldmessagesColorRGBA;
55 Uint32 msgScanBallColorRGBA;
56 Uint32 msgScanSafeColorRGBA;
57 Uint32 msgScanCoverColorRGBA;
58 Uint32 msgScanPopColorRGBA;
59 Uint32 ballColorRGBA;
60 
61 Uint32 meterBorderColorRGBA;
62 Uint32 fuelMeterColorRGBA;
63 Uint32 powerMeterColorRGBA;
64 Uint32 turnSpeedMeterColorRGBA;
65 Uint32 packetSizeMeterColorRGBA;
66 Uint32 packetLossMeterColorRGBA;
67 Uint32 packetDropMeterColorRGBA;
68 Uint32 packetLagMeterColorRGBA;
69 Uint32 temporaryMeterColorRGBA;
70 
71 Uint32 dirPtrColorRGBA;
72 Uint32 hudHLineColorRGBA;
73 Uint32 hudVLineColorRGBA;
74 Uint32 hudItemsColorRGBA;
75 Uint32 fuelGaugeColorRGBA;
76 Uint32 selfLWColorRGBA;
77 Uint32 teamLWColorRGBA;
78 Uint32 enemyLWColorRGBA;
79 Uint32 teamShipColorRGBA;
80 Uint32 team0ColorRGBA;
81 Uint32 team1ColorRGBA;
82 Uint32 team2ColorRGBA;
83 Uint32 team3ColorRGBA;
84 Uint32 team4ColorRGBA;
85 Uint32 team5ColorRGBA;
86 Uint32 team6ColorRGBA;
87 Uint32 team7ColorRGBA;
88 Uint32 team8ColorRGBA;
89 Uint32 team9ColorRGBA;
90 Uint32 shipNameColorRGBA;
91 Uint32 baseNameColorRGBA;
92 Uint32 manyLivesColorRGBA;
93 Uint32 twoLivesColorRGBA;
94 Uint32 oneLifeColorRGBA;
95 Uint32 zeroLivesColorRGBA;
96 
97 Uint32 hudRadarEnemyColorRGBA;
98 Uint32 hudRadarOtherColorRGBA;
99 Uint32 hudRadarObjectColorRGBA;
100 
101 Uint32 scoreInactiveSelfColorRGBA;
102 Uint32 scoreInactiveColorRGBA;
103 Uint32 scoreSelfColorRGBA;
104 Uint32 scoreColorRGBA;
105 Uint32 scoreOwnTeamColorRGBA;
106 Uint32 scoreEnemyTeamColorRGBA;
107 
108 Uint32 selectionColorRGBA;
109 
110 static int meterWidth	= 60;
111 static int meterHeight	= 10;
112 
113 float hudRadarMapScale;
114 int   hudRadarEnemyShape;
115 int   hudRadarOtherShape;
116 int   hudRadarObjectShape;
117 float hudRadarDotScale;
118 
119 static double shipLineWidth;
120 static bool smoothLines;
121 static bool texturedBalls;
122 static bool texturedShips;
123 static GLuint polyListBase = 0;
124 static GLuint polyEdgeListBase = 0;
125 static GLuint asteroid = 0;
126 
127 irec_t *select_bounds;
128 
129 string_tex_t score_object_texs[MAX_SCORE_OBJECTS];
130 string_tex_t meter_texs[MAX_METERS];
131 string_tex_t message_texs[2*MAX_MSGS];
132 string_tex_t HUD_texs[MAX_HUD_TEXS+MAX_SCORE_OBJECTS];
133 
134 int Gui_init(void);
135 void Gui_cleanup(void);
136 
137 /* better to use alpha everywhere, less confusion */
set_alphacolor(Uint32 color)138 void set_alphacolor(Uint32 color)
139 {
140     glColor4ub((color >> 24) & 255,
141     	       (color >> 16) & 255,
142 	       (color >> 8) & 255,
143 	       color & 255);
144 }
145 
get_alpha(Uint32 color)146 static GLubyte get_alpha(Uint32 color)
147 {
148     return (color & 255);
149 }
150 
GL_X(int x)151 int GL_X(int x)
152 {
153     return (int)((x - world.x) * clData.scale);
154 }
155 
GL_Y(int y)156 int GL_Y(int y)
157 {
158     return (int)((y - world.y) * clData.scale);
159 }
160 
161 
162 /* remove this later maybe? to tedious for me to edit them all away now */
Segment_add(Uint32 color,int x_1,int y_1,int x_2,int y_2)163 void Segment_add(Uint32 color, int x_1, int y_1, int x_2, int y_2)
164 {
165     if (smoothLines) glEnable(GL_LINE_SMOOTH);
166     set_alphacolor(color);
167     glBegin( GL_LINE_LOOP );
168     	glVertex2i(x_1,y_1);
169 	glVertex2i(x_2,y_2);
170     glEnd();
171     if (smoothLines) glDisable(GL_LINE_SMOOTH);
172 }
173 
Circle(Uint32 color,int x,int y,int radius,int filled)174 void Circle(Uint32 color,
175 	    int x, int y,
176 	    int radius, int filled)
177 {
178     float i,resolution = 16;
179     set_alphacolor(color);
180     if (filled)
181     	glBegin( GL_POLYGON );
182     else
183     	glBegin( GL_LINE_LOOP );
184     	/* Silly resolution */
185     	for (i = 0.0f; i < TABLE_SIZE; i=i+((float)TABLE_SIZE)/resolution)
186     	    glVertex2f((x + tcos((int)i)*radius),(y + tsin((int)i)*radius));
187     glEnd();
188 }
189 
wrap(int * xp,int * yp)190 static int wrap(int *xp, int *yp)
191 {
192     int			x = *xp, y = *yp;
193     int returnval =1;
194 
195     if (x < world.x || x > world.x + ext_view_width) {
196 	if (x < realWorld.x || x > realWorld.x + ext_view_width)
197 	    returnval = 0;
198 	*xp += world.x - realWorld.x;
199     }
200     if (y < world.y || y > world.y + ext_view_height) {
201 	if (y < realWorld.y || y > realWorld.y + ext_view_height)
202 	    returnval = 0;
203 	*yp += world.y - realWorld.y;
204     }
205     return returnval;
206 }
207 
208 #ifndef CALLBACK
209 #define CALLBACK
210 #endif
211 
vertex_callback(ipos_t * p,irec_t * trec)212 static void CALLBACK vertex_callback(ipos_t *p, irec_t *trec)
213 {
214     if (trec != NULL) {
215 	glTexCoord2f((p->x + trec->x) / (GLfloat)trec->w,
216 		     (p->y + trec->y) / (GLfloat)trec->h);
217     }
218     glVertex2i(p->x, p->y);
219 }
220 
tessellate_polygon(GLUtriangulatorObj * tess,int ind)221 static void tessellate_polygon(GLUtriangulatorObj *tess, int ind)
222 {
223     int i, x, y, minx, miny;
224     xp_polygon_t polygon;
225     polygon_style_t p_style;
226     image_t *texture = NULL;
227     irec_t trec;
228     GLdouble v[3] = { 0, 0, 0 };
229     ipos_t p[MAX_VERTICES];
230 
231     polygon = polygons[ind];
232     p_style = polygon_styles[polygon.style];
233 
234     p[0].x = p[0].y = 0;
235     if (BIT(p_style.flags, STYLE_TEXTURED)) {
236 	texture = Image_get_texture(p_style.texture);
237 	if (texture != NULL) {
238 	    x = y = minx = miny = 0;
239 	    for (i = 1; i < polygon.num_points; i++) {
240 		x += polygon.points[i].x;
241 		y += polygon.points[i].y;
242 		if (x < minx) minx = x;
243 		if (y < miny) miny = y;
244 	    }
245 	    trec.x = -minx;
246 	    trec.y = -miny - (polygon.bounds.h % texture->height);
247 	    trec.w = texture->frame_width;
248 	    trec.h = texture->height;
249 	}
250     }
251     glNewList(polyListBase + ind,  GL_COMPILE);
252     gluTessBeginPolygon(tess, texture ? &trec : NULL);
253     gluTessVertex(tess, v, &p[0]);
254     for (i = 1; i < polygon.num_points; i++) {
255 	v[0] = p[i].x = p[i - 1].x + polygon.points[i].x;
256 	v[1] = p[i].y = p[i - 1].y + polygon.points[i].y;
257 	gluTessVertex(tess, v, &p[i]);
258     }
259     gluTessEndPolygon(tess);
260     glEndList();
261 
262     glNewList(polyEdgeListBase + ind,  GL_COMPILE);
263     if (polygon.edge_styles == NULL) { /* No special edges */
264 	glBegin(GL_LINE_LOOP);
265 	x = y = 0;
266 	glVertex2i(x, y);
267 	for (i = 1; i < polygon.num_points; i++) {
268 	    x += polygon.points[i].x;
269 	    y += polygon.points[i].y;
270 	    glVertex2i(x, y);
271 	}
272 	glEnd();
273     }
274     else { 	/* This polygon has special edges */
275 	ipos_t pos1, pos2;
276 	int sindex;
277 
278 	glBegin(GL_LINES);
279 	pos1.x = 0;
280 	pos1.y = 0;
281 	for (i = 1; i < polygon.num_points; i++) {
282 	    pos2.x = pos1.x + polygon.points[i].x;
283 	    pos2.y = pos1.y + polygon.points[i].y;
284 	    sindex = polygon.edge_styles[i - 1];
285 	    /* Style 0 means internal edges which are never shown */
286 	    if (sindex != 0) {
287 		glVertex2i(pos1.x, pos1.y);
288 		glVertex2i(pos2.x, pos2.y);
289 	    }
290 	    pos1 = pos2;
291 	}
292 	glEnd();
293     }
294     glEndList();
295 }
296 
asteroid_init(void)297 static int asteroid_init(void)
298 {
299     int i;
300     if ((asteroid = glGenLists(1)) == 0)
301 	return -1;
302     glNewList(asteroid, GL_COMPILE);
303     glBegin(GL_TRIANGLES);
304     for (i = 0; i < VERTEX_COUNT; i++) {
305 	glNormal3fv(normal_vectors[i]);
306 	glTexCoord2fv(uv_vectors[i]);
307 	glVertex3fv(vertex_vectors[i]);
308     }
309     glEnd();
310     glEndList();
311     return 0;
312 }
313 
asteroid_cleanup(void)314 static void asteroid_cleanup(void)
315 {
316     if (asteroid)
317 	glDeleteLists(asteroid, 1);
318 }
319 
Gui_init(void)320 int Gui_init(void)
321 {
322     int i;
323     GLUtriangulatorObj *tess;
324 
325     if (asteroid_init() == -1) {
326 	error("failed to initialize asteroids");
327 	return -1;
328     }
329 
330     if (num_polygons == 0) return 0;
331 
332     polyListBase = glGenLists(num_polygons);
333     polyEdgeListBase = glGenLists(num_polygons);
334     if ((!polyListBase)||(!polyEdgeListBase)) {
335 	error("failed to generate display lists");
336 	return -1;
337     }
338 
339     tess = gluNewTess();
340     if (tess == NULL) {
341 	error("failed to create tessellation object");
342 	return -1;
343     }
344 
345     /* TODO: figure out proper casting here do not use _GLUfuncptr */
346     /* it doesn't work on windows  or MAC OS X */
347 #ifdef _MSC_VER
348     gluTessCallback(tess, GLU_TESS_BEGIN, glBegin);
349     gluTessCallback(tess, GLU_TESS_VERTEX_DATA, vertex_callback);
350 #else
351     gluTessCallback(tess, GLU_TESS_BEGIN, (GLvoid (*)(void))glBegin);
352     gluTessCallback(tess, GLU_TESS_VERTEX_DATA, (GLvoid (*)(void))vertex_callback);
353 #endif
354     gluTessCallback(tess, GLU_TESS_END, glEnd);
355 
356     for (i = 0; i < num_polygons; i++) {
357 	tessellate_polygon(tess, i);
358     }
359 
360     gluDeleteTess(tess);
361 
362     return 0;
363 }
364 
Gui_cleanup(void)365 void Gui_cleanup(void)
366 {
367     if (polyListBase)
368 	glDeleteLists(polyListBase, num_polygons);
369     asteroid_cleanup();
370 }
371 
372 /* Map painting */
373 
Gui_paint_cannon(int x,int y,int type)374 void Gui_paint_cannon(int x, int y, int type)
375 {
376     switch (type) {
377     case SETUP_CANNON_UP:
378         Image_paint(IMG_CANNON_DOWN, x, y, 0, whiteRGBA);
379         break;
380     case SETUP_CANNON_DOWN:
381         Image_paint(IMG_CANNON_UP, x, y + 1, 0, whiteRGBA);
382         break;
383     case SETUP_CANNON_LEFT:
384         Image_paint(IMG_CANNON_RIGHT, x, y, 0, whiteRGBA);
385         break;
386     case SETUP_CANNON_RIGHT:
387         Image_paint(IMG_CANNON_LEFT, x - 1, y, 0, whiteRGBA);
388         break;
389     default:
390         errno = 0;
391         error("Bad cannon dir.");
392         return;
393     }
394 }
395 
Gui_paint_fuel(int x,int y,double fuel)396 void Gui_paint_fuel(int x, int y, double fuel)
397 {
398 #define FUEL_BORDER 3
399 
400     int size, frame;
401     irec_t area;
402     image_t *img;
403 
404     img = Image_get(IMG_FUEL);
405     if (img == NULL) return;
406 
407     /* x + x * y will give a pseudo random number,
408      * so different fuelcells will not be displayed with the same
409      * image-frame. */
410     frame = ABS(loopsSlow + x + x * y) % (img->num_frames * 2);
411 
412     /* the animation is played from image 0-15 then back again
413      * from image 15-0 */
414     if (frame >= img->num_frames)
415 	frame = (2 * img->num_frames - 1) - frame;
416 
417     size = (int)((BLOCK_SZ - 2 * FUEL_BORDER) * fuel / MAX_STATION_FUEL);
418 
419     Image_paint(IMG_FUELCELL, x, y, 0, fuelColorRGBA);
420 
421     area.x = 0;
422     area.y = (int)((BLOCK_SZ - 2 * FUEL_BORDER)
423 		   * (1 - fuel / MAX_STATION_FUEL));
424     area.w = BLOCK_SZ - 2 * FUEL_BORDER;
425     area.h = size;
426     Image_paint_area(IMG_FUEL,
427 		     x + FUEL_BORDER,
428 		     y + FUEL_BORDER,
429 		     frame,
430 		     &area,
431 		     fuelColorRGBA);
432 }
433 
Gui_paint_base(int x,int y,int id,int team,int type)434 void Gui_paint_base(int x, int y, int id, int team, int type)
435 {
436     Uint32 color;
437     homebase_t *base = NULL;
438     other_t *other;
439     bool do_basewarning = false;
440 
441     switch (type) {
442     case SETUP_BASE_UP:
443         Image_paint(IMG_BASE_DOWN, x, y, 0, whiteRGBA);
444         break;
445     case SETUP_BASE_DOWN:
446         Image_paint(IMG_BASE_UP, x, y + 1, 0, whiteRGBA);
447         break;
448     case SETUP_BASE_LEFT:
449         Image_paint(IMG_BASE_RIGHT, x, y, 0, whiteRGBA);
450         break;
451     case SETUP_BASE_RIGHT:
452         Image_paint(IMG_BASE_LEFT, x - 1, y, 0, whiteRGBA);
453         break;
454     default:
455         errno = 0;
456         error("Bad base dir.");
457         return;
458     }
459 
460     if (!(other = Other_by_id(id))) return;
461 
462     if (baseNameColorRGBA) {
463 	if (!(color = Life_color(other)))
464 	    color = baseNameColorRGBA;
465     } else
466 	color = whiteRGBA;
467 
468     x = x + BLOCK_SZ / 2;
469     y = y + BLOCK_SZ / 2;
470 
471     base = Homebase_by_id(id);
472     if (base != NULL) {
473 	/*
474 	 * Hacks to support Mara's base warning on new servers and
475 	 * the red "meter" basewarning on old servers.
476 	 */
477 	if (loops < base->appeartime)
478 	    do_basewarning = true;
479 
480 	if (version < 0x4F12 && do_basewarning) {
481 	    if (baseWarningType & 1) {
482 		/* We assume the ship will appear after 3 seconds. */
483 		int count = (int)(360 * (base->appeartime - loops)
484 				  / (3 * clientFPS));
485 		LIMIT(count, 0, 360);
486 		/* red box basewarning */
487 		if (count > 0 && (baseWarningType & 1))
488 		    Gui_paint_appearing(x, y,
489 					id, count);
490 	    }
491 	}
492     }
493     /* Mara's flashy basewarning */
494     if (do_basewarning && (baseWarningType & 2)) {
495 	if (loopsSlow & 1) {
496 	    if (color != whiteRGBA)
497 		color = whiteRGBA;
498 	    else
499 		color = redRGBA;
500 	}
501     }
502 
503     switch (type) {
504     case SETUP_BASE_UP:
505 	mapnprint(&mapfont,color,CENTER,DOWN ,(x) ,(y - BLOCK_SZ / 2),maxCharsInNames,"%s",other->nick_name);
506         break;
507     case SETUP_BASE_DOWN:
508 	mapnprint(&mapfont,color,CENTER,UP   ,(x) ,(int)(y + BLOCK_SZ / 1.5),maxCharsInNames,"%s",other->nick_name);
509         break;
510     case SETUP_BASE_LEFT:
511 	mapnprint(&mapfont,color,RIGHT,UP    ,(x + BLOCK_SZ / 2) ,(y),maxCharsInNames,"%s",other->nick_name);
512         break;
513     case SETUP_BASE_RIGHT:
514 	mapnprint(&mapfont,color,LEFT,UP     ,(x - BLOCK_SZ / 2) ,(y),maxCharsInNames,"%s",other->nick_name);
515         break;
516     default:
517         errno = 0;
518         error("Bad base dir.");
519     }
520 }
521 
Gui_paint_decor(int x,int y,int xi,int yi,int type,bool last,bool more_y)522 void Gui_paint_decor(int x, int y, int xi, int yi, int type,
523 		     bool last, bool more_y)
524 {
525 	int mask;
526     static unsigned char    decor[256];
527     static int		    decorReady = 0;
528 
529     if (!decorReady) {
530 		memset(decor, 0, sizeof decor);
531 		decor[SETUP_DECOR_FILLED]
532 			= DECOR_UP | DECOR_LEFT | DECOR_DOWN | DECOR_RIGHT;
533 		decor[SETUP_DECOR_RU] = DECOR_UP | DECOR_RIGHT | DECOR_CLOSED;
534 		decor[SETUP_DECOR_RD]
535 			= DECOR_DOWN | DECOR_RIGHT | DECOR_OPEN | DECOR_BELOW;
536 		decor[SETUP_DECOR_LU] = DECOR_UP | DECOR_LEFT | DECOR_OPEN;
537 		decor[SETUP_DECOR_LD]
538 			= DECOR_LEFT | DECOR_DOWN | DECOR_CLOSED | DECOR_BELOW;
539     }
540 
541     mask = decor[type];
542 
543     set_alphacolor(decorColorRGBA);
544     glBegin(GL_LINES);
545 
546     if (mask & DECOR_LEFT) {
547 		glVertex2i(x, y);
548 		glVertex2i(x, y + BLOCK_SZ);
549     }
550     if (mask & DECOR_DOWN) {
551 		glVertex2i(x, y);
552 		glVertex2i(x + BLOCK_SZ, y);
553     }
554     if (mask & DECOR_RIGHT) {
555 		glVertex2i(x + BLOCK_SZ, y);
556 		glVertex2i(x + BLOCK_SZ, y + BLOCK_SZ);
557     }
558     if (mask & DECOR_UP) {
559 		glVertex2i(x, y + BLOCK_SZ);
560 		glVertex2i(x + BLOCK_SZ, y + BLOCK_SZ);
561     }
562 	if (mask & DECOR_OPEN) {
563 		glVertex2i(x, y);
564 		glVertex2i(x + BLOCK_SZ, y + BLOCK_SZ);
565     } else if (mask & DECOR_CLOSED) {
566 		glVertex2i(x, y + BLOCK_SZ);
567 		glVertex2i(x + BLOCK_SZ, y);
568     }
569     glEnd();
570 }
571 
Gui_paint_border(int x,int y,int xi,int yi)572 void Gui_paint_border(int x, int y, int xi, int yi)
573 {
574     set_alphacolor(wallColorRGBA);
575     glBegin(GL_LINE);
576     	glVertex2i(x, y);
577     	glVertex2i(xi, yi);
578     glEnd();
579 }
580 
Gui_paint_visible_border(int x,int y,int xi,int yi)581 void Gui_paint_visible_border(int x, int y, int xi, int yi)
582 {
583     setupPaint_moving();
584     set_alphacolor(hudColorRGBA);
585     glBegin(GL_LINE_LOOP);
586     	glVertex2i(x, y);
587     	glVertex2i(x, yi);
588     	glVertex2i(xi, yi);
589     	glVertex2i(xi, y);
590     glEnd();
591     setupPaint_stationary();
592 }
593 
Gui_paint_hudradar_limit(int x,int y,int xi,int yi)594 void Gui_paint_hudradar_limit(int x, int y, int xi, int yi)
595 {
596     set_alphacolor(blueRGBA);
597     glBegin(GL_LINE_LOOP);
598     	glVertex2i(x, y);
599     	glVertex2i(x, yi);
600     	glVertex2i(xi, yi);
601     	glVertex2i(xi, y);
602     glEnd();
603 }
604 
Gui_paint_setup_check(int x,int y,bool isNext)605 void Gui_paint_setup_check(int x, int y, bool isNext)
606 {
607     if (isNext) {
608 	Image_paint(IMG_CHECKPOINT, x, y, 0, whiteRGBA);
609     } else {
610 	Image_paint(IMG_CHECKPOINT, x, y, 0, whiteRGBA - 128);
611     }
612 }
613 
Gui_paint_setup_acwise_grav(int x,int y)614 void Gui_paint_setup_acwise_grav(int x, int y)
615 {
616     Image_paint(IMG_ACWISEGRAV, x, y, loopsSlow % 6, whiteRGBA);
617 }
618 
Gui_paint_setup_cwise_grav(int x,int y)619 void Gui_paint_setup_cwise_grav(int x, int y)
620 {
621     Image_paint(IMG_CWISEGRAV, x, y, loopsSlow % 6, whiteRGBA);
622 }
623 
Gui_paint_setup_pos_grav(int x,int y)624 void Gui_paint_setup_pos_grav(int x, int y)
625 {
626     Image_paint(IMG_PLUSGRAVITY, x, y, 0, whiteRGBA);
627 }
628 
Gui_paint_setup_neg_grav(int x,int y)629 void Gui_paint_setup_neg_grav(int x, int y)
630 {
631     Image_paint(IMG_MINUSGRAVITY, x, y, 0, whiteRGBA);
632 }
633 
paint_dir_grav(int x,int y,int dir)634 static void paint_dir_grav(int x, int y, int dir)
635 {
636     const int sz = BLOCK_SZ;
637     int cb, c0, c1, c2, p1, p2, swp;
638 
639     cb = redRGBA - 255;
640     p1 = loops % sz;
641     p2 = (loops + sz / 2) % sz;
642 
643     if (p1 < p2) {
644 	c0 = cb + p1 * 128 / (sz / 2);
645 	c1 = cb;
646 	c2 = cb + 128;
647     } else {
648 	c0 = cb + (sz - p1) * 128 / (sz / 2);
649 	c1 = cb + 128;
650 	c2 = cb;
651 	swp = p1; p1 = p2; p2 = swp;
652     }
653 
654     glEnable(GL_BLEND);
655 
656 #define GRAV(x0,y0,x1,y1,x2,y2,x3,y3,x4,y4,x5,y5,x6,y6,x7,y7) \
657     glBegin(GL_QUAD_STRIP);\
658     set_alphacolor(c0); glVertex2i(x+x0,y+y0); glVertex2i(x+x1,y+y1);\
659     set_alphacolor(c1); glVertex2i(x+x2,y+y2); glVertex2i(x+x3,y+y3);\
660     set_alphacolor(c2); glVertex2i(x+x4,y+y4); glVertex2i(x+x5,y+y5);\
661     set_alphacolor(c0); glVertex2i(x+x6,y+y6); glVertex2i(x+x7,y+y7);\
662     glEnd();
663 
664     switch(dir) {
665     case 0: /* up */
666 	GRAV( 0,  0, sz,  0,
667 	      0, p1, sz, p1,
668 	      0, p2, sz, p2,
669 	      0, sz, sz, sz);
670 	break;
671     case 1: /* right */
672 	GRAV( 0,  0,  0, sz,
673 	     p1,  0, p1, sz,
674 	     p2,  0, p2, sz,
675 	     sz,  0, sz, sz);
676 	break;
677     case 2: /* down */
678 	GRAV( 0,    sz, sz,    sz,
679 	      0, sz-p1, sz, sz-p1,
680 	      0, sz-p2, sz, sz-p2,
681 	      0,     0, sz,     0);
682 	break;
683     case 3: /* left */
684 	GRAV(   sz, 0,    sz, sz,
685 	     sz-p1, 0, sz-p1, sz,
686 	     sz-p2, 0, sz-p2, sz,
687 	        0,  0,     0, sz);
688 	break;
689     }
690 #undef GRAV
691 
692     glDisable(GL_BLEND);
693 }
694 
Gui_paint_setup_up_grav(int x,int y)695 void Gui_paint_setup_up_grav(int x, int y)
696 {
697     paint_dir_grav(x, y, 0);
698 }
699 
Gui_paint_setup_down_grav(int x,int y)700 void Gui_paint_setup_down_grav(int x, int y)
701 {
702     paint_dir_grav(x, y, 2);
703 }
704 
Gui_paint_setup_right_grav(int x,int y)705 void Gui_paint_setup_right_grav(int x, int y)
706 {
707     paint_dir_grav(x, y, 1);
708 }
709 
Gui_paint_setup_left_grav(int x,int y)710 void Gui_paint_setup_left_grav(int x, int y)
711 {
712     paint_dir_grav(x, y, 3);
713 }
714 
Gui_paint_setup_worm(int x,int y)715 void Gui_paint_setup_worm(int x, int y)
716 {
717     Image_paint_rotated(IMG_WORMHOLE, x, y, (loopsSlow << 3) % TABLE_SIZE, whiteRGBA);
718 }
719 
Gui_paint_setup_item_concentrator(int x,int y)720 void Gui_paint_setup_item_concentrator(int x, int y)
721 {
722     Image_paint_rotated(IMG_CONCENTRATOR, x, y, (loopsSlow << 3) % TABLE_SIZE, whiteRGBA);
723 }
724 
Gui_paint_setup_asteroid_concentrator(int x,int y)725 void Gui_paint_setup_asteroid_concentrator(int x, int y)
726 {
727     Image_paint_rotated(IMG_ASTEROIDCONC, x, y, (loopsSlow << 4) % TABLE_SIZE, whiteRGBA);
728 }
729 
Gui_paint_decor_dot(int x,int y,int size)730 void Gui_paint_decor_dot(int x, int y, int size)
731 {
732 	set_alphacolor(wallColorRGBA);
733 	glBegin(GL_QUADS);
734 	glVertex2i(x + ((BLOCK_SZ - size) >> 1),
735 			   y + ((BLOCK_SZ - size) >> 1));
736 	glVertex2i(x + ((BLOCK_SZ - size) >> 1),
737 			   y + ((BLOCK_SZ + size) >> 1));
738 	glVertex2i(x + ((BLOCK_SZ + size) >> 1),
739 			   y + ((BLOCK_SZ + size) >> 1));
740 	glVertex2i(x + ((BLOCK_SZ + size) >> 1),
741 			   y + ((BLOCK_SZ - size) >> 1));
742 	glEnd();
743 }
744 
Gui_paint_setup_target(int x,int y,int team,double damage,bool own)745 void Gui_paint_setup_target(int x, int y, int team, double damage, bool own)
746 {
747 	int damage_y;
748 
749 	Image_paint(IMG_TARGET, x, y, 0, whiteRGBA);
750 	if (BIT(Setup->mode, TEAM_PLAY)) {
751 		mapprint(&mapfont, whiteRGBA, RIGHT, UP, x + BLOCK_SZ, y, "%d", team);
752 	}
753 	if (damage != TARGET_DAMAGE) {
754 		damage_y = y + (int)((BLOCK_SZ - 3) * (damage / TARGET_DAMAGE));
755 		set_alphacolor(own ? blueRGBA : redRGBA);
756 		glBegin(GL_LINE_LOOP);
757 		glVertex2i(x, y + 3);
758 		glVertex2i(x, y + BLOCK_SZ);
759 		glVertex2i(x + 5, y + BLOCK_SZ);
760 		glVertex2i(x + 5, y + 3);
761 		glEnd();
762 		glBegin(GL_QUADS);
763 		glVertex2i(x, y + 3);
764 		glVertex2i(x, damage_y);
765 		glVertex2i(x + 5, damage_y);
766 		glVertex2i(x + 5, y + 3);
767 		glEnd();
768 	}
769 }
770 
Gui_paint_setup_treasure(int x,int y,int team,bool own)771 void Gui_paint_setup_treasure(int x, int y, int team, bool own)
772 {
773     Image_paint(own ? IMG_HOLDER_FRIEND : IMG_HOLDER_ENEMY, x, y, 0, whiteRGBA);
774 }
775 
Gui_paint_walls(int x,int y,int type)776 void Gui_paint_walls(int x, int y, int type)
777 {
778     set_alphacolor(wallColorRGBA);
779     glBegin(GL_LINES);
780 
781 
782     if (type & BLUE_LEFT) {
783 	glVertex2i(x, y);
784 	glVertex2i(x, y + BLOCK_SZ);
785     }
786     if (type & BLUE_DOWN) {
787 	glVertex2i(x, y);
788 	glVertex2i(x + BLOCK_SZ, y);
789     }
790     if (type & BLUE_RIGHT) {
791 	glVertex2i(x + BLOCK_SZ, y);
792 	glVertex2i(x + BLOCK_SZ, y + BLOCK_SZ);
793     }
794     if (type & BLUE_UP) {
795 	glVertex2i(x, y + BLOCK_SZ);
796 	glVertex2i(x + BLOCK_SZ, y + BLOCK_SZ);
797     }
798     if ((type & BLUE_FUEL) == BLUE_FUEL) {
799     } else if (type & BLUE_OPEN) {
800 	glVertex2i(x, y);
801 	glVertex2i(x + BLOCK_SZ, y + BLOCK_SZ);
802     } else if (type & BLUE_CLOSED) {
803 	glVertex2i(x, y + BLOCK_SZ);
804 	glVertex2i(x + BLOCK_SZ, y);
805     }
806     glEnd();
807 }
808 
Gui_paint_filled_slice(int bl,int tl,int tr,int br,int y)809 void Gui_paint_filled_slice(int bl, int tl, int tr, int br, int y)
810 {
811     set_alphacolor(wallColorRGBA);
812     glBegin(GL_QUADS);
813     glVertex2i(bl, y);
814     glVertex2i(tl, y + BLOCK_SZ);
815     glVertex2i(tr, y + BLOCK_SZ);
816     glVertex2i(br, y);
817     glEnd();
818 }
819 
Gui_paint_polygon(int i,int xoff,int yoff)820 void Gui_paint_polygon(int i, int xoff, int yoff)
821 {
822     xp_polygon_t polygon;
823     polygon_style_t p_style;
824     edge_style_t e_style;
825     int width;
826     bool did_fill = false;
827 
828     polygon = polygons[i];
829     p_style = polygon_styles[polygon.style];
830     e_style = edge_styles[p_style.def_edge_style];
831 
832     if (BIT(p_style.flags, STYLE_INVISIBLE))
833 	return;
834 
835     glMatrixMode(GL_MODELVIEW);
836     glPushMatrix();
837     glLoadIdentity();
838 
839     glTranslatef(polygon.points[0].x * clData.scale +
840 		 rint((xoff * Setup->width - world.x) * clData.scale),
841 		 polygon.points[0].y * clData.scale +
842 		 rint((yoff * Setup->height - world.y) * clData.scale), 0);
843     glScalef(clData.scale, clData.scale, 0);
844 
845     /* possibly paint the polygon as filled or textured */
846     if ((instruments.texturedWalls || instruments.filledWorld) &&
847 	    BIT(p_style.flags, STYLE_TEXTURED | STYLE_FILLED)) {
848 	if (BIT(p_style.flags, STYLE_TEXTURED)
849 	        && instruments.texturedWalls) {
850 	    Image_use_texture(p_style.texture);
851 	    glCallList(polyListBase + i);
852 	    Image_no_texture();
853 	}
854 	else {
855 	    set_alphacolor((p_style.rgb << 8) | 0xff);
856 	    glCallList(polyListBase + i);
857 	}
858 	did_fill = true;
859     }
860 
861     width = e_style.width;
862     if (!did_fill && width == -1)
863 	width = 1;
864 
865     /* possibly paint the edges around the polygon */
866     if (width != -1) {
867 	set_alphacolor((e_style.rgb << 8) | 0xff);
868 	glLineWidth(width * clData.scale);
869 	if (smoothLines) {
870 	    glEnable(GL_BLEND);
871 	    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
872 	    glEnable(GL_LINE_SMOOTH);
873 	}
874 	glCallList(polyEdgeListBase + i);
875 	if (smoothLines) {
876 	    glDisable(GL_LINE_SMOOTH);
877 	    glDisable(GL_BLEND);
878 	}
879 	glLineWidth(1);
880     }
881     glPopMatrix();
882 }
883 
884 
885 /* Object painting */
886 
887 
Gui_paint_item_object(int type,int x,int y)888 void Gui_paint_item_object(int type, int x, int y)
889 {
890     int sz = 16;
891     Image_paint(IMG_ALL_ITEMS, x - 8, y - 4, type, whiteRGBA);
892     set_alphacolor(blueRGBA);
893     if (smoothLines) glEnable(GL_LINE_SMOOTH);
894     glBegin(GL_LINE_LOOP);
895     glVertex2i(x + sz, y + sz);
896     glVertex2i(x, y - sz);
897     glVertex2i(x - sz, y + sz);
898     glEnd();
899     if (smoothLines) glDisable(GL_LINE_SMOOTH);
900 }
901 
Gui_paint_ball(int x,int y,int style)902 void Gui_paint_ball(int x, int y, int style)
903 {
904     int rgba = ballColorRGBA;
905 
906     if (style >= 0 && style < num_polygon_styles)
907 	rgba = (polygon_styles[style].rgb << 8) | 0xff;
908 
909     if (texturedBalls)
910 	Image_paint(IMG_BALL, x - BALL_RADIUS, y - BALL_RADIUS, 0, rgba);
911     else {
912 	int i, numvert = 16, ang = RES / numvert;
913 	/* kps hack, feel free to improve */
914 	glEnable(GL_BLEND);
915 	glBlendFunc(GL_SRC_ALPHA, GL_ONE);
916 	set_alphacolor(ballColorRGBA);
917 	if (smoothLines) glEnable(GL_LINE_SMOOTH);
918 	glBegin(GL_LINE_LOOP);
919 	for (i = 0; i < numvert; i++)
920 	    glVertex2d((double)x + tcos(i * ang) * BALL_RADIUS,
921 		       (double)y + tsin(i * ang) * BALL_RADIUS);
922 	glEnd();
923 	if (smoothLines) glDisable(GL_LINE_SMOOTH);
924     }
925 }
926 
Gui_paint_ball_connector(int x_1,int y_1,int x_2,int y_2)927 void Gui_paint_ball_connector(int x_1, int y_1, int x_2, int y_2)
928 {
929     glEnable(GL_BLEND);
930     glBlendFunc(GL_SRC_ALPHA, GL_ONE);
931     set_alphacolor(connColorRGBA);
932     if (smoothLines) glEnable(GL_LINE_SMOOTH);
933     glBegin(GL_LINES);
934     glVertex2i(x_1, y_1);
935     glVertex2i(x_2, y_2);
936     glEnd();
937     if (smoothLines) glDisable(GL_LINE_SMOOTH);
938 }
939 
Gui_paint_mine(int x,int y,int teammine,char * name)940 void Gui_paint_mine(int x, int y, int teammine, char *name)
941 {
942     Image_paint(teammine ? IMG_MINE_TEAM : IMG_MINE_OTHER,
943 		x - 10, y - 7, 0, whiteRGBA);
944     if (name) {
945 	mapnprint(  &mapfont,
946     	    	    teammine ? blueRGBA : whiteRGBA,
947     	    	    CENTER, DOWN,
948     	    	    x, y - 15,
949     	    	    maxCharsInNames,"%s", name	);
950     }
951 }
952 
Gui_paint_spark(int color,int x,int y)953 void Gui_paint_spark(int color, int x, int y)
954 {
955     /*
956     Image_paint(IMG_SPARKS,
957 		x + world.x,
958 		world.y + ext_view_height - y,
959 		color);
960     */
961     glColor3ub(255 * (color + 1) / 8,
962 	       255 * color * color / 64,
963 	       0);
964     glPointSize(sparkSize);
965     glBegin(GL_POINTS);
966     glVertex2i(x + world.x, world.y + ext_view_height - y);
967     glEnd();
968 }
969 
Gui_paint_wreck(int x,int y,bool deadly,int wtype,int rot,int size)970 void Gui_paint_wreck(int x, int y, bool deadly, int wtype, int rot, int size)
971 {
972     int cnt, tx, ty;
973 
974     set_alphacolor(deadly ? whiteRGBA : redRGBA);
975     glBegin(GL_LINE_LOOP);
976     for (cnt = 0; cnt < NUM_WRECKAGE_POINTS; cnt++) {
977 	tx = (int)(wreckageShapes[wtype][cnt][rot].x * size) >> 8;
978 	ty = (int)(wreckageShapes[wtype][cnt][rot].y * size) >> 8;
979 	glVertex2i(x + tx, y + ty);
980     }
981     glEnd();
982 }
983 
Gui_paint_asteroids_begin(void)984 void Gui_paint_asteroids_begin(void)
985 {
986     image_t *img;
987     GLfloat ambient[] = { 0.7F, 0.7F, 0.7F, 1.0F };
988 
989     img = Image_get(IMG_ASTEROID);
990     if (img != NULL) {
991 	glEnable(GL_TEXTURE_2D);
992 	glBindTexture(GL_TEXTURE_2D, img->name);
993     }
994     glColor4ub(255, 255, 255, 255);
995     glEnable(GL_LIGHTING);
996     glEnable(GL_LIGHT0);
997     glLightfv(GL_LIGHT0, GL_AMBIENT, ambient);
998     glEnable(GL_CULL_FACE);
999 }
1000 
Gui_paint_asteroids_end(void)1001 void Gui_paint_asteroids_end(void)
1002 {
1003     glDisable(GL_CULL_FACE);
1004     glDisable(GL_LIGHT0);
1005     glDisable(GL_LIGHTING);
1006     glDisable(GL_TEXTURE_2D);
1007 
1008 /* this displays the asteroid hit area */
1009 #if 0
1010     int i, x, y, size;
1011     for (i = 0; i < num_asteroids; i++) {
1012 	x = asteroid_ptr[i].x;
1013 	y = asteroid_ptr[i].y;
1014 	if (wrap(&x, &y)) {
1015 	    size = asteroid_ptr[i].size;
1016 	    Circle(whiteRGBA, x, y, (int)(0.8 * SHIP_SZ * size), 0);
1017 	}
1018     }
1019 #endif
1020 }
1021 
Gui_paint_asteroid(int x,int y,int type,int rot,int size)1022 void Gui_paint_asteroid(int x, int y, int type, int rot, int size)
1023 {
1024     GLfloat real_size;
1025 
1026     real_size = 0.9 * SHIP_SZ * size;
1027     glPushMatrix();
1028     glTranslatef((GLfloat)x, (GLfloat)y, 0.0);
1029     glScalef(real_size, real_size, 1.0);
1030     glRotatef(360.0 * rot / TABLE_SIZE,
1031 	   (type & 1) - 0.5,
1032 	   (type & 2) - 1,
1033 	   (type & 4) - 2);
1034     glCallList(asteroid);
1035     glEnd();
1036     glPopMatrix();
1037 }
1038 
1039 
1040 /*
1041  * It seems that currently the screen coordinates are calculated already
1042  * in paintobjects.c. This should be changed.
1043  */
Gui_paint_fastshot(int color,int x,int y)1044 void Gui_paint_fastshot(int color, int x, int y)
1045 {
1046     int size = MIN(shotSize, 16);
1047 
1048     Image_paint(IMG_BULLET,
1049 		x + world.x - size/2,
1050 		world.y - 16 + size/2 - 1 + ext_view_height - y,
1051 		size - 1, whiteRGBA);
1052 }
1053 
Gui_paint_teamshot(int x,int y)1054 void Gui_paint_teamshot(int x, int y)
1055 {
1056     int size = MIN(teamShotSize, 16);
1057 
1058     Image_paint(IMG_BULLET_OWN,
1059 		x + world.x - size/2,
1060 		world.y - 16 + size/2 - 1 + ext_view_height - y,
1061 		size - 1, whiteRGBA);
1062 }
1063 
Gui_paint_missiles_begin(void)1064 void Gui_paint_missiles_begin(void)
1065 {
1066 }
1067 
Gui_paint_missiles_end(void)1068 void Gui_paint_missiles_end(void)
1069 {
1070 }
1071 
Gui_paint_missile(int x,int y,int len,int dir)1072 void Gui_paint_missile(int x, int y, int len, int dir)
1073 {
1074     Image_paint_rotated(IMG_MISSILE, x - 16, y - 16, dir, whiteRGBA);
1075 }
1076 
Gui_paint_lasers_begin(void)1077 void Gui_paint_lasers_begin(void)
1078 {
1079     glEnable(GL_BLEND);
1080     glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1081     if (smoothLines) glEnable(GL_LINE_SMOOTH);
1082 }
1083 
Gui_paint_lasers_end(void)1084 void Gui_paint_lasers_end(void)
1085 {
1086     glDisable(GL_BLEND);
1087     if (smoothLines) glDisable(GL_LINE_SMOOTH);
1088 }
1089 
Gui_paint_laser(int color,int x_1,int y_1,int len,int dir)1090 void Gui_paint_laser(int color, int x_1, int y_1, int len, int dir)
1091 {
1092     int	x_2, y_2, rgba;
1093     x_2 = (int)(x_1 + len * tcos(dir));
1094     y_2 = (int)(y_1 + len * tsin(dir));
1095 
1096     rgba =
1097 	(color == RED) ? redRGBA :
1098 	(color == BLUE) ? blueRGBA :
1099 	whiteRGBA;
1100 
1101     set_alphacolor(rgba - 128);
1102     glLineWidth(5);
1103     glBegin(GL_LINES);
1104     glVertex2i(x_1, y_1);
1105     glVertex2i(x_2, y_2);
1106     glEnd();
1107 
1108     set_alphacolor(rgba);
1109     glLineWidth(1);
1110     glBegin(GL_LINES);
1111     glVertex2i(x_1, y_1);
1112     glVertex2i(x_2, y_2);
1113     glEnd();
1114 }
1115 
Gui_paint_paused(int x,int y,int count)1116 void Gui_paint_paused(int x, int y, int count)
1117 {
1118     Image_paint(IMG_PAUSED,
1119 		x - BLOCK_SZ / 2,
1120 		y - BLOCK_SZ / 2,
1121 		(count <= 0 || loopsSlow % 10 >= 5) ? 1 : 0, whiteRGBA);
1122 }
1123 
Gui_paint_appearing(int x,int y,int id,int count)1124 void Gui_paint_appearing(int x, int y, int id, int count)
1125 {
1126     const unsigned hsize = 3 * BLOCK_SZ / 7;
1127     int minx,miny,maxx,maxy;
1128     Uint32 color;
1129     other_t *other = Other_by_id(id);
1130 
1131     /* Make a note we are doing the base warning */
1132     if (version >= 0x4F12) {
1133 	homebase_t *base = Homebase_by_id(id);
1134 	if (base != NULL)
1135 	    base->appeartime = (long)(loops + (count * clientFPS) / 120);
1136     }
1137 
1138     minx = x - (int)hsize;
1139     miny = y - (int)hsize;
1140     maxx = minx + 2 * hsize + 1;
1141     maxy = miny + (unsigned)(count / 180. * hsize + 1);
1142 
1143     color = Life_color(other);
1144     set_alphacolor((color)?color:redRGBA);
1145 
1146     glEnable(GL_BLEND);
1147     glBlendFunc(GL_SRC_ALPHA, GL_ONE);
1148     glBegin(GL_QUADS);
1149     	glVertex2i(minx , miny);
1150     	glVertex2i(maxx , miny);
1151     	glVertex2i(maxx , maxy);
1152     	glVertex2i(minx , maxy);
1153     glEnd();
1154 }
1155 
Gui_paint_ecm(int x,int y,int size)1156 void Gui_paint_ecm(int x, int y, int size)
1157 {
1158 }
1159 
Gui_paint_refuel(int x_0,int y_0,int x_1,int y_1)1160 void Gui_paint_refuel(int x_0, int y_0, int x_1, int y_1)
1161 {
1162     int stipple = 4;
1163 
1164     set_alphacolor(fuelColorRGBA);
1165     glEnable(GL_BLEND);
1166     glBlendFunc(GL_SRC_ALPHA, GL_ONE);
1167     glLineStipple(stipple, 0xAAAA);
1168     glEnable(GL_LINE_STIPPLE);
1169     if (smoothLines) glEnable(GL_LINE_SMOOTH);
1170     glBegin(GL_LINES);
1171     glVertex2i(x_0, y_0);
1172     glVertex2i(x_1, y_1);
1173     glEnd();
1174     if (smoothLines) glDisable(GL_LINE_SMOOTH);
1175     glDisable(GL_LINE_STIPPLE);
1176 }
1177 
Gui_paint_connector(int x_0,int y_0,int x_1,int y_1,int tractor)1178 void Gui_paint_connector(int x_0, int y_0, int x_1, int y_1, int tractor)
1179 {
1180     glEnable(GL_BLEND);
1181     glBlendFunc(GL_SRC_ALPHA, GL_ONE);
1182     set_alphacolor(connColorRGBA);
1183     glLineStipple(tractor ? 2 : 4, 0xAAAA);
1184     glEnable(GL_LINE_STIPPLE);
1185     if (smoothLines) glEnable(GL_LINE_SMOOTH);
1186     glBegin(GL_LINES);
1187     glVertex2i(x_0, y_0);
1188     glVertex2i(x_1, y_1);
1189     glEnd();
1190     if (smoothLines) glDisable(GL_LINE_SMOOTH);
1191     glDisable(GL_LINE_STIPPLE);
1192     /*glDisable(GL_BLEND);*/
1193 }
1194 
Gui_paint_transporter(int x_0,int y_0,int x_1,int y_1)1195 void Gui_paint_transporter(int x_0, int y_0, int x_1, int y_1)
1196 {
1197 }
1198 
Gui_paint_all_connectors_begin(void)1199 void Gui_paint_all_connectors_begin(void)
1200 {
1201 }
1202 
Gui_paint_ships_begin(void)1203 void Gui_paint_ships_begin(void)
1204 {
1205 }
1206 
Gui_paint_ships_end(void)1207 void Gui_paint_ships_end(void)
1208 {
1209 }
1210 
1211 /*
1212  * Assume MAX_TEAMS is 10
1213  */
Team_color(int team)1214 int Team_color(int team)
1215 {
1216     switch (team) {
1217     case 0:	return team0ColorRGBA;
1218     case 1:	return team1ColorRGBA;
1219     case 2:	return team2ColorRGBA;
1220     case 3:	return team3ColorRGBA;
1221     case 4:	return team4ColorRGBA;
1222     case 5:	return team5ColorRGBA;
1223     case 6:	return team6ColorRGBA;
1224     case 7:	return team7ColorRGBA;
1225     case 8:	return team8ColorRGBA;
1226     case 9:	return team9ColorRGBA;
1227     default:    break;
1228     }
1229     return 0;
1230 }
1231 
Life_color_by_life(int life)1232 int Life_color_by_life(int life)
1233 {
1234     int color;
1235 
1236     if (life > 2)
1237 	color = manyLivesColorRGBA;
1238     else if (life == 2)
1239 	color = twoLivesColorRGBA;
1240     else if (life == 1)
1241 	color = oneLifeColorRGBA;
1242     else /* we catch all */
1243 	color = zeroLivesColorRGBA;
1244     return color;
1245 }
1246 
Life_color(other_t * other)1247 int Life_color(other_t *other)
1248 {
1249     int color = 0; /* default is 'no special color' */
1250 
1251     if (other
1252 	&& (other->mychar == ' ' || other->mychar == 'R')
1253 	&& BIT(Setup->mode, LIMITED_LIVES))
1254 	color = Life_color_by_life(other->life);
1255     return color;
1256 }
1257 
Gui_is_my_tank(other_t * other)1258 static int Gui_is_my_tank(other_t *other)
1259 {
1260     char	tank_name[MAX_NAME_LEN];
1261 
1262     if (self == NULL
1263 	|| other == NULL
1264 	|| other->mychar != 'T'
1265 	|| (BIT(Setup->mode, TEAM_PLAY)
1266 	&& self->team != other->team)) {
1267 	    return 0;
1268     }
1269 
1270     if (strlcpy(tank_name, self->nick_name, MAX_NAME_LEN) < MAX_NAME_LEN)
1271 	strlcat(tank_name, "'s tank", MAX_NAME_LEN);
1272 
1273     if (strcmp(tank_name, other->nick_name))
1274 	return 0;
1275 
1276     return 1;
1277 }
1278 
Gui_calculate_ship_color(int id,other_t * other)1279 static int Gui_calculate_ship_color(int id, other_t *other)
1280 {
1281     Uint32 ship_color = whiteRGBA;
1282 
1283 #ifndef NO_BLUE_TEAM
1284     if (BIT(Setup->mode, TEAM_PLAY)
1285 	&& eyesId != id
1286 	&& other != NULL
1287 	&& eyeTeam == other->team) {
1288 	/* Paint teammates and allies ships with last life in teamLWColorRGBA */
1289 	if (BIT(Setup->mode, LIMITED_LIVES)
1290 	    && (other->life == 0))
1291 	    ship_color = teamLWColorRGBA;
1292 	else
1293 	    ship_color = teamShipColorRGBA;
1294     }
1295 
1296     if (eyes != NULL
1297 	&& eyesId != id
1298 	&& other != NULL
1299 	&& eyes->alliance != ' '
1300 	&& eyes->alliance == other->alliance) {
1301 	/* Paint teammates and allies ships with last life in teamLWColorRGBA */
1302 	if (BIT(Setup->mode, LIMITED_LIVES)
1303 	    && (other->life == 0))
1304 	    ship_color = teamLWColorRGBA;
1305 	else
1306 	    ship_color = teamShipColorRGBA;
1307     }
1308 
1309     if (Gui_is_my_tank(other))
1310 	ship_color = blueRGBA;
1311 #endif
1312     if (roundDelay > 0 && ship_color == whiteRGBA)
1313 	ship_color = redRGBA;
1314 
1315     /* Check for team color */
1316     if (other && BIT(Setup->mode, TEAM_PLAY)) {
1317 	int team_color = Team_color(other->team);
1318 	if (team_color)
1319 	    return team_color;
1320     }
1321 
1322     /* Vato color hack start, edited by mara & kps */
1323     if (BIT(Setup->mode, LIMITED_LIVES)) {
1324 	/* Paint your ship in selfLWColorRGBA when on last life */
1325 	if (eyes != NULL
1326 	    && eyes->id == id
1327 	    && eyes->life == 0) {
1328 	    ship_color = selfLWColorRGBA;
1329 	}
1330 
1331 	/* Paint enemy ships with last life in enemyLWColorRGBA */
1332 	if (eyes != NULL
1333 	    && eyes->id != id
1334 	    && other != NULL
1335 	    && eyeTeam != other->team
1336 	    && other->life == 0) {
1337 	    ship_color = enemyLWColorRGBA;
1338 	}
1339     }
1340     /* Vato color hack end */
1341 
1342     return ship_color;
1343 }
1344 
Gui_paint_ship_name(int x,int y,other_t * other)1345 static void Gui_paint_ship_name(int x, int y, other_t *other)
1346 {
1347     int color = Life_color(other);
1348 
1349     /* TODO : do all name painting together, so we don't need
1350      * all theese setupPaint<foo> calls
1351      */
1352     if (shipNameColorRGBA) {
1353 	if (!color)
1354 	    color = shipNameColorRGBA;
1355 
1356 	mapnprint(&mapfont, color, CENTER, DOWN,x,y - SHIP_SZ,maxCharsInNames,"%s",other->id_string);
1357     } else
1358 	color = blueRGBA;
1359 
1360     if (instruments.showLivesByShip
1361 	&& BIT(Setup->mode, LIMITED_LIVES)) {
1362 	if (other->life < 1)
1363 	    color = whiteRGBA;
1364 
1365 	mapprint(&mapfont, color, LEFT, CENTER,x + SHIP_SZ,y,"%d", other->life);
1366     }
1367 }
1368 
Gui_paint_ship(int x,int y,int dir,int id,int cloak,int phased,int shield,int deflector,int eshield)1369 void Gui_paint_ship(int x, int y, int dir, int id, int cloak, int phased,
1370 		    int shield, int deflector, int eshield)
1371 {
1372     int i, color, img;
1373     shipshape_t *ship;
1374     position_t point;
1375     other_t *other;
1376 
1377     if (!(other = Other_by_id(id))) return;
1378 
1379     if (!(color = Gui_calculate_ship_color(id,other))) return;
1380 
1381     if ((!instruments.showShipShapes) && (self != NULL) && (self->id != id))
1382 			ship = Default_ship();
1383     else if ((!instruments.showMyShipShape) && (self != NULL) && (self->id == id))
1384 			ship = Default_ship();
1385 		else
1386 			ship = Ship_by_id(id);
1387 
1388     if (shield) {
1389     	Image_paint(IMG_SHIELD, x - 27, y - 27, 0, (color & 0xffffff00) + ((color & 0x000000ff)/2));
1390     }
1391 	if (texturedShips) {
1392     	    if (BIT(Setup->mode, TEAM_PLAY)
1393 			&& other != NULL
1394 			&& self != NULL
1395 			&& self->team == other->team) {
1396 			img = IMG_SHIP_FRIEND;
1397     	    } else if (self != NULL && self->id != id) {
1398 			img = IMG_SHIP_ENEMY;
1399     	    } else {
1400 			img = IMG_SHIP_SELF;
1401     	    }
1402     	    if (cloak || phased) Image_paint_rotated(img, x, y, dir, (color & 0xffffff00) + ((color & 0x000000ff)/2));
1403 	    else Image_paint_rotated(img, x, y, dir, color);
1404 	} else {
1405     	    glEnable(GL_BLEND);
1406     	    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1407     	    glEnable(GL_LINE_SMOOTH);
1408     	    glLineWidth(shipLineWidth);
1409     	    set_alphacolor(color);
1410 
1411     	    if (cloak || phased ) {
1412     	    	glEnable(GL_LINE_STIPPLE);
1413     	    	glLineStipple( 3, 0xAAAA );
1414 	    }
1415 
1416     	    glBegin(GL_LINE_LOOP);
1417     	    	for (i = 0; i < ship->num_points; i++) {
1418     	    	    point = Ship_get_point_position(ship, i, dir);
1419     	    	    glVertex2d(x + point.x, y + point.y);
1420     	    	}
1421     	    glEnd();
1422 
1423     	    if (cloak || phased ) glDisable(GL_LINE_STIPPLE);
1424 
1425     	    glLineWidth(1);
1426     	    glDisable(GL_LINE_SMOOTH);
1427     	    glDisable(GL_BLEND);
1428 	}
1429     if (self != NULL
1430     	&& self->id != id
1431     	&& other != NULL)
1432 		Gui_paint_ship_name(x,y,other);
1433 }
1434 
Paint_score_objects(void)1435 void Paint_score_objects(void)
1436 {
1437     int		i, x, y;
1438 
1439     if (!get_alpha(scoreObjectColorRGBA))
1440 	return;
1441 
1442     for (i = 0; i < MAX_SCORE_OBJECTS; i++) {
1443 	score_object_t*	sobj = &score_objects[i];
1444 	if (sobj->life_time > 0) {
1445 	    if (loopsSlow % 3) {
1446 	    	/* approximate font width to h =( */
1447 		x = sobj->x * BLOCK_SZ + BLOCK_SZ/2;
1448 		y = sobj->y * BLOCK_SZ + BLOCK_SZ/2;
1449   		if (wrap(&x, &y)) {
1450 		    /*mapprint(&mapfont,scoreObjectColorRGBA,CENTER,CENTER,x,y,"%s",sobj->msg);*/
1451 		    if (!score_object_texs[i].tex_list || strcmp(sobj->msg,score_object_texs[i].text)) {
1452 		    	free_string_texture(&score_object_texs[i]);
1453 		    	draw_text(&mapfont, scoreObjectColorRGBA
1454 			    	    ,CENTER,CENTER, x, y, sobj->msg, true
1455 				    , &score_object_texs[i],false);
1456 		    } else disp_text(&score_object_texs[i],scoreObjectColorRGBA,CENTER,CENTER,x,y,false);
1457 		}
1458 	    }
1459 	    sobj->life_time -= timePerFrame;
1460 	    if (sobj->life_time <= 0.0) {
1461 		sobj->life_time = 0.0;
1462 		sobj->hud_msg_len = 0;
1463 	    }
1464 	} else {
1465 	    if (score_object_texs[i].tex_list) free_string_texture(&score_object_texs[i]);
1466 	}
1467     }
1468 }
1469 
Paint_select(void)1470 void Paint_select(void)
1471 {
1472     if(!select_bounds) return;
1473     set_alphacolor(selectionColorRGBA);
1474     glBegin(GL_LINE_LOOP);
1475     	glVertex2i(select_bounds->x 	    	    	,select_bounds->y   	    	    );
1476     	glVertex2i(select_bounds->x + select_bounds->w	,select_bounds->y   	    	    );
1477     	glVertex2i(select_bounds->x + select_bounds->w	,select_bounds->y + select_bounds->h);
1478     	glVertex2i(select_bounds->x 	    	    	,select_bounds->y + select_bounds->h);
1479     glEnd();
1480 }
1481 
Paint_HUD_values(void)1482 void Paint_HUD_values(void)
1483 {
1484     int x, y;
1485 
1486     if (!hudColorRGBA)
1487 	return;
1488 
1489     x = draw_width - 20;
1490     /* Better make sure it's below the meters */
1491     y = draw_height - 9*(MAX((GLuint)meterHeight,gamefont.h) + 6);
1492 
1493     HUDprint(&gamefont,hudColorRGBA,RIGHT,DOWN,x,y,"FPS: %.3f",clientFPS);
1494     HUDprint(&gamefont,hudColorRGBA,RIGHT,DOWN,x,y-20,"CL.LAG : %.1f ms", clData.clientLag);
1495 }
1496 
Paint_meter(int xoff,int y,string_tex_t * tex,int val,int max,int meter_color)1497 static void Paint_meter(int xoff, int y, string_tex_t *tex, int val, int max,
1498 			int meter_color)
1499 {
1500     int	mw1_4 = meterWidth/4,
1501     	mw2_4 = meterWidth/2,
1502     	mw3_4 = 3*meterWidth/4,
1503     	mw4_4 = meterWidth,
1504     	BORDER = 5;
1505     int		x, xstr;
1506     int x_alignment;
1507     int color;
1508 
1509     if (xoff >= 0) {
1510 	x = xoff;
1511         xstr = x + meterWidth + BORDER;
1512 	x_alignment = LEFT;
1513     } else {
1514 	x = draw_width - (meterWidth - xoff);
1515         xstr = x - BORDER;
1516 	x_alignment = RIGHT;
1517     }
1518 
1519     set_alphacolor(meter_color);
1520     glBegin( GL_POLYGON );
1521     	glVertex2i(x,y);
1522     	glVertex2i(x,y+2+meterHeight-3);
1523     	glVertex2i(x+(int)(((meterWidth)*val)/(max?max:1)),y+2+meterHeight-3);
1524     	glVertex2i(x+(int)(((meterWidth)*val)/(max?max:1)),y);
1525     glEnd();
1526 
1527 
1528 
1529     /* meterBorderColorRGBA = 0 obviously means no meter borders are drawn */
1530     if (meterBorderColorRGBA) {
1531     	color = meterBorderColorRGBA;
1532 
1533 	set_alphacolor(color);
1534 	glBegin( GL_LINE_LOOP );
1535 	    glVertex2i(x,y);
1536 	    glVertex2i(x,y + meterHeight);
1537 	    glVertex2i(x + meterWidth,y + meterHeight);
1538 	    glVertex2i(x + meterWidth,y);
1539 	glEnd();
1540 
1541 	glBegin( GL_LINES );
1542 	    glVertex2i(x,       y-4);glVertex2i(x,       y+meterHeight+4);
1543 	    glVertex2i(x+mw4_4, y-4);glVertex2i(x+mw4_4, y+meterHeight+4);
1544 	    glVertex2i(x+mw2_4, y-3);glVertex2i(x+mw2_4, y+meterHeight+3);
1545 	    glVertex2i(x+mw1_4, y-1);glVertex2i(x+mw1_4, y+meterHeight+1);
1546 	    glVertex2i(x+mw3_4, y-1);glVertex2i(x+mw3_4, y+meterHeight+1);
1547 	glEnd();
1548     }
1549 
1550     if (!meterBorderColorRGBA)
1551 	color = meter_color;
1552 
1553     disp_text(tex,color,x_alignment,CENTER,xstr,draw_height - y - meterHeight/2,true);
1554 }
1555 
Paint_meters(void)1556 void Paint_meters(void)
1557 {
1558     int spacing = MAX((GLuint)meterHeight,gamefont.h) + 6;
1559     int y = spacing, color;
1560     static bool setup_texs = true;
1561 
1562     if (setup_texs) {
1563     	render_text(&gamefont,"Fuel"	    	, &meter_texs[0]);
1564     	render_text(&gamefont,"Power"	    	, &meter_texs[1]);
1565      	render_text(&gamefont,"Turnspeed"   	, &meter_texs[2]);
1566    	render_text(&gamefont,"Packet"	   	, &meter_texs[3]);
1567     	render_text(&gamefont,"Loss"	    	, &meter_texs[4]);
1568     	render_text(&gamefont,"Drop"	    	, &meter_texs[5]);
1569     	render_text(&gamefont,"Lag" 	    	, &meter_texs[6]);
1570     	render_text(&gamefont,"Thrust Left" 	, &meter_texs[7]);
1571     	render_text(&gamefont,"Shields Left"	, &meter_texs[8]);
1572     	render_text(&gamefont,"Phasing left"	, &meter_texs[9]);
1573     	render_text(&gamefont,"Self destructing", &meter_texs[10]);
1574     	render_text(&gamefont,"SHUTDOWN"    	, &meter_texs[11]);
1575 	setup_texs = false;
1576     }
1577 
1578     glEnable(GL_BLEND);
1579     glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1580     if (fuelMeterColorRGBA)
1581 	Paint_meter(-10, y += spacing, &meter_texs[0],
1582 		    (int)fuelSum, (int)fuelMax, fuelMeterColorRGBA);
1583 
1584     if (powerMeterColorRGBA)
1585 	color = powerMeterColorRGBA;
1586     else if (controlTime > 0.0)
1587 	color = temporaryMeterColorRGBA;
1588     else
1589 	color = 0;
1590 
1591     if (color)
1592 	Paint_meter(-10, y += spacing, &meter_texs[1],
1593 		    (int)displayedPower, (int)MAX_PLAYER_POWER, color);
1594 
1595     if (turnSpeedMeterColorRGBA)
1596 	color = turnSpeedMeterColorRGBA;
1597     else if (controlTime > 0.0)
1598 	color = temporaryMeterColorRGBA;
1599     else
1600 	color = 0;
1601 
1602     if (color)
1603 	Paint_meter(-10, y += spacing, &meter_texs[2],
1604 		    (int)displayedTurnspeed, (int)MAX_PLAYER_TURNSPEED, color);
1605 
1606     if (controlTime > 0.0) {
1607 	controlTime -= timePerFrame;
1608 	if (controlTime <= 0.0)
1609 	    controlTime = 0.0;
1610     }
1611 
1612     if (packetSizeMeterColorRGBA)
1613 	Paint_meter(-10, y += spacing, &meter_texs[3],
1614 		   (packet_size >= 4096) ? 4096 : packet_size, 4096,
1615 		    packetSizeMeterColorRGBA);
1616     if (packetLossMeterColorRGBA)
1617 	Paint_meter(-10, y += spacing, &meter_texs[4], packet_loss, FPS,
1618 		    packetLossMeterColorRGBA);
1619     if (packetDropMeterColorRGBA)
1620 	Paint_meter(-10, y += spacing, &meter_texs[5], packet_drop, FPS,
1621 		    packetDropMeterColorRGBA);
1622     if (packetLagMeterColorRGBA)
1623 	Paint_meter(-10, y += spacing, &meter_texs[6], MIN(packet_lag, 1 * FPS), 1 * FPS,
1624 		    packetLagMeterColorRGBA);
1625 
1626     if (temporaryMeterColorRGBA) {
1627 	if (thrusttime >= 0 && thrusttimemax > 0)
1628 	    Paint_meter((ext_view_width-300)/2 -32, 2*ext_view_height/3,
1629 			&meter_texs[7],
1630 			(thrusttime >= thrusttimemax
1631 			 ? thrusttimemax : thrusttime),
1632 			thrusttimemax, temporaryMeterColorRGBA);
1633 
1634 	if (shieldtime >= 0 && shieldtimemax > 0)
1635 	    Paint_meter((ext_view_width-300)/2 -32, 2*ext_view_height/3 + spacing,
1636 			&meter_texs[8],
1637 			(shieldtime >= shieldtimemax
1638 			 ? shieldtimemax : shieldtime),
1639 			shieldtimemax, temporaryMeterColorRGBA);
1640 
1641 	if (phasingtime >= 0 && phasingtimemax > 0)
1642 	    Paint_meter((ext_view_width-300)/2 -32, 2*ext_view_height/3 + 2*spacing,
1643 			&meter_texs[9],
1644 			(phasingtime >= phasingtimemax
1645 			 ? phasingtimemax : phasingtime),
1646 			phasingtimemax, temporaryMeterColorRGBA);
1647 
1648 	if (destruct > 0)
1649 	    Paint_meter((ext_view_width-300)/2 -32, 2*ext_view_height/3 + 3*spacing,
1650 			&meter_texs[10], destruct, (int)SELF_DESTRUCT_DELAY,
1651 			temporaryMeterColorRGBA);
1652 
1653 	if (shutdown_count >= 0)
1654 	    Paint_meter((ext_view_width-300)/2 -32, 2*ext_view_height/3 + 4*spacing,
1655 			&meter_texs[11], shutdown_count, shutdown_delay,
1656 			temporaryMeterColorRGBA);
1657     }
1658     glDisable(GL_BLEND);
1659 }
1660 
Paint_lock(int hud_pos_x,int hud_pos_y)1661 static void Paint_lock(int hud_pos_x, int hud_pos_y)
1662 {
1663     other_t *target;
1664     const int BORDER = 2;
1665 
1666     if ((target = Other_by_id(lock_id)) == NULL)
1667 	return;
1668 
1669     if (hudColorRGBA) {
1670 	int color = Life_color(target);
1671 
1672 	if (!color)
1673 	    color = hudColorRGBA;
1674 
1675 	HUDnprint(&gamefont,
1676 		  color,CENTER,CENTER,
1677 		  hud_pos_x,
1678 		  hud_pos_y -(- hudSize + HUD_OFFSET - BORDER),
1679 		  strlen(target->id_string),"%s",target->id_string);
1680 
1681     }
1682 
1683 
1684 }
1685 
Paint_hudradar_dot(int x,int y,Uint32 col,int shape,int sz)1686 static void Paint_hudradar_dot(int x, int y, Uint32 col, int shape, int sz)
1687 {
1688     if (col == 0 || shape < 2 || sz == 0) return;
1689     set_alphacolor(col);
1690 
1691     switch(shape) {
1692     case 2:
1693     case 3:
1694 	Circle(col, x, y, sz, shape == 2 ? 1 : 0);
1695 	break;
1696     case 4:
1697     case 5:
1698 	glBegin(shape == 4 ? GL_QUADS : GL_LINE_LOOP);
1699 	glVertex2i(x - sz, y - sz);
1700 	glVertex2i(x - sz, y + sz);
1701 	glVertex2i(x + sz, y + sz);
1702 	glVertex2i(x + sz, y - sz);
1703 	glEnd();
1704 	break;
1705     case 6:
1706     case 7:
1707 	glBegin(shape == 6 ? GL_TRIANGLES : GL_LINE_LOOP);
1708 	glVertex2i(x - sz, y + sz);
1709 	glVertex2i(x, y - sz);
1710 	glVertex2i(x + sz, y + sz);
1711 	glEnd();
1712 	break;
1713     }
1714 }
1715 
Paint_hudradar(double hrscale,double xlimit,double ylimit,int sz)1716 static void Paint_hudradar(double hrscale, double xlimit, double ylimit, int sz)
1717 {
1718     Uint32 c;
1719     int i, x, y, shape, size;
1720     int hrw = (int)(hrscale * 256);
1721     int hrh = (int)(hrscale * RadarHeight);
1722     double xf = (double) hrw / (double) Setup->width;
1723     double yf = (double) hrh / (double) Setup->height;
1724 
1725     for (i = 0; i < num_radar; i++) {
1726 	x = (int)(radar_ptr[i].x * hrscale
1727 		  - (world.x + ext_view_width / 2) * xf);
1728 	y = (int)(radar_ptr[i].y * hrscale
1729 		  - (world.y + ext_view_height / 2) * yf);
1730 
1731 	if (x < -hrw / 2)
1732 	    x += hrw;
1733 	else if (x > hrw / 2)
1734 	    x -= hrw;
1735 
1736 	if (y < -hrh / 2)
1737 	    y += hrh;
1738 	else if (y > hrh / 2)
1739 	    y -= hrh;
1740 
1741 	if (!((x <= xlimit) && (x >= -xlimit)
1742 	      && (y <= ylimit) && (y >= -ylimit))) {
1743 
1744  	    x = x + draw_width / 2;
1745  	    y = -y + draw_height / 2;
1746 
1747 	    if (radar_ptr[i].type == RadarEnemy) {
1748 		c = hudRadarEnemyColorRGBA;
1749 		shape = hudRadarEnemyShape;
1750 	    } else {
1751 		c = hudRadarOtherColorRGBA;
1752 		shape = hudRadarOtherShape;
1753 	    }
1754 	    size = sz;
1755 	    if (radar_ptr[i].size == 0) {
1756 		size >>= 1;
1757 		if (hudRadarObjectColorRGBA)
1758 		    c = hudRadarObjectColorRGBA;
1759 		if (hudRadarObjectShape)
1760 		    shape = hudRadarObjectShape;
1761 	    }
1762 	    Paint_hudradar_dot(x, y, c, shape, size);
1763 	}
1764     }
1765 }
1766 
Paint_HUD_items(int hud_pos_x,int hud_pos_y)1767 static void Paint_HUD_items(int hud_pos_x, int hud_pos_y)
1768 {
1769     const int		BORDER = 3;
1770     char		str[50];
1771     int     	    	vert_pos, horiz_pos, minx, miny, maxx, maxy;
1772     int     	    	i, maxWidth = -1,
1773 			rect_x, rect_y, rect_width = 0, rect_height = 0;
1774     static int		vertSpacing = -1;
1775     static fontbounds	fb;
1776 
1777 
1778     /* Special itemtypes */
1779     if (vertSpacing < 0)
1780 	vertSpacing = MAX(ITEM_SIZE, gamefont.h) + 1;
1781     /* find the scaled location, then work in pixels */
1782     vert_pos = hud_pos_y - hudSize+HUD_OFFSET + BORDER;
1783     horiz_pos = hud_pos_x - hudSize+HUD_OFFSET - BORDER;
1784     rect_width = 0;
1785     rect_height = 0;
1786     rect_x = horiz_pos;
1787     rect_y = vert_pos;
1788 
1789     for (i = 0; i < NUM_ITEMS; i++) {
1790 	int num = numItems[i];
1791 
1792 	if (i == ITEM_FUEL)
1793 	    continue;
1794 
1795 	if (instruments.showItems) {
1796 	    lastNumItems[i] = num;
1797 	    if (num <= 0)
1798 		num = -1;
1799 	} else {
1800 	    if (num != lastNumItems[i]) {
1801 		numItemsTime[i] = (int)(showItemsTime * (double)FPS);
1802 		lastNumItems[i] = num;
1803 	    }
1804 	    if (numItemsTime[i]-- <= 0) {
1805 		numItemsTime[i] = 0;
1806 		num = -1;
1807 	    }
1808 	}
1809 
1810 	if (num >= 0) {
1811 
1812     	    Image_paint(IMG_HUD_ITEMS,
1813 			horiz_pos - ITEM_SIZE,
1814 			vert_pos, (u_byte)i,
1815 			hudItemsColorRGBA);
1816 
1817 	    if (i == lose_item) {
1818 		if (lose_item_active != 0) {
1819 		    if (lose_item_active < 0)
1820 			lose_item_active++;
1821 			minx = horiz_pos-ITEM_SIZE-2;
1822 			maxx = horiz_pos;
1823 			miny = vert_pos-2;
1824 			maxy = vert_pos + ITEM_SIZE;
1825 
1826     	    	    	glBegin(GL_LINE_LOOP);
1827     	    	    	    glVertex2i(minx , miny);
1828     	    	    	    glVertex2i(maxx , miny);
1829     	    	    	    glVertex2i(maxx , maxy);
1830     	    	    	    glVertex2i(minx , maxy);
1831     	    	    	glEnd();
1832 		}
1833 	    }
1834 
1835 	    /* Paint item count */
1836 	    sprintf(str, "%d", num);
1837 	    fb = printsize(&gamefont,"%s",str);
1838 
1839 	    maxWidth = MAX(maxWidth, fb.width + BORDER + ITEM_SIZE);
1840 
1841 	    HUDprint(&gamefont,hudItemsColorRGBA,RIGHT,UP,horiz_pos - ITEM_SIZE - BORDER
1842 	    	    ,draw_height - vert_pos - ITEM_SIZE,"%s",str);
1843 
1844 	    vert_pos += vertSpacing;
1845 
1846 	    if (vert_pos+vertSpacing
1847 		> hud_pos_y+hudSize-HUD_OFFSET-BORDER) {
1848 		rect_width += maxWidth + 2*BORDER;
1849 		rect_height = MAX(rect_height, vert_pos - rect_y);
1850 		horiz_pos -= maxWidth + 2*BORDER;
1851 		vert_pos = hud_pos_y - hudSize+HUD_OFFSET + BORDER;
1852 		maxWidth = -1;
1853 	    }
1854 	}
1855     }
1856     if (maxWidth != -1)
1857 	rect_width += maxWidth + BORDER;
1858 
1859     if (rect_width > 0) {
1860 	if (rect_height == 0)
1861 	    rect_height = vert_pos - rect_y;
1862 	rect_x -= rect_width;
1863     }
1864 
1865 }
1866 
1867 typedef char hud_text_t[50];
1868 
Paint_HUD(void)1869 void Paint_HUD(void)
1870 {
1871     const int		BORDER = 3;
1872     char		str[50];
1873     int			hud_pos_x, hud_pos_y, size;
1874     int			did_fuel = 0;
1875     int			i, j, tex_index, modlen = 0;
1876     static char		autopilot[] = "Autopilot";
1877     int tempx,tempy,tempw,temph;
1878     static hud_text_t 	hud_texts[MAX_HUD_TEXS+MAX_SCORE_OBJECTS];
1879 
1880     fontbounds dummy;
1881     tex_index = 0;
1882     glEnable(GL_BLEND);
1883     /*
1884      * Show speed pointer
1885      */
1886     glBlendFunc(GL_SRC_ALPHA, GL_ONE);
1887     if (ptr_move_fact != 0.0
1888 	&& selfVisible
1889 	&& (selfVel.x != 0 || selfVel.y != 0))
1890     	Segment_add(hudColorRGBA,
1891 		    draw_width / 2,
1892 		    draw_height / 2,
1893 		    (int)(draw_width / 2 - ptr_move_fact * selfVel.x),
1894 		    (int)(draw_height / 2 + ptr_move_fact * selfVel.y));
1895 
1896     if (selfVisible && dirPtrColorRGBA) {
1897 	Segment_add(dirPtrColorRGBA,
1898 		    (int) (draw_width / 2 +
1899 			   (100 - 15) * tcos(heading)),
1900 		    (int) (draw_height / 2 -
1901 			   (100 - 15) * tsin(heading)),
1902 		    (int) (draw_width / 2 + 100 * tcos(heading)),
1903 		    (int) (draw_height / 2 - 100 * tsin(heading)));
1904     }
1905 
1906     /* TODO */
1907     /* This should be done in a nicer way now (using radar.c maybe) */
1908     glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1909 
1910     if (hudRadarEnemyColorRGBA
1911 	|| hudRadarOtherColorRGBA
1912 	|| hudRadarObjectColorRGBA) {
1913 	hudRadarMapScale = (double) Setup->width / (double) 256;
1914 	Paint_hudradar(
1915 	    hudRadarScale,
1916 	    (int)(hudRadarLimit * (ext_view_width / 2)
1917 		  * hudRadarScale / hudRadarMapScale),
1918 	    (int)(hudRadarLimit * (ext_view_height / 2)
1919 		  * hudRadarScale / hudRadarMapScale),
1920 	    hudRadarDotSize);
1921 
1922 	Paint_hudradar(hudRadarMapScale*clData.scale,
1923 		       (active_view_width / 2)*clData.scale,
1924 		       (active_view_height / 2)*clData.scale,
1925 		       SHIP_SZ);
1926     }
1927 
1928 
1929     glDisable(GL_BLEND);
1930     /* message scan hack by mara and jpv */
1931     if (Bms_test_state(BmsBall) && msgScanBallColorRGBA)
1932 	Circle(msgScanBallColorRGBA, draw_width / 2,
1933 	       draw_height / 2, (int)(8*clData.scale),0);
1934     if (Bms_test_state(BmsCover) && msgScanCoverColorRGBA)
1935 	Circle(msgScanCoverColorRGBA, draw_width / 2,
1936 	       draw_height / 2, (int)(6*clData.scale),0);
1937 
1938     glEnable(GL_BLEND);
1939 
1940     /*
1941      * Display the HUD
1942      */
1943     hud_pos_x = (int)(draw_width / 2 - hud_move_fact * selfVel.x);
1944     hud_pos_y = (int)(draw_height / 2 + hud_move_fact * selfVel.y);
1945 
1946     glBlendFunc(GL_SRC_ALPHA, GL_ONE);
1947     /* HUD frame */
1948     glLineStipple(4, 0xAAAA);
1949     glEnable(GL_LINE_STIPPLE);
1950     if (hudHLineColorRGBA) {
1951     	set_alphacolor(hudHLineColorRGBA);
1952     	glBegin(GL_LINES);
1953     	    glVertex2i(hud_pos_x - hudSize,hud_pos_y - hudSize + HUD_OFFSET);
1954 	    glVertex2i(hud_pos_x + hudSize,hud_pos_y - hudSize + HUD_OFFSET);
1955 
1956 	    glVertex2i(hud_pos_x - hudSize,hud_pos_y + hudSize - HUD_OFFSET);
1957 	    glVertex2i(hud_pos_x + hudSize,hud_pos_y + hudSize - HUD_OFFSET);
1958     	glEnd();
1959     }
1960     if (hudVLineColorRGBA) {
1961     	set_alphacolor(hudVLineColorRGBA);
1962     	glBegin(GL_LINES);
1963     	    glVertex2i(hud_pos_x - hudSize + HUD_OFFSET,hud_pos_y - hudSize);
1964 	    glVertex2i(hud_pos_x - hudSize + HUD_OFFSET,hud_pos_y + hudSize);
1965 
1966 	    glVertex2i(hud_pos_x + hudSize - HUD_OFFSET,hud_pos_y - hudSize);
1967 	    glVertex2i(hud_pos_x + hudSize - HUD_OFFSET,hud_pos_y + hudSize);
1968     	glEnd();
1969     }
1970     glDisable(GL_LINE_STIPPLE);
1971 
1972     if (hudItemsColorRGBA)
1973 	Paint_HUD_items(hud_pos_x, hud_pos_y);
1974 
1975     /* Fuel notify, HUD meter on */
1976     if (hudColorRGBA && (fuelTime > 0.0 || fuelSum < fuelNotify)) {
1977 	did_fuel = 1;
1978 	/* TODO fix this */
1979 	sprintf(str, "%04d", (int)fuelSum);
1980 	tex_index=0;
1981 	if (strcmp(str,hud_texts[tex_index])!=0) {
1982     	    if (HUD_texs[tex_index].tex_list)
1983 	    	free_string_texture(&HUD_texs[tex_index]);
1984 	    strlcpy(hud_texts[tex_index],str,50);
1985 	}
1986 	if (!HUD_texs[tex_index].tex_list)
1987 	    render_text(&gamefont, str, &HUD_texs[tex_index]);
1988 	disp_text(  &HUD_texs[tex_index],hudColorRGBA,LEFT,DOWN
1989 	    	    ,hud_pos_x + hudSize-HUD_OFFSET+BORDER
1990 		    ,hud_pos_y - (hudSize-HUD_OFFSET+BORDER)
1991 		    ,true   );
1992 
1993 	if (numItems[ITEM_TANK]) {
1994 	    if (fuelCurrent == 0)
1995 		strcpy(str,"M ");
1996 	    else
1997 		sprintf(str, "T%d", fuelCurrent);
1998 
1999 	    tex_index=1;
2000 	    if (strcmp(str,hud_texts[tex_index])!=0) {
2001     	    	if (HUD_texs[tex_index].tex_list)
2002 		    free_string_texture(&HUD_texs[tex_index]);
2003     	    	strlcpy(hud_texts[tex_index],str,50);
2004 	    }
2005 	    if (!HUD_texs[tex_index].tex_list)
2006 	    	render_text(&gamefont, str, &HUD_texs[tex_index]);
2007 	    disp_text(  &HUD_texs[tex_index],hudColorRGBA,LEFT,DOWN
2008 	    	    ,hud_pos_x + hudSize-HUD_OFFSET + BORDER
2009 		    ,hud_pos_y - hudSize-HUD_OFFSET + BORDER
2010 		    ,true   );
2011 
2012 	}
2013     }
2014 
2015     /* Update the lock display */
2016     Paint_lock(hud_pos_x, hud_pos_y);
2017 
2018     /* Draw last score on hud if it is an message attached to it */
2019     if (hudColorRGBA) {
2020 	for (i = 0, j = 0; i < MAX_SCORE_OBJECTS; i++) {
2021 	    score_object_t*	sobj = &score_objects[(i+score_object)%MAX_SCORE_OBJECTS];
2022 	    if (sobj->hud_msg_len > 0) {
2023 	    	dummy = printsize(&gamefont,"%s",sobj->hud_msg);
2024 		if (sobj->hud_msg_width == -1)
2025 		    sobj->hud_msg_width = (int)dummy.width;
2026 		if (j == 0 &&
2027 		    sobj->hud_msg_width > 2*hudSize-HUD_OFFSET*2 &&
2028 		    (did_fuel || hudVLineColorRGBA))
2029 		    ++j;
2030 
2031 		tex_index=MAX_HUD_TEXS+i;
2032 		if (strcmp(sobj->hud_msg,hud_texts[tex_index])!=0) {
2033     	    	    if (HUD_texs[tex_index].tex_list)
2034 		    	free_string_texture(&HUD_texs[tex_index]);
2035     	    	    strlcpy(hud_texts[tex_index],sobj->hud_msg,50);
2036 	    	}
2037 	    	if (!HUD_texs[tex_index].tex_list)
2038 	    	    render_text(&gamefont, sobj->hud_msg, &HUD_texs[tex_index]);
2039 
2040 		disp_text(  &HUD_texs[tex_index],hudColorRGBA,CENTER,DOWN
2041 	    	    ,hud_pos_x
2042 		    ,hud_pos_y - (hudSize-HUD_OFFSET + BORDER + j * HUD_texs[tex_index].height)
2043 		    ,true   );
2044 		j++;
2045 	    }
2046 	}
2047 
2048 	if (time_left > 0) {
2049 	    sprintf(str, "%3d:%02d", (int)(time_left / 60), (int)(time_left % 60));
2050 	    tex_index=3;
2051 	    if (strcmp(str,hud_texts[tex_index])!=0) {
2052     	    	if (HUD_texs[tex_index].tex_list)
2053 		    free_string_texture(&HUD_texs[tex_index]);
2054     	    	strlcpy(hud_texts[tex_index],str,50);
2055 	    }
2056 	    if (!HUD_texs[tex_index].tex_list)
2057 	    	render_text(&gamefont, str, &HUD_texs[tex_index]);
2058 	    disp_text(  &HUD_texs[tex_index],hudColorRGBA,RIGHT,DOWN
2059 	    	    ,hud_pos_x - hudSize+HUD_OFFSET - BORDER
2060 		    ,hud_pos_y + hudSize+HUD_OFFSET + BORDER
2061 		    ,true   );
2062 	}
2063 
2064 	/* Update the modifiers */
2065 	modlen = strlen(mods);
2066 	tex_index=4;
2067 	if (strcmp(mods,hud_texts[tex_index])!=0) {
2068     	    if (HUD_texs[tex_index].tex_list)
2069 	    	free_string_texture(&HUD_texs[tex_index]);
2070     	    strlcpy(hud_texts[tex_index],mods,50);
2071 	}
2072 	if(strlen(mods)) {
2073 	    if (!HUD_texs[tex_index].tex_list)
2074 	    	render_text(&gamefont, mods, &HUD_texs[tex_index]);
2075 	    disp_text(  &HUD_texs[tex_index],hudColorRGBA,RIGHT,UP
2076 		    	,hud_pos_x - hudSize+HUD_OFFSET-BORDER
2077 	    	    	,hud_pos_y - hudSize+HUD_OFFSET-BORDER
2078 	    	    	,true	);
2079     	}
2080 
2081 	if (autopilotLight) {
2082 	    tex_index=5;
2083 	    if (strcmp(autopilot,hud_texts[tex_index])!=0) {
2084     	    	if (HUD_texs[tex_index].tex_list)
2085 		    free_string_texture(&HUD_texs[tex_index]);
2086     	    	strlcpy(hud_texts[tex_index],autopilot,50);
2087 	    }
2088 	    if (!HUD_texs[tex_index].tex_list)
2089 	    	render_text(&gamefont, autopilot, &HUD_texs[tex_index]);
2090 	    disp_text(  &HUD_texs[tex_index],hudColorRGBA,RIGHT,DOWN
2091 	    	    ,hud_pos_x
2092 		    ,hud_pos_y + hudSize+HUD_OFFSET + BORDER + HUD_texs[tex_index].height*2
2093 		    ,true   );
2094 	}
2095     }
2096 
2097     if (fuelTime > 0.0) {
2098 	fuelTime -= timePerFrame;
2099 	if (fuelTime <= 0.0)
2100 	    fuelTime = 0.0;
2101     }
2102 
2103     /* draw fuel gauge */
2104     if (fuelGaugeColorRGBA &&
2105 	((fuelTime > 0.0)
2106 	 || (fuelSum < fuelNotify
2107 	     && ((fuelSum < fuelCritical && (loopsSlow % 4) < 2)
2108 		 || (fuelSum < fuelWarning
2109 		     && fuelSum > fuelCritical
2110 		     && (loopsSlow % 8) < 4)
2111 		 || (fuelSum > fuelWarning))))) {
2112 
2113 	set_alphacolor(fuelGaugeColorRGBA);
2114 	tempx = hud_pos_x + hudSize - HUD_OFFSET + FUEL_GAUGE_OFFSET - 1;
2115 	tempy = hud_pos_y - hudSize + HUD_OFFSET + FUEL_GAUGE_OFFSET - 1;
2116 	tempw = HUD_OFFSET - (2*FUEL_GAUGE_OFFSET) + 3;
2117 	temph = HUD_FUEL_GAUGE_SIZE + 3;
2118 	glBegin(GL_LINE_LOOP);
2119 	    glVertex2i(tempx,tempy);
2120 	    glVertex2i(tempx,tempy+temph);
2121 	    glVertex2i(tempx+tempw,tempy+temph);
2122 	    glVertex2i(tempx+tempw,tempy);
2123 	glEnd();
2124 
2125 	size = (int)((HUD_FUEL_GAUGE_SIZE * fuelSum) / fuelMax);
2126 	tempx = hud_pos_x + hudSize - HUD_OFFSET + FUEL_GAUGE_OFFSET + 1;
2127     	tempy = hud_pos_y - hudSize + HUD_OFFSET + FUEL_GAUGE_OFFSET + HUD_FUEL_GAUGE_SIZE - size + 1;
2128     	tempw = HUD_OFFSET - (2*FUEL_GAUGE_OFFSET);
2129     	temph = size;
2130 	glBegin(GL_POLYGON);
2131 	    glVertex2i(tempx,tempy);
2132 	    glVertex2i(tempx,tempy+temph);
2133 	    glVertex2i(tempx+tempw,tempy+temph);
2134 	    glVertex2i(tempx+tempw,tempy);
2135 	glEnd();
2136     }
2137     glDisable(GL_BLEND);
2138 }
2139 
2140 typedef struct alert_timeout_struct alert_timeout;
2141 struct alert_timeout_struct {
2142     GLWidget	    *msg;   /* use to build widget lists */
2143     double     	    timeout;
2144     alert_timeout   *next;
2145 };
2146 static alert_timeout *alert_timeout_list = NULL;
2147 
Add_alert_message(const char * message,double timeout)2148 void Add_alert_message(const char *message, double timeout)
2149 {
2150     GLWidget *tmp = NULL;
2151     alert_timeout *tol;
2152 
2153     tmp = Init_LabelWidget(message,&whiteRGBA,&nullRGBA,CENTER,CENTER);
2154     if (tmp) {
2155     	ListWidget_Prepend(((WrapperWidget *)(MainWidget->wid_info))->alert_msgs,tmp);
2156     } else {
2157     	error("Add_alert_message: Failed to create LabelWidget");
2158 	return;
2159     }
2160 
2161     tol = alert_timeout_list;
2162     alert_timeout_list = (alert_timeout *)malloc(sizeof(alert_timeout));
2163     alert_timeout_list->next = tol;
2164     alert_timeout_list->timeout = timeout;
2165     alert_timeout_list->msg = tmp;
2166 }
2167 
Clear_alert_messages(void)2168 void Clear_alert_messages(void)
2169 {
2170     GLWidget *tmp,*list;
2171     bool dummy;
2172     alert_timeout *tol;
2173 
2174     while ((tol = alert_timeout_list)) {
2175     	alert_timeout_list = alert_timeout_list->next;
2176 	free(tol);
2177     }
2178 
2179     list = ((WrapperWidget *)(MainWidget->wid_info))->alert_msgs;
2180     dummy = true;
2181     while (dummy) {
2182     	tmp = ListWidget_GetItemByIndex( list, 0 );
2183 	if (tmp == NULL) break;
2184     	dummy = ListWidget_Remove( list, tmp );
2185     }
2186 }
2187 
Paint_messages(void)2188 void Paint_messages(void)
2189 {
2190     static int old_maxMessages = 0;
2191     static message_t **msgs[2];
2192     static GLWidget *msg_list[2] = {NULL,NULL};
2193     static bool showMessages = true;
2194 
2195     int j, i = 0;
2196     Uint32 *msg_color;
2197     /*const int BORDER = 10;*/
2198     GLWidget *tmp = NULL,*tmp2 = NULL;
2199     LabelWidget *wi;
2200     message_t	*msg;
2201 
2202     alert_timeout *garbage, **tol = &alert_timeout_list;
2203     static int lastloops;
2204 
2205     msgs[0] = TalkMsg;
2206     msgs[1] = GameMsg;
2207 
2208     msg_list[0] = ((WrapperWidget *)(MainWidget->wid_info))->chat_msgs;
2209     msg_list[1] = ((WrapperWidget *)(MainWidget->wid_info))->game_msgs;
2210 
2211     if ( showMessages != instruments.showMessages ) {
2212     	if (!instruments.showMessages)
2213 	    DelGLWidgetListItem( &(MainWidget->children), ((WrapperWidget *)(MainWidget->wid_info))->game_msgs );
2214 	else
2215 	    AppendGLWidgetList( &(MainWidget->children), ((WrapperWidget *)(MainWidget->wid_info))->game_msgs );
2216 
2217 	showMessages = instruments.showMessages;
2218     }
2219 
2220     if ( maxMessages < old_maxMessages ) {
2221     	for (i=0;i<2;++i)
2222 	    while ((tmp = ListWidget_GetItemByIndex(msg_list[i],maxMessages)) != NULL) {
2223     	    	ListWidget_Remove(msg_list[i],tmp);
2224 	    	Close_Widget(&tmp);
2225     	    }
2226     }
2227 
2228     /* Check if any alert message has timed out, if so remove it */
2229     while ((*tol)) {
2230 	if ((*tol)->timeout != 0.0) {
2231 	    (*tol)->timeout -= (loops - lastloops)/(double)FPS;
2232 	    if ((*tol)->timeout <= 0.0) {
2233 	    	garbage = (*tol);
2234 		*tol = (*tol)->next;
2235     	    	ListWidget_Remove( ((WrapperWidget *)(MainWidget->wid_info))->alert_msgs, garbage->msg );
2236 	    	free(garbage);
2237 		continue;
2238 	    }
2239 	}
2240     	tol = &((*tol)->next);
2241     }
2242     lastloops = loops;
2243 
2244     /* TODO: check whether there is a more efficient way to do this!
2245      * i.e. add labelwidgets as messages are added/removed
2246      * For now this will have to do...
2247      */
2248     for ( i=0 ; i < 2 ; ++i)
2249     for ( j=0 ; j <= maxMessages-1 ; ++j) {
2250     	msg = (msgs[i])[j];
2251 	tmp = tmp2 = NULL;
2252 
2253     	if ((msg->lifeTime -= timePerFrame) <= 0.0) {
2254     	    msg->txt[0] = '\0';
2255     	    msg->len = 0;
2256     	    msg->lifeTime = 0.0;
2257     	}
2258 
2259 	if ((tmp = ListWidget_GetItemByIndex(msg_list[i],j) ) != NULL) {
2260 	    if ( !(wi = (LabelWidget *)tmp->wid_info) ) {
2261 	    	error("Paint_messages: ListWidget lacks a wid_info ptr!");
2262 		continue;
2263 	    }
2264 	    if (strlen(msg->txt)) {
2265 	    	if ( strcmp(msg->txt, wi->tex.text) ) {
2266 		    tmp2 = Init_LabelWidget(msg->txt,&messagesColorRGBA,&nullRGBA,LEFT,CENTER);
2267 		    ListWidget_Insert(msg_list[i],tmp,tmp2);
2268 		    if (ListWidget_NELEM(msg_list[i])>maxMessages) {
2269 		    	tmp = ListWidget_GetItemByIndex(msg_list[i],maxMessages);
2270 			ListWidget_Remove(msg_list[i],tmp);
2271 			Close_Widget(&tmp);
2272 		    }
2273 		} else tmp2 = tmp;
2274 	    } else {
2275 	    	ListWidget_Remove(msg_list[i],tmp);
2276 		Close_Widget(&tmp);
2277 	    }
2278 	} else {
2279 	    if (strlen(msg->txt)) {
2280 		tmp2 = Init_LabelWidget(msg->txt,&messagesColorRGBA,&nullRGBA,LEFT,CENTER);
2281 		ListWidget_Append(msg_list[i],tmp2);
2282 	    }
2283 	}
2284 
2285 	if (msg->lifeTime <= MSG_FLASH_TIME)
2286 	    msg_color = &oldmessagesColorRGBA;
2287 	else {
2288 	    /* If paused, don't bother to paint messages in mscScan* colors. */
2289 	    if (self && strchr("P", self->mychar))
2290 		msg_color = &messagesColorRGBA;
2291 	    else {
2292 		switch (msg->bmsinfo) {
2293 		case BmsBall:	msg_color = &msgScanBallColorRGBA;	break;
2294 		case BmsSafe:	msg_color = &msgScanSafeColorRGBA;	break;
2295 		case BmsCover:	msg_color = &msgScanCoverColorRGBA;	break;
2296 		case BmsPop:	msg_color = &msgScanPopColorRGBA;	break;
2297 		default:	msg_color = &messagesColorRGBA;	    	break;
2298 		}
2299 	    }
2300 	}
2301 
2302 	/* kps ugly hack */
2303 	if (newbie && msg->txt) {
2304 	    const char *help = "[*Newbie help*]";
2305 	    size_t sz = strlen(msg->txt);
2306 	    size_t hsz = strlen(help);
2307 
2308 	    if (sz > hsz
2309 		&& !strcmp(help, &msg->txt[sz - hsz]))
2310 		msg_color = &whiteRGBA;
2311 	}
2312 
2313 
2314 	if (tmp2) LabelWidget_SetColor(tmp2, msg_color, &nullRGBA);
2315     }
2316 
2317     old_maxMessages = maxMessages;
2318 }
2319 
set_rgba_color_option(xp_option_t * opt,const char * val)2320 static bool set_rgba_color_option(xp_option_t *opt, const char *val)
2321 {
2322     int c = 0;
2323     assert(val);
2324     if (*val != '#') return false;
2325     c = strtoul(val + 1, NULL, 16) & 0xffffffff;
2326     *((int*)Option_get_private_data(opt)) = c;
2327     return true;
2328 }
2329 
get_rgba_color_option(xp_option_t * opt)2330 static const char *get_rgba_color_option(xp_option_t *opt)
2331 {
2332     static char buf[10];
2333     sprintf(buf, "#%08X", *((int*)Option_get_private_data(opt)));
2334     return buf;
2335 }
2336 
2337 #define COLOR(variable, defval, description) \
2338     XP_STRING_OPTION(#variable, \
2339 		     defval, \
2340                      NULL, \
2341 		     0, \
2342 		     set_rgba_color_option, \
2343 		     &variable, \
2344 		     get_rgba_color_option, \
2345 		     XP_OPTFLAG_CONFIG_COLORS, \
2346 		     "The color of " description ".\n")
2347 
2348 
2349 static xp_option_t sdlgui_options[] = {
2350 
2351     COLOR(messagesColorRGBA, "#00aaaaff", "messages"),
2352     COLOR(oldmessagesColorRGBA, "#008888ff", "old messages"),
2353     COLOR(msgScanBallColorRGBA, "#ff0000ff", "ball warning"),
2354     COLOR(msgScanSafeColorRGBA, "#00ff00ff", "ball safe announcement"),
2355     COLOR(msgScanCoverColorRGBA, "#4e7cffff", "cover request"),
2356     COLOR(msgScanPopColorRGBA, "#ffbb11ff", "ball pop announcement"),
2357 
2358     COLOR(meterBorderColorRGBA, "#0000ffaa", "meter borders"),
2359     COLOR(fuelMeterColorRGBA, "#ff0000aa", "fuel meter"),
2360     COLOR(fuelGaugeColorRGBA, "#0000ff44", "fuel gauge"),
2361     COLOR(powerMeterColorRGBA, "#ff0000aa", "power meter"),
2362     COLOR(turnSpeedMeterColorRGBA, "#ff0000aa", "turn speed meter"),
2363     COLOR(packetSizeMeterColorRGBA, "#ff0000aa", "packet size meter"),
2364     COLOR(packetLossMeterColorRGBA, "#ff0000aa", "packet loss meter"),
2365     COLOR(packetDropMeterColorRGBA, "#ff0000aa", "drop meter"),
2366     COLOR(packetLagMeterColorRGBA, "#ff0000aa", "lag meter"),
2367     COLOR(temporaryMeterColorRGBA, "#ff0000aa", "time meter"),
2368 
2369     COLOR(ballColorRGBA, "#00ff00ff", "balls"),
2370     COLOR(connColorRGBA, "#00ff0088", "the ball connector"),
2371     COLOR(fuelColorRGBA, "#ffffff7f", "fuel cells"),
2372     COLOR(wallColorRGBA, "#0000ffff", "walls on blockmaps"),
2373     COLOR(decorColorRGBA, "#bb7700ff", "decorations on blockmaps"),
2374     COLOR(baseNameColorRGBA, "#77bbffff", "base name"),
2375     COLOR(shipNameColorRGBA, "#77bbffff", "ship name"),
2376     COLOR(scoreObjectColorRGBA, "#00ff0088", "score objects"),
2377 
2378     COLOR(hudColorRGBA, "#ff000088", "the HUD"),
2379     COLOR(hudHLineColorRGBA, "#0000ff44", "horizontal HUD line"),
2380     COLOR(hudVLineColorRGBA, "#0000ff44", "vertical HUD line"),
2381     COLOR(hudItemsColorRGBA, "#0080ffaa", "hud items"),
2382     COLOR(hudRadarEnemyColorRGBA, "#ff000088", "enemy on HUD radar"),
2383     COLOR(hudRadarOtherColorRGBA, "#0000ff88", "friend on HUD radar"),
2384     COLOR(hudRadarObjectColorRGBA, "#00000000", "small object on HUD radar"),
2385 
2386     COLOR(dirPtrColorRGBA, "#0000ff22", "direction pointer"),
2387     COLOR(selectionColorRGBA, "#ff0000ff", "selection"),
2388 
2389     COLOR(scoreInactiveSelfColorRGBA, "#88008888", "my score when inactive"),
2390     COLOR(scoreInactiveColorRGBA, "#8800aa88", "score when inactive"),
2391     COLOR(scoreSelfColorRGBA, "#ffff00ff", "my score"),
2392     COLOR(scoreColorRGBA, "#888800ff", "score"),
2393     COLOR(scoreOwnTeamColorRGBA, "#0000ffff", "my team score"),
2394     COLOR(scoreEnemyTeamColorRGBA, "#ff0000ff", "enemy team score"),
2395 
2396     COLOR(teamShipColorRGBA, "#0000ffff", "teammate color"),
2397     COLOR(team0ColorRGBA, "#00000000", "team 0"),
2398     COLOR(team1ColorRGBA, "#00000000", "team 1"),
2399     COLOR(team2ColorRGBA, "#00000000", "team 2"),
2400     COLOR(team3ColorRGBA, "#00000000", "team 3"),
2401     COLOR(team4ColorRGBA, "#00000000", "team 4"),
2402     COLOR(team5ColorRGBA, "#00000000", "team 5"),
2403     COLOR(team6ColorRGBA, "#00000000", "team 6"),
2404     COLOR(team7ColorRGBA, "#00000000", "team 7"),
2405     COLOR(team8ColorRGBA, "#00000000", "team 8"),
2406     COLOR(team9ColorRGBA, "#00000000", "team 9"),
2407 
2408     COLOR(selfLWColorRGBA, "#ff0000ff", "my ship on last life"),
2409     COLOR(teamLWColorRGBA, "#ff00ffff", "team ship on last life"),
2410     COLOR(enemyLWColorRGBA, "#ffff00ff", "enemy ship on last life"),
2411     COLOR(manyLivesColorRGBA, "#666666aa", "name of ship with many lives"),
2412     COLOR(twoLivesColorRGBA, "#008800aa", "name of ship with two lives"),
2413     COLOR(oneLifeColorRGBA, "#aaaa00aa", "name of ship with one life"),
2414     COLOR(zeroLivesColorRGBA, "#ff0000aa", "name of ship with no lives"),
2415 
2416     XP_INT_OPTION(
2417         "meterWidth",
2418 	60, 0, 600,
2419 	&meterWidth,
2420 	NULL,
2421 	XP_OPTFLAG_CONFIG_DEFAULT,
2422 	"Set the width of the meters.\n"),
2423 
2424     XP_INT_OPTION(
2425         "meterHeight",
2426 	10, 0, 100,
2427 	&meterHeight,
2428 	NULL,
2429 	XP_OPTFLAG_CONFIG_DEFAULT,
2430 	"Set the height of a meter.\n"),
2431 
2432     XP_DOUBLE_OPTION(
2433         "shipLineWidth",
2434 	1.0, 1.0, 10.0,
2435 	&shipLineWidth,
2436 	NULL,
2437 	XP_OPTFLAG_CONFIG_DEFAULT,
2438 	"Set the line width of ships.\n"),
2439 
2440     XP_BOOL_OPTION(
2441         "smoothLines",
2442         true,
2443 	&smoothLines,
2444 	NULL,
2445 	XP_OPTFLAG_CONFIG_DEFAULT,
2446 	"Use antialized smooth lines.\n"),
2447 
2448     XP_BOOL_OPTION(
2449         "texturedBalls",
2450         true,
2451 	&texturedBalls,
2452 	NULL,
2453 	XP_OPTFLAG_CONFIG_DEFAULT,
2454 	"Draw balls with textures.\n"),
2455 
2456     XP_BOOL_OPTION(
2457         "texturedShips",
2458         true,
2459 	&texturedShips,
2460 	NULL,
2461 	XP_OPTFLAG_CONFIG_DEFAULT,
2462 	"Draw ships with textures.\n"),
2463 
2464     XP_INT_OPTION(
2465         "hudRadarEnemyShape",
2466 	2, 1, 7,
2467 	&hudRadarEnemyShape,
2468 	NULL,
2469 	XP_OPTFLAG_CONFIG_DEFAULT,
2470 	"The shape of enemy ships on hud radar.\n"),
2471 
2472     XP_INT_OPTION(
2473         "hudRadarOtherShape",
2474 	2, 1, 7,
2475 	&hudRadarOtherShape,
2476 	NULL,
2477 	XP_OPTFLAG_CONFIG_DEFAULT,
2478 	"The shape of friendly ships on hud radar.\n"),
2479 
2480     XP_INT_OPTION(
2481         "hudRadarObjectShape",
2482 	0, 0, 7,
2483 	&hudRadarObjectShape,
2484 	NULL,
2485 	XP_OPTFLAG_CONFIG_DEFAULT,
2486 	"The shape of small objects on hud radar.\n")
2487 };
2488 
Store_sdlgui_options(void)2489 void Store_sdlgui_options(void)
2490 {
2491     STORE_OPTIONS(sdlgui_options);
2492 }
2493