1 /***********************************************************
2 * Artsoft Retro-Game Library                               *
3 *----------------------------------------------------------*
4 * (c) 1994-2006 Artsoft Entertainment                      *
5 *               Holger Schemel                             *
6 *               Detmolder Strasse 189                      *
7 *               33604 Bielefeld                            *
8 *               Germany                                    *
9 *               e-mail: info@artsoft.org                   *
10 *----------------------------------------------------------*
11 * sdl.c                                                    *
12 ***********************************************************/
13 
14 #include "system.h"
15 #include "sound.h"
16 #include "joystick.h"
17 #include "misc.h"
18 #include "setup.h"
19 
20 
21 #if defined(TARGET_SDL)
22 
23 /* ========================================================================= */
24 /* video functions                                                           */
25 /* ========================================================================= */
26 
27 /* functions from SGE library */
28 void sge_Line(SDL_Surface *, Sint16, Sint16, Sint16, Sint16, Uint32);
29 
30 /* stuff needed to work around SDL/Windows fullscreen drawing bug */
31 static int fullscreen_width;
32 static int fullscreen_height;
33 static int fullscreen_xoffset;
34 static int fullscreen_yoffset;
35 static int video_xoffset;
36 static int video_yoffset;
37 
setFullscreenParameters(char * fullscreen_mode_string)38 static void setFullscreenParameters(char *fullscreen_mode_string)
39 {
40   struct ScreenModeInfo *fullscreen_mode;
41   int i;
42 
43   fullscreen_mode = get_screen_mode_from_string(fullscreen_mode_string);
44 
45   if (fullscreen_mode == NULL)
46     return;
47 
48   for (i = 0; video.fullscreen_modes[i].width != -1; i++)
49   {
50     if (fullscreen_mode->width  == video.fullscreen_modes[i].width &&
51 	fullscreen_mode->height == video.fullscreen_modes[i].height)
52     {
53       fullscreen_width  = fullscreen_mode->width;
54       fullscreen_height = fullscreen_mode->height;
55 
56       fullscreen_xoffset = (fullscreen_width  - video.width)  / 2;
57       fullscreen_yoffset = (fullscreen_height - video.height) / 2;
58 
59       break;
60     }
61   }
62 }
63 
SDLSetWindowIcon(char * basename)64 static void SDLSetWindowIcon(char *basename)
65 {
66   /* (setting the window icon on Mac OS X would replace the high-quality
67      dock icon with the currently smaller (and uglier) icon from file) */
68 
69 #if !defined(PLATFORM_MACOSX)
70   char *filename = getCustomImageFilename(basename);
71   SDL_Surface *surface;
72 
73   if (filename == NULL)
74   {
75     Error(ERR_WARN, "SDLSetWindowIcon(): cannot find file '%s'", basename);
76 
77     return;
78   }
79 
80   if ((surface = IMG_Load(filename)) == NULL)
81   {
82     Error(ERR_WARN, "IMG_Load() failed: %s", SDL_GetError());
83 
84     return;
85   }
86 
87   /* set transparent color */
88   SDL_SetColorKey(surface, SDL_SRCCOLORKEY,
89 		  SDL_MapRGB(surface->format, 0x00, 0x00, 0x00));
90 
91   SDL_WM_SetIcon(surface, NULL);
92 #endif
93 }
94 
SDLInitVideoDisplay(void)95 void SDLInitVideoDisplay(void)
96 {
97   if (!strEqual(setup.system.sdl_videodriver, ARG_DEFAULT))
98     SDL_putenv(getStringCat2("SDL_VIDEODRIVER=", setup.system.sdl_videodriver));
99 
100   SDL_putenv("SDL_VIDEO_CENTERED=1");
101 
102   /* initialize SDL video */
103   if (SDL_InitSubSystem(SDL_INIT_VIDEO) < 0)
104     Error(ERR_EXIT, "SDL_InitSubSystem() failed: %s", SDL_GetError());
105 
106   /* set default SDL depth */
107   video.default_depth = SDL_GetVideoInfo()->vfmt->BitsPerPixel;
108 }
109 
SDLInitVideoBuffer(DrawBuffer ** backbuffer,DrawWindow ** window,boolean fullscreen)110 void SDLInitVideoBuffer(DrawBuffer **backbuffer, DrawWindow **window,
111 			boolean fullscreen)
112 {
113   static int screen_xy[][2] =
114   {
115     {  640, 480 },
116     {  800, 600 },
117     { 1024, 768 },
118     {   -1,  -1 }
119   };
120   SDL_Rect **modes;
121   int i, j;
122 
123   /* default: normal game window size */
124   fullscreen_width = video.width;
125   fullscreen_height = video.height;
126   fullscreen_xoffset = 0;
127   fullscreen_yoffset = 0;
128 
129   for (i = 0; screen_xy[i][0] != -1; i++)
130   {
131     if (screen_xy[i][0] >= video.width && screen_xy[i][1] >= video.height)
132     {
133       fullscreen_width  = screen_xy[i][0];
134       fullscreen_height = screen_xy[i][1];
135 
136       break;
137     }
138   }
139 
140   fullscreen_xoffset = (fullscreen_width  - video.width)  / 2;
141   fullscreen_yoffset = (fullscreen_height - video.height) / 2;
142 
143 #if 1
144   checked_free(video.fullscreen_modes);
145 
146   video.fullscreen_modes = NULL;
147   video.fullscreen_mode_current = NULL;
148 #endif
149 
150   /* get available hardware supported fullscreen modes */
151   modes = SDL_ListModes(NULL, SDL_FULLSCREEN | SDL_HWSURFACE);
152 
153   if (modes == NULL)
154   {
155     /* no screen modes available => no fullscreen mode support */
156     video.fullscreen_available = FALSE;
157   }
158   else if (modes == (SDL_Rect **)-1)
159   {
160     /* fullscreen resolution is not restricted -- all resolutions available */
161     video.fullscreen_modes = checked_calloc(2 * sizeof(struct ScreenModeInfo));
162 
163     /* use native video buffer size for fullscreen mode */
164     video.fullscreen_modes[0].width  = video.width;
165     video.fullscreen_modes[0].height = video.height;
166 
167     video.fullscreen_modes[1].width  = -1;
168     video.fullscreen_modes[1].height = -1;
169   }
170   else
171   {
172     /* in this case, a certain number of screen modes is available */
173     int num_modes = 0;
174 
175     for(i = 0; modes[i] != NULL; i++)
176     {
177       boolean found_mode = FALSE;
178 
179       /* screen mode is smaller than video buffer size -- skip it */
180       if (modes[i]->w < video.width || modes[i]->h < video.height)
181 	continue;
182 
183       if (video.fullscreen_modes != NULL)
184 	for (j = 0; video.fullscreen_modes[j].width != -1; j++)
185 	  if (modes[i]->w == video.fullscreen_modes[j].width &&
186 	      modes[i]->h == video.fullscreen_modes[j].height)
187 	    found_mode = TRUE;
188 
189       if (found_mode)		/* screen mode already stored -- skip it */
190 	continue;
191 
192       /* new mode found; add it to list of available fullscreen modes */
193 
194       num_modes++;
195 
196       video.fullscreen_modes = checked_realloc(video.fullscreen_modes,
197 					       (num_modes + 1) *
198 					       sizeof(struct ScreenModeInfo));
199 
200       video.fullscreen_modes[num_modes - 1].width  = modes[i]->w;
201       video.fullscreen_modes[num_modes - 1].height = modes[i]->h;
202 
203       video.fullscreen_modes[num_modes].width  = -1;
204       video.fullscreen_modes[num_modes].height = -1;
205     }
206 
207     if (num_modes == 0)
208     {
209       /* no appropriate screen modes available => no fullscreen mode support */
210       video.fullscreen_available = FALSE;
211     }
212   }
213 
214   /* set window icon */
215   SDLSetWindowIcon(program.sdl_icon_filename);
216 
217   /* open SDL video output device (window or fullscreen mode) */
218   if (!SDLSetVideoMode(backbuffer, fullscreen))
219     Error(ERR_EXIT, "setting video mode failed");
220 
221   /* set window and icon title */
222   SDL_WM_SetCaption(program.window_title, program.window_title);
223 
224   /* SDL cannot directly draw to the visible video framebuffer like X11,
225      but always uses a backbuffer, which is then blitted to the visible
226      video framebuffer with 'SDL_UpdateRect' (or replaced with the current
227      visible video framebuffer with 'SDL_Flip', if the hardware supports
228      this). Therefore do not use an additional backbuffer for drawing, but
229      use a symbolic buffer (distinguishable from the SDL backbuffer) called
230      'window', which indicates that the SDL backbuffer should be updated to
231      the visible video framebuffer when attempting to blit to it.
232 
233      For convenience, it seems to be a good idea to create this symbolic
234      buffer 'window' at the same size as the SDL backbuffer. Although it
235      should never be drawn to directly, it would do no harm nevertheless. */
236 
237   /* create additional (symbolic) buffer for double-buffering */
238 #if 1
239   ReCreateBitmap(window, video.width, video.height, video.depth);
240 #else
241   *window = CreateBitmap(video.width, video.height, video.depth);
242 #endif
243 }
244 
SDLSetVideoMode(DrawBuffer ** backbuffer,boolean fullscreen)245 boolean SDLSetVideoMode(DrawBuffer **backbuffer, boolean fullscreen)
246 {
247   boolean success = TRUE;
248   int surface_flags_fullscreen = SURFACE_FLAGS | SDL_FULLSCREEN;
249   int surface_flags_window = SURFACE_FLAGS;
250   SDL_Surface *new_surface = NULL;
251 
252   if (*backbuffer == NULL)
253     *backbuffer = CreateBitmapStruct();
254 
255   /* (real bitmap might be larger in fullscreen mode with video offsets) */
256   (*backbuffer)->width  = video.width;
257   (*backbuffer)->height = video.height;
258 
259   if (fullscreen && !video.fullscreen_enabled && video.fullscreen_available)
260   {
261     setFullscreenParameters(setup.fullscreen_mode);
262 
263     video_xoffset = fullscreen_xoffset;
264     video_yoffset = fullscreen_yoffset;
265 
266     /* switch display to fullscreen mode, if available */
267     if ((new_surface = SDL_SetVideoMode(fullscreen_width, fullscreen_height,
268 					video.depth, surface_flags_fullscreen))
269 	== NULL)
270     {
271       /* switching display to fullscreen mode failed */
272       Error(ERR_WARN, "SDL_SetVideoMode() failed: %s", SDL_GetError());
273 
274       /* do not try it again */
275       video.fullscreen_available = FALSE;
276 
277       success = FALSE;
278     }
279     else
280     {
281       (*backbuffer)->surface = new_surface;
282 
283       video.fullscreen_enabled = TRUE;
284       video.fullscreen_mode_current = setup.fullscreen_mode;
285 
286       success = TRUE;
287     }
288   }
289 
290   if ((!fullscreen && video.fullscreen_enabled) || new_surface == NULL)
291   {
292     video_xoffset = 0;
293     video_yoffset = 0;
294 
295     /* switch display to window mode */
296     if ((new_surface = SDL_SetVideoMode(video.width, video.height,
297 					video.depth, surface_flags_window))
298 	== NULL)
299     {
300       /* switching display to window mode failed -- should not happen */
301       Error(ERR_WARN, "SDL_SetVideoMode() failed: %s", SDL_GetError());
302 
303       success = FALSE;
304     }
305     else
306     {
307       (*backbuffer)->surface = new_surface;
308 
309       video.fullscreen_enabled = FALSE;
310 
311       success = TRUE;
312     }
313   }
314 
315 #if 1
316   SDL_EventState(SDL_SYSWMEVENT, SDL_ENABLE);
317 
318 #if defined(PLATFORM_WIN32)
319   {
320     SDL_SysWMinfo wminfo;
321     HWND hwnd;
322 
323     SDL_VERSION(&wminfo.version);
324     SDL_GetWMInfo(&wminfo);
325 
326     hwnd = wminfo.window;
327 
328     DragAcceptFiles(hwnd, TRUE);
329   }
330 #endif
331 #endif
332 
333 
334   return success;
335 }
336 
SDLCreateBitmapContent(Bitmap * new_bitmap,int width,int height,int depth)337 void SDLCreateBitmapContent(Bitmap *new_bitmap, int width, int height,
338 			    int depth)
339 {
340   SDL_Surface *surface_tmp, *surface_native;
341 
342   if ((surface_tmp = SDL_CreateRGBSurface(SURFACE_FLAGS, width, height, depth,
343 					  0, 0, 0, 0))
344       == NULL)
345     Error(ERR_EXIT, "SDL_CreateRGBSurface() failed: %s", SDL_GetError());
346 
347   if ((surface_native = SDL_DisplayFormat(surface_tmp)) == NULL)
348     Error(ERR_EXIT, "SDL_DisplayFormat() failed: %s", SDL_GetError());
349 
350   SDL_FreeSurface(surface_tmp);
351 
352   new_bitmap->surface = surface_native;
353 }
354 
SDLFreeBitmapPointers(Bitmap * bitmap)355 void SDLFreeBitmapPointers(Bitmap *bitmap)
356 {
357   if (bitmap->surface)
358     SDL_FreeSurface(bitmap->surface);
359   if (bitmap->surface_masked)
360     SDL_FreeSurface(bitmap->surface_masked);
361   bitmap->surface = NULL;
362   bitmap->surface_masked = NULL;
363 }
364 
SDLCopyArea(Bitmap * src_bitmap,Bitmap * dst_bitmap,int src_x,int src_y,int width,int height,int dst_x,int dst_y,int mask_mode)365 void SDLCopyArea(Bitmap *src_bitmap, Bitmap *dst_bitmap,
366 		 int src_x, int src_y, int width, int height,
367 		 int dst_x, int dst_y, int mask_mode)
368 {
369   Bitmap *real_dst_bitmap = (dst_bitmap == window ? backbuffer : dst_bitmap);
370   SDL_Rect src_rect, dst_rect;
371 
372   if (src_bitmap == backbuffer)
373   {
374     src_x += video_xoffset;
375     src_y += video_yoffset;
376   }
377 
378   src_rect.x = src_x;
379   src_rect.y = src_y;
380   src_rect.w = width;
381   src_rect.h = height;
382 
383   if (dst_bitmap == backbuffer || dst_bitmap == window)
384   {
385     dst_x += video_xoffset;
386     dst_y += video_yoffset;
387   }
388 
389   dst_rect.x = dst_x;
390   dst_rect.y = dst_y;
391   dst_rect.w = width;
392   dst_rect.h = height;
393 
394   if (src_bitmap != backbuffer || dst_bitmap != window)
395     SDL_BlitSurface((mask_mode == BLIT_MASKED ?
396 		     src_bitmap->surface_masked : src_bitmap->surface),
397 		    &src_rect, real_dst_bitmap->surface, &dst_rect);
398 
399   if (dst_bitmap == window)
400     SDL_UpdateRect(backbuffer->surface, dst_x, dst_y, width, height);
401 }
402 
SDLFillRectangle(Bitmap * dst_bitmap,int x,int y,int width,int height,Uint32 color)403 void SDLFillRectangle(Bitmap *dst_bitmap, int x, int y, int width, int height,
404 		      Uint32 color)
405 {
406   Bitmap *real_dst_bitmap = (dst_bitmap == window ? backbuffer : dst_bitmap);
407   SDL_Rect rect;
408 
409   if (dst_bitmap == backbuffer || dst_bitmap == window)
410   {
411     x += video_xoffset;
412     y += video_yoffset;
413   }
414 
415   rect.x = x;
416   rect.y = y;
417   rect.w = width;
418   rect.h = height;
419 
420   SDL_FillRect(real_dst_bitmap->surface, &rect, color);
421 
422   if (dst_bitmap == window)
423     SDL_UpdateRect(backbuffer->surface, x, y, width, height);
424 }
425 
SDLFadeRectangle(Bitmap * bitmap_cross,int x,int y,int width,int height,int fade_mode,int fade_delay,int post_delay,void (* draw_border_function)(void))426 void SDLFadeRectangle(Bitmap *bitmap_cross, int x, int y, int width, int height,
427 		      int fade_mode, int fade_delay, int post_delay,
428 		      void (*draw_border_function)(void))
429 {
430   static boolean initialization_needed = TRUE;
431   static SDL_Surface *surface_source = NULL;
432   static SDL_Surface *surface_target = NULL;
433   static SDL_Surface *surface_black = NULL;
434   SDL_Surface *surface_screen = backbuffer->surface;
435   SDL_Surface *surface_cross = (bitmap_cross ? bitmap_cross->surface : NULL);
436   SDL_Rect src_rect, dst_rect;
437   int src_x = x, src_y = y;
438   int dst_x = x, dst_y = y;
439   unsigned int time_last, time_current;
440 
441   /* check if screen size has changed */
442   if (surface_source != NULL && (video.width  != surface_source->w ||
443 				 video.height != surface_source->h))
444   {
445     SDL_FreeSurface(surface_source);
446     SDL_FreeSurface(surface_target);
447     SDL_FreeSurface(surface_black);
448 
449     initialization_needed = TRUE;
450   }
451 
452   src_rect.x = src_x;
453   src_rect.y = src_y;
454   src_rect.w = width;
455   src_rect.h = height;
456 
457   dst_x += video_xoffset;
458   dst_y += video_yoffset;
459 
460   dst_rect.x = dst_x;
461   dst_rect.y = dst_y;
462   dst_rect.w = width;		/* (ignored) */
463   dst_rect.h = height;		/* (ignored) */
464 
465   if (initialization_needed)
466   {
467     unsigned int flags = SDL_SRCALPHA;
468 
469     /* use same surface type as screen surface */
470     if ((surface_screen->flags & SDL_HWSURFACE))
471       flags |= SDL_HWSURFACE;
472     else
473       flags |= SDL_SWSURFACE;
474 
475     /* create surface for temporary copy of screen buffer (source) */
476     if ((surface_source =
477 	 SDL_CreateRGBSurface(flags,
478 			      video.width,
479 			      video.height,
480 			      surface_screen->format->BitsPerPixel,
481 			      surface_screen->format->Rmask,
482 			      surface_screen->format->Gmask,
483 			      surface_screen->format->Bmask,
484 			      surface_screen->format->Amask)) == NULL)
485       Error(ERR_EXIT, "SDL_CreateRGBSurface() failed: %s", SDL_GetError());
486 
487     /* create surface for cross-fading screen buffer (target) */
488     if ((surface_target =
489 	 SDL_CreateRGBSurface(flags,
490 			      video.width,
491 			      video.height,
492 			      surface_screen->format->BitsPerPixel,
493 			      surface_screen->format->Rmask,
494 			      surface_screen->format->Gmask,
495 			      surface_screen->format->Bmask,
496 			      surface_screen->format->Amask)) == NULL)
497       Error(ERR_EXIT, "SDL_CreateRGBSurface() failed: %s", SDL_GetError());
498 
499     /* create black surface for fading from/to black */
500     if ((surface_black =
501 	 SDL_CreateRGBSurface(flags,
502 			      video.width,
503 			      video.height,
504 			      surface_screen->format->BitsPerPixel,
505 			      surface_screen->format->Rmask,
506 			      surface_screen->format->Gmask,
507 			      surface_screen->format->Bmask,
508 			      surface_screen->format->Amask)) == NULL)
509       Error(ERR_EXIT, "SDL_CreateRGBSurface() failed: %s", SDL_GetError());
510 
511     /* completely fill the surface with black color pixels */
512     SDL_FillRect(surface_black, NULL,
513 		 SDL_MapRGB(surface_screen->format, 0, 0, 0));
514 
515     initialization_needed = FALSE;
516   }
517 
518   /* copy source and target surfaces to temporary surfaces for fading */
519   if (fade_mode & FADE_TYPE_TRANSFORM)
520   {
521     SDL_BlitSurface(surface_cross,  &src_rect, surface_source, &src_rect);
522     SDL_BlitSurface(surface_screen, &dst_rect, surface_target, &src_rect);
523   }
524   else if (fade_mode & FADE_TYPE_FADE_IN)
525   {
526     SDL_BlitSurface(surface_black,  &src_rect, surface_source, &src_rect);
527     SDL_BlitSurface(surface_screen, &dst_rect, surface_target, &src_rect);
528   }
529   else		/* FADE_TYPE_FADE_OUT */
530   {
531     SDL_BlitSurface(surface_screen, &dst_rect, surface_source, &src_rect);
532     SDL_BlitSurface(surface_black,  &src_rect, surface_target, &src_rect);
533   }
534 
535   time_current = SDL_GetTicks();
536 
537   if (fade_mode == FADE_MODE_MELT)
538   {
539     boolean done = FALSE;
540     int melt_pixels = 2;
541     int melt_columns = width / melt_pixels;
542     int ypos[melt_columns];
543     int max_steps = height / 8 + 32;
544     int steps_done = 0;
545     float steps = 0;
546     int i;
547 
548     SDL_BlitSurface(surface_source, &src_rect, surface_screen, &dst_rect);
549     SDL_SetAlpha(surface_target, 0, 0);		/* disable alpha blending */
550 
551     ypos[0] = -GetSimpleRandom(16);
552 
553     for (i = 1 ; i < melt_columns; i++)
554     {
555       int r = GetSimpleRandom(3) - 1;	/* randomly choose from { -1, 0, -1 } */
556 
557       ypos[i] = ypos[i - 1] + r;
558 
559       if (ypos[i] > 0)
560         ypos[i] = 0;
561       else
562         if (ypos[i] == -16)
563           ypos[i] = -15;
564     }
565 
566     while (!done)
567     {
568       int steps_final;
569 
570       time_last = time_current;
571       time_current = SDL_GetTicks();
572       steps += max_steps * ((float)(time_current - time_last) / fade_delay);
573       steps_final = MIN(MAX(0, steps), max_steps);
574 
575       steps_done++;
576 
577       done = (steps_done >= steps_final);
578 
579       for (i = 0 ; i < melt_columns; i++)
580       {
581 	if (ypos[i] < 0)
582         {
583           ypos[i]++;
584 
585           done = FALSE;
586         }
587 	else if (ypos[i] < height)
588 	{
589 	  int y1 = 16;
590 	  int y2 = 8;
591 	  int y3 = 8;
592 	  int dy = (ypos[i] < y1) ? ypos[i] + 1 : y2 + GetSimpleRandom(y3);
593 
594 	  if (ypos[i] + dy >= height)
595 	    dy = height - ypos[i];
596 
597 	  /* copy part of (appearing) target surface to upper area */
598 	  src_rect.x = src_x + i * melt_pixels;
599 	  // src_rect.y = src_y + ypos[i];
600 	  src_rect.y = src_y;
601 	  src_rect.w = melt_pixels;
602 	  // src_rect.h = dy;
603 	  src_rect.h = ypos[i] + dy;
604 
605 	  dst_rect.x = dst_x + i * melt_pixels;
606 	  // dst_rect.y = dst_y + ypos[i];
607 	  dst_rect.y = dst_y;
608 
609 	  if (steps_done >= steps_final)
610 	    SDL_BlitSurface(surface_target, &src_rect,
611 			    surface_screen, &dst_rect);
612 
613 	  ypos[i] += dy;
614 
615 	  /* copy part of (disappearing) source surface to lower area */
616 	  src_rect.x = src_x + i * melt_pixels;
617 	  src_rect.y = src_y;
618 	  src_rect.w = melt_pixels;
619 	  src_rect.h = height - ypos[i];
620 
621 	  dst_rect.x = dst_x + i * melt_pixels;
622 	  dst_rect.y = dst_y + ypos[i];
623 
624 	  if (steps_done >= steps_final)
625 	    SDL_BlitSurface(surface_source, &src_rect,
626 			    surface_screen, &dst_rect);
627 
628 	  done = FALSE;
629 	}
630 	else
631 	{
632 	  src_rect.x = src_x + i * melt_pixels;
633 	  src_rect.y = src_y;
634 	  src_rect.w = melt_pixels;
635 	  src_rect.h = height;
636 
637 	  dst_rect.x = dst_x + i * melt_pixels;
638 	  dst_rect.y = dst_y;
639 
640 	  if (steps_done >= steps_final)
641 	    SDL_BlitSurface(surface_target, &src_rect,
642 			    surface_screen, &dst_rect);
643 	}
644       }
645 
646       if (steps_done >= steps_final)
647       {
648 	if (draw_border_function != NULL)
649 	  draw_border_function();
650 
651 	SDL_UpdateRect(surface_screen, dst_x, dst_y, width, height);
652       }
653     }
654   }
655   else
656   {
657     float alpha;
658     int alpha_final;
659 
660     for (alpha = 0.0; alpha < 255.0;)
661     {
662       time_last = time_current;
663       time_current = SDL_GetTicks();
664       alpha += 255 * ((float)(time_current - time_last) / fade_delay);
665       alpha_final = MIN(MAX(0, alpha), 255);
666 
667       /* draw existing (source) image to screen buffer */
668       SDL_BlitSurface(surface_source, &src_rect, surface_screen, &dst_rect);
669 
670       /* draw new (target) image to screen buffer using alpha blending */
671       SDL_SetAlpha(surface_target, SDL_SRCALPHA, alpha_final);
672       SDL_BlitSurface(surface_target, &src_rect, surface_screen, &dst_rect);
673 
674       if (draw_border_function != NULL)
675 	draw_border_function();
676 
677 #if 1
678       /* only update the region of the screen that is affected from fading */
679       SDL_UpdateRect(surface_screen, dst_x, dst_y, width, height);
680 #else
681       SDL_Flip(surface_screen);
682 #endif
683     }
684   }
685 
686   Delay(post_delay);
687 }
688 
SDLDrawSimpleLine(Bitmap * dst_bitmap,int from_x,int from_y,int to_x,int to_y,Uint32 color)689 void SDLDrawSimpleLine(Bitmap *dst_bitmap, int from_x, int from_y,
690 		       int to_x, int to_y, Uint32 color)
691 {
692   SDL_Surface *surface = dst_bitmap->surface;
693   SDL_Rect rect;
694 
695   if (from_x > to_x)
696     swap_numbers(&from_x, &to_x);
697 
698   if (from_y > to_y)
699     swap_numbers(&from_y, &to_y);
700 
701   rect.x = from_x;
702   rect.y = from_y;
703   rect.w = (to_x - from_x + 1);
704   rect.h = (to_y - from_y + 1);
705 
706   if (dst_bitmap == backbuffer || dst_bitmap == window)
707   {
708     rect.x += video_xoffset;
709     rect.y += video_yoffset;
710   }
711 
712   SDL_FillRect(surface, &rect, color);
713 }
714 
SDLDrawLine(Bitmap * dst_bitmap,int from_x,int from_y,int to_x,int to_y,Uint32 color)715 void SDLDrawLine(Bitmap *dst_bitmap, int from_x, int from_y,
716 		 int to_x, int to_y, Uint32 color)
717 {
718   if (dst_bitmap == backbuffer || dst_bitmap == window)
719   {
720     from_x += video_xoffset;
721     from_y += video_yoffset;
722     to_x += video_xoffset;
723     to_y += video_yoffset;
724   }
725 
726   sge_Line(dst_bitmap->surface, from_x, from_y, to_x, to_y, color);
727 }
728 
729 #if 0
730 void SDLDrawLines(SDL_Surface *surface, struct XY *points,
731 		  int num_points, Uint32 color)
732 {
733   int i, x, y;
734   int line_width = 4;
735 
736   for (i = 0; i < num_points - 1; i++)
737   {
738     for (x = 0; x < line_width; x++)
739     {
740       for (y = 0; y < line_width; y++)
741       {
742 	int dx = x - line_width / 2;
743 	int dy = y - line_width / 2;
744 
745 	if ((x == 0 && y == 0) ||
746 	    (x == 0 && y == line_width - 1) ||
747 	    (x == line_width - 1 && y == 0) ||
748 	    (x == line_width - 1 && y == line_width - 1))
749 	  continue;
750 
751 	sge_Line(surface, points[i].x + dx, points[i].y + dy,
752 		 points[i+1].x + dx, points[i+1].y + dy, color);
753       }
754     }
755   }
756 }
757 #endif
758 
SDLGetPixel(Bitmap * src_bitmap,int x,int y)759 Pixel SDLGetPixel(Bitmap *src_bitmap, int x, int y)
760 {
761   SDL_Surface *surface = src_bitmap->surface;
762 
763   if (src_bitmap == backbuffer || src_bitmap == window)
764   {
765     x += video_xoffset;
766     y += video_yoffset;
767   }
768 
769   switch (surface->format->BytesPerPixel)
770   {
771     case 1:		/* assuming 8-bpp */
772     {
773       return *((Uint8 *)surface->pixels + y * surface->pitch + x);
774     }
775     break;
776 
777     case 2:		/* probably 15-bpp or 16-bpp */
778     {
779       return *((Uint16 *)surface->pixels + y * surface->pitch / 2 + x);
780     }
781     break;
782 
783   case 3:		/* slow 24-bpp mode; usually not used */
784     {
785       /* does this work? */
786       Uint8 *pix = (Uint8 *)surface->pixels + y * surface->pitch + x * 3;
787       Uint32 color = 0;
788       int shift;
789 
790       shift = surface->format->Rshift;
791       color |= *(pix + shift / 8) >> shift;
792       shift = surface->format->Gshift;
793       color |= *(pix + shift / 8) >> shift;
794       shift = surface->format->Bshift;
795       color |= *(pix + shift / 8) >> shift;
796 
797       return color;
798     }
799     break;
800 
801   case 4:		/* probably 32-bpp */
802     {
803       return *((Uint32 *)surface->pixels + y * surface->pitch / 4 + x);
804     }
805     break;
806   }
807 
808   return 0;
809 }
810 
811 
812 /* ========================================================================= */
813 /* The following functions were taken from the SGE library                   */
814 /* (SDL Graphics Extension Library) by Anders Lindstr�m                      */
815 /* http://www.etek.chalmers.se/~e8cal1/sge/index.html                        */
816 /* ========================================================================= */
817 
_PutPixel(SDL_Surface * surface,Sint16 x,Sint16 y,Uint32 color)818 void _PutPixel(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
819 {
820   if (x >= 0 && x <= surface->w - 1 && y >= 0 && y <= surface->h - 1)
821   {
822     switch (surface->format->BytesPerPixel)
823     {
824       case 1:
825       {
826 	/* Assuming 8-bpp */
827 	*((Uint8 *)surface->pixels + y*surface->pitch + x) = color;
828       }
829       break;
830 
831       case 2:
832       {
833 	/* Probably 15-bpp or 16-bpp */
834 	*((Uint16 *)surface->pixels + y*surface->pitch/2 + x) = color;
835       }
836       break;
837 
838       case 3:
839       {
840 	/* Slow 24-bpp mode, usually not used */
841 	Uint8 *pix;
842 	int shift;
843 
844 	/* Gack - slow, but endian correct */
845 	pix = (Uint8 *)surface->pixels + y * surface->pitch + x*3;
846 	shift = surface->format->Rshift;
847 	*(pix+shift/8) = color>>shift;
848 	shift = surface->format->Gshift;
849 	*(pix+shift/8) = color>>shift;
850 	shift = surface->format->Bshift;
851 	*(pix+shift/8) = color>>shift;
852       }
853       break;
854 
855       case 4:
856       {
857 	/* Probably 32-bpp */
858 	*((Uint32 *)surface->pixels + y*surface->pitch/4 + x) = color;
859       }
860       break;
861     }
862   }
863 }
864 
_PutPixelRGB(SDL_Surface * surface,Sint16 x,Sint16 y,Uint8 R,Uint8 G,Uint8 B)865 void _PutPixelRGB(SDL_Surface *surface, Sint16 x, Sint16 y,
866 		  Uint8 R, Uint8 G, Uint8 B)
867 {
868   _PutPixel(surface, x, y, SDL_MapRGB(surface->format, R, G, B));
869 }
870 
_PutPixel8(SDL_Surface * surface,Sint16 x,Sint16 y,Uint32 color)871 void _PutPixel8(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
872 {
873   *((Uint8 *)surface->pixels + y*surface->pitch + x) = color;
874 }
875 
_PutPixel16(SDL_Surface * surface,Sint16 x,Sint16 y,Uint32 color)876 void _PutPixel16(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
877 {
878   *((Uint16 *)surface->pixels + y*surface->pitch/2 + x) = color;
879 }
880 
_PutPixel24(SDL_Surface * surface,Sint16 x,Sint16 y,Uint32 color)881 void _PutPixel24(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
882 {
883   Uint8 *pix;
884   int shift;
885 
886   /* Gack - slow, but endian correct */
887   pix = (Uint8 *)surface->pixels + y * surface->pitch + x*3;
888   shift = surface->format->Rshift;
889   *(pix+shift/8) = color>>shift;
890   shift = surface->format->Gshift;
891   *(pix+shift/8) = color>>shift;
892   shift = surface->format->Bshift;
893   *(pix+shift/8) = color>>shift;
894 }
895 
_PutPixel32(SDL_Surface * surface,Sint16 x,Sint16 y,Uint32 color)896 void _PutPixel32(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
897 {
898   *((Uint32 *)surface->pixels + y*surface->pitch/4 + x) = color;
899 }
900 
_PutPixelX(SDL_Surface * dest,Sint16 x,Sint16 y,Uint32 color)901 void _PutPixelX(SDL_Surface *dest,Sint16 x,Sint16 y,Uint32 color)
902 {
903   switch (dest->format->BytesPerPixel)
904   {
905     case 1:
906       *((Uint8 *)dest->pixels + y*dest->pitch + x) = color;
907       break;
908 
909     case 2:
910       *((Uint16 *)dest->pixels + y*dest->pitch/2 + x) = color;
911       break;
912 
913     case 3:
914       _PutPixel24(dest,x,y,color);
915       break;
916 
917     case 4:
918       *((Uint32 *)dest->pixels + y*dest->pitch/4 + x) = color;
919       break;
920   }
921 }
922 
sge_PutPixel(SDL_Surface * surface,Sint16 x,Sint16 y,Uint32 color)923 void sge_PutPixel(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
924 {
925   if (SDL_MUSTLOCK(surface))
926   {
927     if (SDL_LockSurface(surface) < 0)
928     {
929       return;
930     }
931   }
932 
933   _PutPixel(surface, x, y, color);
934 
935   if (SDL_MUSTLOCK(surface))
936   {
937     SDL_UnlockSurface(surface);
938   }
939 }
940 
sge_PutPixelRGB(SDL_Surface * surface,Sint16 x,Sint16 y,Uint8 r,Uint8 g,Uint8 b)941 void sge_PutPixelRGB(SDL_Surface *surface, Sint16 x, Sint16 y,
942 		  Uint8 r, Uint8 g, Uint8 b)
943 {
944   sge_PutPixel(surface, x, y, SDL_MapRGB(surface->format, r, g, b));
945 }
946 
sge_CalcYPitch(SDL_Surface * dest,Sint16 y)947 Sint32 sge_CalcYPitch(SDL_Surface *dest, Sint16 y)
948 {
949   if (y >= 0 && y <= dest->h - 1)
950   {
951     switch (dest->format->BytesPerPixel)
952     {
953       case 1:
954 	return y*dest->pitch;
955 	break;
956 
957       case 2:
958 	return y*dest->pitch/2;
959 	break;
960 
961       case 3:
962 	return y*dest->pitch;
963 	break;
964 
965       case 4:
966 	return y*dest->pitch/4;
967 	break;
968     }
969   }
970 
971   return -1;
972 }
973 
sge_pPutPixel(SDL_Surface * surface,Sint16 x,Sint32 ypitch,Uint32 color)974 void sge_pPutPixel(SDL_Surface *surface, Sint16 x, Sint32 ypitch, Uint32 color)
975 {
976   if (x >= 0 && x <= surface->w - 1 && ypitch >= 0)
977   {
978     switch (surface->format->BytesPerPixel)
979     {
980       case 1:
981       {
982 	/* Assuming 8-bpp */
983 	*((Uint8 *)surface->pixels + ypitch + x) = color;
984       }
985       break;
986 
987       case 2:
988       {
989 	/* Probably 15-bpp or 16-bpp */
990 	*((Uint16 *)surface->pixels + ypitch + x) = color;
991       }
992       break;
993 
994       case 3:
995       {
996 	/* Slow 24-bpp mode, usually not used */
997 	Uint8 *pix;
998 	int shift;
999 
1000 	/* Gack - slow, but endian correct */
1001 	pix = (Uint8 *)surface->pixels + ypitch + x*3;
1002 	shift = surface->format->Rshift;
1003 	*(pix+shift/8) = color>>shift;
1004 	shift = surface->format->Gshift;
1005 	*(pix+shift/8) = color>>shift;
1006 	shift = surface->format->Bshift;
1007 	*(pix+shift/8) = color>>shift;
1008       }
1009       break;
1010 
1011       case 4:
1012       {
1013 	/* Probably 32-bpp */
1014 	*((Uint32 *)surface->pixels + ypitch + x) = color;
1015       }
1016       break;
1017     }
1018   }
1019 }
1020 
sge_HLine(SDL_Surface * Surface,Sint16 x1,Sint16 x2,Sint16 y,Uint32 Color)1021 void sge_HLine(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y,
1022 	       Uint32 Color)
1023 {
1024   SDL_Rect l;
1025 
1026   if (SDL_MUSTLOCK(Surface))
1027   {
1028     if (SDL_LockSurface(Surface) < 0)
1029     {
1030       return;
1031     }
1032   }
1033 
1034   if (x1 > x2)
1035   {
1036     Sint16 tmp = x1;
1037     x1 = x2;
1038     x2 = tmp;
1039   }
1040 
1041   /* Do the clipping */
1042   if (y < 0 || y > Surface->h - 1 || x1 > Surface->w - 1 || x2 < 0)
1043     return;
1044   if (x1 < 0)
1045     x1 = 0;
1046   if (x2 > Surface->w - 1)
1047     x2 = Surface->w - 1;
1048 
1049   l.x = x1;
1050   l.y = y;
1051   l.w = x2 - x1 + 1;
1052   l.h = 1;
1053 
1054   SDL_FillRect(Surface, &l, Color);
1055 
1056   if (SDL_MUSTLOCK(Surface))
1057   {
1058     SDL_UnlockSurface(Surface);
1059   }
1060 }
1061 
sge_HLineRGB(SDL_Surface * Surface,Sint16 x1,Sint16 x2,Sint16 y,Uint8 R,Uint8 G,Uint8 B)1062 void sge_HLineRGB(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y,
1063 		  Uint8 R, Uint8 G, Uint8 B)
1064 {
1065   sge_HLine(Surface, x1, x2, y, SDL_MapRGB(Surface->format, R, G, B));
1066 }
1067 
_HLine(SDL_Surface * Surface,Sint16 x1,Sint16 x2,Sint16 y,Uint32 Color)1068 void _HLine(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y, Uint32 Color)
1069 {
1070   SDL_Rect l;
1071 
1072   if (x1 > x2)
1073   {
1074     Sint16 tmp = x1;
1075     x1 = x2;
1076     x2 = tmp;
1077   }
1078 
1079   /* Do the clipping */
1080   if (y < 0 || y > Surface->h - 1 || x1 > Surface->w - 1 || x2 < 0)
1081     return;
1082   if (x1 < 0)
1083     x1 = 0;
1084   if (x2 > Surface->w - 1)
1085     x2 = Surface->w - 1;
1086 
1087   l.x = x1;
1088   l.y = y;
1089   l.w = x2 - x1 + 1;
1090   l.h = 1;
1091 
1092   SDL_FillRect(Surface, &l, Color);
1093 }
1094 
sge_VLine(SDL_Surface * Surface,Sint16 x,Sint16 y1,Sint16 y2,Uint32 Color)1095 void sge_VLine(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2,
1096 	       Uint32 Color)
1097 {
1098   SDL_Rect l;
1099 
1100   if (SDL_MUSTLOCK(Surface))
1101   {
1102     if (SDL_LockSurface(Surface) < 0)
1103     {
1104       return;
1105     }
1106   }
1107 
1108   if (y1 > y2)
1109   {
1110     Sint16 tmp = y1;
1111     y1 = y2;
1112     y2 = tmp;
1113   }
1114 
1115   /* Do the clipping */
1116   if (x < 0 || x > Surface->w - 1 || y1 > Surface->h - 1 || y2 < 0)
1117     return;
1118   if (y1 < 0)
1119     y1 = 0;
1120   if (y2 > Surface->h - 1)
1121     y2 = Surface->h - 1;
1122 
1123   l.x = x;
1124   l.y = y1;
1125   l.w = 1;
1126   l.h = y2 - y1 + 1;
1127 
1128   SDL_FillRect(Surface, &l, Color);
1129 
1130   if (SDL_MUSTLOCK(Surface))
1131   {
1132     SDL_UnlockSurface(Surface);
1133   }
1134 }
1135 
sge_VLineRGB(SDL_Surface * Surface,Sint16 x,Sint16 y1,Sint16 y2,Uint8 R,Uint8 G,Uint8 B)1136 void sge_VLineRGB(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2,
1137 		  Uint8 R, Uint8 G, Uint8 B)
1138 {
1139   sge_VLine(Surface, x, y1, y2, SDL_MapRGB(Surface->format, R, G, B));
1140 }
1141 
_VLine(SDL_Surface * Surface,Sint16 x,Sint16 y1,Sint16 y2,Uint32 Color)1142 void _VLine(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2, Uint32 Color)
1143 {
1144   SDL_Rect l;
1145 
1146   if (y1 > y2)
1147   {
1148     Sint16 tmp = y1;
1149     y1 = y2;
1150     y2 = tmp;
1151   }
1152 
1153   /* Do the clipping */
1154   if (x < 0 || x > Surface->w - 1 || y1 > Surface->h - 1 || y2 < 0)
1155     return;
1156   if (y1 < 0)
1157     y1 = 0;
1158   if (y2 > Surface->h - 1)
1159     y2 = Surface->h - 1;
1160 
1161   l.x = x;
1162   l.y = y1;
1163   l.w = 1;
1164   l.h = y2 - y1 + 1;
1165 
1166   SDL_FillRect(Surface, &l, Color);
1167 }
1168 
sge_DoLine(SDL_Surface * Surface,Sint16 x1,Sint16 y1,Sint16 x2,Sint16 y2,Uint32 Color,void Callback (SDL_Surface * Surf,Sint16 X,Sint16 Y,Uint32 Color))1169 void sge_DoLine(SDL_Surface *Surface, Sint16 x1, Sint16 y1,
1170 		Sint16 x2, Sint16 y2, Uint32 Color,
1171 		void Callback(SDL_Surface *Surf, Sint16 X, Sint16 Y,
1172 			      Uint32 Color))
1173 {
1174   Sint16 dx, dy, sdx, sdy, x, y, px, py;
1175 
1176   dx = x2 - x1;
1177   dy = y2 - y1;
1178 
1179   sdx = (dx < 0) ? -1 : 1;
1180   sdy = (dy < 0) ? -1 : 1;
1181 
1182   dx = sdx * dx + 1;
1183   dy = sdy * dy + 1;
1184 
1185   x = y = 0;
1186 
1187   px = x1;
1188   py = y1;
1189 
1190   if (dx >= dy)
1191   {
1192     for (x = 0; x < dx; x++)
1193     {
1194       Callback(Surface, px, py, Color);
1195 
1196       y += dy;
1197       if (y >= dx)
1198       {
1199 	y -= dx;
1200 	py += sdy;
1201       }
1202 
1203       px += sdx;
1204     }
1205   }
1206   else
1207   {
1208     for (y = 0; y < dy; y++)
1209     {
1210       Callback(Surface, px, py, Color);
1211 
1212       x += dx;
1213       if (x >= dy)
1214       {
1215 	x -= dy;
1216 	px += sdx;
1217       }
1218 
1219       py += sdy;
1220     }
1221   }
1222 }
1223 
sge_DoLineRGB(SDL_Surface * Surface,Sint16 X1,Sint16 Y1,Sint16 X2,Sint16 Y2,Uint8 R,Uint8 G,Uint8 B,void Callback (SDL_Surface * Surf,Sint16 X,Sint16 Y,Uint32 Color))1224 void sge_DoLineRGB(SDL_Surface *Surface, Sint16 X1, Sint16 Y1,
1225 		   Sint16 X2, Sint16 Y2, Uint8 R, Uint8 G, Uint8 B,
1226 		   void Callback(SDL_Surface *Surf, Sint16 X, Sint16 Y,
1227 				 Uint32 Color))
1228 {
1229   sge_DoLine(Surface, X1, Y1, X2, Y2,
1230 	     SDL_MapRGB(Surface->format, R, G, B), Callback);
1231 }
1232 
sge_Line(SDL_Surface * Surface,Sint16 x1,Sint16 y1,Sint16 x2,Sint16 y2,Uint32 Color)1233 void sge_Line(SDL_Surface *Surface, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2,
1234 	      Uint32 Color)
1235 {
1236   if (SDL_MUSTLOCK(Surface))
1237   {
1238     if (SDL_LockSurface(Surface) < 0)
1239       return;
1240    }
1241 
1242    /* Draw the line */
1243    sge_DoLine(Surface, x1, y1, x2, y2, Color, _PutPixel);
1244 
1245    /* unlock the display */
1246    if (SDL_MUSTLOCK(Surface))
1247    {
1248       SDL_UnlockSurface(Surface);
1249    }
1250 }
1251 
sge_LineRGB(SDL_Surface * Surface,Sint16 x1,Sint16 y1,Sint16 x2,Sint16 y2,Uint8 R,Uint8 G,Uint8 B)1252 void sge_LineRGB(SDL_Surface *Surface, Sint16 x1, Sint16 y1, Sint16 x2,
1253 		 Sint16 y2, Uint8 R, Uint8 G, Uint8 B)
1254 {
1255   sge_Line(Surface, x1, y1, x2, y2, SDL_MapRGB(Surface->format, R, G, B));
1256 }
1257 
SDLPutPixel(Bitmap * dst_bitmap,int x,int y,Pixel pixel)1258 void SDLPutPixel(Bitmap *dst_bitmap, int x, int y, Pixel pixel)
1259 {
1260   if (dst_bitmap == backbuffer || dst_bitmap == window)
1261   {
1262     x += video_xoffset;
1263     y += video_yoffset;
1264   }
1265 
1266   sge_PutPixel(dst_bitmap->surface, x, y, pixel);
1267 }
1268 
1269 
1270 /*
1271   -----------------------------------------------------------------------------
1272   quick (no, it's slow) and dirty hack to "invert" rectangle inside SDL surface
1273   -----------------------------------------------------------------------------
1274 */
1275 
SDLInvertArea(Bitmap * bitmap,int src_x,int src_y,int width,int height,Uint32 color)1276 void SDLInvertArea(Bitmap *bitmap, int src_x, int src_y,
1277 		   int width, int height, Uint32 color)
1278 {
1279   int x, y;
1280 
1281   for (y = src_y; y < src_y + height; y++)
1282   {
1283     for (x = src_x; x < src_x + width; x++)
1284     {
1285       Uint32 pixel = SDLGetPixel(bitmap, x, y);
1286 
1287       SDLPutPixel(bitmap, x, y, pixel == BLACK_PIXEL ? color : BLACK_PIXEL);
1288     }
1289   }
1290 }
1291 
SDLCopyInverseMasked(Bitmap * src_bitmap,Bitmap * dst_bitmap,int src_x,int src_y,int width,int height,int dst_x,int dst_y)1292 void SDLCopyInverseMasked(Bitmap *src_bitmap, Bitmap *dst_bitmap,
1293 			  int src_x, int src_y, int width, int height,
1294 			  int dst_x, int dst_y)
1295 {
1296   int x, y;
1297 
1298   for (y = 0; y < height; y++)
1299   {
1300     for (x = 0; x < width; x++)
1301     {
1302       Uint32 pixel = SDLGetPixel(src_bitmap, src_x + x, src_y + y);
1303 
1304       if (pixel != BLACK_PIXEL)
1305 	SDLPutPixel(dst_bitmap, dst_x + x, dst_y + y, BLACK_PIXEL);
1306     }
1307   }
1308 }
1309 
1310 
1311 /* ========================================================================= */
1312 /* The following functions were taken from the SDL_gfx library version 2.0.3 */
1313 /* (Rotozoomer) by Andreas Schiffler                                         */
1314 /* http://www.ferzkopp.net/Software/SDL_gfx-2.0/index.html                   */
1315 /* ========================================================================= */
1316 
1317 /*
1318   -----------------------------------------------------------------------------
1319   32 bit zoomer
1320 
1321   zoomes 32bit RGBA/ABGR 'src' surface to 'dst' surface.
1322   -----------------------------------------------------------------------------
1323 */
1324 
1325 typedef struct
1326 {
1327   Uint8 r;
1328   Uint8 g;
1329   Uint8 b;
1330   Uint8 a;
1331 } tColorRGBA;
1332 
zoomSurfaceRGBA_scaleDownBy2(SDL_Surface * src,SDL_Surface * dst)1333 int zoomSurfaceRGBA_scaleDownBy2(SDL_Surface *src, SDL_Surface *dst)
1334 {
1335   int x, y;
1336   tColorRGBA *sp, *csp, *dp;
1337 #if 0
1338   int sgap;
1339 #endif
1340   int dgap;
1341 
1342   /* pointer setup */
1343   sp = csp = (tColorRGBA *) src->pixels;
1344   dp = (tColorRGBA *) dst->pixels;
1345 #if 0
1346   sgap = src->pitch - src->w * 4;
1347 #endif
1348   dgap = dst->pitch - dst->w * 4;
1349 
1350   for (y = 0; y < dst->h; y++)
1351   {
1352     sp = csp;
1353 
1354     for (x = 0; x < dst->w; x++)
1355     {
1356       tColorRGBA *sp0 = sp;
1357       tColorRGBA *sp1 = (tColorRGBA *) ((Uint8 *) sp + src->pitch);
1358       tColorRGBA *sp00 = &sp0[0];
1359       tColorRGBA *sp01 = &sp0[1];
1360       tColorRGBA *sp10 = &sp1[0];
1361       tColorRGBA *sp11 = &sp1[1];
1362       tColorRGBA new;
1363 
1364       /* create new color pixel from all four source color pixels */
1365       new.r = (sp00->r + sp01->r + sp10->r + sp11->r) / 4;
1366       new.g = (sp00->g + sp01->g + sp10->g + sp11->g) / 4;
1367       new.b = (sp00->b + sp01->b + sp10->b + sp11->b) / 4;
1368       new.a = (sp00->a + sp01->a + sp10->a + sp11->a) / 4;
1369 
1370       /* draw */
1371       *dp = new;
1372 
1373       /* advance source pointers */
1374       sp += 2;
1375 
1376       /* advance destination pointer */
1377       dp++;
1378     }
1379 
1380     /* advance source pointer */
1381     csp = (tColorRGBA *) ((Uint8 *) csp + 2 * src->pitch);
1382 
1383     /* advance destination pointers */
1384     dp = (tColorRGBA *) ((Uint8 *) dp + dgap);
1385   }
1386 
1387   return 0;
1388 }
1389 
zoomSurfaceRGBA(SDL_Surface * src,SDL_Surface * dst)1390 int zoomSurfaceRGBA(SDL_Surface *src, SDL_Surface *dst)
1391 {
1392   int x, y, sx, sy, *sax, *say, *csax, *csay, csx, csy;
1393   tColorRGBA *sp, *csp, *dp;
1394 #if 0
1395   int sgap;
1396 #endif
1397   int dgap;
1398 
1399   /* use specialized zoom function when scaling down to exactly half size */
1400   if (src->w == 2 * dst->w &&
1401       src->h == 2 * dst->h)
1402     return zoomSurfaceRGBA_scaleDownBy2(src, dst);
1403 
1404   /* variable setup */
1405   sx = (int) (65536.0 * (float) src->w / (float) dst->w);
1406   sy = (int) (65536.0 * (float) src->h / (float) dst->h);
1407 
1408   /* allocate memory for row increments */
1409   sax = (int *)checked_malloc((dst->w + 1) * sizeof(Uint32));
1410   say = (int *)checked_malloc((dst->h + 1) * sizeof(Uint32));
1411 
1412   /* precalculate row increments */
1413   csx = 0;
1414   csax = sax;
1415   for (x = 0; x <= dst->w; x++)
1416   {
1417     *csax = csx;
1418     csax++;
1419     csx &= 0xffff;
1420     csx += sx;
1421   }
1422 
1423   csy = 0;
1424   csay = say;
1425   for (y = 0; y <= dst->h; y++)
1426   {
1427     *csay = csy;
1428     csay++;
1429     csy &= 0xffff;
1430     csy += sy;
1431   }
1432 
1433   /* pointer setup */
1434   sp = csp = (tColorRGBA *) src->pixels;
1435   dp = (tColorRGBA *) dst->pixels;
1436 #if 0
1437   sgap = src->pitch - src->w * 4;
1438 #endif
1439   dgap = dst->pitch - dst->w * 4;
1440 
1441   csay = say;
1442   for (y = 0; y < dst->h; y++)
1443   {
1444     sp = csp;
1445     csax = sax;
1446 
1447     for (x = 0; x < dst->w; x++)
1448     {
1449       /* draw */
1450       *dp = *sp;
1451 
1452       /* advance source pointers */
1453       csax++;
1454       sp += (*csax >> 16);
1455 
1456       /* advance destination pointer */
1457       dp++;
1458     }
1459 
1460     /* advance source pointer */
1461     csay++;
1462     csp = (tColorRGBA *) ((Uint8 *) csp + (*csay >> 16) * src->pitch);
1463 
1464     /* advance destination pointers */
1465     dp = (tColorRGBA *) ((Uint8 *) dp + dgap);
1466   }
1467 
1468   free(sax);
1469   free(say);
1470 
1471   return 0;
1472 }
1473 
1474 /*
1475   -----------------------------------------------------------------------------
1476   8 bit zoomer
1477 
1478   zoomes 8 bit palette/Y 'src' surface to 'dst' surface
1479   -----------------------------------------------------------------------------
1480 */
1481 
zoomSurfaceY(SDL_Surface * src,SDL_Surface * dst)1482 int zoomSurfaceY(SDL_Surface * src, SDL_Surface * dst)
1483 {
1484   Uint32 x, y, sx, sy, *sax, *say, *csax, *csay, csx, csy;
1485   Uint8 *sp, *dp, *csp;
1486   int dgap;
1487 
1488   /* variable setup */
1489   sx = (Uint32) (65536.0 * (float) src->w / (float) dst->w);
1490   sy = (Uint32) (65536.0 * (float) src->h / (float) dst->h);
1491 
1492   /* allocate memory for row increments */
1493   sax = (Uint32 *)checked_malloc(dst->w * sizeof(Uint32));
1494   say = (Uint32 *)checked_malloc(dst->h * sizeof(Uint32));
1495 
1496   /* precalculate row increments */
1497   csx = 0;
1498   csax = sax;
1499   for (x = 0; x < dst->w; x++)
1500   {
1501     csx += sx;
1502     *csax = (csx >> 16);
1503     csx &= 0xffff;
1504     csax++;
1505   }
1506 
1507   csy = 0;
1508   csay = say;
1509   for (y = 0; y < dst->h; y++)
1510   {
1511     csy += sy;
1512     *csay = (csy >> 16);
1513     csy &= 0xffff;
1514     csay++;
1515   }
1516 
1517   csx = 0;
1518   csax = sax;
1519   for (x = 0; x < dst->w; x++)
1520   {
1521     csx += (*csax);
1522     csax++;
1523   }
1524 
1525   csy = 0;
1526   csay = say;
1527   for (y = 0; y < dst->h; y++)
1528   {
1529     csy += (*csay);
1530     csay++;
1531   }
1532 
1533   /* pointer setup */
1534   sp = csp = (Uint8 *) src->pixels;
1535   dp = (Uint8 *) dst->pixels;
1536   dgap = dst->pitch - dst->w;
1537 
1538   /* draw */
1539   csay = say;
1540   for (y = 0; y < dst->h; y++)
1541   {
1542     csax = sax;
1543     sp = csp;
1544     for (x = 0; x < dst->w; x++)
1545     {
1546       /* draw */
1547       *dp = *sp;
1548 
1549       /* advance source pointers */
1550       sp += (*csax);
1551       csax++;
1552 
1553       /* advance destination pointer */
1554       dp++;
1555     }
1556 
1557     /* advance source pointer (for row) */
1558     csp += ((*csay) * src->pitch);
1559     csay++;
1560 
1561     /* advance destination pointers */
1562     dp += dgap;
1563   }
1564 
1565   free(sax);
1566   free(say);
1567 
1568   return 0;
1569 }
1570 
1571 /*
1572   -----------------------------------------------------------------------------
1573   zoomSurface()
1574 
1575   Zooms a 32bit or 8bit 'src' surface to newly created 'dst' surface.
1576   'zoomx' and 'zoomy' are scaling factors for width and height.
1577   If the surface is not 8bit or 32bit RGBA/ABGR it will be converted
1578   into a 32bit RGBA format on the fly.
1579   -----------------------------------------------------------------------------
1580 */
1581 
zoomSurface(SDL_Surface * src,int dst_width,int dst_height)1582 SDL_Surface *zoomSurface(SDL_Surface *src, int dst_width, int dst_height)
1583 {
1584   SDL_Surface *zoom_src = NULL;
1585   SDL_Surface *zoom_dst = NULL;
1586   boolean is_converted = FALSE;
1587   boolean is_32bit;
1588   int i;
1589 
1590   if (src == NULL)
1591     return NULL;
1592 
1593   /* determine if source surface is 32 bit or 8 bit */
1594   is_32bit = (src->format->BitsPerPixel == 32);
1595 
1596   if (is_32bit || src->format->BitsPerPixel == 8)
1597   {
1598     /* use source surface 'as is' */
1599     zoom_src = src;
1600   }
1601   else
1602   {
1603     /* new source surface is 32 bit with a defined RGB ordering */
1604     zoom_src = SDL_CreateRGBSurface(SDL_SWSURFACE, src->w, src->h, 32,
1605 				    0x000000ff, 0x0000ff00, 0x00ff0000, 0);
1606     SDL_BlitSurface(src, NULL, zoom_src, NULL);
1607     is_32bit = TRUE;
1608     is_converted = TRUE;
1609   }
1610 
1611   /* allocate surface to completely contain the zoomed surface */
1612   if (is_32bit)
1613   {
1614     /* target surface is 32 bit with source RGBA/ABGR ordering */
1615     zoom_dst = SDL_CreateRGBSurface(SDL_SWSURFACE, dst_width, dst_height, 32,
1616 				    zoom_src->format->Rmask,
1617 				    zoom_src->format->Gmask,
1618 				    zoom_src->format->Bmask, 0);
1619   }
1620   else
1621   {
1622     /* target surface is 8 bit */
1623     zoom_dst = SDL_CreateRGBSurface(SDL_SWSURFACE, dst_width, dst_height, 8,
1624 				    0, 0, 0, 0);
1625   }
1626 
1627   /* lock source surface */
1628   SDL_LockSurface(zoom_src);
1629 
1630   /* check which kind of surface we have */
1631   if (is_32bit)
1632   {
1633     /* call the 32 bit transformation routine to do the zooming */
1634     zoomSurfaceRGBA(zoom_src, zoom_dst);
1635   }
1636   else
1637   {
1638     /* copy palette */
1639     for (i = 0; i < zoom_src->format->palette->ncolors; i++)
1640       zoom_dst->format->palette->colors[i] =
1641 	zoom_src->format->palette->colors[i];
1642     zoom_dst->format->palette->ncolors = zoom_src->format->palette->ncolors;
1643 
1644     /* call the 8 bit transformation routine to do the zooming */
1645     zoomSurfaceY(zoom_src, zoom_dst);
1646   }
1647 
1648   /* unlock source surface */
1649   SDL_UnlockSurface(zoom_src);
1650 
1651   /* free temporary surface */
1652   if (is_converted)
1653     SDL_FreeSurface(zoom_src);
1654 
1655   /* return destination surface */
1656   return zoom_dst;
1657 }
1658 
SDLZoomBitmap(Bitmap * src_bitmap,Bitmap * dst_bitmap)1659 void SDLZoomBitmap(Bitmap *src_bitmap, Bitmap *dst_bitmap)
1660 {
1661   SDL_Surface *sdl_surface_tmp;
1662   int dst_width = dst_bitmap->width;
1663   int dst_height = dst_bitmap->height;
1664 
1665   /* throw away old destination surface */
1666   SDL_FreeSurface(dst_bitmap->surface);
1667 
1668   /* create zoomed temporary surface from source surface */
1669   sdl_surface_tmp = zoomSurface(src_bitmap->surface, dst_width, dst_height);
1670 
1671   /* create native format destination surface from zoomed temporary surface */
1672   dst_bitmap->surface = SDL_DisplayFormat(sdl_surface_tmp);
1673 
1674   /* free temporary surface */
1675   SDL_FreeSurface(sdl_surface_tmp);
1676 }
1677 
1678 
1679 /* ========================================================================= */
1680 /* load image to bitmap                                                      */
1681 /* ========================================================================= */
1682 
SDLLoadImage(char * filename)1683 Bitmap *SDLLoadImage(char *filename)
1684 {
1685   Bitmap *new_bitmap = CreateBitmapStruct();
1686   SDL_Surface *sdl_image_tmp;
1687 
1688   /* load image to temporary surface */
1689   if ((sdl_image_tmp = IMG_Load(filename)) == NULL)
1690   {
1691     SetError("IMG_Load(): %s", SDL_GetError());
1692 
1693     return NULL;
1694   }
1695 
1696   UPDATE_BUSY_STATE();
1697 
1698   /* create native non-transparent surface for current image */
1699   if ((new_bitmap->surface = SDL_DisplayFormat(sdl_image_tmp)) == NULL)
1700   {
1701     SetError("SDL_DisplayFormat(): %s", SDL_GetError());
1702 
1703     return NULL;
1704   }
1705 
1706   UPDATE_BUSY_STATE();
1707 
1708   /* create native transparent surface for current image */
1709   SDL_SetColorKey(sdl_image_tmp, SDL_SRCCOLORKEY,
1710 		  SDL_MapRGB(sdl_image_tmp->format, 0x00, 0x00, 0x00));
1711   if ((new_bitmap->surface_masked = SDL_DisplayFormat(sdl_image_tmp)) == NULL)
1712   {
1713     SetError("SDL_DisplayFormat(): %s", SDL_GetError());
1714 
1715     return NULL;
1716   }
1717 
1718   UPDATE_BUSY_STATE();
1719 
1720   /* free temporary surface */
1721   SDL_FreeSurface(sdl_image_tmp);
1722 
1723   new_bitmap->width = new_bitmap->surface->w;
1724   new_bitmap->height = new_bitmap->surface->h;
1725 
1726   return new_bitmap;
1727 }
1728 
1729 
1730 /* ------------------------------------------------------------------------- */
1731 /* custom cursor fuctions                                                    */
1732 /* ------------------------------------------------------------------------- */
1733 
create_cursor(struct MouseCursorInfo * cursor_info)1734 static SDL_Cursor *create_cursor(struct MouseCursorInfo *cursor_info)
1735 {
1736   return SDL_CreateCursor(cursor_info->data, cursor_info->mask,
1737 			  cursor_info->width, cursor_info->height,
1738 			  cursor_info->hot_x, cursor_info->hot_y);
1739 }
1740 
SDLSetMouseCursor(struct MouseCursorInfo * cursor_info)1741 void SDLSetMouseCursor(struct MouseCursorInfo *cursor_info)
1742 {
1743   static struct MouseCursorInfo *last_cursor_info = NULL;
1744   static struct MouseCursorInfo *last_cursor_info2 = NULL;
1745   static SDL_Cursor *cursor_default = NULL;
1746   static SDL_Cursor *cursor_current = NULL;
1747 
1748   /* if invoked for the first time, store the SDL default cursor */
1749   if (cursor_default == NULL)
1750     cursor_default = SDL_GetCursor();
1751 
1752   /* only create new cursor if cursor info (custom only) has changed */
1753   if (cursor_info != NULL && cursor_info != last_cursor_info)
1754   {
1755     cursor_current = create_cursor(cursor_info);
1756     last_cursor_info = cursor_info;
1757   }
1758 
1759   /* only set new cursor if cursor info (custom or NULL) has changed */
1760   if (cursor_info != last_cursor_info2)
1761     SDL_SetCursor(cursor_info ? cursor_current : cursor_default);
1762 
1763   last_cursor_info2 = cursor_info;
1764 }
1765 
1766 
1767 /* ========================================================================= */
1768 /* audio functions                                                           */
1769 /* ========================================================================= */
1770 
SDLOpenAudio(void)1771 void SDLOpenAudio(void)
1772 {
1773   if (!strEqual(setup.system.sdl_audiodriver, ARG_DEFAULT))
1774     SDL_putenv(getStringCat2("SDL_AUDIODRIVER=", setup.system.sdl_audiodriver));
1775 
1776   if (SDL_InitSubSystem(SDL_INIT_AUDIO) < 0)
1777   {
1778     Error(ERR_WARN, "SDL_InitSubSystem() failed: %s", SDL_GetError());
1779     return;
1780   }
1781 
1782   if (Mix_OpenAudio(DEFAULT_AUDIO_SAMPLE_RATE, MIX_DEFAULT_FORMAT,
1783 		    AUDIO_NUM_CHANNELS_STEREO,
1784 		    setup.system.audio_fragment_size) < 0)
1785   {
1786     Error(ERR_WARN, "Mix_OpenAudio() failed: %s", SDL_GetError());
1787     return;
1788   }
1789 
1790   audio.sound_available = TRUE;
1791   audio.music_available = TRUE;
1792   audio.loops_available = TRUE;
1793   audio.sound_enabled = TRUE;
1794 
1795   /* set number of available mixer channels */
1796   audio.num_channels = Mix_AllocateChannels(NUM_MIXER_CHANNELS);
1797   audio.music_channel = MUSIC_CHANNEL;
1798   audio.first_sound_channel = FIRST_SOUND_CHANNEL;
1799 
1800   Mixer_InitChannels();
1801 }
1802 
SDLCloseAudio(void)1803 void SDLCloseAudio(void)
1804 {
1805   Mix_HaltMusic();
1806   Mix_HaltChannel(-1);
1807 
1808   Mix_CloseAudio();
1809   SDL_QuitSubSystem(SDL_INIT_AUDIO);
1810 }
1811 
1812 
1813 /* ========================================================================= */
1814 /* event functions                                                           */
1815 /* ========================================================================= */
1816 
SDLNextEvent(Event * event)1817 void SDLNextEvent(Event *event)
1818 {
1819   SDL_WaitEvent(event);
1820 
1821   if (event->type == EVENT_BUTTONPRESS ||
1822       event->type == EVENT_BUTTONRELEASE)
1823   {
1824     if (((ButtonEvent *)event)->x > video_xoffset)
1825       ((ButtonEvent *)event)->x -= video_xoffset;
1826     else
1827       ((ButtonEvent *)event)->x = 0;
1828     if (((ButtonEvent *)event)->y > video_yoffset)
1829       ((ButtonEvent *)event)->y -= video_yoffset;
1830     else
1831       ((ButtonEvent *)event)->y = 0;
1832   }
1833   else if (event->type == EVENT_MOTIONNOTIFY)
1834   {
1835     if (((MotionEvent *)event)->x > video_xoffset)
1836       ((MotionEvent *)event)->x -= video_xoffset;
1837     else
1838       ((MotionEvent *)event)->x = 0;
1839     if (((MotionEvent *)event)->y > video_yoffset)
1840       ((MotionEvent *)event)->y -= video_yoffset;
1841     else
1842       ((MotionEvent *)event)->y = 0;
1843   }
1844 }
1845 
SDLHandleWindowManagerEvent(Event * event)1846 void SDLHandleWindowManagerEvent(Event *event)
1847 {
1848 #if defined(PLATFORM_WIN32)
1849   SDL_SysWMEvent *syswmevent = (SDL_SysWMEvent *)event;
1850   SDL_SysWMmsg *syswmmsg = (SDL_SysWMmsg *)(syswmevent->msg);
1851 
1852   if (syswmmsg->msg == WM_DROPFILES)
1853   {
1854     HDROP hdrop = (HDROP)syswmmsg->wParam;
1855     int i, num_files;
1856 
1857     printf("::: SDL_SYSWMEVENT:\n");
1858 
1859     num_files = DragQueryFile(hdrop, 0xffffffff, NULL, 0);
1860 
1861     for (i = 0; i < num_files; i++)
1862     {
1863       int buffer_len = DragQueryFile(hdrop, i, NULL, 0);
1864       char buffer[buffer_len + 1];
1865 
1866       DragQueryFile(hdrop, i, buffer, buffer_len + 1);
1867 
1868       printf("::: - '%s'\n", buffer);
1869     }
1870 
1871     DragFinish((HDROP)syswmmsg->wParam);
1872   }
1873 #endif
1874 }
1875 
1876 
1877 /* ========================================================================= */
1878 /* joystick functions                                                        */
1879 /* ========================================================================= */
1880 
1881 static SDL_Joystick *sdl_joystick[MAX_PLAYERS] = { NULL, NULL, NULL, NULL };
1882 static int sdl_js_axis[MAX_PLAYERS][2]   = { {0, 0}, {0, 0}, {0, 0}, {0, 0} };
1883 static int sdl_js_button[MAX_PLAYERS][2] = { {0, 0}, {0, 0}, {0, 0}, {0, 0} };
1884 
SDLOpenJoystick(int nr)1885 static boolean SDLOpenJoystick(int nr)
1886 {
1887   if (nr < 0 || nr > MAX_PLAYERS)
1888     return FALSE;
1889 
1890   return ((sdl_joystick[nr] = SDL_JoystickOpen(nr)) == NULL ? FALSE : TRUE);
1891 }
1892 
SDLCloseJoystick(int nr)1893 static void SDLCloseJoystick(int nr)
1894 {
1895   if (nr < 0 || nr > MAX_PLAYERS)
1896     return;
1897 
1898   SDL_JoystickClose(sdl_joystick[nr]);
1899 }
1900 
SDLCheckJoystickOpened(int nr)1901 static boolean SDLCheckJoystickOpened(int nr)
1902 {
1903   if (nr < 0 || nr > MAX_PLAYERS)
1904     return FALSE;
1905 
1906   return (SDL_JoystickOpened(nr) ? TRUE : FALSE);
1907 }
1908 
HandleJoystickEvent(Event * event)1909 void HandleJoystickEvent(Event *event)
1910 {
1911   switch(event->type)
1912   {
1913     case SDL_JOYAXISMOTION:
1914       if (event->jaxis.axis < 2)
1915 	sdl_js_axis[event->jaxis.which][event->jaxis.axis]= event->jaxis.value;
1916       break;
1917 
1918     case SDL_JOYBUTTONDOWN:
1919       if (event->jbutton.button < 2)
1920 	sdl_js_button[event->jbutton.which][event->jbutton.button] = TRUE;
1921       break;
1922 
1923     case SDL_JOYBUTTONUP:
1924       if (event->jbutton.button < 2)
1925 	sdl_js_button[event->jbutton.which][event->jbutton.button] = FALSE;
1926       break;
1927 
1928     default:
1929       break;
1930   }
1931 }
1932 
SDLInitJoysticks()1933 void SDLInitJoysticks()
1934 {
1935   static boolean sdl_joystick_subsystem_initialized = FALSE;
1936   boolean print_warning = !sdl_joystick_subsystem_initialized;
1937   int i;
1938 
1939   if (!sdl_joystick_subsystem_initialized)
1940   {
1941     sdl_joystick_subsystem_initialized = TRUE;
1942 
1943     if (SDL_Init(SDL_INIT_JOYSTICK) < 0)
1944     {
1945       Error(ERR_EXIT, "SDL_Init() failed: %s", SDL_GetError());
1946       return;
1947     }
1948   }
1949 
1950   for (i = 0; i < MAX_PLAYERS; i++)
1951   {
1952     /* get configured joystick for this player */
1953     char *device_name = setup.input[i].joy.device_name;
1954     int joystick_nr = getJoystickNrFromDeviceName(device_name);
1955 
1956     if (joystick_nr >= SDL_NumJoysticks())
1957     {
1958       if (setup.input[i].use_joystick && print_warning)
1959 	Error(ERR_WARN, "cannot find joystick %d", joystick_nr);
1960 
1961       joystick_nr = -1;
1962     }
1963 
1964     /* misuse joystick file descriptor variable to store joystick number */
1965     joystick.fd[i] = joystick_nr;
1966 
1967     if (joystick_nr == -1)
1968       continue;
1969 
1970     /* this allows subsequent calls to 'InitJoysticks' for re-initialization */
1971     if (SDLCheckJoystickOpened(joystick_nr))
1972       SDLCloseJoystick(joystick_nr);
1973 
1974     if (!setup.input[i].use_joystick)
1975       continue;
1976 
1977     if (!SDLOpenJoystick(joystick_nr))
1978     {
1979       if (print_warning)
1980 	Error(ERR_WARN, "cannot open joystick %d", joystick_nr);
1981 
1982       continue;
1983     }
1984 
1985     joystick.status = JOYSTICK_ACTIVATED;
1986   }
1987 }
1988 
SDLReadJoystick(int nr,int * x,int * y,boolean * b1,boolean * b2)1989 boolean SDLReadJoystick(int nr, int *x, int *y, boolean *b1, boolean *b2)
1990 {
1991   if (nr < 0 || nr >= MAX_PLAYERS)
1992     return FALSE;
1993 
1994   if (x != NULL)
1995     *x = sdl_js_axis[nr][0];
1996   if (y != NULL)
1997     *y = sdl_js_axis[nr][1];
1998 
1999   if (b1 != NULL)
2000     *b1 = sdl_js_button[nr][0];
2001   if (b2 != NULL)
2002     *b2 = sdl_js_button[nr][1];
2003 
2004   return TRUE;
2005 }
2006 
2007 #endif /* TARGET_SDL */
2008