rnd-20030823-2-src
[rocksndiamonds.git] / src / libgame / sdl.c
1 /***********************************************************
2 * Artsoft Retro-Game Library                               *
3 *----------------------------------------------------------*
4 * (c) 1994-2002 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
19
20 #if defined(TARGET_SDL)
21
22 /* ========================================================================= */
23 /* video functions                                                           */
24 /* ========================================================================= */
25
26 /* functions from SGE library */
27 inline void sge_Line(SDL_Surface *, Sint16, Sint16, Sint16, Sint16, Uint32);
28
29 /* #ifdef PLATFORM_WIN32 */
30 #define FULLSCREEN_BUG
31 /* #endif */
32
33 /* stuff needed to work around SDL/Windows fullscreen drawing bug */
34 static int fullscreen_width;
35 static int fullscreen_height;
36 static int fullscreen_xoffset;
37 static int fullscreen_yoffset;
38 static int video_xoffset;
39 static int video_yoffset;
40
41 inline void SDLInitVideoDisplay(void)
42 {
43   putenv("SDL_VIDEO_CENTERED=1");
44
45   /* initialize SDL video */
46   if (SDL_InitSubSystem(SDL_INIT_VIDEO) < 0)
47     Error(ERR_EXIT, "SDL_InitSubSystem() failed: %s", SDL_GetError());
48
49   /* set default SDL depth */
50   video.default_depth = SDL_GetVideoInfo()->vfmt->BitsPerPixel;
51 }
52
53 inline void SDLInitVideoBuffer(DrawBuffer **backbuffer, DrawWindow **window,
54                                boolean fullscreen)
55 {
56 #ifdef FULLSCREEN_BUG
57   int i;
58   static int screen_xy[][2] =
59   {
60     {  640, 480 },
61     {  800, 600 },
62     { 1024, 768 },
63     {   -1,  -1 }
64   };
65 #endif
66
67   /* default: normal game window size */
68   fullscreen_width = video.width;
69   fullscreen_height = video.height;
70   fullscreen_xoffset = 0;
71   fullscreen_yoffset = 0;
72
73 #ifdef FULLSCREEN_BUG
74   for (i=0; screen_xy[i][0] != -1; i++)
75   {
76     if (video.width <= screen_xy[i][0] && video.height <= screen_xy[i][1])
77     {
78       fullscreen_width = screen_xy[i][0];
79       fullscreen_height = screen_xy[i][1];
80       break;
81     }
82   }
83
84   fullscreen_xoffset = (fullscreen_width - video.width) / 2;
85   fullscreen_yoffset = (fullscreen_height - video.height) / 2;
86 #endif
87
88   /* open SDL video output device (window or fullscreen mode) */
89   if (!SDLSetVideoMode(backbuffer, fullscreen))
90     Error(ERR_EXIT, "setting video mode failed");
91
92   /* set window and icon title */
93   SDL_WM_SetCaption(program.window_title, program.window_title);
94
95   /* SDL cannot directly draw to the visible video framebuffer like X11,
96      but always uses a backbuffer, which is then blitted to the visible
97      video framebuffer with 'SDL_UpdateRect' (or replaced with the current
98      visible video framebuffer with 'SDL_Flip', if the hardware supports
99      this). Therefore do not use an additional backbuffer for drawing, but
100      use a symbolic buffer (distinguishable from the SDL backbuffer) called
101      'window', which indicates that the SDL backbuffer should be updated to
102      the visible video framebuffer when attempting to blit to it.
103
104      For convenience, it seems to be a good idea to create this symbolic
105      buffer 'window' at the same size as the SDL backbuffer. Although it
106      should never be drawn to directly, it would do no harm nevertheless. */
107
108   /* create additional (symbolic) buffer for double-buffering */
109   *window = CreateBitmap(video.width, video.height, video.depth);
110 }
111
112 inline boolean SDLSetVideoMode(DrawBuffer **backbuffer, boolean fullscreen)
113 {
114   boolean success = TRUE;
115   int surface_flags_fullscreen = SURFACE_FLAGS | SDL_FULLSCREEN;
116   int surface_flags_window = SURFACE_FLAGS;
117   SDL_Surface *new_surface = NULL;
118
119   if (*backbuffer == NULL)
120     *backbuffer = CreateBitmapStruct();
121
122   if (fullscreen && !video.fullscreen_enabled && video.fullscreen_available)
123   {
124     video_xoffset = fullscreen_xoffset;
125     video_yoffset = fullscreen_yoffset;
126
127     /* switch display to fullscreen mode, if available */
128     if ((new_surface = SDL_SetVideoMode(fullscreen_width, fullscreen_height,
129                                         video.depth, surface_flags_fullscreen))
130         == NULL)
131     {
132       /* switching display to fullscreen mode failed */
133       Error(ERR_WARN, "SDL_SetVideoMode() failed: %s", SDL_GetError());
134
135       /* do not try it again */
136       video.fullscreen_available = FALSE;
137       success = FALSE;
138     }
139     else
140     {
141       (*backbuffer)->surface = new_surface;
142
143       video.fullscreen_enabled = TRUE;
144       success = TRUE;
145     }
146   }
147
148   if ((!fullscreen && video.fullscreen_enabled) || new_surface == NULL)
149   {
150     video_xoffset = 0;
151     video_yoffset = 0;
152
153     /* switch display to window mode */
154     if ((new_surface = SDL_SetVideoMode(video.width, video.height,
155                                         video.depth, surface_flags_window))
156         == NULL)
157     {
158       /* switching display to window mode failed -- should not happen */
159       Error(ERR_WARN, "SDL_SetVideoMode() failed: %s", SDL_GetError());
160
161       success = FALSE;
162     }
163     else
164     {
165       (*backbuffer)->surface = new_surface;
166
167       video.fullscreen_enabled = FALSE;
168       success = TRUE;
169     }
170   }
171
172   return success;
173 }
174
175 inline void SDLCreateBitmapContent(Bitmap *new_bitmap,
176                                    int width, int height, int depth)
177 {
178   SDL_Surface *surface_tmp, *surface_native;
179
180   if ((surface_tmp = SDL_CreateRGBSurface(SURFACE_FLAGS, width, height, depth,
181                                           0, 0, 0, 0))
182       == NULL)
183     Error(ERR_EXIT, "SDL_CreateRGBSurface() failed: %s", SDL_GetError());
184
185   if ((surface_native = SDL_DisplayFormat(surface_tmp)) == NULL)
186     Error(ERR_EXIT, "SDL_DisplayFormat() failed: %s", SDL_GetError());
187
188   SDL_FreeSurface(surface_tmp);
189
190   new_bitmap->surface = surface_native;
191 }
192
193 inline void SDLFreeBitmapPointers(Bitmap *bitmap)
194 {
195   if (bitmap->surface)
196     SDL_FreeSurface(bitmap->surface);
197   if (bitmap->surface_masked)
198     SDL_FreeSurface(bitmap->surface_masked);
199   bitmap->surface = NULL;
200   bitmap->surface_masked = NULL;
201 }
202
203 inline void SDLCopyArea(Bitmap *src_bitmap, Bitmap *dst_bitmap,
204                         int src_x, int src_y,
205                         int width, int height,
206                         int dst_x, int dst_y, int mask_mode)
207 {
208   Bitmap *real_dst_bitmap = (dst_bitmap == window ? backbuffer : dst_bitmap);
209   SDL_Rect src_rect, dst_rect;
210
211 #ifdef FULLSCREEN_BUG
212   if (src_bitmap == backbuffer)
213   {
214     src_x += video_xoffset;
215     src_y += video_yoffset;
216   }
217 #endif
218
219   src_rect.x = src_x;
220   src_rect.y = src_y;
221   src_rect.w = width;
222   src_rect.h = height;
223
224 #ifdef FULLSCREEN_BUG
225   if (dst_bitmap == backbuffer || dst_bitmap == window)
226   {
227     dst_x += video_xoffset;
228     dst_y += video_yoffset;
229   }
230 #endif
231
232   dst_rect.x = dst_x;
233   dst_rect.y = dst_y;
234   dst_rect.w = width;
235   dst_rect.h = height;
236
237   if (src_bitmap != backbuffer || dst_bitmap != window)
238     SDL_BlitSurface((mask_mode == BLIT_MASKED ?
239                      src_bitmap->surface_masked : src_bitmap->surface),
240                     &src_rect, real_dst_bitmap->surface, &dst_rect);
241
242   if (dst_bitmap == window)
243     SDL_UpdateRect(backbuffer->surface, dst_x, dst_y, width, height);
244 }
245
246 inline void SDLFillRectangle(Bitmap *dst_bitmap, int x, int y,
247                              int width, int height, Uint32 color)
248 {
249   Bitmap *real_dst_bitmap = (dst_bitmap == window ? backbuffer : dst_bitmap);
250   SDL_Rect rect;
251 #if 0
252   unsigned int color_r = (color >> 16) & 0xff;
253   unsigned int color_g = (color >>  8) & 0xff;
254   unsigned int color_b = (color >>  0) & 0xff;
255 #endif
256
257 #ifdef FULLSCREEN_BUG
258   if (dst_bitmap == backbuffer || dst_bitmap == window)
259   {
260     x += video_xoffset;
261     y += video_yoffset;
262   }
263 #endif
264
265   rect.x = x;
266   rect.y = y;
267   rect.w = width;
268   rect.h = height;
269
270 #if 1
271   SDL_FillRect(real_dst_bitmap->surface, &rect, color);
272 #else
273   SDL_FillRect(real_dst_bitmap->surface, &rect,
274                SDL_MapRGB(real_dst_bitmap->surface->format,
275                           color_r, color_g, color_b));
276 #endif
277
278   if (dst_bitmap == window)
279     SDL_UpdateRect(backbuffer->surface, x, y, width, height);
280 }
281
282 inline void SDLDrawSimpleLine(Bitmap *dst_bitmap, int from_x, int from_y,
283                               int to_x, int to_y, Uint32 color)
284 {
285   SDL_Surface *surface = dst_bitmap->surface;
286   SDL_Rect rect;
287 #if 0
288   unsigned int color_r = (color >> 16) & 0xff;
289   unsigned int color_g = (color >>  8) & 0xff;
290   unsigned int color_b = (color >>  0) & 0xff;
291 #endif
292
293   if (from_x > to_x)
294     swap_numbers(&from_x, &to_x);
295
296   if (from_y > to_y)
297     swap_numbers(&from_y, &to_y);
298
299   rect.x = from_x;
300   rect.y = from_y;
301   rect.w = (to_x - from_x + 1);
302   rect.h = (to_y - from_y + 1);
303
304 #ifdef FULLSCREEN_BUG
305   if (dst_bitmap == backbuffer || dst_bitmap == window)
306   {
307     rect.x += video_xoffset;
308     rect.y += video_yoffset;
309   }
310 #endif
311
312 #if 1
313   SDL_FillRect(surface, &rect, color);
314 #else
315   SDL_FillRect(surface, &rect,
316                SDL_MapRGB(surface->format, color_r, color_g, color_b));
317 #endif
318 }
319
320 inline void SDLDrawLine(Bitmap *dst_bitmap, int from_x, int from_y,
321                         int to_x, int to_y, Uint32 color)
322 {
323 #ifdef FULLSCREEN_BUG
324   if (dst_bitmap == backbuffer || dst_bitmap == window)
325   {
326     from_x += video_xoffset;
327     from_y += video_yoffset;
328     to_x += video_xoffset;
329     to_y += video_yoffset;
330   }
331 #endif
332
333   sge_Line(dst_bitmap->surface, from_x, from_y, to_x, to_y, color);
334 }
335
336 #if 0
337 inline void SDLDrawLines(SDL_Surface *surface, struct XY *points,
338                          int num_points, Uint32 color)
339 {
340   int i, x, y;
341   int line_width = 4;
342
343   for (i=0; i<num_points - 1; i++)
344   {
345     for (x=0; x<line_width; x++)
346     {
347       for (y=0; y<line_width; y++)
348       {
349         int dx = x - line_width / 2;
350         int dy = y - line_width / 2;
351
352         if ((x == 0 && y == 0) ||
353             (x == 0 && y == line_width - 1) ||
354             (x == line_width - 1 && y == 0) ||
355             (x == line_width - 1 && y == line_width - 1))
356           continue;
357
358         sge_Line(surface, points[i].x + dx, points[i].y + dy,
359                  points[i+1].x + dx, points[i+1].y + dy, color);
360       }
361     }
362   }
363 }
364 #endif
365
366 inline Pixel SDLGetPixel(Bitmap *src_bitmap, int x, int y)
367 {
368   SDL_Surface *surface = src_bitmap->surface;
369
370 #ifdef FULLSCREEN_BUG
371   if (src_bitmap == backbuffer || src_bitmap == window)
372   {
373     x += video_xoffset;
374     y += video_yoffset;
375   }
376 #endif
377
378   switch (surface->format->BytesPerPixel)
379   {
380     case 1:             /* assuming 8-bpp */
381     {
382       return *((Uint8 *)surface->pixels + y * surface->pitch + x);
383     }
384     break;
385
386     case 2:             /* probably 15-bpp or 16-bpp */
387     {
388       return *((Uint16 *)surface->pixels + y * surface->pitch / 2 + x);
389     }
390     break;
391
392   case 3:               /* slow 24-bpp mode; usually not used */
393     {
394       /* does this work? */
395       Uint8 *pix = (Uint8 *)surface->pixels + y * surface->pitch + x * 3;
396       Uint32 color = 0;
397       int shift;
398
399       shift = surface->format->Rshift;
400       color |= *(pix + shift / 8) >> shift;
401       shift = surface->format->Gshift;
402       color |= *(pix + shift / 8) >> shift;
403       shift = surface->format->Bshift;
404       color |= *(pix + shift / 8) >> shift;
405
406       return color;
407     }
408     break;
409
410   case 4:               /* probably 32-bpp */
411     {
412       return *((Uint32 *)surface->pixels + y * surface->pitch / 4 + x);
413     }
414     break;
415   }
416
417   return 0;
418 }
419
420
421 /* ========================================================================= */
422 /* The following functions were taken from the SGE library                   */
423 /* (SDL Graphics Extension Library) by Anders Lindström                      */
424 /* http://www.etek.chalmers.se/~e8cal1/sge/index.html                        */
425 /* ========================================================================= */
426
427 void _PutPixel(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
428 {
429   if (x >= 0 && x <= surface->w - 1 && y >= 0 && y <= surface->h - 1)
430   {
431     switch (surface->format->BytesPerPixel)
432     {
433       case 1:
434       {
435         /* Assuming 8-bpp */
436         *((Uint8 *)surface->pixels + y*surface->pitch + x) = color;
437       }
438       break;
439
440       case 2:
441       {
442         /* Probably 15-bpp or 16-bpp */
443         *((Uint16 *)surface->pixels + y*surface->pitch/2 + x) = color;
444       }
445       break;
446
447       case 3:
448       {
449         /* Slow 24-bpp mode, usually not used */
450         Uint8 *pix;
451         int shift;
452
453         /* Gack - slow, but endian correct */
454         pix = (Uint8 *)surface->pixels + y * surface->pitch + x*3;
455         shift = surface->format->Rshift;
456         *(pix+shift/8) = color>>shift;
457         shift = surface->format->Gshift;
458         *(pix+shift/8) = color>>shift;
459         shift = surface->format->Bshift;
460         *(pix+shift/8) = color>>shift;
461       }
462       break;
463
464       case 4:
465       {
466         /* Probably 32-bpp */
467         *((Uint32 *)surface->pixels + y*surface->pitch/4 + x) = color;
468       }
469       break;
470     }
471   }
472 }
473
474 void _PutPixelRGB(SDL_Surface *surface, Sint16 x, Sint16 y,
475                   Uint8 R, Uint8 G, Uint8 B)
476 {
477   _PutPixel(surface, x, y, SDL_MapRGB(surface->format, R, G, B));
478 }
479
480 void _PutPixel8(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
481 {
482   *((Uint8 *)surface->pixels + y*surface->pitch + x) = color;
483 }
484
485 void _PutPixel16(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
486 {
487   *((Uint16 *)surface->pixels + y*surface->pitch/2 + x) = color;
488 }
489
490 void _PutPixel24(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
491 {
492   Uint8 *pix;
493   int shift;
494
495   /* Gack - slow, but endian correct */
496   pix = (Uint8 *)surface->pixels + y * surface->pitch + x*3;
497   shift = surface->format->Rshift;
498   *(pix+shift/8) = color>>shift;
499   shift = surface->format->Gshift;
500   *(pix+shift/8) = color>>shift;
501   shift = surface->format->Bshift;
502   *(pix+shift/8) = color>>shift;
503 }
504
505 void _PutPixel32(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
506 {
507   *((Uint32 *)surface->pixels + y*surface->pitch/4 + x) = color;
508 }
509
510 void _PutPixelX(SDL_Surface *dest,Sint16 x,Sint16 y,Uint32 color)
511 {
512   switch (dest->format->BytesPerPixel)
513   {
514     case 1:
515       *((Uint8 *)dest->pixels + y*dest->pitch + x) = color;
516       break;
517
518     case 2:
519       *((Uint16 *)dest->pixels + y*dest->pitch/2 + x) = color;
520       break;
521
522     case 3:
523       _PutPixel24(dest,x,y,color);
524       break;
525
526     case 4:
527       *((Uint32 *)dest->pixels + y*dest->pitch/4 + x) = color;
528       break;
529   }
530 }
531
532 void sge_PutPixel(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
533 {
534   if (SDL_MUSTLOCK(surface))
535   {
536     if (SDL_LockSurface(surface) < 0)
537     {
538       return;
539     }
540   }
541
542   _PutPixel(surface, x, y, color);
543
544   if (SDL_MUSTLOCK(surface))
545   {
546     SDL_UnlockSurface(surface);
547   }
548 }
549
550 void sge_PutPixelRGB(SDL_Surface *surface, Sint16 x, Sint16 y,
551                   Uint8 r, Uint8 g, Uint8 b)
552 {
553   sge_PutPixel(surface, x, y, SDL_MapRGB(surface->format, r, g, b));
554 }
555
556 Sint32 sge_CalcYPitch(SDL_Surface *dest, Sint16 y)
557 {
558   if (y >= 0 && y <= dest->h - 1)
559   {
560     switch (dest->format->BytesPerPixel)
561     {
562       case 1:
563         return y*dest->pitch;
564         break;
565
566       case 2:
567         return y*dest->pitch/2;
568         break;
569
570       case 3:
571         return y*dest->pitch;
572         break;
573
574       case 4:
575         return y*dest->pitch/4;
576         break;
577     }
578   }
579
580   return -1;
581 }
582
583 void sge_pPutPixel(SDL_Surface *surface, Sint16 x, Sint32 ypitch, Uint32 color)
584 {
585   if (x >= 0 && x <= surface->w - 1 && ypitch >= 0)
586   {
587     switch (surface->format->BytesPerPixel)
588     {
589       case 1:
590       {
591         /* Assuming 8-bpp */
592         *((Uint8 *)surface->pixels + ypitch + x) = color;
593       }
594       break;
595
596       case 2:
597       {
598         /* Probably 15-bpp or 16-bpp */
599         *((Uint16 *)surface->pixels + ypitch + x) = color;
600       }
601       break;
602
603       case 3:
604       {
605         /* Slow 24-bpp mode, usually not used */
606         Uint8 *pix;
607         int shift;
608
609         /* Gack - slow, but endian correct */
610         pix = (Uint8 *)surface->pixels + ypitch + x*3;
611         shift = surface->format->Rshift;
612         *(pix+shift/8) = color>>shift;
613         shift = surface->format->Gshift;
614         *(pix+shift/8) = color>>shift;
615         shift = surface->format->Bshift;
616         *(pix+shift/8) = color>>shift;
617       }
618       break;
619
620       case 4:
621       {
622         /* Probably 32-bpp */
623         *((Uint32 *)surface->pixels + ypitch + x) = color;
624       }
625       break;
626     }
627   }
628 }
629
630 void sge_HLine(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y,
631                Uint32 Color)
632 {
633   SDL_Rect l;
634
635   if (SDL_MUSTLOCK(Surface))
636   {
637     if (SDL_LockSurface(Surface) < 0)
638     {
639       return;
640     }
641   }
642
643   if (x1 > x2)
644   {
645     Sint16 tmp = x1;
646     x1 = x2;
647     x2 = tmp;
648   }
649
650   /* Do the clipping */
651   if (y < 0 || y > Surface->h - 1 || x1 > Surface->w - 1 || x2 < 0)
652     return;
653   if (x1 < 0)
654     x1 = 0;
655   if (x2 > Surface->w - 1)
656     x2 = Surface->w - 1;
657
658   l.x = x1;
659   l.y = y;
660   l.w = x2 - x1 + 1;
661   l.h = 1;
662
663   SDL_FillRect(Surface, &l, Color);
664
665   if (SDL_MUSTLOCK(Surface))
666   {
667     SDL_UnlockSurface(Surface);
668   }
669 }
670
671 void sge_HLineRGB(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y,
672                   Uint8 R, Uint8 G, Uint8 B)
673 {
674   sge_HLine(Surface, x1, x2, y, SDL_MapRGB(Surface->format, R, G, B));
675 }
676
677 void _HLine(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y, Uint32 Color)
678 {
679   SDL_Rect l;
680
681   if (x1 > x2)
682   {
683     Sint16 tmp = x1;
684     x1 = x2;
685     x2 = tmp;
686   }
687
688   /* Do the clipping */
689   if (y < 0 || y > Surface->h - 1 || x1 > Surface->w - 1 || x2 < 0)
690     return;
691   if (x1 < 0)
692     x1 = 0;
693   if (x2 > Surface->w - 1)
694     x2 = Surface->w - 1;
695
696   l.x = x1;
697   l.y = y;
698   l.w = x2 - x1 + 1;
699   l.h = 1;
700
701   SDL_FillRect(Surface, &l, Color);
702 }
703
704 void sge_VLine(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2,
705                Uint32 Color)
706 {
707   SDL_Rect l;
708
709   if (SDL_MUSTLOCK(Surface))
710   {
711     if (SDL_LockSurface(Surface) < 0)
712     {
713       return;
714     }
715   }
716
717   if (y1 > y2)
718   {
719     Sint16 tmp = y1;
720     y1 = y2;
721     y2 = tmp;
722   }
723
724   /* Do the clipping */
725   if (x < 0 || x > Surface->w - 1 || y1 > Surface->h - 1 || y2 < 0)
726     return;
727   if (y1 < 0)
728     y1 = 0;
729   if (y2 > Surface->h - 1)
730     y2 = Surface->h - 1;
731
732   l.x = x;
733   l.y = y1;
734   l.w = 1;
735   l.h = y2 - y1 + 1;
736
737   SDL_FillRect(Surface, &l, Color);
738
739   if (SDL_MUSTLOCK(Surface))
740   {
741     SDL_UnlockSurface(Surface);
742   }
743 }
744
745 void sge_VLineRGB(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2,
746                   Uint8 R, Uint8 G, Uint8 B)
747 {
748   sge_VLine(Surface, x, y1, y2, SDL_MapRGB(Surface->format, R, G, B));
749 }
750
751 void _VLine(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2, Uint32 Color)
752 {
753   SDL_Rect l;
754
755   if (y1 > y2)
756   {
757     Sint16 tmp = y1;
758     y1 = y2;
759     y2 = tmp;
760   }
761
762   /* Do the clipping */
763   if (x < 0 || x > Surface->w - 1 || y1 > Surface->h - 1 || y2 < 0)
764     return;
765   if (y1 < 0)
766     y1 = 0;
767   if (y2 > Surface->h - 1)
768     y2 = Surface->h - 1;
769
770   l.x = x;
771   l.y = y1;
772   l.w = 1;
773   l.h = y2 - y1 + 1;
774
775   SDL_FillRect(Surface, &l, Color);
776 }
777
778 void sge_DoLine(SDL_Surface *Surface, Sint16 x1, Sint16 y1,
779                 Sint16 x2, Sint16 y2, Uint32 Color,
780                 void Callback(SDL_Surface *Surf, Sint16 X, Sint16 Y,
781                               Uint32 Color))
782 {
783   Sint16 dx, dy, sdx, sdy, x, y, px, py;
784
785   dx = x2 - x1;
786   dy = y2 - y1;
787
788   sdx = (dx < 0) ? -1 : 1;
789   sdy = (dy < 0) ? -1 : 1;
790
791   dx = sdx * dx + 1;
792   dy = sdy * dy + 1;
793
794   x = y = 0;
795
796   px = x1;
797   py = y1;
798
799   if (dx >= dy)
800   {
801     for (x = 0; x < dx; x++)
802     {
803       Callback(Surface, px, py, Color);
804
805       y += dy;
806       if (y >= dx)
807       {
808         y -= dx;
809         py += sdy;
810       }
811
812       px += sdx;
813     }
814   }
815   else
816   {
817     for (y = 0; y < dy; y++)
818     {
819       Callback(Surface, px, py, Color);
820
821       x += dx;
822       if (x >= dy)
823       {
824         x -= dy;
825         px += sdx;
826       }
827
828       py += sdy;
829     }
830   }
831 }
832
833 void sge_DoLineRGB(SDL_Surface *Surface, Sint16 X1, Sint16 Y1,
834                    Sint16 X2, Sint16 Y2, Uint8 R, Uint8 G, Uint8 B,
835                    void Callback(SDL_Surface *Surf, Sint16 X, Sint16 Y,
836                                  Uint32 Color))
837 {
838   sge_DoLine(Surface, X1, Y1, X2, Y2,
839              SDL_MapRGB(Surface->format, R, G, B), Callback);
840 }
841
842 void sge_Line(SDL_Surface *Surface, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2,
843               Uint32 Color)
844 {
845   if (SDL_MUSTLOCK(Surface))
846   {
847     if (SDL_LockSurface(Surface) < 0)
848       return;
849    }
850
851    /* Draw the line */
852    sge_DoLine(Surface, x1, y1, x2, y2, Color, _PutPixel);
853
854    /* unlock the display */
855    if (SDL_MUSTLOCK(Surface))
856    {
857       SDL_UnlockSurface(Surface);
858    }
859 }
860
861 void sge_LineRGB(SDL_Surface *Surface, Sint16 x1, Sint16 y1, Sint16 x2,
862                  Sint16 y2, Uint8 R, Uint8 G, Uint8 B)
863 {
864   sge_Line(Surface, x1, y1, x2, y2, SDL_MapRGB(Surface->format, R, G, B));
865 }
866
867 inline void SDLPutPixel(Bitmap *dst_bitmap, int x, int y, Pixel pixel)
868 {
869 #ifdef FULLSCREEN_BUG
870   if (dst_bitmap == backbuffer || dst_bitmap == window)
871   {
872     x += video_xoffset;
873     y += video_yoffset;
874   }
875 #endif
876
877   sge_PutPixel(dst_bitmap->surface, x, y, pixel);
878 }
879
880
881 /*
882   -----------------------------------------------------------------------------
883   quick (no, it's slow) and dirty hack to "invert" rectangle inside SDL surface
884   -----------------------------------------------------------------------------
885 */
886
887 inline void SDLInvertArea(Bitmap *bitmap, int src_x, int src_y,
888                           int width, int height, Uint32 color)
889 {
890   int x, y;
891
892   for (y=src_y; y < src_y + height; y++)
893   {
894     for (x=src_x; x < src_x + width; x++)
895     {
896       Uint32 pixel = SDLGetPixel(bitmap, x, y);
897
898       SDLPutPixel(bitmap, x, y, pixel == BLACK_PIXEL ? color : BLACK_PIXEL);
899     }
900   }
901 }
902
903 inline void SDLCopyInverseMasked(Bitmap *src_bitmap, Bitmap *dst_bitmap,
904                                  int src_x, int src_y, int width, int height,
905                                  int dst_x, int dst_y)
906 {
907   int x, y;
908
909   for (y=0; y < height; y++)
910   {
911     for (x=0; x < width; x++)
912     {
913       Uint32 pixel = SDLGetPixel(src_bitmap, src_x + x, src_y + y);
914
915       if (pixel != BLACK_PIXEL)
916         SDLPutPixel(dst_bitmap, dst_x + x, dst_y + y, BLACK_PIXEL);
917     }
918   }
919 }
920
921
922 /* ========================================================================= */
923 /* The following functions were taken from the SDL_gfx library version 2.0.3 */
924 /* (Rotozoomer) by Andreas Schiffler                                         */
925 /* http://www.ferzkopp.net/Software/SDL_gfx-2.0/index.html                   */
926 /* ========================================================================= */
927
928 /*
929   -----------------------------------------------------------------------------
930   32 bit zoomer
931
932   zoomes 32bit RGBA/ABGR 'src' surface to 'dst' surface.
933   -----------------------------------------------------------------------------
934 */
935
936 typedef struct
937 {
938   Uint8 r;
939   Uint8 g;
940   Uint8 b;
941   Uint8 a;
942 } tColorRGBA;
943
944 int zoomSurfaceRGBA(SDL_Surface *src, SDL_Surface *dst)
945 {
946   int x, y, sx, sy, *sax, *say, *csax, *csay, csx, csy;
947   tColorRGBA *sp, *csp, *dp;
948   int sgap, dgap;
949
950   /* variable setup */
951   sx = (int) (65536.0 * (float) src->w / (float) dst->w);
952   sy = (int) (65536.0 * (float) src->h / (float) dst->h);
953
954   /* allocate memory for row increments */
955   sax = (int *)checked_malloc((dst->w + 1) * sizeof(Uint32));
956   say = (int *)checked_malloc((dst->h + 1) * sizeof(Uint32));
957
958   /* precalculate row increments */
959   csx = 0;
960   csax = sax;
961   for (x = 0; x <= dst->w; x++)
962   {
963     *csax = csx;
964     csax++;
965     csx &= 0xffff;
966     csx += sx;
967   }
968
969   csy = 0;
970   csay = say;
971   for (y = 0; y <= dst->h; y++)
972   {
973     *csay = csy;
974     csay++;
975     csy &= 0xffff;
976     csy += sy;
977   }
978
979   /* pointer setup */
980   sp = csp = (tColorRGBA *) src->pixels;
981   dp = (tColorRGBA *) dst->pixels;
982   sgap = src->pitch - src->w * 4;
983   dgap = dst->pitch - dst->w * 4;
984
985   csay = say;
986   for (y = 0; y < dst->h; y++)
987   {
988     sp = csp;
989     csax = sax;
990
991     for (x = 0; x < dst->w; x++)
992     {
993       /* draw */
994       *dp = *sp;
995
996       /* advance source pointers */
997       csax++;
998       sp += (*csax >> 16);
999
1000       /* advance destination pointer */
1001       dp++;
1002     }
1003
1004     /* advance source pointer */
1005     csay++;
1006     csp = (tColorRGBA *) ((Uint8 *) csp + (*csay >> 16) * src->pitch);
1007
1008     /* advance destination pointers */
1009     dp = (tColorRGBA *) ((Uint8 *) dp + dgap);
1010   }
1011
1012   free(sax);
1013   free(say);
1014
1015   return 0;
1016 }
1017
1018 /*
1019   -----------------------------------------------------------------------------
1020   8 bit zoomer
1021
1022   zoomes 8 bit palette/Y 'src' surface to 'dst' surface
1023   -----------------------------------------------------------------------------
1024 */
1025
1026 int zoomSurfaceY(SDL_Surface * src, SDL_Surface * dst)
1027 {
1028   Uint32 x, y, sx, sy, *sax, *say, *csax, *csay, csx, csy;
1029   Uint8 *sp, *dp, *csp;
1030   int dgap;
1031
1032   /* variable setup */
1033   sx = (Uint32) (65536.0 * (float) src->w / (float) dst->w);
1034   sy = (Uint32) (65536.0 * (float) src->h / (float) dst->h);
1035
1036   /* allocate memory for row increments */
1037   sax = (Uint32 *)checked_malloc(dst->w * sizeof(Uint32));
1038   say = (Uint32 *)checked_malloc(dst->h * sizeof(Uint32));
1039
1040   /* precalculate row increments */
1041   csx = 0;
1042   csax = sax;
1043   for (x = 0; x < dst->w; x++)
1044   {
1045     csx += sx;
1046     *csax = (csx >> 16);
1047     csx &= 0xffff;
1048     csax++;
1049   }
1050
1051   csy = 0;
1052   csay = say;
1053   for (y = 0; y < dst->h; y++)
1054   {
1055     csy += sy;
1056     *csay = (csy >> 16);
1057     csy &= 0xffff;
1058     csay++;
1059   }
1060
1061   csx = 0;
1062   csax = sax;
1063   for (x = 0; x < dst->w; x++)
1064   {
1065     csx += (*csax);
1066     csax++;
1067   }
1068
1069   csy = 0;
1070   csay = say;
1071   for (y = 0; y < dst->h; y++)
1072   {
1073     csy += (*csay);
1074     csay++;
1075   }
1076
1077   /* pointer setup */
1078   sp = csp = (Uint8 *) src->pixels;
1079   dp = (Uint8 *) dst->pixels;
1080   dgap = dst->pitch - dst->w;
1081
1082   /* draw */
1083   csay = say;
1084   for (y = 0; y < dst->h; y++)
1085   {
1086     csax = sax;
1087     sp = csp;
1088     for (x = 0; x < dst->w; x++)
1089     {
1090       /* draw */
1091       *dp = *sp;
1092
1093       /* advance source pointers */
1094       sp += (*csax);
1095       csax++;
1096
1097       /* advance destination pointer */
1098       dp++;
1099     }
1100
1101     /* advance source pointer (for row) */
1102     csp += ((*csay) * src->pitch);
1103     csay++;
1104
1105     /* advance destination pointers */
1106     dp += dgap;
1107   }
1108
1109   free(sax);
1110   free(say);
1111
1112   return 0;
1113 }
1114
1115 /*
1116   -----------------------------------------------------------------------------
1117   zoomSurface()
1118
1119   Zoomes a 32bit or 8bit 'src' surface to newly created 'dst' surface.
1120   'zoomx' and 'zoomy' are scaling factors for width and height.
1121   If 'smooth' is 1 then the destination 32bit surface is anti-aliased.
1122   If the surface is not 8bit or 32bit RGBA/ABGR it will be converted
1123   into a 32bit RGBA format on the fly.
1124   -----------------------------------------------------------------------------
1125 */
1126
1127 SDL_Surface *zoomSurface(SDL_Surface *src, int dst_width, int dst_height)
1128 {
1129   SDL_Surface *zoom_src = NULL;
1130   SDL_Surface *zoom_dst = NULL;
1131   boolean is_converted = FALSE;
1132   boolean is_32bit;
1133   int i;
1134
1135   if (src == NULL)
1136     return NULL;
1137
1138   /* determine if source surface is 32 bit or 8 bit */
1139   is_32bit = (src->format->BitsPerPixel == 32);
1140
1141   if (is_32bit || src->format->BitsPerPixel == 8)
1142   {
1143     /* use source surface 'as is' */
1144     zoom_src = src;
1145   }
1146   else
1147   {
1148     /* new source surface is 32 bit with a defined RGB ordering */
1149     zoom_src = SDL_CreateRGBSurface(SDL_SWSURFACE, src->w, src->h, 32,
1150                                     0x000000ff, 0x0000ff00, 0x00ff0000, 0);
1151     SDL_BlitSurface(src, NULL, zoom_src, NULL);
1152     is_32bit = TRUE;
1153     is_converted = TRUE;
1154   }
1155
1156   /* allocate surface to completely contain the zoomed surface */
1157   if (is_32bit)
1158   {
1159     /* target surface is 32 bit with source RGBA/ABGR ordering */
1160     zoom_dst = SDL_CreateRGBSurface(SDL_SWSURFACE, dst_width, dst_height, 32,
1161                                     zoom_src->format->Rmask,
1162                                     zoom_src->format->Gmask,
1163                                     zoom_src->format->Bmask, 0);
1164   }
1165   else
1166   {
1167     /* target surface is 8 bit */
1168     zoom_dst = SDL_CreateRGBSurface(SDL_SWSURFACE, dst_width, dst_height, 8,
1169                                     0, 0, 0, 0);
1170   }
1171
1172   /* lock source surface */
1173   SDL_LockSurface(zoom_src);
1174
1175   /* check which kind of surface we have */
1176   if (is_32bit)
1177   {
1178     /* call the 32 bit transformation routine to do the zooming */
1179     zoomSurfaceRGBA(zoom_src, zoom_dst);
1180   }
1181   else
1182   {
1183     /* copy palette */
1184     for (i=0; i < zoom_src->format->palette->ncolors; i++)
1185       zoom_dst->format->palette->colors[i] =
1186         zoom_src->format->palette->colors[i];
1187     zoom_dst->format->palette->ncolors = zoom_src->format->palette->ncolors;
1188
1189     /* call the 8 bit transformation routine to do the zooming */
1190     zoomSurfaceY(zoom_src, zoom_dst);
1191   }
1192
1193   /* unlock source surface */
1194   SDL_UnlockSurface(zoom_src);
1195
1196   /* free temporary surface */
1197   if (is_converted)
1198     SDL_FreeSurface(zoom_src);
1199
1200   /* return destination surface */
1201   return zoom_dst;
1202 }
1203
1204 void SDLZoomBitmap(Bitmap *src_bitmap, Bitmap *dst_bitmap)
1205 {
1206   SDL_Surface *sdl_surface_tmp;
1207   int dst_width = dst_bitmap->width;
1208   int dst_height = dst_bitmap->height;
1209
1210   /* throw away old destination surface */
1211   SDL_FreeSurface(dst_bitmap->surface);
1212
1213   /* create zoomed temporary surface from source surface */
1214   sdl_surface_tmp = zoomSurface(src_bitmap->surface, dst_width, dst_height);
1215
1216   /* create native format destination surface from zoomed temporary surface */
1217   dst_bitmap->surface = SDL_DisplayFormat(sdl_surface_tmp);
1218
1219   /* free temporary surface */
1220   SDL_FreeSurface(sdl_surface_tmp);
1221 }
1222
1223
1224 /* ========================================================================= */
1225 /* load image to bitmap                                                      */
1226 /* ========================================================================= */
1227
1228 Bitmap *SDLLoadImage(char *filename)
1229 {
1230   Bitmap *new_bitmap = CreateBitmapStruct();
1231   SDL_Surface *sdl_image_tmp;
1232
1233   /* load image to temporary surface */
1234   if ((sdl_image_tmp = IMG_Load(filename)) == NULL)
1235   {
1236     SetError("IMG_Load(): %s", SDL_GetError());
1237     return NULL;
1238   }
1239
1240   /* create native non-transparent surface for current image */
1241   if ((new_bitmap->surface = SDL_DisplayFormat(sdl_image_tmp)) == NULL)
1242   {
1243     SetError("SDL_DisplayFormat(): %s", SDL_GetError());
1244     return NULL;
1245   }
1246
1247   /* create native transparent surface for current image */
1248   SDL_SetColorKey(sdl_image_tmp, SDL_SRCCOLORKEY,
1249                   SDL_MapRGB(sdl_image_tmp->format, 0x00, 0x00, 0x00));
1250   if ((new_bitmap->surface_masked = SDL_DisplayFormat(sdl_image_tmp)) == NULL)
1251   {
1252     SetError("SDL_DisplayFormat(): %s", SDL_GetError());
1253     return NULL;
1254   }
1255
1256   /* free temporary surface */
1257   SDL_FreeSurface(sdl_image_tmp);
1258
1259   new_bitmap->width = new_bitmap->surface->w;
1260   new_bitmap->height = new_bitmap->surface->h;
1261
1262   return new_bitmap;
1263 }
1264
1265
1266 /* ------------------------------------------------------------------------- */
1267 /* custom cursor fuctions                                                    */
1268 /* ------------------------------------------------------------------------- */
1269
1270 static SDL_Cursor *create_cursor(struct MouseCursorInfo *cursor_info)
1271 {
1272   return SDL_CreateCursor(cursor_info->data, cursor_info->mask,
1273                           cursor_info->width, cursor_info->height,
1274                           cursor_info->hot_x, cursor_info->hot_y);
1275 }
1276
1277 void SDLSetMouseCursor(struct MouseCursorInfo *cursor_info)
1278 {
1279   static struct MouseCursorInfo *last_cursor_info = NULL;
1280   static struct MouseCursorInfo *last_cursor_info2 = NULL;
1281   static SDL_Cursor *cursor_default = NULL;
1282   static SDL_Cursor *cursor_current = NULL;
1283
1284   /* if invoked for the first time, store the SDL default cursor */
1285   if (cursor_default == NULL)
1286     cursor_default = SDL_GetCursor();
1287
1288   /* only create new cursor if cursor info (custom only) has changed */
1289   if (cursor_info != NULL && cursor_info != last_cursor_info)
1290   {
1291     cursor_current = create_cursor(cursor_info);
1292     last_cursor_info = cursor_info;
1293   }
1294
1295   /* only set new cursor if cursor info (custom or NULL) has changed */
1296   if (cursor_info != last_cursor_info2)
1297     SDL_SetCursor(cursor_info ? cursor_current : cursor_default);
1298
1299   last_cursor_info2 = cursor_info;
1300 }
1301
1302
1303 /* ========================================================================= */
1304 /* audio functions                                                           */
1305 /* ========================================================================= */
1306
1307 inline void SDLOpenAudio(void)
1308 {
1309   if (strcmp(setup.system.sdl_audiodriver, ARG_DEFAULT) != 0)
1310     putenv(getStringCat2("SDL_AUDIODRIVER=", setup.system.sdl_audiodriver));
1311
1312   if (SDL_InitSubSystem(SDL_INIT_AUDIO) < 0)
1313   {
1314     Error(ERR_WARN, "SDL_InitSubSystem() failed: %s", SDL_GetError());
1315     return;
1316   }
1317
1318   if (Mix_OpenAudio(DEFAULT_AUDIO_SAMPLE_RATE, MIX_DEFAULT_FORMAT,
1319                     AUDIO_NUM_CHANNELS_STEREO,
1320                     setup.system.audio_fragment_size) < 0)
1321   {
1322     Error(ERR_WARN, "Mix_OpenAudio() failed: %s", SDL_GetError());
1323     return;
1324   }
1325
1326   audio.sound_available = TRUE;
1327   audio.music_available = TRUE;
1328   audio.loops_available = TRUE;
1329   audio.sound_enabled = TRUE;
1330
1331   /* set number of available mixer channels */
1332   audio.num_channels = Mix_AllocateChannels(NUM_MIXER_CHANNELS);
1333   audio.music_channel = MUSIC_CHANNEL;
1334   audio.first_sound_channel = FIRST_SOUND_CHANNEL;
1335
1336   Mixer_InitChannels();
1337 }
1338
1339 inline void SDLCloseAudio(void)
1340 {
1341   Mix_HaltMusic();
1342   Mix_HaltChannel(-1);
1343
1344   Mix_CloseAudio();
1345   SDL_QuitSubSystem(SDL_INIT_AUDIO);
1346 }
1347
1348
1349 /* ========================================================================= */
1350 /* event functions                                                           */
1351 /* ========================================================================= */
1352
1353 inline void SDLNextEvent(Event *event)
1354 {
1355   SDL_WaitEvent(event);
1356
1357 #ifdef FULLSCREEN_BUG
1358   if (event->type == EVENT_BUTTONPRESS ||
1359       event->type == EVENT_BUTTONRELEASE)
1360   {
1361     if (((ButtonEvent *)event)->x > video_xoffset)
1362       ((ButtonEvent *)event)->x -= video_xoffset;
1363     else
1364       ((ButtonEvent *)event)->x = 0;
1365     if (((ButtonEvent *)event)->y > video_yoffset)
1366       ((ButtonEvent *)event)->y -= video_yoffset;
1367     else
1368       ((ButtonEvent *)event)->y = 0;
1369   }
1370   else if (event->type == EVENT_MOTIONNOTIFY)
1371   {
1372     if (((MotionEvent *)event)->x > video_xoffset)
1373       ((MotionEvent *)event)->x -= video_xoffset;
1374     else
1375       ((MotionEvent *)event)->x = 0;
1376     if (((MotionEvent *)event)->y > video_yoffset)
1377       ((MotionEvent *)event)->y -= video_yoffset;
1378     else
1379       ((MotionEvent *)event)->y = 0;
1380   }
1381 #endif
1382 }
1383
1384
1385 /* ========================================================================= */
1386 /* joystick functions                                                        */
1387 /* ========================================================================= */
1388
1389 static SDL_Joystick *sdl_joystick[MAX_PLAYERS] = { NULL, NULL, NULL, NULL };
1390 static int sdl_js_axis[MAX_PLAYERS][2]   = { {0, 0}, {0, 0}, {0, 0}, {0, 0} };
1391 static int sdl_js_button[MAX_PLAYERS][2] = { {0, 0}, {0, 0}, {0, 0}, {0, 0} };
1392
1393 static boolean SDLOpenJoystick(int nr)
1394 {
1395   if (nr < 0 || nr > MAX_PLAYERS)
1396     return FALSE;
1397
1398   return ((sdl_joystick[nr] = SDL_JoystickOpen(nr)) == NULL ? FALSE : TRUE);
1399 }
1400
1401 static void SDLCloseJoystick(int nr)
1402 {
1403   if (nr < 0 || nr > MAX_PLAYERS)
1404     return;
1405
1406   SDL_JoystickClose(sdl_joystick[nr]);
1407 }
1408
1409 static boolean SDLCheckJoystickOpened(int nr)
1410 {
1411   if (nr < 0 || nr > MAX_PLAYERS)
1412     return FALSE;
1413
1414   return (SDL_JoystickOpened(nr) ? TRUE : FALSE);
1415 }
1416
1417 void HandleJoystickEvent(Event *event)
1418 {
1419   switch(event->type)
1420   {
1421     case SDL_JOYAXISMOTION:
1422       if (event->jaxis.axis < 2)
1423         sdl_js_axis[event->jaxis.which][event->jaxis.axis]= event->jaxis.value;
1424       break;
1425
1426     case SDL_JOYBUTTONDOWN:
1427       if (event->jbutton.button < 2)
1428         sdl_js_button[event->jbutton.which][event->jbutton.button] = TRUE;
1429       break;
1430
1431     case SDL_JOYBUTTONUP:
1432       if (event->jbutton.button < 2)
1433         sdl_js_button[event->jbutton.which][event->jbutton.button] = FALSE;
1434       break;
1435
1436     default:
1437       break;
1438   }
1439 }
1440
1441 void SDLInitJoysticks()
1442 {
1443   static boolean sdl_joystick_subsystem_initialized = FALSE;
1444   int i;
1445
1446   if (!sdl_joystick_subsystem_initialized)
1447   {
1448     sdl_joystick_subsystem_initialized = TRUE;
1449
1450     if (SDL_Init(SDL_INIT_JOYSTICK) < 0)
1451     {
1452       Error(ERR_EXIT, "SDL_Init() failed: %s", SDL_GetError());
1453       return;
1454     }
1455   }
1456
1457   for (i=0; i<MAX_PLAYERS; i++)
1458   {
1459     char *device_name = setup.input[i].joy.device_name;
1460     int joystick_nr = getJoystickNrFromDeviceName(device_name);
1461
1462     if (joystick_nr >= SDL_NumJoysticks())
1463       joystick_nr = -1;
1464
1465     /* misuse joystick file descriptor variable to store joystick number */
1466     joystick.fd[i] = joystick_nr;
1467
1468     /* this allows subsequent calls to 'InitJoysticks' for re-initialization */
1469     if (SDLCheckJoystickOpened(joystick_nr))
1470       SDLCloseJoystick(joystick_nr);
1471
1472     if (!setup.input[i].use_joystick)
1473       continue;
1474
1475     if (!SDLOpenJoystick(joystick_nr))
1476     {
1477       Error(ERR_WARN, "cannot open joystick %d", joystick_nr);
1478       continue;
1479     }
1480
1481     joystick.status = JOYSTICK_ACTIVATED;
1482   }
1483 }
1484
1485 boolean SDLReadJoystick(int nr, int *x, int *y, boolean *b1, boolean *b2)
1486 {
1487   if (nr < 0 || nr >= MAX_PLAYERS)
1488     return FALSE;
1489
1490   if (x != NULL)
1491     *x = sdl_js_axis[nr][0];
1492   if (y != NULL)
1493     *y = sdl_js_axis[nr][1];
1494
1495   if (b1 != NULL)
1496     *b1 = sdl_js_button[nr][0];
1497   if (b2 != NULL)
1498     *b2 = sdl_js_button[nr][1];
1499
1500   return TRUE;
1501 }
1502
1503 #endif /* TARGET_SDL */