1 /*
2  * SDLRoids - An Astroids clone.
3  *
4  * Copyright (c) 2000 David Hedbor <david@hedbor.org>
5  * 	based on xhyperoid by Russel Marks.
6  * 	xhyperoid is based on a Win16 game, Hyperoid by Edward Hutchins
7  *
8  * This program is distributed in the hope that it will be useful,
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11  * GNU General Public License for more details.
12  *
13  * You should have received a copy of the GNU General Public License
14  * along with this program; if not, write to the Free Software
15  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
16  *
17  */
18 
19 /*
20  * sdl.c - Graphics handling for SDL.
21  */
22 
23 #include "config.h"
24 RCSID("$Id: sdl.c,v 1.18 2001/03/27 23:23:52 neotron Exp $");
25 
26 #include <stdio.h>
27 #include <ctype.h>
28 #include <stdlib.h>
29 #include <math.h>
30 #include <SDL.h>
31 #include <string.h>
32 
33 #include "misc.h"	/* for POINT */
34 #include "getargs.h"
35 #include "graphics.h"
36 #include "sdlsound.h"
37 #include "roidsupp.h"
38 
39 
40 static SDL_Joystick *joystick = NULL;
41 static int num_buttons = 0;
42 
43 #define NUM_BITMAPS	18
44 /* Loaded BMPs... */
45 SDL_Surface *bitmaps[NUM_BITMAPS];
46 
47 static char *gfxname[] = {
48   "bmp/num0.bmp",
49   "bmp/num1.bmp",
50   "bmp/num2.bmp",
51   "bmp/num3.bmp",
52   "bmp/num4.bmp",
53   "bmp/num5.bmp",
54   "bmp/num6.bmp",
55   "bmp/num7.bmp",
56   "bmp/num8.bmp",
57   "bmp/num9.bmp",
58   "bmp/blank.bmp",
59   "bmp/bomb.bmp",
60   "bmp/level.bmp",
61   "bmp/life.bmp",
62   "bmp/plus.bmp",
63   "bmp/score.bmp",
64   "bmp/shield.bmp",
65   "bmp/icon.bmp",
66 };
67 
68 /* indicies in above array */
69 #define BMP_NUM0	0
70 #define BMP_NUM1	1
71 #define BMP_NUM2	2
72 #define BMP_NUM3	3
73 #define BMP_NUM4	4
74 #define BMP_NUM5	5
75 #define BMP_NUM6	6
76 #define BMP_NUM7	7
77 #define BMP_NUM8	8
78 #define BMP_NUM9	9
79 #define BMP_BLANK	10
80 #define BMP_BOMB	11
81 #define BMP_LEVEL	12
82 #define BMP_LIFE	13
83 #define BMP_PLUS	14
84 #define BMP_SCORE	15
85 #define BMP_SHIELD	16
86 #define BMP_ICON	17
87 
88 #define R colortable.colors[current_color].r
89 #define G colortable.colors[current_color].g
90 #define B colortable.colors[current_color].b
91 
92 static Uint32 colors[16];
93 static SDL_Surface *screen;
94 static SDL_Palette colortable;
95 
96 static int maxx=0, maxy=0, minx=-1, miny=-1;
97 static int offx=0, offy=0;
98 
99 static int current_x = 0, current_y = 0;
100 static Uint32 current_color; /* current color */
101 /* this leaves 16 lines at the top for score etc. */
102 static int width = 480 , height = 480, mindimhalf = 240;
103 
104 /* We will at most redraw MAX_OBJS*2+2 in a frame. The eraser, the new object
105  * and the special case - the new/old shield locations.
106  */
107 static SDL_Rect rects[MAX_OBJS*2+2];
108 static int rec_counter=0;
109 
110 /* this oddity is needed to simulate the mapping the original used a
111  * Windows call for. MAX_COORD is a power of 2, so when optimised
112  * this isn't too evil.
113  */
114 #define USE_CONV_TABLE
115 #ifdef USE_CONV_TABLE
116 #define MAX_DRAW_COORD (MAX_COORD+1000)
117 
118 /* Tables to translate virtual coord to actual coord */
119 static Sint16 coord2x[MAX_DRAW_COORD*2], coord2y[MAX_DRAW_COORD*2];
120 static Sint16 *conv_coord2x = coord2x + MAX_DRAW_COORD;
121 static Sint16 *conv_coord2y = coord2y + MAX_DRAW_COORD;
122 
123 #define calc_convx(i,x)	coord2x[i] = ((mindimhalf+(x)*(mindimhalf)/MAX_COORD))
124 #define calc_convy(i,y)	coord2y[i] = ((mindimhalf-(y)*(mindimhalf)/MAX_COORD))
125 
126 #define convx(x) conv_coord2x[x]
127 #define convy(y) conv_coord2y[y]
128 #else
129 #define convx(x) ((mindimhalf+(x)*(mindimhalf)/MAX_COORD))
130 #define convy(y) ((mindimhalf-(y)*(mindimhalf)/MAX_COORD))
131 #endif
132 
133 #define convr(r)        ((width*r)/MAX_COORD)
134 
135 static float joy_x = 0.0, joy_y = 0.0;
136 static int *joy_button;
IsKeyDown(int key)137 float IsKeyDown(int key)
138 {
139   Uint8 *keystate;
140   keystate = SDL_GetKeyState(NULL);
141   switch(key)
142   {
143    case KEY_F1:		return keystate[SDLK_F1];
144    case KEY_TAB:	return keystate[SDLK_TAB]
145 			  || (ARG_JSHIELD < num_buttons &&
146 			      joy_button[ARG_JSHIELD]);
147    case KEY_S:		return keystate[SDLK_s]
148 			  || (ARG_JBOMB < num_buttons
149 			      && joy_button[ARG_JBOMB]);
150    case KEY_LEFT:	return keystate[SDLK_LEFT]
151 			  ? 1 : (joy_x < 0 ? -joy_x : 0 );
152    case KEY_RIGHT:	return keystate[SDLK_RIGHT]
153 			  ? 1 : (joy_x > 0 ? joy_x :0);
154    case KEY_DOWN:	return keystate[SDLK_DOWN]
155 			  ? 1 : (joy_y > 0 ? joy_y : 0 );
156    case KEY_UP:		return keystate[SDLK_UP]
157 			  ? 1 : (joy_y < 0 ? -joy_y : 0 );
158    case KEY_SPACE:	return keystate[SDLK_SPACE]
159 			  || (ARG_JFIRE < num_buttons
160 			      && joy_button[ARG_JFIRE]);
161    case KEY_ESC:	return keystate[SDLK_ESCAPE];
162    default:
163     return 0;
164   }
165 
166 }
167 
fast_putpixel1(Uint16 x,Uint16 y,Uint32 pixel)168 void fast_putpixel1(Uint16 x, Uint16 y, Uint32 pixel)
169 {
170   *((Uint8 *)screen->pixels + y * screen->pitch + x) = pixel;
171 }
fast_putpixel2(Uint16 x,Uint16 y,Uint32 pixel)172 void fast_putpixel2(Uint16 x, Uint16 y, Uint32 pixel)
173 {
174   *((Uint16 *)screen->pixels + y * screen->pitch/2 + x) = pixel;
175 }
176 
fast_putpixel3(Uint16 x,Uint16 y,Uint32 pixel)177 void fast_putpixel3(Uint16 x, Uint16 y, Uint32 pixel)
178 {
179     Uint8 *pix = (Uint8 *)screen->pixels + y * screen->pitch + x * 3;
180     if(SDL_BYTEORDER == SDL_BIG_ENDIAN) {
181         pix[2] = pixel;
182         pix[1] = pixel >> 8;
183         pix[0] = pixel >> 16;
184     } else {
185         pix[0] = pixel;
186         pix[1] = pixel >> 8;
187         pix[2] = pixel >> 16;
188     }
189 }
fast_putpixel4(Uint16 x,Uint16 y,Uint32 pixel)190 void fast_putpixel4(Uint16 x, Uint16 y, Uint32 pixel)
191 {
192   *((Uint32 *)screen->pixels + y * screen->pitch/4 + x) = pixel;
193 }
194 void (*fast_putpixel)(Uint16 x, Uint16 y, Uint32 pixel);
195 
_sdl_drawpixel(int x,int y,int r,int g,int b)196 inline static void _sdl_drawpixel(int x, int y, int r, int g, int b)
197 {
198   Uint8 *bits, bpp;
199   Uint32 pixel = SDL_MapRGB(screen->format, r, g, b);
200   /*  printf("Drawing %dx%d in %d,%d,%d\n", x, y, r, g, b); */
201   bpp = screen->format->BytesPerPixel;
202   bits = ((Uint8 *)screen->pixels)+y*screen->pitch+x*bpp;
203 
204   /* Set the pixel */
205   switch(bpp)
206   {
207    case 1:
208     *((Uint8 *)(bits)) = (Uint8)pixel;
209     break;
210    case 2:
211     *((Uint16 *)(bits)) = (Uint16)pixel;
212     break;
213    case 3: { /* Format/endian independent */
214      Uint8 r, g, b;
215 
216      r = (pixel>>screen->format->Rshift)&0xFF;
217      g = (pixel>>screen->format->Gshift)&0xFF;
218      b = (pixel>>screen->format->Bshift)&0xFF;
219      *((bits)+screen->format->Rshift/8) = r;
220      *((bits)+screen->format->Gshift/8) = g;
221      *((bits)+screen->format->Bshift/8) = b;
222    }
223    break;
224    case 4:
225     *((Uint32 *)(bits)) = (Uint32)pixel;
226     break;
227   }
228 }
229 
sdl_drawpixel(int x,int y)230 static void sdl_drawpixel(int x, int y)
231 {
232   if(x >= width || x < 0 ||
233      y >= height || y < 0) {
234     return;
235   }
236   x += offx;
237   y += offy;
238   if(x > maxx) maxx = x;
239   if(y > maxy) maxy = y;
240   if(minx < 0 || x < minx)   minx = x;
241   if(miny < 0 || y < miny)   miny = y;
242   /* Fast method */
243   (*fast_putpixel)(x, y, colors[current_color]);
244 }
245 
246 /* Draw a circle in the current color. Based off the version in SGE. */
drawcircle(Sint16 x,Sint16 y,Sint32 r)247 static inline void drawcircle(Sint16 x, Sint16 y, Sint32 r)
248 {
249   Sint32 cx = 0;
250   Sint32 cy = r;
251   Sint32 df = 1 - r;
252   Sint32 d_e = 3;
253   Sint32 d_se = -2 * r + 5;
254   do {
255     sdl_drawpixel(x+cx, y+cy);
256     sdl_drawpixel(x-cx, y+cy);
257     sdl_drawpixel(x+cx, y-cy);
258     sdl_drawpixel(x-cx, y-cy);
259     sdl_drawpixel(x+cy, y+cx);
260     sdl_drawpixel(x+cy, y-cx);
261     sdl_drawpixel(x-cy, y+cx);
262     sdl_drawpixel(x-cy, y-cx);
263 
264     if (df < 0)  {
265       df   += d_e;
266       d_e  += 2;
267       d_se += 2;
268     } else {
269       df   += d_se;
270       d_e  += 2;
271       d_se += 4;
272       cy--;
273     }
274     cx++;
275   } while(cx <= cy);
276 }
277 
278 /* absolute value of a */
279 #define ABS(a)		(((a)<0) ? -(a) : (a))
280 
281 /* take binary sign of a, either -1, or 1 if >= 0 */
282 #define SGN(a)		(((a)<0) ? -1 : 1)
283 
284 /* Draw an horizontal line in the current color */
draw_horzline(Sint16 x1,Sint16 x2,Sint32 y)285 inline void draw_horzline(Sint16 x1, Sint16 x2, Sint32 y)
286 {
287   int i;
288   if (x1 < x2) {
289     for (i = x1; i <= x2; i++)
290       sdl_drawpixel(i, y);
291   } else {
292     for (i = x2; i <= x1; i++)
293       sdl_drawpixel(i, y);
294   }
295   return;
296 }
297 
298 /* Draw an vertical line in the current color */
draw_vertline(Sint16 x,Sint16 y1,Sint32 y2)299 inline void draw_vertline(Sint16 x, Sint16 y1, Sint32 y2)
300 {
301   int i;
302   if (y1 < y2) {
303     for (i = y1; i <= y2; i++)
304       sdl_drawpixel(x, i);
305   } else {
306     for (i = y2; i <= y1; i++)
307       sdl_drawpixel(x, i);
308   }
309   return;
310 }
311 
312 /* Draw a line between two coordinates */
drawline(int x1,int y1,int x2,int y2)313 inline void drawline(int x1,int y1,int x2,int y2)
314 {
315   int d, x, y, ax, ay, sx, sy, dx, dy;
316   if((dx = x2 - x1) == 0) { /* vertical line */
317     draw_vertline(x1, y1, y2);
318     return;
319   }
320   if((dy = y2 - y1) == 0) { /* horizontal line */
321     draw_horzline(x1, x2, y1);
322     return;
323   }
324   ax = ABS(dx)<<1;  sx = SGN(dx);
325   ay = ABS(dy)<<1;  sy = SGN(dy);
326 
327   x = x1;
328   y = y1;
329   if (ax>ay)
330   {		/* x dominant */
331     d = ay-(ax>>1);
332     for(;;)
333     {
334       sdl_drawpixel(x,y);
335       if (x==x2) return;
336       if (d>=0)
337       {
338 	y += sy;
339 	d -= ax;
340       }
341       x += sx;
342       d += ay;
343     }
344   } else {			/* y dominant */
345     d = ax-(ay>>1);
346     for (;;)
347     {
348       sdl_drawpixel(x,y);
349       if (y==y2) return;
350       if (d>=0)
351       {
352 	x += sx;
353 	d -= ay;
354       }
355       y += sy;
356       d += ax;
357     }
358   }
359 }
360 
MoveTo(int x,int y)361 inline void MoveTo(int x,int y)
362 {
363   current_x = convx(x);
364   current_y = convy(y);
365 }
366 
367 
368 /* Scaling blit function by Greg Velichansky */
ifloor(Uint32 i)369 inline Uint32 ifloor(Uint32 i)
370 {
371   return i & 0xFFFF0000;
372 }
373 
iceil(Uint32 i)374 inline Uint32 iceil(Uint32 i)
375 {
376   return (i & 0xFFFF) ? i : ifloor(i) + (1<<16);
377 }
378 
379 
380 /* The most pedantic-a%& getpixel and putpixel ever, hopefully. */
381 /* There may still be endianness bugs! These will be fixed after adequte testing. XXX XXX XXX */
SDL_GetPixel(SDL_Surface * f,Uint32 x,Uint32 y,Uint8 * r,Uint8 * g,Uint8 * b)382 inline int SDL_GetPixel (SDL_Surface *f, Uint32 x, Uint32 y,
383 			 Uint8 *r, Uint8 *g, Uint8 *b)
384 {
385   /*const Uint32 mask[] = {0x0, 0xff, 0xffff, 0xffffff, 0xffffffff};*/
386   Uint32 pixel;
387 
388   Uint8 *pp;
389 
390   int n; /* general purpose 'n'. */
391 
392   if (f == NULL) return -1;
393 
394   pp = (Uint8 *) f->pixels;
395 
396   if (x >= f->w || y >= f->h) return -1;
397 
398   pp += (f->pitch * y);
399 
400   pp += (x * f->format->BytesPerPixel);
401 
402   /* we do not lock the surface here, it would be inefficient XXX */
403   /* this reads the pixel as though it was a big-endian integer XXX */
404   /* I'm trying to avoid reading part the end of the pixel data by
405    * using a data-type that's larger than the pixels */
406   for (n = 0, pixel = 0; n < f->format->BytesPerPixel; ++n, ++pp)
407   {
408 #if SDL_BYTEORDER == SDL_LIL_ENDIAN
409     pixel >>= 8;
410     pixel |= *pp << (f->format->BitsPerPixel - 8);
411 #else
412     pixel |= *pp;
413     pixel <<= 8;
414 #endif
415   }
416 
417   SDL_GetRGB(pixel, f->format, r, g, b);
418   return 0;
419 }
420 
421 
SDL_FastScaleBlit(SDL_Surface * src,SDL_Rect * sr,SDL_Surface * dst,SDL_Rect * dr)422 int SDL_FastScaleBlit(SDL_Surface *src, SDL_Rect *sr,
423 		      SDL_Surface *dst, SDL_Rect *dr)
424 {
425   Uint8 r, g, b;
426   Uint32 rs, gs, bs; /* sums. */
427 
428   /* temp storage for large int multiplies. Uint64 doen't exist anywhere */
429   double farea;
430   Uint32 area;
431 
432   Uint32 sx, sy;
433   Uint32 dsx, dsy;
434 
435   Uint32 wsx, wsy;
436 
437   Uint32 x, y; /* x and y, for sub-area */
438 
439   Uint32 tx, ty; /* normal integers */
440   Uint32 lx, ly; /* normal integers */
441 
442   Uint32 w, e, n, s; /* temp variables, named after compass directions */
443 
444   if (src == NULL || sr == NULL || dst == NULL || dr == NULL) return -1;
445 
446   if (!dr->w || !dr->h) return -1;
447 
448 
449   /* TODO FIXME check for possible overflows! */
450 
451   wsx = dsx = (sr->w << 16) / dr->w;
452   if (!(wsx & 0xFFFF0000)) wsx = 1 << 16;
453   wsy = dsy = (sr->h << 16) / dr->h;
454   if (!(wsy & 0xFFFF0000)) wsy = 1 << 16;
455 
456   lx = dr->x + dr->w;
457   ly = dr->y + dr->h;
458 
459   /* lazy multiplication. Hey, it's only once per blit. :P */
460   farea = ((double)wsx) * ((double)wsy);
461   farea /= (double)(1 << 16);
462   area = (Uint32) farea;
463 
464   /* For optimization, those setup routines should be moved into
465    * SDL_ScaleTiledBitmap() for that function.
466    */
467 
468   for (ty = dr->y, sy = sr->y << 16; ty < ly; ++ty, sy+=dsy)
469   {
470     for (tx = dr->x, sx = sr->x << 16; tx < lx; ++tx, sx+=dsx)
471     {
472       rs = gs = bs = 0;
473       for (y = ifloor(sy); iceil(sy + wsy) > y; y += (1<<16))
474       {
475 	for (x = ifloor(sx); iceil(sx + wsx) > x; x += (1<<16))
476 	{
477 	  w = (x > sx) ? 0 : sx - x;
478 	  n = (y > sy) ? 0 : sy - y;
479 
480 	  e = (sx+wsx >= x+(1<<16)) ? 1<<16 : sx+wsx - x;
481 	  s = (sy+wsy >= y+(1<<16)) ? 1<<16 : sy+wsy - y;
482 
483 	  if (w > e || s < n) continue;
484 
485 #define gsx ((x >> 16) >= sr->x+sr->w ? sr->x+sr->w-1 : x >> 16)
486 #define gsy ((y >> 16) >= sr->y+sr->h ? sr->y+sr->h-1 : y >> 16)
487 
488 	  SDL_GetPixel (src, gsx, gsy, &r, &g, &b);
489 
490 	  rs += ((e - w)>>8) * ((s - n)>>8) * r;
491 	  gs += ((e - w)>>8) * ((s - n)>>8) * g;
492 	  bs += ((e - w)>>8) * ((s - n)>>8) * b;
493 	}
494       }
495       rs /= area;
496       gs /= area;
497       bs /= area;
498 
499       r = (Uint8) rs;
500       g = (Uint8) gs;
501       b = (Uint8) bs;
502 
503       (*fast_putpixel)(tx, ty, SDL_MapRGB(screen->format, r, g, b));
504     }
505   }
506 
507   return 0;
508 #undef gsx
509 #undef gsy
510 }
511 
unlock_graphics()512 void unlock_graphics()
513 {
514   if ( SDL_MUSTLOCK(screen) ) {
515     SDL_UnlockSurface(screen);
516   }
517 }
lock_graphics()518 inline void lock_graphics() {
519   if ( SDL_MUSTLOCK(screen) ) {
520     if ( SDL_LockSurface(screen) < 0 ) {
521       return;
522     }
523   }
524 }
525 
ResetRefreshCoords()526 inline void ResetRefreshCoords()
527 {
528   minx = miny = -1;
529   maxx = maxy = 0;
530 }
531 
RedrawObject()532 inline void RedrawObject() {
533   if(minx >= 0) {
534     rects[rec_counter].x = minx;
535     rects[rec_counter].y = miny;
536     rects[rec_counter].w = maxx-minx+1;
537     rects[rec_counter].h = maxy-miny+1;
538     rec_counter++;
539   }
540 }
541 
542 static int is_poly=0;
LineTo(int x,int y)543 inline void LineTo(int x,int y)
544 {
545   x = convx(x); y = convy(y);
546   drawline(current_x,current_y,x,y);
547   current_x=x;
548   current_y=y;
549 }
550 
551 
Polyline(POINT * pts,int n)552 inline void Polyline(POINT *pts,int n)
553 {
554   int f;
555   if(n<2) return;
556   is_poly = 1;
557   MoveTo(pts->x,pts->y);
558   pts++;
559   for(f = 1; f < n; f++, pts++)
560     LineTo(pts->x, pts->y);
561 }
562 
Circle(Sint16 x,Sint16 y,Sint32 r)563 inline void Circle(Sint16 x, Sint16 y, Sint32 r)
564 {
565   x = convx(x);
566   y = convy(y);
567 
568   drawcircle(x, y,convr(r));
569 }
570 
571 /* doesn't set current_[xy] because hyperoid.c doesn't need it to */
SetPixel(Sint16 x,Sint16 y,Uint32 c)572 inline void SetPixel(Sint16 x, Sint16 y,Uint32 c)
573 {
574   current_color = c;
575   x = convx(x);
576   y = convy(y);
577   sdl_drawpixel(x,y);
578 }
579 
580 
set_colour(int c)581 inline void set_colour(int c)
582 {
583   current_color = c;
584 }
585 
586 
587 /* SetIndicator - set a quantity indicator */
588 
SetIndicator(char * npBuff,char bitmap,int nQuant)589 int SetIndicator( char * npBuff, char bitmap, int nQuant )
590 {
591   if (nQuant > 5)
592   {
593     *npBuff++ = bitmap; *npBuff++ = bitmap;
594     *npBuff++ = bitmap; *npBuff++ = bitmap;
595     *npBuff++ = BMP_PLUS;
596   }
597   else
598   {
599     int nBlank = 5 - nQuant;
600     while (nQuant--) *npBuff++ = bitmap;
601     while (nBlank--) *npBuff++ = BMP_BLANK;
602   }
603   return( 5 );
604 }
605 
606 
607 /* score_graphics - draw score and rest of status display */
608 
609 static int force_score_redraw = 1;
score_graphics(int level,int score,int lives,int shield,int bomb)610 void score_graphics(int level,int score,int lives,int shield,int bomb)
611 {
612   SDL_Rect src, dest;
613   static int olevel=-1, oscore=-1, olives=-1, oshield=-1, obomb=-1;
614   static char szScore[40];
615   static char ozScore[40];
616   char szBuff[sizeof(szScore)];
617   char *npBuff = szBuff;
618   int nLen, x, myoffx=0, mywidth, xysize;
619   float scale;
620   if(!force_score_redraw &&
621      level == olevel && score == oscore &&
622      lives == olives && shield == oshield && bomb == obomb)
623     return;
624   olevel = level;  oscore = score;
625   olives = lives;  oshield = shield;
626   obomb = bomb;
627   if(force_score_redraw) {
628     memset(ozScore, NUM_BITMAPS, 40);
629     force_score_redraw = 0;
630   }
631 
632   *npBuff++ = BMP_LEVEL;
633   sprintf( npBuff, "%2.2d", level );
634   while (isdigit( *npBuff ))
635     *npBuff = (char)(*npBuff + BMP_NUM0 - '0'), ++npBuff;
636   *npBuff++ = BMP_BLANK;
637   *npBuff++ = BMP_SCORE;
638   sprintf( npBuff, "%7.7d", score );
639   while (isdigit( *npBuff ))
640     *npBuff = (char)(*npBuff + BMP_NUM0 - '0'), ++npBuff;
641   *npBuff++ = BMP_BLANK;
642   *npBuff++ = BMP_SHIELD;
643   sprintf( npBuff, "%3.3d", shield );
644   while (isdigit( *npBuff ))
645     *npBuff = (char)(*npBuff + BMP_NUM0 - '0'), ++npBuff;
646   *npBuff++ = BMP_BLANK;
647   npBuff += SetIndicator( npBuff, BMP_LIFE, lives );
648   npBuff += SetIndicator( npBuff, BMP_BOMB, bomb );
649   nLen = npBuff - szBuff;
650 
651   mywidth = nLen * 16;
652   if(mywidth > screen->w) {
653     scale = (float)screen->w / (float)mywidth;
654     xysize = (int)floor(16.0 * scale);
655   } else {
656     myoffx = (screen->w - mywidth)/2;
657     if(myoffx > offx) myoffx = offx;
658     xysize = 16;
659   }
660   src.w = src.h = 16;
661   src.x = src.y = 0;
662   dest.w = dest.h = xysize;
663   dest.y = offy - 2 - xysize;
664   if(dest.y < 0) dest.y = 0;
665 
666   for(x = 0;x < nLen; x++) {
667     if(ozScore[x] != szBuff[x]) {
668       ozScore[x] = szBuff[x];
669       dest.x = myoffx + x*xysize;
670       if(xysize != 16) {
671 	SDL_FastScaleBlit(bitmaps[ (int)szBuff[x] ], &src,
672 			  screen, &dest);
673       } else {
674 	SDL_BlitSurface(bitmaps[ (int)szBuff[x] ], &src,
675 			screen, &dest);
676       }
677       SDL_UpdateRect(screen, dest.x, dest.y, xysize, xysize);
678     }
679   }
680 }
681 
bmp2surface(int num)682 int bmp2surface(int num)
683 {
684   int i;
685   SDL_Surface *loaded, *converted;
686 
687   if((loaded = SDL_LoadBMP(gfxname[num])) ||
688      (loaded = SDL_LoadBMP(datafilename(NULL, gfxname[num]))) ||
689      (loaded = SDL_LoadBMP(datafilename(DATADIR, gfxname[num]))) ||
690      (loaded = SDL_LoadBMP(datafilename(bindir, gfxname[num])))) {
691     /* Ugly hack to set the "transparent" color to black :-) */
692     if(loaded->format->BytesPerPixel == 1) {
693       for(i = 0; i < loaded->format->palette->ncolors; i++)
694       {
695 	/* Make the "transparent" color black... */
696 	if(loaded->format->palette->colors[i].r == 255 &&
697 	   loaded->format->palette->colors[i].g == 0   &&
698 	   loaded->format->palette->colors[i].b == 255) {
699 	  loaded->format->palette->colors[i].r =
700 	    loaded->format->palette->colors[i].g =
701 	    loaded->format->palette->colors[i].b = 0;
702 	  break;
703 	}
704       }
705     }
706     converted = SDL_DisplayFormat(loaded);
707     SDL_FreeSurface(loaded);
708     bitmaps[num] = converted;
709     return 1;
710   } else {
711     fprintf(stderr, "Error loading image %s!\n", gfxname[num]);
712     return 0;
713   }
714 }
715 
load_images()716 void load_images()
717 {
718   int f;
719   for(f = 0; f < NUM_BITMAPS; f++) {
720     if(!bmp2surface(f)) {
721       exit(1);
722     }
723   }
724 }
725 
init_colours(int * palrgb)726 void init_colours(int *palrgb)
727 {
728   SDL_Color clut[16];
729   colortable.ncolors = 256;
730   colortable.colors = malloc(256 * sizeof(SDL_Color));
731   for(current_color=0; current_color < 16; current_color++)
732   {
733     R = ((palrgb[current_color*3  ]<<8)|palrgb[current_color*3  ]);
734     G = ((palrgb[current_color*3+1]<<8)|palrgb[current_color*3+1]);
735     B = ((palrgb[current_color*3+2]<<8)|palrgb[current_color*3+2]);
736     if ( screen->format->palette ) {
737       clut[current_color].r = R;
738       clut[current_color].g = G;
739       clut[current_color].b = B;
740     }
741     colors[current_color] = SDL_MapRGB(screen->format, R, G, B);
742   }
743   if ( screen->format->palette ) {
744     SDL_SetColors(screen, clut, 0, 16);
745   }
746 }
747 
draw_boundary_box()748 void draw_boundary_box()
749 {
750 #ifdef USE_CONV_TABLE
751   int i;
752 #endif
753   int myoffy, myoffx;
754 
755   lock_graphics();
756 
757   set_colour(RED);
758   offx=offy=0;
759   if(width < (height - 16)) {
760     myoffy = (height-width)/2;
761     myoffx = 0;
762     drawline(myoffx, myoffy+16, myoffx+width, myoffy+16);
763     drawline(myoffx, myoffy+width+15, myoffx+width, myoffy+width+15);
764     drawline(myoffx, myoffy+16, myoffx, myoffy+width+15);
765     drawline(myoffx+width-1, myoffy+16, myoffx+width-1, myoffy+width+15);
766 
767     height = width;
768   }
769   else {
770     myoffx = (width-height)/2 + 8;
771     myoffy = 0;
772 
773     drawline(myoffx, 16, myoffx+height-16, 16);
774     drawline(myoffx, height-1, myoffx+height-16, height-1);
775     drawline(myoffx, 16, myoffx, height);
776     drawline(myoffx+height-16, 16, myoffx+height-16, height-1);
777 
778     height -= 16;
779     width = height;
780   }
781   offx = myoffx+1; offy = myoffy+17;
782   height = width -= 2;
783   mindimhalf = height/2;
784 #ifdef USE_CONV_TABLE
785   for(i = 0; i < (MAX_DRAW_COORD*2); i++)
786   {
787     int mycoord = i - MAX_DRAW_COORD;
788     calc_convx(i, mycoord);
789     calc_convy(i, mycoord);
790   }
791 #endif
792   unlock_graphics();
793   SDL_UpdateRect(screen, 0,0, 0,0);
794 }
795 
init_graphics(int * palrgb)796 void init_graphics(int *palrgb)
797 {
798   int video_flags;
799   int i;
800   video_flags = SDL_SWSURFACE;
801   if(ARG_FSCRN)
802     video_flags = SDL_FULLSCREEN|SDL_HWSURFACE;
803   video_flags |= SDL_ASYNCBLIT;
804   video_flags |= SDL_RESIZABLE;
805 
806   if ( SDL_Init(SDL_INIT_VIDEO|SDL_INIT_AUDIO|SDL_INIT_JOYSTICK) < 0 ) {
807     fprintf(stderr,
808 	    "Couldn't initialize SDL: %s\n", SDL_GetError());
809     exit(1);
810   }
811   atexit(SDL_Quit);
812   if(ARG_FSCRN) {
813     SDL_ShowCursor(0);
814   }
815   /* Print information about the joysticks */
816   if(SDL_NumJoysticks()) {
817     printf("There are %d joysticks attached\n", SDL_NumJoysticks());
818     for ( i=0; i<SDL_NumJoysticks(); ++i ) {
819       const char *name;
820       name = SDL_JoystickName(i);
821       printf("Joystick %d = %s",i,name ? name : "Unknown Joystick");
822       if(ARG_JLIST == 0 && i == ARG_JOYNUM) {
823 	joystick = SDL_JoystickOpen(i );
824 	if(joystick == NULL) {
825 	  printf(" (failed to open)\n");
826 	} else{
827 	  printf(" (opened)\n");
828 	}
829       } else {
830 	printf("\n");
831       }
832     }
833     if(joystick != NULL) {
834       joy_button = calloc(num_buttons = SDL_JoystickNumButtons(joystick), sizeof(int));
835       if(ARG_JFIRE >= num_buttons ||
836 	 ARG_JSHIELD >= num_buttons ||
837 	 ARG_JBOMB >= num_buttons) {
838 	fprintf(stderr, "Selected joystick button out of range (0-%d)\n",
839 		num_buttons-1);
840 	exit(1);
841       }
842     }
843     if(ARG_JLIST) {
844       exit(0);
845     }
846   }
847 
848   if(ARG_WIDTH) {
849     width  = ARG_WIDTH;
850     height = ARG_HEIGHT;
851   }
852   /* Initialize the display */
853   screen = SDL_SetVideoMode(width, height,
854 			    SDL_GetVideoInfo()->vfmt->BitsPerPixel,
855 			    video_flags);
856   if ( screen == NULL ) {
857     fprintf(stderr, "Couldn't set %dx%d video mode: %s\n",width, height,
858 	    SDL_GetError());
859     exit(1);
860   }
861 
862   /* Decide which pixel drawing function to use. This is an optimization */
863   switch (screen->format->BytesPerPixel) {
864    case 1:
865     fast_putpixel = fast_putpixel1;
866     break;
867    case 2:
868     fast_putpixel = fast_putpixel2;
869     break;
870    case 3:
871     fast_putpixel = fast_putpixel3;
872     break;
873    case 4:
874     fast_putpixel = fast_putpixel4;
875     break;
876    default:
877     fprintf(stderr, "Unknown video bytes-per-pixel!\n");
878     exit(1);
879   }
880   init_colours(palrgb);
881   load_images();
882   draw_boundary_box();
883 
884 
885   SDL_WM_SetCaption("SDLRoids " VERSION, "SDLRoids");
886   SDL_WM_SetIcon(bitmaps[BMP_ICON], NULL);
887 }
888 
889 extern int bPaused;
890 
Pause(int stop)891 static void Pause(int stop) {
892   POINT Pt;
893   Pt.x = 0;
894   Pt.y = 0;
895   if(stop) {
896     //    PrintLetters( "PAUSED", Pt, Pt, RED, 600 );
897     bPaused = 1;
898   } else {
899     bPaused = 0;
900     //    PrintLetters( "PAUSED", Pt, Pt, BLACK, 600 );
901   }
902   SDL_PauseAudio(bPaused);
903 }
904 
update_graphics(void)905 void update_graphics(void)
906 {
907   float value;
908   SDL_Event event;
909   while ( SDL_PollEvent(&event) ) {
910     switch (event.type) {
911      case SDL_ACTIVEEVENT:
912       if(event.active.state == SDL_APPACTIVE) {
913 	Pause(!event.active.gain);
914       }
915       break;
916 
917      case SDL_QUIT:
918       SDL_Quit();
919       exit(0);
920      case SDL_KEYDOWN:
921       if((event.key.keysym.sym == SDLK_RETURN &&
922 	  event.key.keysym.mod & (KMOD_ALT | KMOD_META)) ||
923 	 event.key.keysym.sym == SDLK_BACKSPACE) {
924 	/* toggle fullscreen*/
925 	if(!(screen->flags & SDL_FULLSCREEN)) {
926 	  /* currently windowed. */
927 	  SDL_ShowCursor(0);
928 	  SDL_WM_GrabInput(SDL_GRAB_ON);
929 	}
930 	if(SDL_WM_ToggleFullScreen(screen)) {
931 	  if(!(screen->flags & SDL_FULLSCREEN)) {
932 	    SDL_ShowCursor(1);
933 	    SDL_WM_GrabInput(SDL_GRAB_OFF);
934 	  }
935 	}
936       } else if(event.key.keysym.sym == SDLK_g &&
937 		event.key.keysym.mod & KMOD_CTRL) {
938 	if(!(screen->flags & SDL_FULLSCREEN)) {
939 	  if(SDL_WM_GrabInput(SDL_GRAB_QUERY) == SDL_GRAB_OFF) {
940 	    if(SDL_WM_GrabInput(SDL_GRAB_ON) == SDL_GRAB_ON) {
941 	      SDL_ShowCursor(0);
942 	    }
943 	  } else {
944 	    if(SDL_WM_GrabInput(SDL_GRAB_OFF) == SDL_GRAB_OFF) {
945 	      SDL_ShowCursor(1);
946 	    }
947 	  }
948 	}
949       } else if(event.key.keysym.sym == SDLK_z &&
950 		event.key.keysym.mod & KMOD_CTRL) {
951 	Pause(1);
952 	if(!SDL_WM_IconifyWindow()) {
953 	  Pause(0); /* iconify failed */
954 	}
955       } else if(event.key.keysym.sym == SDLK_PAUSE) {
956 	Pause(!bPaused);
957       } else if(event.key.keysym.sym == SDLK_DOWN ||
958 		event.key.keysym.sym == SDLK_UP)
959       {
960 	loopsam(PTHRUST_CHANNEL,PTHRUST_SAMPLE);
961       }
962 
963       break;
964      case SDL_KEYUP:
965       if(event.key.keysym.sym == SDLK_DOWN ||
966 	 event.key.keysym.sym == SDLK_UP)
967       {
968 	loopsam(PTHRUST_CHANNEL,-1);
969       }
970       break;
971      case SDL_VIDEORESIZE:
972       screen = SDL_SetVideoMode(event.resize.w,
973 				event.resize.h,
974 				screen->format->BitsPerPixel,
975 				screen->flags);
976       width = event.resize.w;
977       height = event.resize.h;
978       /* Draw the boundary box, calculate offsets etc */
979       draw_boundary_box();
980       /* Force redraw of the score display */
981       force_score_redraw=1;
982       break;
983      case SDL_JOYAXISMOTION:
984       if(event.jaxis.value > 5000 || event.jaxis.value < -5000)
985 	value = event.jaxis.value / 32767.0;
986       else
987 	value = 0;
988       switch(event.jaxis.axis)
989       {
990        case 0: joy_x = value; break;
991        case 1: joy_y = value; break;
992       }
993 
994       break;
995      case SDL_JOYBUTTONDOWN:
996       if(joystick != NULL)
997 	joy_button[event.jbutton.button] = 1;
998       break;
999      case SDL_JOYBUTTONUP:
1000       if(joystick != NULL)
1001 	joy_button[event.jbutton.button] = 0;
1002       break;
1003     }
1004   }
1005   if(!force_score_redraw && rec_counter) {
1006     /* Update all changed rects, but if we draw the boundary box
1007      * there is no need since it's already done.
1008      */
1009     SDL_UpdateRects(screen, rec_counter, rects);
1010   }
1011   rec_counter = 0;
1012 }
1013 
exit_graphics(void)1014 void exit_graphics(void)
1015 {
1016   int i;
1017   for(i = 0; i < NUM_BITMAPS; i++)
1018     SDL_FreeSurface(bitmaps[i]);
1019   SDL_FreeSurface(screen);
1020   free(colortable.colors);
1021   if(joystick != NULL) {
1022     SDL_JoystickClose(joystick);
1023     free(joy_button);
1024   }
1025 }
1026 
1027 
1028 
1029 
1030