rocksndiamonds-2.0.1
[rocksndiamonds.git] / src / libgame / sdl.c
1 /***********************************************************
2 * Artsoft Retro-Game Library                               *
3 *----------------------------------------------------------*
4 * (c) 1994-2001 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 "misc.h"
17
18
19 #if defined(TARGET_SDL)
20
21 /* ========================================================================= */
22 /* video functions                                                           */
23 /* ========================================================================= */
24
25 /* functions from SGE library */
26 inline void sge_Line(SDL_Surface *, Sint16, Sint16, Sint16, Sint16, Uint32);
27
28 #ifdef PLATFORM_WIN32
29 #define FULLSCREEN_BUG
30 #endif
31
32 /* stuff needed to work around SDL/Windows fullscreen drawing bug */
33 static int fullscreen_width;
34 static int fullscreen_height;
35 static int fullscreen_xoffset;
36 static int fullscreen_yoffset;
37 static int video_xoffset;
38 static int video_yoffset;
39
40 inline void SDLInitVideoDisplay(void)
41 {
42   /* initialize SDL video */
43   if (SDL_InitSubSystem(SDL_INIT_VIDEO) < 0)
44     Error(ERR_EXIT, "SDL_InitSubSystem() failed: %s", SDL_GetError());
45
46   /* set default SDL depth */
47   video.default_depth = SDL_GetVideoInfo()->vfmt->BitsPerPixel;
48 }
49
50 inline void SDLInitVideoBuffer(DrawBuffer **backbuffer, DrawWindow **window,
51                                boolean fullscreen)
52 {
53 #ifdef FULLSCREEN_BUG
54   int i;
55   static int screen_xy[][2] =
56   {
57     {  640, 480 },
58     {  800, 600 },
59     { 1024, 768 },
60     {   -1,  -1 }
61   };
62 #endif
63
64   /* default: normal game window size */
65   fullscreen_width = video.width;
66   fullscreen_height = video.height;
67   fullscreen_xoffset = 0;
68   fullscreen_yoffset = 0;
69
70 #ifdef FULLSCREEN_BUG
71   for (i=0; screen_xy[i][0] != -1; i++)
72   {
73     if (video.width <= screen_xy[i][0] && video.height <= screen_xy[i][1])
74     {
75       fullscreen_width = screen_xy[i][0];
76       fullscreen_height = screen_xy[i][1];
77       break;
78     }
79   }
80
81   fullscreen_xoffset = (fullscreen_width - video.width) / 2;
82   fullscreen_yoffset = (fullscreen_height - video.height) / 2;
83 #endif
84
85   /* open SDL video output device (window or fullscreen mode) */
86   if (!SDLSetVideoMode(backbuffer, fullscreen))
87     Error(ERR_EXIT, "setting video mode failed");
88
89   /* set window and icon title */
90   SDL_WM_SetCaption(program.window_title, program.window_title);
91
92   /* SDL cannot directly draw to the visible video framebuffer like X11,
93      but always uses a backbuffer, which is then blitted to the visible
94      video framebuffer with 'SDL_UpdateRect' (or replaced with the current
95      visible video framebuffer with 'SDL_Flip', if the hardware supports
96      this). Therefore do not use an additional backbuffer for drawing, but
97      use a symbolic buffer (distinguishable from the SDL backbuffer) called
98      'window', which indicates that the SDL backbuffer should be updated to
99      the visible video framebuffer when attempting to blit to it.
100
101      For convenience, it seems to be a good idea to create this symbolic
102      buffer 'window' at the same size as the SDL backbuffer. Although it
103      should never be drawn to directly, it would do no harm nevertheless. */
104
105   /* create additional (symbolic) buffer for double-buffering */
106   *window = CreateBitmap(video.width, video.height, video.depth);
107 }
108
109 inline boolean SDLSetVideoMode(DrawBuffer **backbuffer, boolean fullscreen)
110 {
111   boolean success = TRUE;
112   int surface_flags_fullscreen = SURFACE_FLAGS | SDL_FULLSCREEN;
113   int surface_flags_window = SURFACE_FLAGS;
114   SDL_Surface *new_surface = NULL;
115
116   if (*backbuffer == NULL)
117     *backbuffer = CreateBitmapStruct();
118
119   if (fullscreen && !video.fullscreen_enabled && video.fullscreen_available)
120   {
121     video_xoffset = fullscreen_xoffset;
122     video_yoffset = fullscreen_yoffset;
123
124     /* switch display to fullscreen mode, if available */
125     if ((new_surface = SDL_SetVideoMode(fullscreen_width, fullscreen_height,
126                                         video.depth, surface_flags_fullscreen))
127         == NULL)
128     {
129       /* switching display to fullscreen mode failed */
130       Error(ERR_WARN, "SDL_SetVideoMode() failed: %s", SDL_GetError());
131
132       /* do not try it again */
133       video.fullscreen_available = FALSE;
134       success = FALSE;
135     }
136     else
137     {
138       (*backbuffer)->surface = new_surface;
139
140       video.fullscreen_enabled = TRUE;
141       success = TRUE;
142     }
143   }
144
145   if ((!fullscreen && video.fullscreen_enabled) || new_surface == NULL)
146   {
147     video_xoffset = 0;
148     video_yoffset = 0;
149
150     /* switch display to window mode */
151     if ((new_surface = SDL_SetVideoMode(video.width, video.height,
152                                         video.depth, surface_flags_window))
153         == NULL)
154     {
155       /* switching display to window mode failed -- should not happen */
156       Error(ERR_WARN, "SDL_SetVideoMode() failed: %s", SDL_GetError());
157
158       success = FALSE;
159     }
160     else
161     {
162       (*backbuffer)->surface = new_surface;
163
164       video.fullscreen_enabled = FALSE;
165       success = TRUE;
166     }
167   }
168
169   return success;
170 }
171
172 inline void SDLCopyArea(Bitmap *src_bitmap, Bitmap *dst_bitmap,
173                         int src_x, int src_y,
174                         int width, int height,
175                         int dst_x, int dst_y, int copy_mode)
176 {
177   Bitmap *real_dst_bitmap = (dst_bitmap == window ? backbuffer : dst_bitmap);
178   SDL_Rect src_rect, dst_rect;
179
180 #ifdef FULLSCREEN_BUG
181   if (src_bitmap == backbuffer)
182   {
183     src_x += video_xoffset;
184     src_y += video_yoffset;
185   }
186 #endif
187
188   src_rect.x = src_x;
189   src_rect.y = src_y;
190   src_rect.w = width;
191   src_rect.h = height;
192
193 #ifdef FULLSCREEN_BUG
194   if (dst_bitmap == backbuffer || dst_bitmap == window)
195   {
196     dst_x += video_xoffset;
197     dst_y += video_yoffset;
198   }
199 #endif
200
201   dst_rect.x = dst_x;
202   dst_rect.y = dst_y;
203   dst_rect.w = width;
204   dst_rect.h = height;
205
206   if (src_bitmap != backbuffer || dst_bitmap != window)
207     SDL_BlitSurface((copy_mode == SDLCOPYAREA_MASKED ?
208                      src_bitmap->surface_masked : src_bitmap->surface),
209                     &src_rect, real_dst_bitmap->surface, &dst_rect);
210
211   if (dst_bitmap == window)
212     SDL_UpdateRect(backbuffer->surface, dst_x, dst_y, width, height);
213 }
214
215 inline void SDLFillRectangle(Bitmap *dst_bitmap, int x, int y,
216                              int width, int height, unsigned int color)
217 {
218   Bitmap *real_dst_bitmap = (dst_bitmap == window ? backbuffer : dst_bitmap);
219   SDL_Rect rect;
220   unsigned int color_r = (color >> 16) && 0xff;
221   unsigned int color_g = (color >>  8) && 0xff;
222   unsigned int color_b = (color >>  0) && 0xff;
223
224 #ifdef FULLSCREEN_BUG
225   if (dst_bitmap == backbuffer || dst_bitmap == window)
226   {
227     x += video_xoffset;
228     y += video_yoffset;
229   }
230 #endif
231
232   rect.x = x;
233   rect.y = y;
234   rect.w = width;
235   rect.h = height;
236
237   SDL_FillRect(real_dst_bitmap->surface, &rect,
238                SDL_MapRGB(real_dst_bitmap->surface->format,
239                           color_r, color_g, color_b));
240
241   if (dst_bitmap == window)
242     SDL_UpdateRect(backbuffer->surface, x, y, width, height);
243 }
244
245 inline void SDLDrawSimpleLine(Bitmap *dst_bitmap, int from_x, int from_y,
246                               int to_x, int to_y, unsigned int color)
247 {
248   SDL_Surface *surface = dst_bitmap->surface;
249   SDL_Rect rect;
250   unsigned int color_r = (color >> 16) & 0xff;
251   unsigned int color_g = (color >>  8) & 0xff;
252   unsigned int color_b = (color >>  0) & 0xff;
253
254   if (from_x > to_x)
255     swap_numbers(&from_x, &to_x);
256
257   if (from_y > to_y)
258     swap_numbers(&from_y, &to_y);
259
260   rect.x = from_x;
261   rect.y = from_y;
262   rect.w = (to_x - from_x + 1);
263   rect.h = (to_y - from_y + 1);
264
265 #ifdef FULLSCREEN_BUG
266   if (dst_bitmap == backbuffer || dst_bitmap == window)
267   {
268     rect.x += video_xoffset;
269     rect.y += video_yoffset;
270   }
271 #endif
272
273   SDL_FillRect(surface, &rect,
274                SDL_MapRGB(surface->format, color_r, color_g, color_b));
275 }
276
277 inline void SDLDrawLine(Bitmap *dst_bitmap, int from_x, int from_y,
278                         int to_x, int to_y, Uint32 color)
279 {
280 #ifdef FULLSCREEN_BUG
281   if (dst_bitmap == backbuffer || dst_bitmap == window)
282   {
283     from_x += video_xoffset;
284     from_y += video_yoffset;
285     to_x += video_xoffset;
286     to_y += video_yoffset;
287   }
288 #endif
289
290   sge_Line(dst_bitmap->surface, from_x, from_y, to_x, to_y, color);
291 }
292
293 #if 0
294 inline void SDLDrawLines(SDL_Surface *surface, struct XY *points,
295                          int num_points, Uint32 color)
296 {
297   int i, x, y;
298   int line_width = 4;
299
300   for (i=0; i<num_points - 1; i++)
301   {
302     for (x=0; x<line_width; x++)
303     {
304       for (y=0; y<line_width; y++)
305       {
306         int dx = x - line_width / 2;
307         int dy = y - line_width / 2;
308
309         if ((x == 0 && y == 0) ||
310             (x == 0 && y == line_width - 1) ||
311             (x == line_width - 1 && y == 0) ||
312             (x == line_width - 1 && y == line_width - 1))
313           continue;
314
315         sge_Line(surface, points[i].x + dx, points[i].y + dy,
316                  points[i+1].x + dx, points[i+1].y + dy, color);
317       }
318     }
319   }
320 }
321 #endif
322
323 inline Pixel SDLGetPixel(Bitmap *dst_bitmap, int x, int y)
324 {
325   SDL_Surface *surface = dst_bitmap->surface;
326
327 #ifdef FULLSCREEN_BUG
328   if (dst_bitmap == backbuffer || dst_bitmap == window)
329   {
330     x += video_xoffset;
331     y += video_yoffset;
332   }
333 #endif
334
335   switch (surface->format->BytesPerPixel)
336   {
337     case 1:             /* assuming 8-bpp */
338     {
339       return *((Uint8 *)surface->pixels + y * surface->pitch + x);
340     }
341     break;
342
343     case 2:             /* probably 15-bpp or 16-bpp */
344     {
345       return *((Uint16 *)surface->pixels + y * surface->pitch / 2 + x);
346     }
347     break;
348
349   case 3:               /* slow 24-bpp mode; usually not used */
350     {
351       /* does this work? */
352       Uint8 *pix = (Uint8 *)surface->pixels + y * surface->pitch + x * 3;
353       Uint32 color = 0;
354       int shift;
355
356       shift = surface->format->Rshift;
357       color |= *(pix + shift / 8) >> shift;
358       shift = surface->format->Gshift;
359       color |= *(pix + shift / 8) >> shift;
360       shift = surface->format->Bshift;
361       color |= *(pix + shift / 8) >> shift;
362
363       return color;
364     }
365     break;
366
367   case 4:               /* probably 32-bpp */
368     {
369       return *((Uint32 *)surface->pixels + y * surface->pitch / 4 + x);
370     }
371     break;
372   }
373
374   return 0;
375 }
376
377
378 /* ========================================================================= */
379 /* The following functions have been taken from the SGE library              */
380 /* (SDL Graphics Extension Library) by Anders Lindström                      */
381 /* http://www.etek.chalmers.se/~e8cal1/sge/index.html                        */
382 /* ========================================================================= */
383
384 void _PutPixel(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
385 {
386   if (x >= 0 && x <= surface->w - 1 && y >= 0 && y <= surface->h - 1)
387   {
388     switch (surface->format->BytesPerPixel)
389     {
390       case 1:
391       {
392         /* Assuming 8-bpp */
393         *((Uint8 *)surface->pixels + y*surface->pitch + x) = color;
394       }
395       break;
396
397       case 2:
398       {
399         /* Probably 15-bpp or 16-bpp */
400         *((Uint16 *)surface->pixels + y*surface->pitch/2 + x) = color;
401       }
402       break;
403
404       case 3:
405       {
406         /* Slow 24-bpp mode, usually not used */
407         Uint8 *pix;
408         int shift;
409
410         /* Gack - slow, but endian correct */
411         pix = (Uint8 *)surface->pixels + y * surface->pitch + x*3;
412         shift = surface->format->Rshift;
413         *(pix+shift/8) = color>>shift;
414         shift = surface->format->Gshift;
415         *(pix+shift/8) = color>>shift;
416         shift = surface->format->Bshift;
417         *(pix+shift/8) = color>>shift;
418       }
419       break;
420
421       case 4:
422       {
423         /* Probably 32-bpp */
424         *((Uint32 *)surface->pixels + y*surface->pitch/4 + x) = color;
425       }
426       break;
427     }
428   }
429 }
430
431 void _PutPixelRGB(SDL_Surface *surface, Sint16 x, Sint16 y,
432                   Uint8 R, Uint8 G, Uint8 B)
433 {
434   _PutPixel(surface, x, y, SDL_MapRGB(surface->format, R, G, B));
435 }
436
437 void _PutPixel8(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
438 {
439   *((Uint8 *)surface->pixels + y*surface->pitch + x) = color;
440 }
441
442 void _PutPixel16(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
443 {
444   *((Uint16 *)surface->pixels + y*surface->pitch/2 + x) = color;
445 }
446
447 void _PutPixel24(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
448 {
449   Uint8 *pix;
450   int shift;
451
452   /* Gack - slow, but endian correct */
453   pix = (Uint8 *)surface->pixels + y * surface->pitch + x*3;
454   shift = surface->format->Rshift;
455   *(pix+shift/8) = color>>shift;
456   shift = surface->format->Gshift;
457   *(pix+shift/8) = color>>shift;
458   shift = surface->format->Bshift;
459   *(pix+shift/8) = color>>shift;
460 }
461
462 void _PutPixel32(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
463 {
464   *((Uint32 *)surface->pixels + y*surface->pitch/4 + x) = color;
465 }
466
467 void _PutPixelX(SDL_Surface *dest,Sint16 x,Sint16 y,Uint32 color)
468 {
469   switch (dest->format->BytesPerPixel)
470   {
471     case 1:
472       *((Uint8 *)dest->pixels + y*dest->pitch + x) = color;
473       break;
474
475     case 2:
476       *((Uint16 *)dest->pixels + y*dest->pitch/2 + x) = color;
477       break;
478
479     case 3:
480       _PutPixel24(dest,x,y,color);
481       break;
482
483     case 4:
484       *((Uint32 *)dest->pixels + y*dest->pitch/4 + x) = color;
485       break;
486   }
487 }
488
489 void sge_PutPixel(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
490 {
491   if (SDL_MUSTLOCK(surface))
492   {
493     if (SDL_LockSurface(surface) < 0)
494     {
495       return;
496     }
497   }
498
499   _PutPixel(surface, x, y, color);
500
501   if (SDL_MUSTLOCK(surface))
502   {
503     SDL_UnlockSurface(surface);
504   }
505 }
506
507 void sge_PutPixelRGB(SDL_Surface *surface, Sint16 x, Sint16 y,
508                   Uint8 R, Uint8 G, Uint8 B)
509 {
510   sge_PutPixel(surface, x, y, SDL_MapRGB(surface->format, R, G, B));
511 }
512
513 Sint32 sge_CalcYPitch(SDL_Surface *dest, Sint16 y)
514 {
515   if (y >= 0 && y <= dest->h - 1)
516   {
517     switch (dest->format->BytesPerPixel)
518     {
519       case 1:
520         return y*dest->pitch;
521         break;
522
523       case 2:
524         return y*dest->pitch/2;
525         break;
526
527       case 3:
528         return y*dest->pitch;
529         break;
530
531       case 4:
532         return y*dest->pitch/4;
533         break;
534     }
535   }
536
537   return -1;
538 }
539
540 void sge_pPutPixel(SDL_Surface *surface, Sint16 x, Sint32 ypitch, Uint32 color)
541 {
542   if (x >= 0 && x <= surface->w - 1 && ypitch >= 0)
543   {
544     switch (surface->format->BytesPerPixel)
545     {
546       case 1:
547       {
548         /* Assuming 8-bpp */
549         *((Uint8 *)surface->pixels + ypitch + x) = color;
550       }
551       break;
552
553       case 2:
554       {
555         /* Probably 15-bpp or 16-bpp */
556         *((Uint16 *)surface->pixels + ypitch + x) = color;
557       }
558       break;
559
560       case 3:
561       {
562         /* Slow 24-bpp mode, usually not used */
563         Uint8 *pix;
564         int shift;
565
566         /* Gack - slow, but endian correct */
567         pix = (Uint8 *)surface->pixels + ypitch + x*3;
568         shift = surface->format->Rshift;
569         *(pix+shift/8) = color>>shift;
570         shift = surface->format->Gshift;
571         *(pix+shift/8) = color>>shift;
572         shift = surface->format->Bshift;
573         *(pix+shift/8) = color>>shift;
574       }
575       break;
576
577       case 4:
578       {
579         /* Probably 32-bpp */
580         *((Uint32 *)surface->pixels + ypitch + x) = color;
581       }
582       break;
583     }
584   }
585 }
586
587 void sge_HLine(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y,
588                Uint32 Color)
589 {
590   SDL_Rect l;
591
592   if (SDL_MUSTLOCK(Surface))
593   {
594     if (SDL_LockSurface(Surface) < 0)
595     {
596       return;
597     }
598   }
599
600   if (x1 > x2)
601   {
602     Sint16 tmp = x1;
603     x1 = x2;
604     x2 = tmp;
605   }
606
607   /* Do the clipping */
608   if (y < 0 || y > Surface->h - 1 || x1 > Surface->w - 1 || x2 < 0)
609     return;
610   if (x1 < 0)
611     x1 = 0;
612   if (x2 > Surface->w - 1)
613     x2 = Surface->w - 1;
614
615   l.x = x1;
616   l.y = y;
617   l.w = x2 - x1 + 1;
618   l.h = 1;
619
620   SDL_FillRect(Surface, &l, Color);
621
622   if (SDL_MUSTLOCK(Surface))
623   {
624     SDL_UnlockSurface(Surface);
625   }
626 }
627
628 void sge_HLineRGB(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y,
629                   Uint8 R, Uint8 G, Uint8 B)
630 {
631   sge_HLine(Surface, x1, x2, y, SDL_MapRGB(Surface->format, R, G, B));
632 }
633
634 void _HLine(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y, Uint32 Color)
635 {
636   SDL_Rect l;
637
638   if (x1 > x2)
639   {
640     Sint16 tmp = x1;
641     x1 = x2;
642     x2 = tmp;
643   }
644
645   /* Do the clipping */
646   if (y < 0 || y > Surface->h - 1 || x1 > Surface->w - 1 || x2 < 0)
647     return;
648   if (x1 < 0)
649     x1 = 0;
650   if (x2 > Surface->w - 1)
651     x2 = Surface->w - 1;
652
653   l.x = x1;
654   l.y = y;
655   l.w = x2 - x1 + 1;
656   l.h = 1;
657
658   SDL_FillRect(Surface, &l, Color);
659 }
660
661 void sge_VLine(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2,
662                Uint32 Color)
663 {
664   SDL_Rect l;
665
666   if (SDL_MUSTLOCK(Surface))
667   {
668     if (SDL_LockSurface(Surface) < 0)
669     {
670       return;
671     }
672   }
673
674   if (y1 > y2)
675   {
676     Sint16 tmp = y1;
677     y1 = y2;
678     y2 = tmp;
679   }
680
681   /* Do the clipping */
682   if (x < 0 || x > Surface->w - 1 || y1 > Surface->h - 1 || y2 < 0)
683     return;
684   if (y1 < 0)
685     y1 = 0;
686   if (y2 > Surface->h - 1)
687     y2 = Surface->h - 1;
688
689   l.x = x;
690   l.y = y1;
691   l.w = 1;
692   l.h = y2 - y1 + 1;
693
694   SDL_FillRect(Surface, &l, Color);
695
696   if (SDL_MUSTLOCK(Surface))
697   {
698     SDL_UnlockSurface(Surface);
699   }
700 }
701
702 void sge_VLineRGB(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2,
703                   Uint8 R, Uint8 G, Uint8 B)
704 {
705   sge_VLine(Surface, x, y1, y2, SDL_MapRGB(Surface->format, R, G, B));
706 }
707
708 void _VLine(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2, Uint32 Color)
709 {
710   SDL_Rect l;
711
712   if (y1 > y2)
713   {
714     Sint16 tmp = y1;
715     y1 = y2;
716     y2 = tmp;
717   }
718
719   /* Do the clipping */
720   if (x < 0 || x > Surface->w - 1 || y1 > Surface->h - 1 || y2 < 0)
721     return;
722   if (y1 < 0)
723     y1 = 0;
724   if (y2 > Surface->h - 1)
725     y2 = Surface->h - 1;
726
727   l.x = x;
728   l.y = y1;
729   l.w = 1;
730   l.h = y2 - y1 + 1;
731
732   SDL_FillRect(Surface, &l, Color);
733 }
734
735 void sge_DoLine(SDL_Surface *Surface, Sint16 x1, Sint16 y1,
736                 Sint16 x2, Sint16 y2, Uint32 Color,
737                 void Callback(SDL_Surface *Surf, Sint16 X, Sint16 Y,
738                               Uint32 Color))
739 {
740   Sint16 dx, dy, sdx, sdy, x, y, px, py;
741
742   dx = x2 - x1;
743   dy = y2 - y1;
744
745   sdx = (dx < 0) ? -1 : 1;
746   sdy = (dy < 0) ? -1 : 1;
747
748   dx = sdx * dx + 1;
749   dy = sdy * dy + 1;
750
751   x = y = 0;
752
753   px = x1;
754   py = y1;
755
756   if (dx >= dy)
757   {
758     for (x = 0; x < dx; x++)
759     {
760       Callback(Surface, px, py, Color);
761
762       y += dy;
763       if (y >= dx)
764       {
765         y -= dx;
766         py += sdy;
767       }
768
769       px += sdx;
770     }
771   }
772   else
773   {
774     for (y = 0; y < dy; y++)
775     {
776       Callback(Surface, px, py, Color);
777
778       x += dx;
779       if (x >= dy)
780       {
781         x -= dy;
782         px += sdx;
783       }
784
785       py += sdy;
786     }
787   }
788 }
789
790 void sge_DoLineRGB(SDL_Surface *Surface, Sint16 X1, Sint16 Y1,
791                    Sint16 X2, Sint16 Y2, Uint8 R, Uint8 G, Uint8 B,
792                    void Callback(SDL_Surface *Surf, Sint16 X, Sint16 Y,
793                                  Uint32 Color))
794 {
795   sge_DoLine(Surface, X1, Y1, X2, Y2,
796              SDL_MapRGB(Surface->format, R, G, B), Callback);
797 }
798
799 void sge_Line(SDL_Surface *Surface, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2,
800               Uint32 Color)
801 {
802   if (SDL_MUSTLOCK(Surface))
803   {
804     if (SDL_LockSurface(Surface) < 0)
805       return;
806    }
807
808    /* Draw the line */
809    sge_DoLine(Surface, x1, y1, x2, y2, Color, _PutPixel);
810
811    /* unlock the display */
812    if (SDL_MUSTLOCK(Surface))
813    {
814       SDL_UnlockSurface(Surface);
815    }
816 }
817
818 void sge_LineRGB(SDL_Surface *Surface, Sint16 x1, Sint16 y1, Sint16 x2,
819                  Sint16 y2, Uint8 R, Uint8 G, Uint8 B)
820 {
821   sge_Line(Surface, x1, y1, x2, y2, SDL_MapRGB(Surface->format, R, G, B));
822 }
823
824 Bitmap *SDLLoadImage(char *filename)
825 {
826   Bitmap *new_bitmap = CreateBitmapStruct();
827   SDL_Surface *sdl_image_tmp;
828
829   /* load image to temporary surface */
830   if ((sdl_image_tmp = IMG_Load(filename)) == NULL)
831     Error(ERR_EXIT, "IMG_Load() failed: %s", SDL_GetError());
832
833   /* create native non-transparent surface for current image */
834   if ((new_bitmap->surface = SDL_DisplayFormat(sdl_image_tmp)) == NULL)
835     Error(ERR_EXIT, "SDL_DisplayFormat() failed: %s", SDL_GetError());
836
837   /* create native transparent surface for current image */
838   SDL_SetColorKey(sdl_image_tmp, SDL_SRCCOLORKEY,
839                   SDL_MapRGB(sdl_image_tmp->format, 0x00, 0x00, 0x00));
840   if ((new_bitmap->surface_masked = SDL_DisplayFormat(sdl_image_tmp)) == NULL)
841     Error(ERR_EXIT, "SDL_DisplayFormat() failed: %s", SDL_GetError());
842
843   /* free temporary surface */
844   SDL_FreeSurface(sdl_image_tmp);
845
846   return new_bitmap;
847 }
848
849
850 /* ========================================================================= */
851 /* audio functions                                                           */
852 /* ========================================================================= */
853
854 inline void SDLOpenAudio(void)
855 {
856   if (SDL_InitSubSystem(SDL_INIT_AUDIO) < 0)
857   {
858     Error(ERR_WARN, "SDL_InitSubSystem() failed: %s", SDL_GetError());
859     return;
860   }
861
862   if (Mix_OpenAudio(DEFAULT_AUDIO_SAMPLE_RATE, AUDIO_S16,
863                     AUDIO_STEREO_CHANNELS,
864                     DEFAULT_AUDIO_FRAGMENT_SIZE) < 0)
865   {
866     Error(ERR_WARN, "Mix_OpenAudio() failed: %s", SDL_GetError());
867     return;
868   }
869
870   audio.sound_available = TRUE;
871   audio.music_available = TRUE;
872   audio.loops_available = TRUE;
873   audio.sound_enabled = TRUE;
874
875   /* determine number of available channels */
876   audio.channels = Mix_AllocateChannels(MIX_CHANNELS);
877
878   if (!audio.mods_available)    /* reserve first channel for music loops */
879   {
880     if (Mix_ReserveChannels(1) == 1)
881       audio.music_channel = 0;
882     else
883       audio.music_available = FALSE;
884   }
885
886   Mix_Volume(-1, SOUND_MAX_VOLUME);
887   Mix_VolumeMusic(SOUND_MAX_VOLUME);
888 }
889
890 inline void SDLCloseAudio(void)
891 {
892   Mix_HaltMusic();
893   Mix_HaltChannel(-1);
894
895   Mix_CloseAudio();
896   SDL_QuitSubSystem(SDL_INIT_AUDIO);
897 }
898
899
900 /* ========================================================================= */
901 /* event functions                                                           */
902 /* ========================================================================= */
903
904 inline void SDLNextEvent(Event *event)
905 {
906   SDL_WaitEvent(event);
907
908 #ifdef FULLSCREEN_BUG
909   if (event->type == EVENT_BUTTONPRESS ||
910       event->type == EVENT_BUTTONRELEASE)
911   {
912     if (((ButtonEvent *)event)->x > video_xoffset)
913       ((ButtonEvent *)event)->x -= video_xoffset;
914     else
915       ((ButtonEvent *)event)->x = 0;
916     if (((ButtonEvent *)event)->y > video_yoffset)
917       ((ButtonEvent *)event)->y -= video_yoffset;
918     else
919       ((ButtonEvent *)event)->y = 0;
920   }
921   else if (event->type == EVENT_MOTIONNOTIFY)
922   {
923     if (((ButtonEvent *)event)->x > video_xoffset)
924       ((ButtonEvent *)event)->x -= video_xoffset;
925     else
926       ((ButtonEvent *)event)->x = 0;
927     if (((ButtonEvent *)event)->y > video_yoffset)
928       ((ButtonEvent *)event)->y -= video_yoffset;
929     else
930       ((ButtonEvent *)event)->y = 0;
931   }
932 #endif
933 }
934
935 #endif /* TARGET_SDL */