1 /***********************************************************
2 * Artsoft Retro-Game Library *
3 *----------------------------------------------------------*
4 * (c) 1994-2002 Artsoft Entertainment *
6 * Detmolder Strasse 189 *
9 * e-mail: info@artsoft.org *
10 *----------------------------------------------------------*
12 ***********************************************************/
21 #if defined(TARGET_SDL)
23 /* ========================================================================= */
25 /* ========================================================================= */
27 /* functions from SGE library */
28 void sge_Line(SDL_Surface *, Sint16, Sint16, Sint16, Sint16, Uint32);
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;
38 static void setFullscreenParameters()
40 struct ScreenModeInfo *fullscreen_mode;
43 fullscreen_mode = get_screen_mode_from_string(setup.fullscreen_mode);
45 if (fullscreen_mode == NULL)
48 for (i = 0; video.fullscreen_modes[i].width != -1; i++)
50 if (fullscreen_mode->width == video.fullscreen_modes[i].width &&
51 fullscreen_mode->height == video.fullscreen_modes[i].height)
53 fullscreen_width = fullscreen_mode->width;
54 fullscreen_height = fullscreen_mode->height;
56 fullscreen_xoffset = (fullscreen_width - video.width) / 2;
57 fullscreen_yoffset = (fullscreen_height - video.height) / 2;
64 static void SDLSetWindowIcon(char *basename)
66 char *filename = getCustomImageFilename(basename);
71 Error(ERR_WARN, "SDLSetWindowIcon(): cannot find file '%s'", basename);
76 if ((surface = IMG_Load(filename)) == NULL)
78 Error(ERR_WARN, "IMG_Load() failed: %s", SDL_GetError());
83 /* set transparent color */
84 SDL_SetColorKey(surface, SDL_SRCCOLORKEY,
85 SDL_MapRGB(surface->format, 0x00, 0x00, 0x00));
87 SDL_WM_SetIcon(surface, NULL);
90 void SDLInitVideoDisplay(void)
92 putenv("SDL_VIDEO_CENTERED=1");
94 /* initialize SDL video */
95 if (SDL_InitSubSystem(SDL_INIT_VIDEO) < 0)
96 Error(ERR_EXIT, "SDL_InitSubSystem() failed: %s", SDL_GetError());
98 /* set default SDL depth */
99 video.default_depth = SDL_GetVideoInfo()->vfmt->BitsPerPixel;
102 void SDLInitVideoBuffer(DrawBuffer **backbuffer, DrawWindow **window,
105 static int screen_xy[][2] =
115 /* default: normal game window size */
116 fullscreen_width = video.width;
117 fullscreen_height = video.height;
118 fullscreen_xoffset = 0;
119 fullscreen_yoffset = 0;
121 for (i = 0; screen_xy[i][0] != -1; i++)
123 if (screen_xy[i][0] >= video.width && screen_xy[i][1] >= video.height)
125 fullscreen_width = screen_xy[i][0];
126 fullscreen_height = screen_xy[i][1];
132 fullscreen_xoffset = (fullscreen_width - video.width) / 2;
133 fullscreen_yoffset = (fullscreen_height - video.height) / 2;
135 /* get available hardware supported fullscreen modes */
136 modes = SDL_ListModes(NULL, SDL_FULLSCREEN | SDL_HWSURFACE);
140 /* no screen modes available => no fullscreen mode support */
141 video.fullscreen_available = FALSE;
143 else if (modes == (SDL_Rect **)-1)
145 /* fullscreen resolution is not restricted -- all resolutions available */
146 video.fullscreen_modes = checked_calloc(2 * sizeof(struct ScreenModeInfo));
148 /* use native video buffer size for fullscreen mode */
149 video.fullscreen_modes[0].width = video.width;
150 video.fullscreen_modes[0].height = video.height;
152 video.fullscreen_modes[1].width = -1;
153 video.fullscreen_modes[1].height = -1;
157 /* in this case, a certain number of screen modes is available */
160 for(i = 0; modes[i] != NULL; i++)
162 boolean found_mode = FALSE;
164 /* screen mode is smaller than video buffer size -- skip it */
165 if (modes[i]->w < video.width || modes[i]->h < video.height)
168 if (video.fullscreen_modes != NULL)
169 for (j = 0; video.fullscreen_modes[j].width != -1; j++)
170 if (modes[i]->w == video.fullscreen_modes[j].width &&
171 modes[i]->h == video.fullscreen_modes[j].height)
174 if (found_mode) /* screen mode already stored -- skip it */
177 /* new mode found; add it to list of available fullscreen modes */
181 video.fullscreen_modes = checked_realloc(video.fullscreen_modes,
183 sizeof(struct ScreenModeInfo));
185 video.fullscreen_modes[num_modes - 1].width = modes[i]->w;
186 video.fullscreen_modes[num_modes - 1].height = modes[i]->h;
188 video.fullscreen_modes[num_modes].width = -1;
189 video.fullscreen_modes[num_modes].height = -1;
194 /* no appropriate screen modes available => no fullscreen mode support */
195 video.fullscreen_available = FALSE;
199 /* set window icon */
200 SDLSetWindowIcon(program.sdl_icon_filename);
202 /* open SDL video output device (window or fullscreen mode) */
203 if (!SDLSetVideoMode(backbuffer, fullscreen))
204 Error(ERR_EXIT, "setting video mode failed");
206 /* set window and icon title */
207 SDL_WM_SetCaption(program.window_title, program.window_title);
209 /* SDL cannot directly draw to the visible video framebuffer like X11,
210 but always uses a backbuffer, which is then blitted to the visible
211 video framebuffer with 'SDL_UpdateRect' (or replaced with the current
212 visible video framebuffer with 'SDL_Flip', if the hardware supports
213 this). Therefore do not use an additional backbuffer for drawing, but
214 use a symbolic buffer (distinguishable from the SDL backbuffer) called
215 'window', which indicates that the SDL backbuffer should be updated to
216 the visible video framebuffer when attempting to blit to it.
218 For convenience, it seems to be a good idea to create this symbolic
219 buffer 'window' at the same size as the SDL backbuffer. Although it
220 should never be drawn to directly, it would do no harm nevertheless. */
222 /* create additional (symbolic) buffer for double-buffering */
223 *window = CreateBitmap(video.width, video.height, video.depth);
226 boolean SDLSetVideoMode(DrawBuffer **backbuffer, boolean fullscreen)
228 boolean success = TRUE;
229 int surface_flags_fullscreen = SURFACE_FLAGS | SDL_FULLSCREEN;
230 int surface_flags_window = SURFACE_FLAGS;
231 SDL_Surface *new_surface = NULL;
233 if (*backbuffer == NULL)
234 *backbuffer = CreateBitmapStruct();
236 if (fullscreen && !video.fullscreen_enabled && video.fullscreen_available)
238 setFullscreenParameters();
240 video_xoffset = fullscreen_xoffset;
241 video_yoffset = fullscreen_yoffset;
243 /* switch display to fullscreen mode, if available */
244 if ((new_surface = SDL_SetVideoMode(fullscreen_width, fullscreen_height,
245 video.depth, surface_flags_fullscreen))
248 /* switching display to fullscreen mode failed */
249 Error(ERR_WARN, "SDL_SetVideoMode() failed: %s", SDL_GetError());
251 /* do not try it again */
252 video.fullscreen_available = FALSE;
257 (*backbuffer)->surface = new_surface;
259 video.fullscreen_enabled = TRUE;
264 if ((!fullscreen && video.fullscreen_enabled) || new_surface == NULL)
269 /* switch display to window mode */
270 if ((new_surface = SDL_SetVideoMode(video.width, video.height,
271 video.depth, surface_flags_window))
274 /* switching display to window mode failed -- should not happen */
275 Error(ERR_WARN, "SDL_SetVideoMode() failed: %s", SDL_GetError());
281 (*backbuffer)->surface = new_surface;
283 video.fullscreen_enabled = FALSE;
291 void SDLCreateBitmapContent(Bitmap *new_bitmap, int width, int height,
294 SDL_Surface *surface_tmp, *surface_native;
296 if ((surface_tmp = SDL_CreateRGBSurface(SURFACE_FLAGS, width, height, depth,
299 Error(ERR_EXIT, "SDL_CreateRGBSurface() failed: %s", SDL_GetError());
301 if ((surface_native = SDL_DisplayFormat(surface_tmp)) == NULL)
302 Error(ERR_EXIT, "SDL_DisplayFormat() failed: %s", SDL_GetError());
304 SDL_FreeSurface(surface_tmp);
306 new_bitmap->surface = surface_native;
309 void SDLFreeBitmapPointers(Bitmap *bitmap)
312 SDL_FreeSurface(bitmap->surface);
313 if (bitmap->surface_masked)
314 SDL_FreeSurface(bitmap->surface_masked);
315 bitmap->surface = NULL;
316 bitmap->surface_masked = NULL;
319 void SDLCopyArea(Bitmap *src_bitmap, Bitmap *dst_bitmap,
320 int src_x, int src_y, int width, int height,
321 int dst_x, int dst_y, int mask_mode)
323 Bitmap *real_dst_bitmap = (dst_bitmap == window ? backbuffer : dst_bitmap);
324 SDL_Rect src_rect, dst_rect;
326 if (src_bitmap == backbuffer)
328 src_x += video_xoffset;
329 src_y += video_yoffset;
337 if (dst_bitmap == backbuffer || dst_bitmap == window)
339 dst_x += video_xoffset;
340 dst_y += video_yoffset;
348 if (src_bitmap != backbuffer || dst_bitmap != window)
349 SDL_BlitSurface((mask_mode == BLIT_MASKED ?
350 src_bitmap->surface_masked : src_bitmap->surface),
351 &src_rect, real_dst_bitmap->surface, &dst_rect);
353 if (dst_bitmap == window)
354 SDL_UpdateRect(backbuffer->surface, dst_x, dst_y, width, height);
357 void SDLFillRectangle(Bitmap *dst_bitmap, int x, int y, int width, int height,
360 Bitmap *real_dst_bitmap = (dst_bitmap == window ? backbuffer : dst_bitmap);
363 if (dst_bitmap == backbuffer || dst_bitmap == window)
374 SDL_FillRect(real_dst_bitmap->surface, &rect, color);
376 if (dst_bitmap == window)
377 SDL_UpdateRect(backbuffer->surface, x, y, width, height);
380 void SDLFadeRectangle(Bitmap *bitmap_cross, int x, int y, int width, int height,
381 int fade_mode, int fade_delay, int post_delay)
383 static boolean initialization_needed = TRUE;
384 static SDL_Surface *surface_source = NULL;
385 static SDL_Surface *surface_target = NULL;
386 static SDL_Surface *surface_black = NULL;
387 SDL_Surface *surface_screen = backbuffer->surface;
388 SDL_Surface *surface_cross = (bitmap_cross ? bitmap_cross->surface : NULL);
389 SDL_Rect src_rect, dst_rect;
390 int src_x = x, src_y = y;
391 int dst_x = x, dst_y = y;
392 unsigned int time_last, time_current;
401 dst_x += video_xoffset;
402 dst_y += video_yoffset;
409 if (initialization_needed)
411 unsigned int flags = SDL_SRCALPHA;
413 /* use same surface type as screen surface */
414 if ((surface_screen->flags & SDL_HWSURFACE))
415 flags |= SDL_HWSURFACE;
417 flags |= SDL_SWSURFACE;
419 /* create surface for temporary copy of screen buffer (source) */
420 if ((surface_source =
421 SDL_CreateRGBSurface(flags,
424 surface_screen->format->BitsPerPixel,
425 surface_screen->format->Rmask,
426 surface_screen->format->Gmask,
427 surface_screen->format->Bmask,
428 surface_screen->format->Amask)) == NULL)
429 Error(ERR_EXIT, "SDL_CreateRGBSurface() failed: %s", SDL_GetError());
431 /* create surface for cross-fading screen buffer (target) */
432 if ((surface_target =
433 SDL_CreateRGBSurface(flags,
436 surface_screen->format->BitsPerPixel,
437 surface_screen->format->Rmask,
438 surface_screen->format->Gmask,
439 surface_screen->format->Bmask,
440 surface_screen->format->Amask)) == NULL)
441 Error(ERR_EXIT, "SDL_CreateRGBSurface() failed: %s", SDL_GetError());
443 /* create black surface for fading from/to black */
445 SDL_CreateRGBSurface(flags,
448 surface_screen->format->BitsPerPixel,
449 surface_screen->format->Rmask,
450 surface_screen->format->Gmask,
451 surface_screen->format->Bmask,
452 surface_screen->format->Amask)) == NULL)
453 Error(ERR_EXIT, "SDL_CreateRGBSurface() failed: %s", SDL_GetError());
455 /* completely fill the surface with black color pixels */
456 SDL_FillRect(surface_black, NULL,
457 SDL_MapRGB(surface_screen->format, 0, 0, 0));
459 initialization_needed = FALSE;
462 /* copy source and target surfaces to temporary surfaces for fading */
463 if (fade_mode == FADE_MODE_CROSSFADE)
465 SDL_BlitSurface(surface_cross, &src_rect, surface_source, &src_rect);
466 SDL_BlitSurface(surface_screen, &dst_rect, surface_target, &src_rect);
468 else if (fade_mode == FADE_MODE_FADE_IN)
470 SDL_BlitSurface(surface_black, &src_rect, surface_source, &src_rect);
471 SDL_BlitSurface(surface_screen, &dst_rect, surface_target, &src_rect);
473 else /* FADE_MODE_FADE_OUT */
475 SDL_BlitSurface(surface_screen, &dst_rect, surface_source, &src_rect);
476 SDL_BlitSurface(surface_black, &src_rect, surface_target, &src_rect);
479 time_current = SDL_GetTicks();
481 for (alpha = 0.0; alpha < 255.0;)
483 time_last = time_current;
484 time_current = SDL_GetTicks();
485 alpha += 255 * ((float)(time_current - time_last) / fade_delay);
486 alpha_final = MIN(MAX(0, alpha), 255);
488 /* draw existing (source) image to screen buffer */
489 SDL_BlitSurface(surface_source, &src_rect, surface_screen, &dst_rect);
491 /* draw new (target) image to screen buffer using alpha blending */
492 SDL_SetAlpha(surface_target, SDL_SRCALPHA, alpha_final);
493 SDL_BlitSurface(surface_target, &src_rect, surface_screen, &dst_rect);
496 /* only update the region of the screen that is affected from fading */
497 SDL_UpdateRect(surface_screen, dst_x, dst_y, width, height);
499 SDL_Flip(surface_screen);
506 void SDLDrawSimpleLine(Bitmap *dst_bitmap, int from_x, int from_y,
507 int to_x, int to_y, Uint32 color)
509 SDL_Surface *surface = dst_bitmap->surface;
513 swap_numbers(&from_x, &to_x);
516 swap_numbers(&from_y, &to_y);
520 rect.w = (to_x - from_x + 1);
521 rect.h = (to_y - from_y + 1);
523 if (dst_bitmap == backbuffer || dst_bitmap == window)
525 rect.x += video_xoffset;
526 rect.y += video_yoffset;
529 SDL_FillRect(surface, &rect, color);
532 void SDLDrawLine(Bitmap *dst_bitmap, int from_x, int from_y,
533 int to_x, int to_y, Uint32 color)
535 if (dst_bitmap == backbuffer || dst_bitmap == window)
537 from_x += video_xoffset;
538 from_y += video_yoffset;
539 to_x += video_xoffset;
540 to_y += video_yoffset;
543 sge_Line(dst_bitmap->surface, from_x, from_y, to_x, to_y, color);
547 void SDLDrawLines(SDL_Surface *surface, struct XY *points,
548 int num_points, Uint32 color)
553 for (i = 0; i < num_points - 1; i++)
555 for (x = 0; x < line_width; x++)
557 for (y = 0; y < line_width; y++)
559 int dx = x - line_width / 2;
560 int dy = y - line_width / 2;
562 if ((x == 0 && y == 0) ||
563 (x == 0 && y == line_width - 1) ||
564 (x == line_width - 1 && y == 0) ||
565 (x == line_width - 1 && y == line_width - 1))
568 sge_Line(surface, points[i].x + dx, points[i].y + dy,
569 points[i+1].x + dx, points[i+1].y + dy, color);
576 Pixel SDLGetPixel(Bitmap *src_bitmap, int x, int y)
578 SDL_Surface *surface = src_bitmap->surface;
580 if (src_bitmap == backbuffer || src_bitmap == window)
586 switch (surface->format->BytesPerPixel)
588 case 1: /* assuming 8-bpp */
590 return *((Uint8 *)surface->pixels + y * surface->pitch + x);
594 case 2: /* probably 15-bpp or 16-bpp */
596 return *((Uint16 *)surface->pixels + y * surface->pitch / 2 + x);
600 case 3: /* slow 24-bpp mode; usually not used */
602 /* does this work? */
603 Uint8 *pix = (Uint8 *)surface->pixels + y * surface->pitch + x * 3;
607 shift = surface->format->Rshift;
608 color |= *(pix + shift / 8) >> shift;
609 shift = surface->format->Gshift;
610 color |= *(pix + shift / 8) >> shift;
611 shift = surface->format->Bshift;
612 color |= *(pix + shift / 8) >> shift;
618 case 4: /* probably 32-bpp */
620 return *((Uint32 *)surface->pixels + y * surface->pitch / 4 + x);
629 /* ========================================================================= */
630 /* The following functions were taken from the SGE library */
631 /* (SDL Graphics Extension Library) by Anders Lindström */
632 /* http://www.etek.chalmers.se/~e8cal1/sge/index.html */
633 /* ========================================================================= */
635 void _PutPixel(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
637 if (x >= 0 && x <= surface->w - 1 && y >= 0 && y <= surface->h - 1)
639 switch (surface->format->BytesPerPixel)
644 *((Uint8 *)surface->pixels + y*surface->pitch + x) = color;
650 /* Probably 15-bpp or 16-bpp */
651 *((Uint16 *)surface->pixels + y*surface->pitch/2 + x) = color;
657 /* Slow 24-bpp mode, usually not used */
661 /* Gack - slow, but endian correct */
662 pix = (Uint8 *)surface->pixels + y * surface->pitch + x*3;
663 shift = surface->format->Rshift;
664 *(pix+shift/8) = color>>shift;
665 shift = surface->format->Gshift;
666 *(pix+shift/8) = color>>shift;
667 shift = surface->format->Bshift;
668 *(pix+shift/8) = color>>shift;
674 /* Probably 32-bpp */
675 *((Uint32 *)surface->pixels + y*surface->pitch/4 + x) = color;
682 void _PutPixelRGB(SDL_Surface *surface, Sint16 x, Sint16 y,
683 Uint8 R, Uint8 G, Uint8 B)
685 _PutPixel(surface, x, y, SDL_MapRGB(surface->format, R, G, B));
688 void _PutPixel8(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
690 *((Uint8 *)surface->pixels + y*surface->pitch + x) = color;
693 void _PutPixel16(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
695 *((Uint16 *)surface->pixels + y*surface->pitch/2 + x) = color;
698 void _PutPixel24(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
703 /* Gack - slow, but endian correct */
704 pix = (Uint8 *)surface->pixels + y * surface->pitch + x*3;
705 shift = surface->format->Rshift;
706 *(pix+shift/8) = color>>shift;
707 shift = surface->format->Gshift;
708 *(pix+shift/8) = color>>shift;
709 shift = surface->format->Bshift;
710 *(pix+shift/8) = color>>shift;
713 void _PutPixel32(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
715 *((Uint32 *)surface->pixels + y*surface->pitch/4 + x) = color;
718 void _PutPixelX(SDL_Surface *dest,Sint16 x,Sint16 y,Uint32 color)
720 switch (dest->format->BytesPerPixel)
723 *((Uint8 *)dest->pixels + y*dest->pitch + x) = color;
727 *((Uint16 *)dest->pixels + y*dest->pitch/2 + x) = color;
731 _PutPixel24(dest,x,y,color);
735 *((Uint32 *)dest->pixels + y*dest->pitch/4 + x) = color;
740 void sge_PutPixel(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
742 if (SDL_MUSTLOCK(surface))
744 if (SDL_LockSurface(surface) < 0)
750 _PutPixel(surface, x, y, color);
752 if (SDL_MUSTLOCK(surface))
754 SDL_UnlockSurface(surface);
758 void sge_PutPixelRGB(SDL_Surface *surface, Sint16 x, Sint16 y,
759 Uint8 r, Uint8 g, Uint8 b)
761 sge_PutPixel(surface, x, y, SDL_MapRGB(surface->format, r, g, b));
764 Sint32 sge_CalcYPitch(SDL_Surface *dest, Sint16 y)
766 if (y >= 0 && y <= dest->h - 1)
768 switch (dest->format->BytesPerPixel)
771 return y*dest->pitch;
775 return y*dest->pitch/2;
779 return y*dest->pitch;
783 return y*dest->pitch/4;
791 void sge_pPutPixel(SDL_Surface *surface, Sint16 x, Sint32 ypitch, Uint32 color)
793 if (x >= 0 && x <= surface->w - 1 && ypitch >= 0)
795 switch (surface->format->BytesPerPixel)
800 *((Uint8 *)surface->pixels + ypitch + x) = color;
806 /* Probably 15-bpp or 16-bpp */
807 *((Uint16 *)surface->pixels + ypitch + x) = color;
813 /* Slow 24-bpp mode, usually not used */
817 /* Gack - slow, but endian correct */
818 pix = (Uint8 *)surface->pixels + ypitch + x*3;
819 shift = surface->format->Rshift;
820 *(pix+shift/8) = color>>shift;
821 shift = surface->format->Gshift;
822 *(pix+shift/8) = color>>shift;
823 shift = surface->format->Bshift;
824 *(pix+shift/8) = color>>shift;
830 /* Probably 32-bpp */
831 *((Uint32 *)surface->pixels + ypitch + x) = color;
838 void sge_HLine(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y,
843 if (SDL_MUSTLOCK(Surface))
845 if (SDL_LockSurface(Surface) < 0)
858 /* Do the clipping */
859 if (y < 0 || y > Surface->h - 1 || x1 > Surface->w - 1 || x2 < 0)
863 if (x2 > Surface->w - 1)
871 SDL_FillRect(Surface, &l, Color);
873 if (SDL_MUSTLOCK(Surface))
875 SDL_UnlockSurface(Surface);
879 void sge_HLineRGB(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y,
880 Uint8 R, Uint8 G, Uint8 B)
882 sge_HLine(Surface, x1, x2, y, SDL_MapRGB(Surface->format, R, G, B));
885 void _HLine(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y, Uint32 Color)
896 /* Do the clipping */
897 if (y < 0 || y > Surface->h - 1 || x1 > Surface->w - 1 || x2 < 0)
901 if (x2 > Surface->w - 1)
909 SDL_FillRect(Surface, &l, Color);
912 void sge_VLine(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2,
917 if (SDL_MUSTLOCK(Surface))
919 if (SDL_LockSurface(Surface) < 0)
932 /* Do the clipping */
933 if (x < 0 || x > Surface->w - 1 || y1 > Surface->h - 1 || y2 < 0)
937 if (y2 > Surface->h - 1)
945 SDL_FillRect(Surface, &l, Color);
947 if (SDL_MUSTLOCK(Surface))
949 SDL_UnlockSurface(Surface);
953 void sge_VLineRGB(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2,
954 Uint8 R, Uint8 G, Uint8 B)
956 sge_VLine(Surface, x, y1, y2, SDL_MapRGB(Surface->format, R, G, B));
959 void _VLine(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2, Uint32 Color)
970 /* Do the clipping */
971 if (x < 0 || x > Surface->w - 1 || y1 > Surface->h - 1 || y2 < 0)
975 if (y2 > Surface->h - 1)
983 SDL_FillRect(Surface, &l, Color);
986 void sge_DoLine(SDL_Surface *Surface, Sint16 x1, Sint16 y1,
987 Sint16 x2, Sint16 y2, Uint32 Color,
988 void Callback(SDL_Surface *Surf, Sint16 X, Sint16 Y,
991 Sint16 dx, dy, sdx, sdy, x, y, px, py;
996 sdx = (dx < 0) ? -1 : 1;
997 sdy = (dy < 0) ? -1 : 1;
1009 for (x = 0; x < dx; x++)
1011 Callback(Surface, px, py, Color);
1025 for (y = 0; y < dy; y++)
1027 Callback(Surface, px, py, Color);
1041 void sge_DoLineRGB(SDL_Surface *Surface, Sint16 X1, Sint16 Y1,
1042 Sint16 X2, Sint16 Y2, Uint8 R, Uint8 G, Uint8 B,
1043 void Callback(SDL_Surface *Surf, Sint16 X, Sint16 Y,
1046 sge_DoLine(Surface, X1, Y1, X2, Y2,
1047 SDL_MapRGB(Surface->format, R, G, B), Callback);
1050 void sge_Line(SDL_Surface *Surface, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2,
1053 if (SDL_MUSTLOCK(Surface))
1055 if (SDL_LockSurface(Surface) < 0)
1060 sge_DoLine(Surface, x1, y1, x2, y2, Color, _PutPixel);
1062 /* unlock the display */
1063 if (SDL_MUSTLOCK(Surface))
1065 SDL_UnlockSurface(Surface);
1069 void sge_LineRGB(SDL_Surface *Surface, Sint16 x1, Sint16 y1, Sint16 x2,
1070 Sint16 y2, Uint8 R, Uint8 G, Uint8 B)
1072 sge_Line(Surface, x1, y1, x2, y2, SDL_MapRGB(Surface->format, R, G, B));
1075 void SDLPutPixel(Bitmap *dst_bitmap, int x, int y, Pixel pixel)
1077 if (dst_bitmap == backbuffer || dst_bitmap == window)
1083 sge_PutPixel(dst_bitmap->surface, x, y, pixel);
1088 -----------------------------------------------------------------------------
1089 quick (no, it's slow) and dirty hack to "invert" rectangle inside SDL surface
1090 -----------------------------------------------------------------------------
1093 void SDLInvertArea(Bitmap *bitmap, int src_x, int src_y,
1094 int width, int height, Uint32 color)
1098 for (y = src_y; y < src_y + height; y++)
1100 for (x = src_x; x < src_x + width; x++)
1102 Uint32 pixel = SDLGetPixel(bitmap, x, y);
1104 SDLPutPixel(bitmap, x, y, pixel == BLACK_PIXEL ? color : BLACK_PIXEL);
1109 void SDLCopyInverseMasked(Bitmap *src_bitmap, Bitmap *dst_bitmap,
1110 int src_x, int src_y, int width, int height,
1111 int dst_x, int dst_y)
1115 for (y = 0; y < height; y++)
1117 for (x = 0; x < width; x++)
1119 Uint32 pixel = SDLGetPixel(src_bitmap, src_x + x, src_y + y);
1121 if (pixel != BLACK_PIXEL)
1122 SDLPutPixel(dst_bitmap, dst_x + x, dst_y + y, BLACK_PIXEL);
1128 /* ========================================================================= */
1129 /* The following functions were taken from the SDL_gfx library version 2.0.3 */
1130 /* (Rotozoomer) by Andreas Schiffler */
1131 /* http://www.ferzkopp.net/Software/SDL_gfx-2.0/index.html */
1132 /* ========================================================================= */
1135 -----------------------------------------------------------------------------
1138 zoomes 32bit RGBA/ABGR 'src' surface to 'dst' surface.
1139 -----------------------------------------------------------------------------
1150 int zoomSurfaceRGBA_scaleDownBy2(SDL_Surface *src, SDL_Surface *dst)
1153 tColorRGBA *sp, *csp, *dp;
1157 sp = csp = (tColorRGBA *) src->pixels;
1158 dp = (tColorRGBA *) dst->pixels;
1159 sgap = src->pitch - src->w * 4;
1160 dgap = dst->pitch - dst->w * 4;
1162 for (y = 0; y < dst->h; y++)
1166 for (x = 0; x < dst->w; x++)
1168 tColorRGBA *sp0 = sp;
1169 tColorRGBA *sp1 = (tColorRGBA *) ((Uint8 *) sp + src->pitch);
1170 tColorRGBA *sp00 = &sp0[0];
1171 tColorRGBA *sp01 = &sp0[1];
1172 tColorRGBA *sp10 = &sp1[0];
1173 tColorRGBA *sp11 = &sp1[1];
1176 /* create new color pixel from all four source color pixels */
1177 new.r = (sp00->r + sp01->r + sp10->r + sp11->r) / 4;
1178 new.g = (sp00->g + sp01->g + sp10->g + sp11->g) / 4;
1179 new.b = (sp00->b + sp01->b + sp10->b + sp11->b) / 4;
1180 new.a = (sp00->a + sp01->a + sp10->a + sp11->a) / 4;
1185 /* advance source pointers */
1188 /* advance destination pointer */
1192 /* advance source pointer */
1193 csp = (tColorRGBA *) ((Uint8 *) csp + 2 * src->pitch);
1195 /* advance destination pointers */
1196 dp = (tColorRGBA *) ((Uint8 *) dp + dgap);
1202 int zoomSurfaceRGBA(SDL_Surface *src, SDL_Surface *dst)
1204 int x, y, sx, sy, *sax, *say, *csax, *csay, csx, csy;
1205 tColorRGBA *sp, *csp, *dp;
1208 /* use specialized zoom function when scaling down to exactly half size */
1209 if (src->w == 2 * dst->w &&
1210 src->h == 2 * dst->h)
1211 return zoomSurfaceRGBA_scaleDownBy2(src, dst);
1213 /* variable setup */
1214 sx = (int) (65536.0 * (float) src->w / (float) dst->w);
1215 sy = (int) (65536.0 * (float) src->h / (float) dst->h);
1217 /* allocate memory for row increments */
1218 sax = (int *)checked_malloc((dst->w + 1) * sizeof(Uint32));
1219 say = (int *)checked_malloc((dst->h + 1) * sizeof(Uint32));
1221 /* precalculate row increments */
1224 for (x = 0; x <= dst->w; x++)
1234 for (y = 0; y <= dst->h; y++)
1243 sp = csp = (tColorRGBA *) src->pixels;
1244 dp = (tColorRGBA *) dst->pixels;
1245 sgap = src->pitch - src->w * 4;
1246 dgap = dst->pitch - dst->w * 4;
1249 for (y = 0; y < dst->h; y++)
1254 for (x = 0; x < dst->w; x++)
1259 /* advance source pointers */
1261 sp += (*csax >> 16);
1263 /* advance destination pointer */
1267 /* advance source pointer */
1269 csp = (tColorRGBA *) ((Uint8 *) csp + (*csay >> 16) * src->pitch);
1271 /* advance destination pointers */
1272 dp = (tColorRGBA *) ((Uint8 *) dp + dgap);
1282 -----------------------------------------------------------------------------
1285 zoomes 8 bit palette/Y 'src' surface to 'dst' surface
1286 -----------------------------------------------------------------------------
1289 int zoomSurfaceY(SDL_Surface * src, SDL_Surface * dst)
1291 Uint32 x, y, sx, sy, *sax, *say, *csax, *csay, csx, csy;
1292 Uint8 *sp, *dp, *csp;
1295 /* variable setup */
1296 sx = (Uint32) (65536.0 * (float) src->w / (float) dst->w);
1297 sy = (Uint32) (65536.0 * (float) src->h / (float) dst->h);
1299 /* allocate memory for row increments */
1300 sax = (Uint32 *)checked_malloc(dst->w * sizeof(Uint32));
1301 say = (Uint32 *)checked_malloc(dst->h * sizeof(Uint32));
1303 /* precalculate row increments */
1306 for (x = 0; x < dst->w; x++)
1309 *csax = (csx >> 16);
1316 for (y = 0; y < dst->h; y++)
1319 *csay = (csy >> 16);
1326 for (x = 0; x < dst->w; x++)
1334 for (y = 0; y < dst->h; y++)
1341 sp = csp = (Uint8 *) src->pixels;
1342 dp = (Uint8 *) dst->pixels;
1343 dgap = dst->pitch - dst->w;
1347 for (y = 0; y < dst->h; y++)
1351 for (x = 0; x < dst->w; x++)
1356 /* advance source pointers */
1360 /* advance destination pointer */
1364 /* advance source pointer (for row) */
1365 csp += ((*csay) * src->pitch);
1368 /* advance destination pointers */
1379 -----------------------------------------------------------------------------
1382 Zooms a 32bit or 8bit 'src' surface to newly created 'dst' surface.
1383 'zoomx' and 'zoomy' are scaling factors for width and height.
1384 If the surface is not 8bit or 32bit RGBA/ABGR it will be converted
1385 into a 32bit RGBA format on the fly.
1386 -----------------------------------------------------------------------------
1389 SDL_Surface *zoomSurface(SDL_Surface *src, int dst_width, int dst_height)
1391 SDL_Surface *zoom_src = NULL;
1392 SDL_Surface *zoom_dst = NULL;
1393 boolean is_converted = FALSE;
1400 /* determine if source surface is 32 bit or 8 bit */
1401 is_32bit = (src->format->BitsPerPixel == 32);
1403 if (is_32bit || src->format->BitsPerPixel == 8)
1405 /* use source surface 'as is' */
1410 /* new source surface is 32 bit with a defined RGB ordering */
1411 zoom_src = SDL_CreateRGBSurface(SDL_SWSURFACE, src->w, src->h, 32,
1412 0x000000ff, 0x0000ff00, 0x00ff0000, 0);
1413 SDL_BlitSurface(src, NULL, zoom_src, NULL);
1415 is_converted = TRUE;
1418 /* allocate surface to completely contain the zoomed surface */
1421 /* target surface is 32 bit with source RGBA/ABGR ordering */
1422 zoom_dst = SDL_CreateRGBSurface(SDL_SWSURFACE, dst_width, dst_height, 32,
1423 zoom_src->format->Rmask,
1424 zoom_src->format->Gmask,
1425 zoom_src->format->Bmask, 0);
1429 /* target surface is 8 bit */
1430 zoom_dst = SDL_CreateRGBSurface(SDL_SWSURFACE, dst_width, dst_height, 8,
1434 /* lock source surface */
1435 SDL_LockSurface(zoom_src);
1437 /* check which kind of surface we have */
1440 /* call the 32 bit transformation routine to do the zooming */
1441 zoomSurfaceRGBA(zoom_src, zoom_dst);
1446 for (i = 0; i < zoom_src->format->palette->ncolors; i++)
1447 zoom_dst->format->palette->colors[i] =
1448 zoom_src->format->palette->colors[i];
1449 zoom_dst->format->palette->ncolors = zoom_src->format->palette->ncolors;
1451 /* call the 8 bit transformation routine to do the zooming */
1452 zoomSurfaceY(zoom_src, zoom_dst);
1455 /* unlock source surface */
1456 SDL_UnlockSurface(zoom_src);
1458 /* free temporary surface */
1460 SDL_FreeSurface(zoom_src);
1462 /* return destination surface */
1466 void SDLZoomBitmap(Bitmap *src_bitmap, Bitmap *dst_bitmap)
1468 SDL_Surface *sdl_surface_tmp;
1469 int dst_width = dst_bitmap->width;
1470 int dst_height = dst_bitmap->height;
1472 /* throw away old destination surface */
1473 SDL_FreeSurface(dst_bitmap->surface);
1475 /* create zoomed temporary surface from source surface */
1476 sdl_surface_tmp = zoomSurface(src_bitmap->surface, dst_width, dst_height);
1478 /* create native format destination surface from zoomed temporary surface */
1479 dst_bitmap->surface = SDL_DisplayFormat(sdl_surface_tmp);
1481 /* free temporary surface */
1482 SDL_FreeSurface(sdl_surface_tmp);
1486 /* ========================================================================= */
1487 /* load image to bitmap */
1488 /* ========================================================================= */
1490 Bitmap *SDLLoadImage(char *filename)
1492 Bitmap *new_bitmap = CreateBitmapStruct();
1493 SDL_Surface *sdl_image_tmp;
1495 /* load image to temporary surface */
1496 if ((sdl_image_tmp = IMG_Load(filename)) == NULL)
1498 SetError("IMG_Load(): %s", SDL_GetError());
1503 /* create native non-transparent surface for current image */
1504 if ((new_bitmap->surface = SDL_DisplayFormat(sdl_image_tmp)) == NULL)
1506 SetError("SDL_DisplayFormat(): %s", SDL_GetError());
1511 /* create native transparent surface for current image */
1512 SDL_SetColorKey(sdl_image_tmp, SDL_SRCCOLORKEY,
1513 SDL_MapRGB(sdl_image_tmp->format, 0x00, 0x00, 0x00));
1514 if ((new_bitmap->surface_masked = SDL_DisplayFormat(sdl_image_tmp)) == NULL)
1516 SetError("SDL_DisplayFormat(): %s", SDL_GetError());
1521 /* free temporary surface */
1522 SDL_FreeSurface(sdl_image_tmp);
1524 new_bitmap->width = new_bitmap->surface->w;
1525 new_bitmap->height = new_bitmap->surface->h;
1531 /* ------------------------------------------------------------------------- */
1532 /* custom cursor fuctions */
1533 /* ------------------------------------------------------------------------- */
1535 static SDL_Cursor *create_cursor(struct MouseCursorInfo *cursor_info)
1537 return SDL_CreateCursor(cursor_info->data, cursor_info->mask,
1538 cursor_info->width, cursor_info->height,
1539 cursor_info->hot_x, cursor_info->hot_y);
1542 void SDLSetMouseCursor(struct MouseCursorInfo *cursor_info)
1544 static struct MouseCursorInfo *last_cursor_info = NULL;
1545 static struct MouseCursorInfo *last_cursor_info2 = NULL;
1546 static SDL_Cursor *cursor_default = NULL;
1547 static SDL_Cursor *cursor_current = NULL;
1549 /* if invoked for the first time, store the SDL default cursor */
1550 if (cursor_default == NULL)
1551 cursor_default = SDL_GetCursor();
1553 /* only create new cursor if cursor info (custom only) has changed */
1554 if (cursor_info != NULL && cursor_info != last_cursor_info)
1556 cursor_current = create_cursor(cursor_info);
1557 last_cursor_info = cursor_info;
1560 /* only set new cursor if cursor info (custom or NULL) has changed */
1561 if (cursor_info != last_cursor_info2)
1562 SDL_SetCursor(cursor_info ? cursor_current : cursor_default);
1564 last_cursor_info2 = cursor_info;
1568 /* ========================================================================= */
1569 /* audio functions */
1570 /* ========================================================================= */
1572 void SDLOpenAudio(void)
1574 if (!strEqual(setup.system.sdl_audiodriver, ARG_DEFAULT))
1575 putenv(getStringCat2("SDL_AUDIODRIVER=", setup.system.sdl_audiodriver));
1577 if (SDL_InitSubSystem(SDL_INIT_AUDIO) < 0)
1579 Error(ERR_WARN, "SDL_InitSubSystem() failed: %s", SDL_GetError());
1583 if (Mix_OpenAudio(DEFAULT_AUDIO_SAMPLE_RATE, MIX_DEFAULT_FORMAT,
1584 AUDIO_NUM_CHANNELS_STEREO,
1585 setup.system.audio_fragment_size) < 0)
1587 Error(ERR_WARN, "Mix_OpenAudio() failed: %s", SDL_GetError());
1591 audio.sound_available = TRUE;
1592 audio.music_available = TRUE;
1593 audio.loops_available = TRUE;
1594 audio.sound_enabled = TRUE;
1596 /* set number of available mixer channels */
1597 audio.num_channels = Mix_AllocateChannels(NUM_MIXER_CHANNELS);
1598 audio.music_channel = MUSIC_CHANNEL;
1599 audio.first_sound_channel = FIRST_SOUND_CHANNEL;
1601 Mixer_InitChannels();
1604 void SDLCloseAudio(void)
1607 Mix_HaltChannel(-1);
1610 SDL_QuitSubSystem(SDL_INIT_AUDIO);
1614 /* ========================================================================= */
1615 /* event functions */
1616 /* ========================================================================= */
1618 void SDLNextEvent(Event *event)
1620 SDL_WaitEvent(event);
1622 if (event->type == EVENT_BUTTONPRESS ||
1623 event->type == EVENT_BUTTONRELEASE)
1625 if (((ButtonEvent *)event)->x > video_xoffset)
1626 ((ButtonEvent *)event)->x -= video_xoffset;
1628 ((ButtonEvent *)event)->x = 0;
1629 if (((ButtonEvent *)event)->y > video_yoffset)
1630 ((ButtonEvent *)event)->y -= video_yoffset;
1632 ((ButtonEvent *)event)->y = 0;
1634 else if (event->type == EVENT_MOTIONNOTIFY)
1636 if (((MotionEvent *)event)->x > video_xoffset)
1637 ((MotionEvent *)event)->x -= video_xoffset;
1639 ((MotionEvent *)event)->x = 0;
1640 if (((MotionEvent *)event)->y > video_yoffset)
1641 ((MotionEvent *)event)->y -= video_yoffset;
1643 ((MotionEvent *)event)->y = 0;
1648 /* ========================================================================= */
1649 /* joystick functions */
1650 /* ========================================================================= */
1652 static SDL_Joystick *sdl_joystick[MAX_PLAYERS] = { NULL, NULL, NULL, NULL };
1653 static int sdl_js_axis[MAX_PLAYERS][2] = { {0, 0}, {0, 0}, {0, 0}, {0, 0} };
1654 static int sdl_js_button[MAX_PLAYERS][2] = { {0, 0}, {0, 0}, {0, 0}, {0, 0} };
1656 static boolean SDLOpenJoystick(int nr)
1658 if (nr < 0 || nr > MAX_PLAYERS)
1661 return ((sdl_joystick[nr] = SDL_JoystickOpen(nr)) == NULL ? FALSE : TRUE);
1664 static void SDLCloseJoystick(int nr)
1666 if (nr < 0 || nr > MAX_PLAYERS)
1669 SDL_JoystickClose(sdl_joystick[nr]);
1672 static boolean SDLCheckJoystickOpened(int nr)
1674 if (nr < 0 || nr > MAX_PLAYERS)
1677 return (SDL_JoystickOpened(nr) ? TRUE : FALSE);
1680 void HandleJoystickEvent(Event *event)
1684 case SDL_JOYAXISMOTION:
1685 if (event->jaxis.axis < 2)
1686 sdl_js_axis[event->jaxis.which][event->jaxis.axis]= event->jaxis.value;
1689 case SDL_JOYBUTTONDOWN:
1690 if (event->jbutton.button < 2)
1691 sdl_js_button[event->jbutton.which][event->jbutton.button] = TRUE;
1694 case SDL_JOYBUTTONUP:
1695 if (event->jbutton.button < 2)
1696 sdl_js_button[event->jbutton.which][event->jbutton.button] = FALSE;
1704 void SDLInitJoysticks()
1706 static boolean sdl_joystick_subsystem_initialized = FALSE;
1707 boolean print_warning = !sdl_joystick_subsystem_initialized;
1710 if (!sdl_joystick_subsystem_initialized)
1712 sdl_joystick_subsystem_initialized = TRUE;
1714 if (SDL_Init(SDL_INIT_JOYSTICK) < 0)
1716 Error(ERR_EXIT, "SDL_Init() failed: %s", SDL_GetError());
1721 for (i = 0; i < MAX_PLAYERS; i++)
1723 /* get configured joystick for this player */
1724 char *device_name = setup.input[i].joy.device_name;
1725 int joystick_nr = getJoystickNrFromDeviceName(device_name);
1727 if (joystick_nr >= SDL_NumJoysticks())
1729 if (setup.input[i].use_joystick && print_warning)
1730 Error(ERR_WARN, "cannot find joystick %d", joystick_nr);
1735 /* misuse joystick file descriptor variable to store joystick number */
1736 joystick.fd[i] = joystick_nr;
1738 if (joystick_nr == -1)
1741 /* this allows subsequent calls to 'InitJoysticks' for re-initialization */
1742 if (SDLCheckJoystickOpened(joystick_nr))
1743 SDLCloseJoystick(joystick_nr);
1745 if (!setup.input[i].use_joystick)
1748 if (!SDLOpenJoystick(joystick_nr))
1751 Error(ERR_WARN, "cannot open joystick %d", joystick_nr);
1756 joystick.status = JOYSTICK_ACTIVATED;
1760 boolean SDLReadJoystick(int nr, int *x, int *y, boolean *b1, boolean *b2)
1762 if (nr < 0 || nr >= MAX_PLAYERS)
1766 *x = sdl_js_axis[nr][0];
1768 *y = sdl_js_axis[nr][1];
1771 *b1 = sdl_js_button[nr][0];
1773 *b2 = sdl_js_button[nr][1];
1778 #endif /* TARGET_SDL */