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