1 /***********************************************************
2 * Artsoft Retro-Game Library *
3 *----------------------------------------------------------*
4 * (c) 1994-2006 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 /* (setting the window icon on Mac OS X would replace the high-quality
67 dock icon with the currently smaller (and uglier) icon from file) */
69 #if !defined(PLATFORM_MACOSX)
70 char *filename = getCustomImageFilename(basename);
75 Error(ERR_WARN, "SDLSetWindowIcon(): cannot find file '%s'", basename);
80 if ((surface = IMG_Load(filename)) == NULL)
82 Error(ERR_WARN, "IMG_Load() failed: %s", SDL_GetError());
87 /* set transparent color */
88 SDL_SetColorKey(surface, SDL_SRCCOLORKEY,
89 SDL_MapRGB(surface->format, 0x00, 0x00, 0x00));
91 SDL_WM_SetIcon(surface, NULL);
95 void SDLInitVideoDisplay(void)
97 putenv("SDL_VIDEO_CENTERED=1");
99 /* initialize SDL video */
100 if (SDL_InitSubSystem(SDL_INIT_VIDEO) < 0)
101 Error(ERR_EXIT, "SDL_InitSubSystem() failed: %s", SDL_GetError());
103 /* set default SDL depth */
104 video.default_depth = SDL_GetVideoInfo()->vfmt->BitsPerPixel;
107 void SDLInitVideoBuffer(DrawBuffer **backbuffer, DrawWindow **window,
110 static int screen_xy[][2] =
120 /* default: normal game window size */
121 fullscreen_width = video.width;
122 fullscreen_height = video.height;
123 fullscreen_xoffset = 0;
124 fullscreen_yoffset = 0;
126 for (i = 0; screen_xy[i][0] != -1; i++)
128 if (screen_xy[i][0] >= video.width && screen_xy[i][1] >= video.height)
130 fullscreen_width = screen_xy[i][0];
131 fullscreen_height = screen_xy[i][1];
137 fullscreen_xoffset = (fullscreen_width - video.width) / 2;
138 fullscreen_yoffset = (fullscreen_height - video.height) / 2;
140 /* get available hardware supported fullscreen modes */
141 modes = SDL_ListModes(NULL, SDL_FULLSCREEN | SDL_HWSURFACE);
145 /* no screen modes available => no fullscreen mode support */
146 video.fullscreen_available = FALSE;
148 else if (modes == (SDL_Rect **)-1)
150 /* fullscreen resolution is not restricted -- all resolutions available */
151 video.fullscreen_modes = checked_calloc(2 * sizeof(struct ScreenModeInfo));
153 /* use native video buffer size for fullscreen mode */
154 video.fullscreen_modes[0].width = video.width;
155 video.fullscreen_modes[0].height = video.height;
157 video.fullscreen_modes[1].width = -1;
158 video.fullscreen_modes[1].height = -1;
162 /* in this case, a certain number of screen modes is available */
165 for(i = 0; modes[i] != NULL; i++)
167 boolean found_mode = FALSE;
169 /* screen mode is smaller than video buffer size -- skip it */
170 if (modes[i]->w < video.width || modes[i]->h < video.height)
173 if (video.fullscreen_modes != NULL)
174 for (j = 0; video.fullscreen_modes[j].width != -1; j++)
175 if (modes[i]->w == video.fullscreen_modes[j].width &&
176 modes[i]->h == video.fullscreen_modes[j].height)
179 if (found_mode) /* screen mode already stored -- skip it */
182 /* new mode found; add it to list of available fullscreen modes */
186 video.fullscreen_modes = checked_realloc(video.fullscreen_modes,
188 sizeof(struct ScreenModeInfo));
190 video.fullscreen_modes[num_modes - 1].width = modes[i]->w;
191 video.fullscreen_modes[num_modes - 1].height = modes[i]->h;
193 video.fullscreen_modes[num_modes].width = -1;
194 video.fullscreen_modes[num_modes].height = -1;
199 /* no appropriate screen modes available => no fullscreen mode support */
200 video.fullscreen_available = FALSE;
204 /* set window icon */
205 SDLSetWindowIcon(program.sdl_icon_filename);
207 /* open SDL video output device (window or fullscreen mode) */
208 if (!SDLSetVideoMode(backbuffer, fullscreen))
209 Error(ERR_EXIT, "setting video mode failed");
211 /* set window and icon title */
212 SDL_WM_SetCaption(program.window_title, program.window_title);
214 /* SDL cannot directly draw to the visible video framebuffer like X11,
215 but always uses a backbuffer, which is then blitted to the visible
216 video framebuffer with 'SDL_UpdateRect' (or replaced with the current
217 visible video framebuffer with 'SDL_Flip', if the hardware supports
218 this). Therefore do not use an additional backbuffer for drawing, but
219 use a symbolic buffer (distinguishable from the SDL backbuffer) called
220 'window', which indicates that the SDL backbuffer should be updated to
221 the visible video framebuffer when attempting to blit to it.
223 For convenience, it seems to be a good idea to create this symbolic
224 buffer 'window' at the same size as the SDL backbuffer. Although it
225 should never be drawn to directly, it would do no harm nevertheless. */
227 /* create additional (symbolic) buffer for double-buffering */
228 *window = CreateBitmap(video.width, video.height, video.depth);
231 boolean SDLSetVideoMode(DrawBuffer **backbuffer, boolean fullscreen)
233 boolean success = TRUE;
234 int surface_flags_fullscreen = SURFACE_FLAGS | SDL_FULLSCREEN;
235 int surface_flags_window = SURFACE_FLAGS;
236 SDL_Surface *new_surface = NULL;
238 if (*backbuffer == NULL)
239 *backbuffer = CreateBitmapStruct();
241 if (fullscreen && !video.fullscreen_enabled && video.fullscreen_available)
243 setFullscreenParameters();
245 video_xoffset = fullscreen_xoffset;
246 video_yoffset = fullscreen_yoffset;
248 /* switch display to fullscreen mode, if available */
249 if ((new_surface = SDL_SetVideoMode(fullscreen_width, fullscreen_height,
250 video.depth, surface_flags_fullscreen))
253 /* switching display to fullscreen mode failed */
254 Error(ERR_WARN, "SDL_SetVideoMode() failed: %s", SDL_GetError());
256 /* do not try it again */
257 video.fullscreen_available = FALSE;
262 (*backbuffer)->surface = new_surface;
264 video.fullscreen_enabled = TRUE;
269 if ((!fullscreen && video.fullscreen_enabled) || new_surface == NULL)
274 /* switch display to window mode */
275 if ((new_surface = SDL_SetVideoMode(video.width, video.height,
276 video.depth, surface_flags_window))
279 /* switching display to window mode failed -- should not happen */
280 Error(ERR_WARN, "SDL_SetVideoMode() failed: %s", SDL_GetError());
286 (*backbuffer)->surface = new_surface;
288 video.fullscreen_enabled = FALSE;
296 void SDLCreateBitmapContent(Bitmap *new_bitmap, int width, int height,
299 SDL_Surface *surface_tmp, *surface_native;
301 if ((surface_tmp = SDL_CreateRGBSurface(SURFACE_FLAGS, width, height, depth,
304 Error(ERR_EXIT, "SDL_CreateRGBSurface() failed: %s", SDL_GetError());
306 if ((surface_native = SDL_DisplayFormat(surface_tmp)) == NULL)
307 Error(ERR_EXIT, "SDL_DisplayFormat() failed: %s", SDL_GetError());
309 SDL_FreeSurface(surface_tmp);
311 new_bitmap->surface = surface_native;
314 void SDLFreeBitmapPointers(Bitmap *bitmap)
317 SDL_FreeSurface(bitmap->surface);
318 if (bitmap->surface_masked)
319 SDL_FreeSurface(bitmap->surface_masked);
320 bitmap->surface = NULL;
321 bitmap->surface_masked = NULL;
324 void SDLCopyArea(Bitmap *src_bitmap, Bitmap *dst_bitmap,
325 int src_x, int src_y, int width, int height,
326 int dst_x, int dst_y, int mask_mode)
328 Bitmap *real_dst_bitmap = (dst_bitmap == window ? backbuffer : dst_bitmap);
329 SDL_Rect src_rect, dst_rect;
331 if (src_bitmap == backbuffer)
333 src_x += video_xoffset;
334 src_y += video_yoffset;
342 if (dst_bitmap == backbuffer || dst_bitmap == window)
344 dst_x += video_xoffset;
345 dst_y += video_yoffset;
353 if (src_bitmap != backbuffer || dst_bitmap != window)
354 SDL_BlitSurface((mask_mode == BLIT_MASKED ?
355 src_bitmap->surface_masked : src_bitmap->surface),
356 &src_rect, real_dst_bitmap->surface, &dst_rect);
358 if (dst_bitmap == window)
359 SDL_UpdateRect(backbuffer->surface, dst_x, dst_y, width, height);
362 void SDLFillRectangle(Bitmap *dst_bitmap, int x, int y, int width, int height,
365 Bitmap *real_dst_bitmap = (dst_bitmap == window ? backbuffer : dst_bitmap);
368 if (dst_bitmap == backbuffer || dst_bitmap == window)
379 SDL_FillRect(real_dst_bitmap->surface, &rect, color);
381 if (dst_bitmap == window)
382 SDL_UpdateRect(backbuffer->surface, x, y, width, height);
385 void SDLFadeRectangle(Bitmap *bitmap_cross, int x, int y, int width, int height,
386 int fade_mode, int fade_delay, int post_delay)
388 static boolean initialization_needed = TRUE;
389 static SDL_Surface *surface_source = NULL;
390 static SDL_Surface *surface_target = NULL;
391 static SDL_Surface *surface_black = NULL;
392 SDL_Surface *surface_screen = backbuffer->surface;
393 SDL_Surface *surface_cross = (bitmap_cross ? bitmap_cross->surface : NULL);
394 SDL_Rect src_rect, dst_rect;
395 int src_x = x, src_y = y;
396 int dst_x = x, dst_y = y;
397 unsigned int time_last, time_current;
406 dst_x += video_xoffset;
407 dst_y += video_yoffset;
414 if (initialization_needed)
416 unsigned int flags = SDL_SRCALPHA;
418 /* use same surface type as screen surface */
419 if ((surface_screen->flags & SDL_HWSURFACE))
420 flags |= SDL_HWSURFACE;
422 flags |= SDL_SWSURFACE;
424 /* create surface for temporary copy of screen buffer (source) */
425 if ((surface_source =
426 SDL_CreateRGBSurface(flags,
429 surface_screen->format->BitsPerPixel,
430 surface_screen->format->Rmask,
431 surface_screen->format->Gmask,
432 surface_screen->format->Bmask,
433 surface_screen->format->Amask)) == NULL)
434 Error(ERR_EXIT, "SDL_CreateRGBSurface() failed: %s", SDL_GetError());
436 /* create surface for cross-fading screen buffer (target) */
437 if ((surface_target =
438 SDL_CreateRGBSurface(flags,
441 surface_screen->format->BitsPerPixel,
442 surface_screen->format->Rmask,
443 surface_screen->format->Gmask,
444 surface_screen->format->Bmask,
445 surface_screen->format->Amask)) == NULL)
446 Error(ERR_EXIT, "SDL_CreateRGBSurface() failed: %s", SDL_GetError());
448 /* create black surface for fading from/to black */
450 SDL_CreateRGBSurface(flags,
453 surface_screen->format->BitsPerPixel,
454 surface_screen->format->Rmask,
455 surface_screen->format->Gmask,
456 surface_screen->format->Bmask,
457 surface_screen->format->Amask)) == NULL)
458 Error(ERR_EXIT, "SDL_CreateRGBSurface() failed: %s", SDL_GetError());
460 /* completely fill the surface with black color pixels */
461 SDL_FillRect(surface_black, NULL,
462 SDL_MapRGB(surface_screen->format, 0, 0, 0));
464 initialization_needed = FALSE;
467 /* copy source and target surfaces to temporary surfaces for fading */
468 if (fade_mode == FADE_MODE_CROSSFADE)
470 SDL_BlitSurface(surface_cross, &src_rect, surface_source, &src_rect);
471 SDL_BlitSurface(surface_screen, &dst_rect, surface_target, &src_rect);
473 else if (fade_mode == FADE_MODE_FADE_IN)
475 SDL_BlitSurface(surface_black, &src_rect, surface_source, &src_rect);
476 SDL_BlitSurface(surface_screen, &dst_rect, surface_target, &src_rect);
478 else /* FADE_MODE_FADE_OUT */
480 SDL_BlitSurface(surface_screen, &dst_rect, surface_source, &src_rect);
481 SDL_BlitSurface(surface_black, &src_rect, surface_target, &src_rect);
484 time_current = SDL_GetTicks();
486 for (alpha = 0.0; alpha < 255.0;)
488 time_last = time_current;
489 time_current = SDL_GetTicks();
490 alpha += 255 * ((float)(time_current - time_last) / fade_delay);
491 alpha_final = MIN(MAX(0, alpha), 255);
493 /* draw existing (source) image to screen buffer */
494 SDL_BlitSurface(surface_source, &src_rect, surface_screen, &dst_rect);
496 /* draw new (target) image to screen buffer using alpha blending */
497 SDL_SetAlpha(surface_target, SDL_SRCALPHA, alpha_final);
498 SDL_BlitSurface(surface_target, &src_rect, surface_screen, &dst_rect);
501 /* only update the region of the screen that is affected from fading */
502 SDL_UpdateRect(surface_screen, dst_x, dst_y, width, height);
504 SDL_Flip(surface_screen);
511 void SDLDrawSimpleLine(Bitmap *dst_bitmap, int from_x, int from_y,
512 int to_x, int to_y, Uint32 color)
514 SDL_Surface *surface = dst_bitmap->surface;
518 swap_numbers(&from_x, &to_x);
521 swap_numbers(&from_y, &to_y);
525 rect.w = (to_x - from_x + 1);
526 rect.h = (to_y - from_y + 1);
528 if (dst_bitmap == backbuffer || dst_bitmap == window)
530 rect.x += video_xoffset;
531 rect.y += video_yoffset;
534 SDL_FillRect(surface, &rect, color);
537 void SDLDrawLine(Bitmap *dst_bitmap, int from_x, int from_y,
538 int to_x, int to_y, Uint32 color)
540 if (dst_bitmap == backbuffer || dst_bitmap == window)
542 from_x += video_xoffset;
543 from_y += video_yoffset;
544 to_x += video_xoffset;
545 to_y += video_yoffset;
548 sge_Line(dst_bitmap->surface, from_x, from_y, to_x, to_y, color);
552 void SDLDrawLines(SDL_Surface *surface, struct XY *points,
553 int num_points, Uint32 color)
558 for (i = 0; i < num_points - 1; i++)
560 for (x = 0; x < line_width; x++)
562 for (y = 0; y < line_width; y++)
564 int dx = x - line_width / 2;
565 int dy = y - line_width / 2;
567 if ((x == 0 && y == 0) ||
568 (x == 0 && y == line_width - 1) ||
569 (x == line_width - 1 && y == 0) ||
570 (x == line_width - 1 && y == line_width - 1))
573 sge_Line(surface, points[i].x + dx, points[i].y + dy,
574 points[i+1].x + dx, points[i+1].y + dy, color);
581 Pixel SDLGetPixel(Bitmap *src_bitmap, int x, int y)
583 SDL_Surface *surface = src_bitmap->surface;
585 if (src_bitmap == backbuffer || src_bitmap == window)
591 switch (surface->format->BytesPerPixel)
593 case 1: /* assuming 8-bpp */
595 return *((Uint8 *)surface->pixels + y * surface->pitch + x);
599 case 2: /* probably 15-bpp or 16-bpp */
601 return *((Uint16 *)surface->pixels + y * surface->pitch / 2 + x);
605 case 3: /* slow 24-bpp mode; usually not used */
607 /* does this work? */
608 Uint8 *pix = (Uint8 *)surface->pixels + y * surface->pitch + x * 3;
612 shift = surface->format->Rshift;
613 color |= *(pix + shift / 8) >> shift;
614 shift = surface->format->Gshift;
615 color |= *(pix + shift / 8) >> shift;
616 shift = surface->format->Bshift;
617 color |= *(pix + shift / 8) >> shift;
623 case 4: /* probably 32-bpp */
625 return *((Uint32 *)surface->pixels + y * surface->pitch / 4 + x);
634 /* ========================================================================= */
635 /* The following functions were taken from the SGE library */
636 /* (SDL Graphics Extension Library) by Anders Lindström */
637 /* http://www.etek.chalmers.se/~e8cal1/sge/index.html */
638 /* ========================================================================= */
640 void _PutPixel(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
642 if (x >= 0 && x <= surface->w - 1 && y >= 0 && y <= surface->h - 1)
644 switch (surface->format->BytesPerPixel)
649 *((Uint8 *)surface->pixels + y*surface->pitch + x) = color;
655 /* Probably 15-bpp or 16-bpp */
656 *((Uint16 *)surface->pixels + y*surface->pitch/2 + x) = color;
662 /* Slow 24-bpp mode, usually not used */
666 /* Gack - slow, but endian correct */
667 pix = (Uint8 *)surface->pixels + y * surface->pitch + x*3;
668 shift = surface->format->Rshift;
669 *(pix+shift/8) = color>>shift;
670 shift = surface->format->Gshift;
671 *(pix+shift/8) = color>>shift;
672 shift = surface->format->Bshift;
673 *(pix+shift/8) = color>>shift;
679 /* Probably 32-bpp */
680 *((Uint32 *)surface->pixels + y*surface->pitch/4 + x) = color;
687 void _PutPixelRGB(SDL_Surface *surface, Sint16 x, Sint16 y,
688 Uint8 R, Uint8 G, Uint8 B)
690 _PutPixel(surface, x, y, SDL_MapRGB(surface->format, R, G, B));
693 void _PutPixel8(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
695 *((Uint8 *)surface->pixels + y*surface->pitch + x) = color;
698 void _PutPixel16(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
700 *((Uint16 *)surface->pixels + y*surface->pitch/2 + x) = color;
703 void _PutPixel24(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
708 /* Gack - slow, but endian correct */
709 pix = (Uint8 *)surface->pixels + y * surface->pitch + x*3;
710 shift = surface->format->Rshift;
711 *(pix+shift/8) = color>>shift;
712 shift = surface->format->Gshift;
713 *(pix+shift/8) = color>>shift;
714 shift = surface->format->Bshift;
715 *(pix+shift/8) = color>>shift;
718 void _PutPixel32(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
720 *((Uint32 *)surface->pixels + y*surface->pitch/4 + x) = color;
723 void _PutPixelX(SDL_Surface *dest,Sint16 x,Sint16 y,Uint32 color)
725 switch (dest->format->BytesPerPixel)
728 *((Uint8 *)dest->pixels + y*dest->pitch + x) = color;
732 *((Uint16 *)dest->pixels + y*dest->pitch/2 + x) = color;
736 _PutPixel24(dest,x,y,color);
740 *((Uint32 *)dest->pixels + y*dest->pitch/4 + x) = color;
745 void sge_PutPixel(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
747 if (SDL_MUSTLOCK(surface))
749 if (SDL_LockSurface(surface) < 0)
755 _PutPixel(surface, x, y, color);
757 if (SDL_MUSTLOCK(surface))
759 SDL_UnlockSurface(surface);
763 void sge_PutPixelRGB(SDL_Surface *surface, Sint16 x, Sint16 y,
764 Uint8 r, Uint8 g, Uint8 b)
766 sge_PutPixel(surface, x, y, SDL_MapRGB(surface->format, r, g, b));
769 Sint32 sge_CalcYPitch(SDL_Surface *dest, Sint16 y)
771 if (y >= 0 && y <= dest->h - 1)
773 switch (dest->format->BytesPerPixel)
776 return y*dest->pitch;
780 return y*dest->pitch/2;
784 return y*dest->pitch;
788 return y*dest->pitch/4;
796 void sge_pPutPixel(SDL_Surface *surface, Sint16 x, Sint32 ypitch, Uint32 color)
798 if (x >= 0 && x <= surface->w - 1 && ypitch >= 0)
800 switch (surface->format->BytesPerPixel)
805 *((Uint8 *)surface->pixels + ypitch + x) = color;
811 /* Probably 15-bpp or 16-bpp */
812 *((Uint16 *)surface->pixels + ypitch + x) = color;
818 /* Slow 24-bpp mode, usually not used */
822 /* Gack - slow, but endian correct */
823 pix = (Uint8 *)surface->pixels + ypitch + x*3;
824 shift = surface->format->Rshift;
825 *(pix+shift/8) = color>>shift;
826 shift = surface->format->Gshift;
827 *(pix+shift/8) = color>>shift;
828 shift = surface->format->Bshift;
829 *(pix+shift/8) = color>>shift;
835 /* Probably 32-bpp */
836 *((Uint32 *)surface->pixels + ypitch + x) = color;
843 void sge_HLine(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y,
848 if (SDL_MUSTLOCK(Surface))
850 if (SDL_LockSurface(Surface) < 0)
863 /* Do the clipping */
864 if (y < 0 || y > Surface->h - 1 || x1 > Surface->w - 1 || x2 < 0)
868 if (x2 > Surface->w - 1)
876 SDL_FillRect(Surface, &l, Color);
878 if (SDL_MUSTLOCK(Surface))
880 SDL_UnlockSurface(Surface);
884 void sge_HLineRGB(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y,
885 Uint8 R, Uint8 G, Uint8 B)
887 sge_HLine(Surface, x1, x2, y, SDL_MapRGB(Surface->format, R, G, B));
890 void _HLine(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y, Uint32 Color)
901 /* Do the clipping */
902 if (y < 0 || y > Surface->h - 1 || x1 > Surface->w - 1 || x2 < 0)
906 if (x2 > Surface->w - 1)
914 SDL_FillRect(Surface, &l, Color);
917 void sge_VLine(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2,
922 if (SDL_MUSTLOCK(Surface))
924 if (SDL_LockSurface(Surface) < 0)
937 /* Do the clipping */
938 if (x < 0 || x > Surface->w - 1 || y1 > Surface->h - 1 || y2 < 0)
942 if (y2 > Surface->h - 1)
950 SDL_FillRect(Surface, &l, Color);
952 if (SDL_MUSTLOCK(Surface))
954 SDL_UnlockSurface(Surface);
958 void sge_VLineRGB(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2,
959 Uint8 R, Uint8 G, Uint8 B)
961 sge_VLine(Surface, x, y1, y2, SDL_MapRGB(Surface->format, R, G, B));
964 void _VLine(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2, Uint32 Color)
975 /* Do the clipping */
976 if (x < 0 || x > Surface->w - 1 || y1 > Surface->h - 1 || y2 < 0)
980 if (y2 > Surface->h - 1)
988 SDL_FillRect(Surface, &l, Color);
991 void sge_DoLine(SDL_Surface *Surface, Sint16 x1, Sint16 y1,
992 Sint16 x2, Sint16 y2, Uint32 Color,
993 void Callback(SDL_Surface *Surf, Sint16 X, Sint16 Y,
996 Sint16 dx, dy, sdx, sdy, x, y, px, py;
1001 sdx = (dx < 0) ? -1 : 1;
1002 sdy = (dy < 0) ? -1 : 1;
1014 for (x = 0; x < dx; x++)
1016 Callback(Surface, px, py, Color);
1030 for (y = 0; y < dy; y++)
1032 Callback(Surface, px, py, Color);
1046 void sge_DoLineRGB(SDL_Surface *Surface, Sint16 X1, Sint16 Y1,
1047 Sint16 X2, Sint16 Y2, Uint8 R, Uint8 G, Uint8 B,
1048 void Callback(SDL_Surface *Surf, Sint16 X, Sint16 Y,
1051 sge_DoLine(Surface, X1, Y1, X2, Y2,
1052 SDL_MapRGB(Surface->format, R, G, B), Callback);
1055 void sge_Line(SDL_Surface *Surface, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2,
1058 if (SDL_MUSTLOCK(Surface))
1060 if (SDL_LockSurface(Surface) < 0)
1065 sge_DoLine(Surface, x1, y1, x2, y2, Color, _PutPixel);
1067 /* unlock the display */
1068 if (SDL_MUSTLOCK(Surface))
1070 SDL_UnlockSurface(Surface);
1074 void sge_LineRGB(SDL_Surface *Surface, Sint16 x1, Sint16 y1, Sint16 x2,
1075 Sint16 y2, Uint8 R, Uint8 G, Uint8 B)
1077 sge_Line(Surface, x1, y1, x2, y2, SDL_MapRGB(Surface->format, R, G, B));
1080 void SDLPutPixel(Bitmap *dst_bitmap, int x, int y, Pixel pixel)
1082 if (dst_bitmap == backbuffer || dst_bitmap == window)
1088 sge_PutPixel(dst_bitmap->surface, x, y, pixel);
1093 -----------------------------------------------------------------------------
1094 quick (no, it's slow) and dirty hack to "invert" rectangle inside SDL surface
1095 -----------------------------------------------------------------------------
1098 void SDLInvertArea(Bitmap *bitmap, int src_x, int src_y,
1099 int width, int height, Uint32 color)
1103 for (y = src_y; y < src_y + height; y++)
1105 for (x = src_x; x < src_x + width; x++)
1107 Uint32 pixel = SDLGetPixel(bitmap, x, y);
1109 SDLPutPixel(bitmap, x, y, pixel == BLACK_PIXEL ? color : BLACK_PIXEL);
1114 void SDLCopyInverseMasked(Bitmap *src_bitmap, Bitmap *dst_bitmap,
1115 int src_x, int src_y, int width, int height,
1116 int dst_x, int dst_y)
1120 for (y = 0; y < height; y++)
1122 for (x = 0; x < width; x++)
1124 Uint32 pixel = SDLGetPixel(src_bitmap, src_x + x, src_y + y);
1126 if (pixel != BLACK_PIXEL)
1127 SDLPutPixel(dst_bitmap, dst_x + x, dst_y + y, BLACK_PIXEL);
1133 /* ========================================================================= */
1134 /* The following functions were taken from the SDL_gfx library version 2.0.3 */
1135 /* (Rotozoomer) by Andreas Schiffler */
1136 /* http://www.ferzkopp.net/Software/SDL_gfx-2.0/index.html */
1137 /* ========================================================================= */
1140 -----------------------------------------------------------------------------
1143 zoomes 32bit RGBA/ABGR 'src' surface to 'dst' surface.
1144 -----------------------------------------------------------------------------
1155 int zoomSurfaceRGBA_scaleDownBy2(SDL_Surface *src, SDL_Surface *dst)
1158 tColorRGBA *sp, *csp, *dp;
1162 sp = csp = (tColorRGBA *) src->pixels;
1163 dp = (tColorRGBA *) dst->pixels;
1164 sgap = src->pitch - src->w * 4;
1165 dgap = dst->pitch - dst->w * 4;
1167 for (y = 0; y < dst->h; y++)
1171 for (x = 0; x < dst->w; x++)
1173 tColorRGBA *sp0 = sp;
1174 tColorRGBA *sp1 = (tColorRGBA *) ((Uint8 *) sp + src->pitch);
1175 tColorRGBA *sp00 = &sp0[0];
1176 tColorRGBA *sp01 = &sp0[1];
1177 tColorRGBA *sp10 = &sp1[0];
1178 tColorRGBA *sp11 = &sp1[1];
1181 /* create new color pixel from all four source color pixels */
1182 new.r = (sp00->r + sp01->r + sp10->r + sp11->r) / 4;
1183 new.g = (sp00->g + sp01->g + sp10->g + sp11->g) / 4;
1184 new.b = (sp00->b + sp01->b + sp10->b + sp11->b) / 4;
1185 new.a = (sp00->a + sp01->a + sp10->a + sp11->a) / 4;
1190 /* advance source pointers */
1193 /* advance destination pointer */
1197 /* advance source pointer */
1198 csp = (tColorRGBA *) ((Uint8 *) csp + 2 * src->pitch);
1200 /* advance destination pointers */
1201 dp = (tColorRGBA *) ((Uint8 *) dp + dgap);
1207 int zoomSurfaceRGBA(SDL_Surface *src, SDL_Surface *dst)
1209 int x, y, sx, sy, *sax, *say, *csax, *csay, csx, csy;
1210 tColorRGBA *sp, *csp, *dp;
1213 /* use specialized zoom function when scaling down to exactly half size */
1214 if (src->w == 2 * dst->w &&
1215 src->h == 2 * dst->h)
1216 return zoomSurfaceRGBA_scaleDownBy2(src, dst);
1218 /* variable setup */
1219 sx = (int) (65536.0 * (float) src->w / (float) dst->w);
1220 sy = (int) (65536.0 * (float) src->h / (float) dst->h);
1222 /* allocate memory for row increments */
1223 sax = (int *)checked_malloc((dst->w + 1) * sizeof(Uint32));
1224 say = (int *)checked_malloc((dst->h + 1) * sizeof(Uint32));
1226 /* precalculate row increments */
1229 for (x = 0; x <= dst->w; x++)
1239 for (y = 0; y <= dst->h; y++)
1248 sp = csp = (tColorRGBA *) src->pixels;
1249 dp = (tColorRGBA *) dst->pixels;
1250 sgap = src->pitch - src->w * 4;
1251 dgap = dst->pitch - dst->w * 4;
1254 for (y = 0; y < dst->h; y++)
1259 for (x = 0; x < dst->w; x++)
1264 /* advance source pointers */
1266 sp += (*csax >> 16);
1268 /* advance destination pointer */
1272 /* advance source pointer */
1274 csp = (tColorRGBA *) ((Uint8 *) csp + (*csay >> 16) * src->pitch);
1276 /* advance destination pointers */
1277 dp = (tColorRGBA *) ((Uint8 *) dp + dgap);
1287 -----------------------------------------------------------------------------
1290 zoomes 8 bit palette/Y 'src' surface to 'dst' surface
1291 -----------------------------------------------------------------------------
1294 int zoomSurfaceY(SDL_Surface * src, SDL_Surface * dst)
1296 Uint32 x, y, sx, sy, *sax, *say, *csax, *csay, csx, csy;
1297 Uint8 *sp, *dp, *csp;
1300 /* variable setup */
1301 sx = (Uint32) (65536.0 * (float) src->w / (float) dst->w);
1302 sy = (Uint32) (65536.0 * (float) src->h / (float) dst->h);
1304 /* allocate memory for row increments */
1305 sax = (Uint32 *)checked_malloc(dst->w * sizeof(Uint32));
1306 say = (Uint32 *)checked_malloc(dst->h * sizeof(Uint32));
1308 /* precalculate row increments */
1311 for (x = 0; x < dst->w; x++)
1314 *csax = (csx >> 16);
1321 for (y = 0; y < dst->h; y++)
1324 *csay = (csy >> 16);
1331 for (x = 0; x < dst->w; x++)
1339 for (y = 0; y < dst->h; y++)
1346 sp = csp = (Uint8 *) src->pixels;
1347 dp = (Uint8 *) dst->pixels;
1348 dgap = dst->pitch - dst->w;
1352 for (y = 0; y < dst->h; y++)
1356 for (x = 0; x < dst->w; x++)
1361 /* advance source pointers */
1365 /* advance destination pointer */
1369 /* advance source pointer (for row) */
1370 csp += ((*csay) * src->pitch);
1373 /* advance destination pointers */
1384 -----------------------------------------------------------------------------
1387 Zooms a 32bit or 8bit 'src' surface to newly created 'dst' surface.
1388 'zoomx' and 'zoomy' are scaling factors for width and height.
1389 If the surface is not 8bit or 32bit RGBA/ABGR it will be converted
1390 into a 32bit RGBA format on the fly.
1391 -----------------------------------------------------------------------------
1394 SDL_Surface *zoomSurface(SDL_Surface *src, int dst_width, int dst_height)
1396 SDL_Surface *zoom_src = NULL;
1397 SDL_Surface *zoom_dst = NULL;
1398 boolean is_converted = FALSE;
1405 /* determine if source surface is 32 bit or 8 bit */
1406 is_32bit = (src->format->BitsPerPixel == 32);
1408 if (is_32bit || src->format->BitsPerPixel == 8)
1410 /* use source surface 'as is' */
1415 /* new source surface is 32 bit with a defined RGB ordering */
1416 zoom_src = SDL_CreateRGBSurface(SDL_SWSURFACE, src->w, src->h, 32,
1417 0x000000ff, 0x0000ff00, 0x00ff0000, 0);
1418 SDL_BlitSurface(src, NULL, zoom_src, NULL);
1420 is_converted = TRUE;
1423 /* allocate surface to completely contain the zoomed surface */
1426 /* target surface is 32 bit with source RGBA/ABGR ordering */
1427 zoom_dst = SDL_CreateRGBSurface(SDL_SWSURFACE, dst_width, dst_height, 32,
1428 zoom_src->format->Rmask,
1429 zoom_src->format->Gmask,
1430 zoom_src->format->Bmask, 0);
1434 /* target surface is 8 bit */
1435 zoom_dst = SDL_CreateRGBSurface(SDL_SWSURFACE, dst_width, dst_height, 8,
1439 /* lock source surface */
1440 SDL_LockSurface(zoom_src);
1442 /* check which kind of surface we have */
1445 /* call the 32 bit transformation routine to do the zooming */
1446 zoomSurfaceRGBA(zoom_src, zoom_dst);
1451 for (i = 0; i < zoom_src->format->palette->ncolors; i++)
1452 zoom_dst->format->palette->colors[i] =
1453 zoom_src->format->palette->colors[i];
1454 zoom_dst->format->palette->ncolors = zoom_src->format->palette->ncolors;
1456 /* call the 8 bit transformation routine to do the zooming */
1457 zoomSurfaceY(zoom_src, zoom_dst);
1460 /* unlock source surface */
1461 SDL_UnlockSurface(zoom_src);
1463 /* free temporary surface */
1465 SDL_FreeSurface(zoom_src);
1467 /* return destination surface */
1471 void SDLZoomBitmap(Bitmap *src_bitmap, Bitmap *dst_bitmap)
1473 SDL_Surface *sdl_surface_tmp;
1474 int dst_width = dst_bitmap->width;
1475 int dst_height = dst_bitmap->height;
1477 /* throw away old destination surface */
1478 SDL_FreeSurface(dst_bitmap->surface);
1480 /* create zoomed temporary surface from source surface */
1481 sdl_surface_tmp = zoomSurface(src_bitmap->surface, dst_width, dst_height);
1483 /* create native format destination surface from zoomed temporary surface */
1484 dst_bitmap->surface = SDL_DisplayFormat(sdl_surface_tmp);
1486 /* free temporary surface */
1487 SDL_FreeSurface(sdl_surface_tmp);
1491 /* ========================================================================= */
1492 /* load image to bitmap */
1493 /* ========================================================================= */
1495 Bitmap *SDLLoadImage(char *filename)
1497 Bitmap *new_bitmap = CreateBitmapStruct();
1498 SDL_Surface *sdl_image_tmp;
1500 /* load image to temporary surface */
1501 if ((sdl_image_tmp = IMG_Load(filename)) == NULL)
1503 SetError("IMG_Load(): %s", SDL_GetError());
1508 /* create native non-transparent surface for current image */
1509 if ((new_bitmap->surface = SDL_DisplayFormat(sdl_image_tmp)) == NULL)
1511 SetError("SDL_DisplayFormat(): %s", SDL_GetError());
1516 /* create native transparent surface for current image */
1517 SDL_SetColorKey(sdl_image_tmp, SDL_SRCCOLORKEY,
1518 SDL_MapRGB(sdl_image_tmp->format, 0x00, 0x00, 0x00));
1519 if ((new_bitmap->surface_masked = SDL_DisplayFormat(sdl_image_tmp)) == NULL)
1521 SetError("SDL_DisplayFormat(): %s", SDL_GetError());
1526 /* free temporary surface */
1527 SDL_FreeSurface(sdl_image_tmp);
1529 new_bitmap->width = new_bitmap->surface->w;
1530 new_bitmap->height = new_bitmap->surface->h;
1536 /* ------------------------------------------------------------------------- */
1537 /* custom cursor fuctions */
1538 /* ------------------------------------------------------------------------- */
1540 static SDL_Cursor *create_cursor(struct MouseCursorInfo *cursor_info)
1542 return SDL_CreateCursor(cursor_info->data, cursor_info->mask,
1543 cursor_info->width, cursor_info->height,
1544 cursor_info->hot_x, cursor_info->hot_y);
1547 void SDLSetMouseCursor(struct MouseCursorInfo *cursor_info)
1549 static struct MouseCursorInfo *last_cursor_info = NULL;
1550 static struct MouseCursorInfo *last_cursor_info2 = NULL;
1551 static SDL_Cursor *cursor_default = NULL;
1552 static SDL_Cursor *cursor_current = NULL;
1554 /* if invoked for the first time, store the SDL default cursor */
1555 if (cursor_default == NULL)
1556 cursor_default = SDL_GetCursor();
1558 /* only create new cursor if cursor info (custom only) has changed */
1559 if (cursor_info != NULL && cursor_info != last_cursor_info)
1561 cursor_current = create_cursor(cursor_info);
1562 last_cursor_info = cursor_info;
1565 /* only set new cursor if cursor info (custom or NULL) has changed */
1566 if (cursor_info != last_cursor_info2)
1567 SDL_SetCursor(cursor_info ? cursor_current : cursor_default);
1569 last_cursor_info2 = cursor_info;
1573 /* ========================================================================= */
1574 /* audio functions */
1575 /* ========================================================================= */
1577 void SDLOpenAudio(void)
1579 if (!strEqual(setup.system.sdl_audiodriver, ARG_DEFAULT))
1580 putenv(getStringCat2("SDL_AUDIODRIVER=", setup.system.sdl_audiodriver));
1582 if (SDL_InitSubSystem(SDL_INIT_AUDIO) < 0)
1584 Error(ERR_WARN, "SDL_InitSubSystem() failed: %s", SDL_GetError());
1588 if (Mix_OpenAudio(DEFAULT_AUDIO_SAMPLE_RATE, MIX_DEFAULT_FORMAT,
1589 AUDIO_NUM_CHANNELS_STEREO,
1590 setup.system.audio_fragment_size) < 0)
1592 Error(ERR_WARN, "Mix_OpenAudio() failed: %s", SDL_GetError());
1596 audio.sound_available = TRUE;
1597 audio.music_available = TRUE;
1598 audio.loops_available = TRUE;
1599 audio.sound_enabled = TRUE;
1601 /* set number of available mixer channels */
1602 audio.num_channels = Mix_AllocateChannels(NUM_MIXER_CHANNELS);
1603 audio.music_channel = MUSIC_CHANNEL;
1604 audio.first_sound_channel = FIRST_SOUND_CHANNEL;
1606 Mixer_InitChannels();
1609 void SDLCloseAudio(void)
1612 Mix_HaltChannel(-1);
1615 SDL_QuitSubSystem(SDL_INIT_AUDIO);
1619 /* ========================================================================= */
1620 /* event functions */
1621 /* ========================================================================= */
1623 void SDLNextEvent(Event *event)
1625 SDL_WaitEvent(event);
1627 if (event->type == EVENT_BUTTONPRESS ||
1628 event->type == EVENT_BUTTONRELEASE)
1630 if (((ButtonEvent *)event)->x > video_xoffset)
1631 ((ButtonEvent *)event)->x -= video_xoffset;
1633 ((ButtonEvent *)event)->x = 0;
1634 if (((ButtonEvent *)event)->y > video_yoffset)
1635 ((ButtonEvent *)event)->y -= video_yoffset;
1637 ((ButtonEvent *)event)->y = 0;
1639 else if (event->type == EVENT_MOTIONNOTIFY)
1641 if (((MotionEvent *)event)->x > video_xoffset)
1642 ((MotionEvent *)event)->x -= video_xoffset;
1644 ((MotionEvent *)event)->x = 0;
1645 if (((MotionEvent *)event)->y > video_yoffset)
1646 ((MotionEvent *)event)->y -= video_yoffset;
1648 ((MotionEvent *)event)->y = 0;
1653 /* ========================================================================= */
1654 /* joystick functions */
1655 /* ========================================================================= */
1657 static SDL_Joystick *sdl_joystick[MAX_PLAYERS] = { NULL, NULL, NULL, NULL };
1658 static int sdl_js_axis[MAX_PLAYERS][2] = { {0, 0}, {0, 0}, {0, 0}, {0, 0} };
1659 static int sdl_js_button[MAX_PLAYERS][2] = { {0, 0}, {0, 0}, {0, 0}, {0, 0} };
1661 static boolean SDLOpenJoystick(int nr)
1663 if (nr < 0 || nr > MAX_PLAYERS)
1666 return ((sdl_joystick[nr] = SDL_JoystickOpen(nr)) == NULL ? FALSE : TRUE);
1669 static void SDLCloseJoystick(int nr)
1671 if (nr < 0 || nr > MAX_PLAYERS)
1674 SDL_JoystickClose(sdl_joystick[nr]);
1677 static boolean SDLCheckJoystickOpened(int nr)
1679 if (nr < 0 || nr > MAX_PLAYERS)
1682 return (SDL_JoystickOpened(nr) ? TRUE : FALSE);
1685 void HandleJoystickEvent(Event *event)
1689 case SDL_JOYAXISMOTION:
1690 if (event->jaxis.axis < 2)
1691 sdl_js_axis[event->jaxis.which][event->jaxis.axis]= event->jaxis.value;
1694 case SDL_JOYBUTTONDOWN:
1695 if (event->jbutton.button < 2)
1696 sdl_js_button[event->jbutton.which][event->jbutton.button] = TRUE;
1699 case SDL_JOYBUTTONUP:
1700 if (event->jbutton.button < 2)
1701 sdl_js_button[event->jbutton.which][event->jbutton.button] = FALSE;
1709 void SDLInitJoysticks()
1711 static boolean sdl_joystick_subsystem_initialized = FALSE;
1712 boolean print_warning = !sdl_joystick_subsystem_initialized;
1715 if (!sdl_joystick_subsystem_initialized)
1717 sdl_joystick_subsystem_initialized = TRUE;
1719 if (SDL_Init(SDL_INIT_JOYSTICK) < 0)
1721 Error(ERR_EXIT, "SDL_Init() failed: %s", SDL_GetError());
1726 for (i = 0; i < MAX_PLAYERS; i++)
1728 /* get configured joystick for this player */
1729 char *device_name = setup.input[i].joy.device_name;
1730 int joystick_nr = getJoystickNrFromDeviceName(device_name);
1732 if (joystick_nr >= SDL_NumJoysticks())
1734 if (setup.input[i].use_joystick && print_warning)
1735 Error(ERR_WARN, "cannot find joystick %d", joystick_nr);
1740 /* misuse joystick file descriptor variable to store joystick number */
1741 joystick.fd[i] = joystick_nr;
1743 if (joystick_nr == -1)
1746 /* this allows subsequent calls to 'InitJoysticks' for re-initialization */
1747 if (SDLCheckJoystickOpened(joystick_nr))
1748 SDLCloseJoystick(joystick_nr);
1750 if (!setup.input[i].use_joystick)
1753 if (!SDLOpenJoystick(joystick_nr))
1756 Error(ERR_WARN, "cannot open joystick %d", joystick_nr);
1761 joystick.status = JOYSTICK_ACTIVATED;
1765 boolean SDLReadJoystick(int nr, int *x, int *y, boolean *b1, boolean *b2)
1767 if (nr < 0 || nr >= MAX_PLAYERS)
1771 *x = sdl_js_axis[nr][0];
1773 *y = sdl_js_axis[nr][1];
1776 *b1 = sdl_js_button[nr][0];
1778 *b2 = sdl_js_button[nr][1];
1783 #endif /* TARGET_SDL */