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_screen_copy = NULL;
385 static SDL_Surface *surface_black = NULL;
386 SDL_Surface *surface_screen = backbuffer->surface;
387 SDL_Surface *surface_cross; /* initialized later */
388 SDL_Rect src_rect, dst_rect;
389 int src_x = x, src_y = y;
390 int dst_x = x, dst_y = y;
391 boolean fade_reverse = (fade_mode == FADE_MODE_FADE_IN ? TRUE : FALSE);
392 unsigned int time_last, time_current;
401 dst_x += video_xoffset;
402 dst_y += video_yoffset;
410 if (!initialization_needed)
412 /* check if screen size has changed (can happen when toggling fullscreen) */
413 if (surface_screen_copy->w != surface_screen->w ||
414 surface_screen_copy->h != surface_screen->h)
416 SDL_FreeSurface(surface_screen_copy);
417 SDL_FreeSurface(surface_black);
419 initialization_needed = TRUE;
424 if (initialization_needed)
426 unsigned int flags = SDL_SRCALPHA;
428 /* use same surface type as screen surface */
429 if ((surface_screen->flags & SDL_HWSURFACE))
430 flags |= SDL_HWSURFACE;
432 flags |= SDL_SWSURFACE;
434 /* create surface for temporary copy of screen buffer */
435 if ((surface_screen_copy =
436 SDL_CreateRGBSurface(flags,
444 surface_screen->format->BitsPerPixel,
445 surface_screen->format->Rmask,
446 surface_screen->format->Gmask,
447 surface_screen->format->Bmask,
448 surface_screen->format->Amask)) == NULL)
449 Error(ERR_EXIT, "SDL_CreateRGBSurface( ) failed: %s", SDL_GetError());
451 /* create black surface for fading from/to black */
453 SDL_CreateRGBSurface(flags,
461 surface_screen->format->BitsPerPixel,
462 surface_screen->format->Rmask,
463 surface_screen->format->Gmask,
464 surface_screen->format->Bmask,
465 surface_screen->format->Amask)) == NULL)
466 Error(ERR_EXIT, "SDL_CreateRGBSurface( ) failed: %s", SDL_GetError());
468 /* completely fill the surface with black color pixels */
469 SDL_FillRect(surface_black, NULL,
470 SDL_MapRGB(surface_screen->format, 0, 0, 0));
472 initialization_needed = FALSE;
475 /* copy the current screen backbuffer to the temporary screen copy buffer */
476 SDL_BlitSurface(surface_screen, &dst_rect, surface_screen_copy, &src_rect);
478 surface_cross = (fade_mode == FADE_MODE_CROSSFADE ? bitmap_cross->surface :
481 time_current = SDL_GetTicks();
483 for (alpha = 0.0; alpha < 255.0;)
485 time_last = time_current;
486 time_current = SDL_GetTicks();
487 alpha += 255 * ((float)(time_current - time_last) / fade_delay);
488 alpha_final = (int)(fade_reverse ? 255.0 - alpha : alpha);
489 alpha_final = MIN(MAX(0, alpha_final), 255);
491 /* draw existing image to screen buffer */
492 SDL_BlitSurface(surface_screen_copy, &src_rect, surface_screen, &dst_rect);
494 /* draw new image to screen buffer using alpha blending */
495 SDL_SetAlpha(surface_cross, SDL_SRCALPHA, alpha_final);
496 SDL_BlitSurface(surface_cross, &src_rect, surface_screen, &dst_rect);
498 /* draw screen buffer to visible display */
500 SDL_UpdateRect(surface_screen, dst_x, dst_y, width, height);
502 SDL_Flip(surface_screen);
509 void SDLDrawSimpleLine(Bitmap *dst_bitmap, int from_x, int from_y,
510 int to_x, int to_y, Uint32 color)
512 SDL_Surface *surface = dst_bitmap->surface;
516 swap_numbers(&from_x, &to_x);
519 swap_numbers(&from_y, &to_y);
523 rect.w = (to_x - from_x + 1);
524 rect.h = (to_y - from_y + 1);
526 if (dst_bitmap == backbuffer || dst_bitmap == window)
528 rect.x += video_xoffset;
529 rect.y += video_yoffset;
532 SDL_FillRect(surface, &rect, color);
535 void SDLDrawLine(Bitmap *dst_bitmap, int from_x, int from_y,
536 int to_x, int to_y, Uint32 color)
538 if (dst_bitmap == backbuffer || dst_bitmap == window)
540 from_x += video_xoffset;
541 from_y += video_yoffset;
542 to_x += video_xoffset;
543 to_y += video_yoffset;
546 sge_Line(dst_bitmap->surface, from_x, from_y, to_x, to_y, color);
550 void SDLDrawLines(SDL_Surface *surface, struct XY *points,
551 int num_points, Uint32 color)
556 for (i = 0; i < num_points - 1; i++)
558 for (x = 0; x < line_width; x++)
560 for (y = 0; y < line_width; y++)
562 int dx = x - line_width / 2;
563 int dy = y - line_width / 2;
565 if ((x == 0 && y == 0) ||
566 (x == 0 && y == line_width - 1) ||
567 (x == line_width - 1 && y == 0) ||
568 (x == line_width - 1 && y == line_width - 1))
571 sge_Line(surface, points[i].x + dx, points[i].y + dy,
572 points[i+1].x + dx, points[i+1].y + dy, color);
579 Pixel SDLGetPixel(Bitmap *src_bitmap, int x, int y)
581 SDL_Surface *surface = src_bitmap->surface;
583 if (src_bitmap == backbuffer || src_bitmap == window)
589 switch (surface->format->BytesPerPixel)
591 case 1: /* assuming 8-bpp */
593 return *((Uint8 *)surface->pixels + y * surface->pitch + x);
597 case 2: /* probably 15-bpp or 16-bpp */
599 return *((Uint16 *)surface->pixels + y * surface->pitch / 2 + x);
603 case 3: /* slow 24-bpp mode; usually not used */
605 /* does this work? */
606 Uint8 *pix = (Uint8 *)surface->pixels + y * surface->pitch + x * 3;
610 shift = surface->format->Rshift;
611 color |= *(pix + shift / 8) >> shift;
612 shift = surface->format->Gshift;
613 color |= *(pix + shift / 8) >> shift;
614 shift = surface->format->Bshift;
615 color |= *(pix + shift / 8) >> shift;
621 case 4: /* probably 32-bpp */
623 return *((Uint32 *)surface->pixels + y * surface->pitch / 4 + x);
632 /* ========================================================================= */
633 /* The following functions were taken from the SGE library */
634 /* (SDL Graphics Extension Library) by Anders Lindström */
635 /* http://www.etek.chalmers.se/~e8cal1/sge/index.html */
636 /* ========================================================================= */
638 void _PutPixel(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
640 if (x >= 0 && x <= surface->w - 1 && y >= 0 && y <= surface->h - 1)
642 switch (surface->format->BytesPerPixel)
647 *((Uint8 *)surface->pixels + y*surface->pitch + x) = color;
653 /* Probably 15-bpp or 16-bpp */
654 *((Uint16 *)surface->pixels + y*surface->pitch/2 + x) = color;
660 /* Slow 24-bpp mode, usually not used */
664 /* Gack - slow, but endian correct */
665 pix = (Uint8 *)surface->pixels + y * surface->pitch + x*3;
666 shift = surface->format->Rshift;
667 *(pix+shift/8) = color>>shift;
668 shift = surface->format->Gshift;
669 *(pix+shift/8) = color>>shift;
670 shift = surface->format->Bshift;
671 *(pix+shift/8) = color>>shift;
677 /* Probably 32-bpp */
678 *((Uint32 *)surface->pixels + y*surface->pitch/4 + x) = color;
685 void _PutPixelRGB(SDL_Surface *surface, Sint16 x, Sint16 y,
686 Uint8 R, Uint8 G, Uint8 B)
688 _PutPixel(surface, x, y, SDL_MapRGB(surface->format, R, G, B));
691 void _PutPixel8(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
693 *((Uint8 *)surface->pixels + y*surface->pitch + x) = color;
696 void _PutPixel16(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
698 *((Uint16 *)surface->pixels + y*surface->pitch/2 + x) = color;
701 void _PutPixel24(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
706 /* Gack - slow, but endian correct */
707 pix = (Uint8 *)surface->pixels + y * surface->pitch + x*3;
708 shift = surface->format->Rshift;
709 *(pix+shift/8) = color>>shift;
710 shift = surface->format->Gshift;
711 *(pix+shift/8) = color>>shift;
712 shift = surface->format->Bshift;
713 *(pix+shift/8) = color>>shift;
716 void _PutPixel32(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
718 *((Uint32 *)surface->pixels + y*surface->pitch/4 + x) = color;
721 void _PutPixelX(SDL_Surface *dest,Sint16 x,Sint16 y,Uint32 color)
723 switch (dest->format->BytesPerPixel)
726 *((Uint8 *)dest->pixels + y*dest->pitch + x) = color;
730 *((Uint16 *)dest->pixels + y*dest->pitch/2 + x) = color;
734 _PutPixel24(dest,x,y,color);
738 *((Uint32 *)dest->pixels + y*dest->pitch/4 + x) = color;
743 void sge_PutPixel(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
745 if (SDL_MUSTLOCK(surface))
747 if (SDL_LockSurface(surface) < 0)
753 _PutPixel(surface, x, y, color);
755 if (SDL_MUSTLOCK(surface))
757 SDL_UnlockSurface(surface);
761 void sge_PutPixelRGB(SDL_Surface *surface, Sint16 x, Sint16 y,
762 Uint8 r, Uint8 g, Uint8 b)
764 sge_PutPixel(surface, x, y, SDL_MapRGB(surface->format, r, g, b));
767 Sint32 sge_CalcYPitch(SDL_Surface *dest, Sint16 y)
769 if (y >= 0 && y <= dest->h - 1)
771 switch (dest->format->BytesPerPixel)
774 return y*dest->pitch;
778 return y*dest->pitch/2;
782 return y*dest->pitch;
786 return y*dest->pitch/4;
794 void sge_pPutPixel(SDL_Surface *surface, Sint16 x, Sint32 ypitch, Uint32 color)
796 if (x >= 0 && x <= surface->w - 1 && ypitch >= 0)
798 switch (surface->format->BytesPerPixel)
803 *((Uint8 *)surface->pixels + ypitch + x) = color;
809 /* Probably 15-bpp or 16-bpp */
810 *((Uint16 *)surface->pixels + ypitch + x) = color;
816 /* Slow 24-bpp mode, usually not used */
820 /* Gack - slow, but endian correct */
821 pix = (Uint8 *)surface->pixels + ypitch + x*3;
822 shift = surface->format->Rshift;
823 *(pix+shift/8) = color>>shift;
824 shift = surface->format->Gshift;
825 *(pix+shift/8) = color>>shift;
826 shift = surface->format->Bshift;
827 *(pix+shift/8) = color>>shift;
833 /* Probably 32-bpp */
834 *((Uint32 *)surface->pixels + ypitch + x) = color;
841 void sge_HLine(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y,
846 if (SDL_MUSTLOCK(Surface))
848 if (SDL_LockSurface(Surface) < 0)
861 /* Do the clipping */
862 if (y < 0 || y > Surface->h - 1 || x1 > Surface->w - 1 || x2 < 0)
866 if (x2 > Surface->w - 1)
874 SDL_FillRect(Surface, &l, Color);
876 if (SDL_MUSTLOCK(Surface))
878 SDL_UnlockSurface(Surface);
882 void sge_HLineRGB(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y,
883 Uint8 R, Uint8 G, Uint8 B)
885 sge_HLine(Surface, x1, x2, y, SDL_MapRGB(Surface->format, R, G, B));
888 void _HLine(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y, Uint32 Color)
899 /* Do the clipping */
900 if (y < 0 || y > Surface->h - 1 || x1 > Surface->w - 1 || x2 < 0)
904 if (x2 > Surface->w - 1)
912 SDL_FillRect(Surface, &l, Color);
915 void sge_VLine(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2,
920 if (SDL_MUSTLOCK(Surface))
922 if (SDL_LockSurface(Surface) < 0)
935 /* Do the clipping */
936 if (x < 0 || x > Surface->w - 1 || y1 > Surface->h - 1 || y2 < 0)
940 if (y2 > Surface->h - 1)
948 SDL_FillRect(Surface, &l, Color);
950 if (SDL_MUSTLOCK(Surface))
952 SDL_UnlockSurface(Surface);
956 void sge_VLineRGB(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2,
957 Uint8 R, Uint8 G, Uint8 B)
959 sge_VLine(Surface, x, y1, y2, SDL_MapRGB(Surface->format, R, G, B));
962 void _VLine(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2, Uint32 Color)
973 /* Do the clipping */
974 if (x < 0 || x > Surface->w - 1 || y1 > Surface->h - 1 || y2 < 0)
978 if (y2 > Surface->h - 1)
986 SDL_FillRect(Surface, &l, Color);
989 void sge_DoLine(SDL_Surface *Surface, Sint16 x1, Sint16 y1,
990 Sint16 x2, Sint16 y2, Uint32 Color,
991 void Callback(SDL_Surface *Surf, Sint16 X, Sint16 Y,
994 Sint16 dx, dy, sdx, sdy, x, y, px, py;
999 sdx = (dx < 0) ? -1 : 1;
1000 sdy = (dy < 0) ? -1 : 1;
1012 for (x = 0; x < dx; x++)
1014 Callback(Surface, px, py, Color);
1028 for (y = 0; y < dy; y++)
1030 Callback(Surface, px, py, Color);
1044 void sge_DoLineRGB(SDL_Surface *Surface, Sint16 X1, Sint16 Y1,
1045 Sint16 X2, Sint16 Y2, Uint8 R, Uint8 G, Uint8 B,
1046 void Callback(SDL_Surface *Surf, Sint16 X, Sint16 Y,
1049 sge_DoLine(Surface, X1, Y1, X2, Y2,
1050 SDL_MapRGB(Surface->format, R, G, B), Callback);
1053 void sge_Line(SDL_Surface *Surface, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2,
1056 if (SDL_MUSTLOCK(Surface))
1058 if (SDL_LockSurface(Surface) < 0)
1063 sge_DoLine(Surface, x1, y1, x2, y2, Color, _PutPixel);
1065 /* unlock the display */
1066 if (SDL_MUSTLOCK(Surface))
1068 SDL_UnlockSurface(Surface);
1072 void sge_LineRGB(SDL_Surface *Surface, Sint16 x1, Sint16 y1, Sint16 x2,
1073 Sint16 y2, Uint8 R, Uint8 G, Uint8 B)
1075 sge_Line(Surface, x1, y1, x2, y2, SDL_MapRGB(Surface->format, R, G, B));
1078 void SDLPutPixel(Bitmap *dst_bitmap, int x, int y, Pixel pixel)
1080 if (dst_bitmap == backbuffer || dst_bitmap == window)
1086 sge_PutPixel(dst_bitmap->surface, x, y, pixel);
1091 -----------------------------------------------------------------------------
1092 quick (no, it's slow) and dirty hack to "invert" rectangle inside SDL surface
1093 -----------------------------------------------------------------------------
1096 void SDLInvertArea(Bitmap *bitmap, int src_x, int src_y,
1097 int width, int height, Uint32 color)
1101 for (y = src_y; y < src_y + height; y++)
1103 for (x = src_x; x < src_x + width; x++)
1105 Uint32 pixel = SDLGetPixel(bitmap, x, y);
1107 SDLPutPixel(bitmap, x, y, pixel == BLACK_PIXEL ? color : BLACK_PIXEL);
1112 void SDLCopyInverseMasked(Bitmap *src_bitmap, Bitmap *dst_bitmap,
1113 int src_x, int src_y, int width, int height,
1114 int dst_x, int dst_y)
1118 for (y = 0; y < height; y++)
1120 for (x = 0; x < width; x++)
1122 Uint32 pixel = SDLGetPixel(src_bitmap, src_x + x, src_y + y);
1124 if (pixel != BLACK_PIXEL)
1125 SDLPutPixel(dst_bitmap, dst_x + x, dst_y + y, BLACK_PIXEL);
1131 /* ========================================================================= */
1132 /* The following functions were taken from the SDL_gfx library version 2.0.3 */
1133 /* (Rotozoomer) by Andreas Schiffler */
1134 /* http://www.ferzkopp.net/Software/SDL_gfx-2.0/index.html */
1135 /* ========================================================================= */
1138 -----------------------------------------------------------------------------
1141 zoomes 32bit RGBA/ABGR 'src' surface to 'dst' surface.
1142 -----------------------------------------------------------------------------
1153 int zoomSurfaceRGBA_scaleDownBy2(SDL_Surface *src, SDL_Surface *dst)
1156 tColorRGBA *sp, *csp, *dp;
1160 sp = csp = (tColorRGBA *) src->pixels;
1161 dp = (tColorRGBA *) dst->pixels;
1162 sgap = src->pitch - src->w * 4;
1163 dgap = dst->pitch - dst->w * 4;
1165 for (y = 0; y < dst->h; y++)
1169 for (x = 0; x < dst->w; x++)
1171 tColorRGBA *sp0 = sp;
1172 tColorRGBA *sp1 = (tColorRGBA *) ((Uint8 *) sp + src->pitch);
1173 tColorRGBA *sp00 = &sp0[0];
1174 tColorRGBA *sp01 = &sp0[1];
1175 tColorRGBA *sp10 = &sp1[0];
1176 tColorRGBA *sp11 = &sp1[1];
1179 /* create new color pixel from all four source color pixels */
1180 new.r = (sp00->r + sp01->r + sp10->r + sp11->r) / 4;
1181 new.g = (sp00->g + sp01->g + sp10->g + sp11->g) / 4;
1182 new.b = (sp00->b + sp01->b + sp10->b + sp11->b) / 4;
1183 new.a = (sp00->a + sp01->a + sp10->a + sp11->a) / 4;
1188 /* advance source pointers */
1191 /* advance destination pointer */
1195 /* advance source pointer */
1196 csp = (tColorRGBA *) ((Uint8 *) csp + 2 * src->pitch);
1198 /* advance destination pointers */
1199 dp = (tColorRGBA *) ((Uint8 *) dp + dgap);
1205 int zoomSurfaceRGBA(SDL_Surface *src, SDL_Surface *dst)
1207 int x, y, sx, sy, *sax, *say, *csax, *csay, csx, csy;
1208 tColorRGBA *sp, *csp, *dp;
1211 /* use specialized zoom function when scaling down to exactly half size */
1212 if (src->w == 2 * dst->w &&
1213 src->h == 2 * dst->h)
1214 return zoomSurfaceRGBA_scaleDownBy2(src, dst);
1216 /* variable setup */
1217 sx = (int) (65536.0 * (float) src->w / (float) dst->w);
1218 sy = (int) (65536.0 * (float) src->h / (float) dst->h);
1220 /* allocate memory for row increments */
1221 sax = (int *)checked_malloc((dst->w + 1) * sizeof(Uint32));
1222 say = (int *)checked_malloc((dst->h + 1) * sizeof(Uint32));
1224 /* precalculate row increments */
1227 for (x = 0; x <= dst->w; x++)
1237 for (y = 0; y <= dst->h; y++)
1246 sp = csp = (tColorRGBA *) src->pixels;
1247 dp = (tColorRGBA *) dst->pixels;
1248 sgap = src->pitch - src->w * 4;
1249 dgap = dst->pitch - dst->w * 4;
1252 for (y = 0; y < dst->h; y++)
1257 for (x = 0; x < dst->w; x++)
1262 /* advance source pointers */
1264 sp += (*csax >> 16);
1266 /* advance destination pointer */
1270 /* advance source pointer */
1272 csp = (tColorRGBA *) ((Uint8 *) csp + (*csay >> 16) * src->pitch);
1274 /* advance destination pointers */
1275 dp = (tColorRGBA *) ((Uint8 *) dp + dgap);
1285 -----------------------------------------------------------------------------
1288 zoomes 8 bit palette/Y 'src' surface to 'dst' surface
1289 -----------------------------------------------------------------------------
1292 int zoomSurfaceY(SDL_Surface * src, SDL_Surface * dst)
1294 Uint32 x, y, sx, sy, *sax, *say, *csax, *csay, csx, csy;
1295 Uint8 *sp, *dp, *csp;
1298 /* variable setup */
1299 sx = (Uint32) (65536.0 * (float) src->w / (float) dst->w);
1300 sy = (Uint32) (65536.0 * (float) src->h / (float) dst->h);
1302 /* allocate memory for row increments */
1303 sax = (Uint32 *)checked_malloc(dst->w * sizeof(Uint32));
1304 say = (Uint32 *)checked_malloc(dst->h * sizeof(Uint32));
1306 /* precalculate row increments */
1309 for (x = 0; x < dst->w; x++)
1312 *csax = (csx >> 16);
1319 for (y = 0; y < dst->h; y++)
1322 *csay = (csy >> 16);
1329 for (x = 0; x < dst->w; x++)
1337 for (y = 0; y < dst->h; y++)
1344 sp = csp = (Uint8 *) src->pixels;
1345 dp = (Uint8 *) dst->pixels;
1346 dgap = dst->pitch - dst->w;
1350 for (y = 0; y < dst->h; y++)
1354 for (x = 0; x < dst->w; x++)
1359 /* advance source pointers */
1363 /* advance destination pointer */
1367 /* advance source pointer (for row) */
1368 csp += ((*csay) * src->pitch);
1371 /* advance destination pointers */
1382 -----------------------------------------------------------------------------
1385 Zooms a 32bit or 8bit 'src' surface to newly created 'dst' surface.
1386 'zoomx' and 'zoomy' are scaling factors for width and height.
1387 If the surface is not 8bit or 32bit RGBA/ABGR it will be converted
1388 into a 32bit RGBA format on the fly.
1389 -----------------------------------------------------------------------------
1392 SDL_Surface *zoomSurface(SDL_Surface *src, int dst_width, int dst_height)
1394 SDL_Surface *zoom_src = NULL;
1395 SDL_Surface *zoom_dst = NULL;
1396 boolean is_converted = FALSE;
1403 /* determine if source surface is 32 bit or 8 bit */
1404 is_32bit = (src->format->BitsPerPixel == 32);
1406 if (is_32bit || src->format->BitsPerPixel == 8)
1408 /* use source surface 'as is' */
1413 /* new source surface is 32 bit with a defined RGB ordering */
1414 zoom_src = SDL_CreateRGBSurface(SDL_SWSURFACE, src->w, src->h, 32,
1415 0x000000ff, 0x0000ff00, 0x00ff0000, 0);
1416 SDL_BlitSurface(src, NULL, zoom_src, NULL);
1418 is_converted = TRUE;
1421 /* allocate surface to completely contain the zoomed surface */
1424 /* target surface is 32 bit with source RGBA/ABGR ordering */
1425 zoom_dst = SDL_CreateRGBSurface(SDL_SWSURFACE, dst_width, dst_height, 32,
1426 zoom_src->format->Rmask,
1427 zoom_src->format->Gmask,
1428 zoom_src->format->Bmask, 0);
1432 /* target surface is 8 bit */
1433 zoom_dst = SDL_CreateRGBSurface(SDL_SWSURFACE, dst_width, dst_height, 8,
1437 /* lock source surface */
1438 SDL_LockSurface(zoom_src);
1440 /* check which kind of surface we have */
1443 /* call the 32 bit transformation routine to do the zooming */
1444 zoomSurfaceRGBA(zoom_src, zoom_dst);
1449 for (i = 0; i < zoom_src->format->palette->ncolors; i++)
1450 zoom_dst->format->palette->colors[i] =
1451 zoom_src->format->palette->colors[i];
1452 zoom_dst->format->palette->ncolors = zoom_src->format->palette->ncolors;
1454 /* call the 8 bit transformation routine to do the zooming */
1455 zoomSurfaceY(zoom_src, zoom_dst);
1458 /* unlock source surface */
1459 SDL_UnlockSurface(zoom_src);
1461 /* free temporary surface */
1463 SDL_FreeSurface(zoom_src);
1465 /* return destination surface */
1469 void SDLZoomBitmap(Bitmap *src_bitmap, Bitmap *dst_bitmap)
1471 SDL_Surface *sdl_surface_tmp;
1472 int dst_width = dst_bitmap->width;
1473 int dst_height = dst_bitmap->height;
1475 /* throw away old destination surface */
1476 SDL_FreeSurface(dst_bitmap->surface);
1478 /* create zoomed temporary surface from source surface */
1479 sdl_surface_tmp = zoomSurface(src_bitmap->surface, dst_width, dst_height);
1481 /* create native format destination surface from zoomed temporary surface */
1482 dst_bitmap->surface = SDL_DisplayFormat(sdl_surface_tmp);
1484 /* free temporary surface */
1485 SDL_FreeSurface(sdl_surface_tmp);
1489 /* ========================================================================= */
1490 /* load image to bitmap */
1491 /* ========================================================================= */
1493 Bitmap *SDLLoadImage(char *filename)
1495 Bitmap *new_bitmap = CreateBitmapStruct();
1496 SDL_Surface *sdl_image_tmp;
1498 /* load image to temporary surface */
1499 if ((sdl_image_tmp = IMG_Load(filename)) == NULL)
1501 SetError("IMG_Load(): %s", SDL_GetError());
1506 /* create native non-transparent surface for current image */
1507 if ((new_bitmap->surface = SDL_DisplayFormat(sdl_image_tmp)) == NULL)
1509 SetError("SDL_DisplayFormat(): %s", SDL_GetError());
1514 /* create native transparent surface for current image */
1515 SDL_SetColorKey(sdl_image_tmp, SDL_SRCCOLORKEY,
1516 SDL_MapRGB(sdl_image_tmp->format, 0x00, 0x00, 0x00));
1517 if ((new_bitmap->surface_masked = SDL_DisplayFormat(sdl_image_tmp)) == NULL)
1519 SetError("SDL_DisplayFormat(): %s", SDL_GetError());
1524 /* free temporary surface */
1525 SDL_FreeSurface(sdl_image_tmp);
1527 new_bitmap->width = new_bitmap->surface->w;
1528 new_bitmap->height = new_bitmap->surface->h;
1534 /* ------------------------------------------------------------------------- */
1535 /* custom cursor fuctions */
1536 /* ------------------------------------------------------------------------- */
1538 static SDL_Cursor *create_cursor(struct MouseCursorInfo *cursor_info)
1540 return SDL_CreateCursor(cursor_info->data, cursor_info->mask,
1541 cursor_info->width, cursor_info->height,
1542 cursor_info->hot_x, cursor_info->hot_y);
1545 void SDLSetMouseCursor(struct MouseCursorInfo *cursor_info)
1547 static struct MouseCursorInfo *last_cursor_info = NULL;
1548 static struct MouseCursorInfo *last_cursor_info2 = NULL;
1549 static SDL_Cursor *cursor_default = NULL;
1550 static SDL_Cursor *cursor_current = NULL;
1552 /* if invoked for the first time, store the SDL default cursor */
1553 if (cursor_default == NULL)
1554 cursor_default = SDL_GetCursor();
1556 /* only create new cursor if cursor info (custom only) has changed */
1557 if (cursor_info != NULL && cursor_info != last_cursor_info)
1559 cursor_current = create_cursor(cursor_info);
1560 last_cursor_info = cursor_info;
1563 /* only set new cursor if cursor info (custom or NULL) has changed */
1564 if (cursor_info != last_cursor_info2)
1565 SDL_SetCursor(cursor_info ? cursor_current : cursor_default);
1567 last_cursor_info2 = cursor_info;
1571 /* ========================================================================= */
1572 /* audio functions */
1573 /* ========================================================================= */
1575 void SDLOpenAudio(void)
1577 if (!strEqual(setup.system.sdl_audiodriver, ARG_DEFAULT))
1578 putenv(getStringCat2("SDL_AUDIODRIVER=", setup.system.sdl_audiodriver));
1580 if (SDL_InitSubSystem(SDL_INIT_AUDIO) < 0)
1582 Error(ERR_WARN, "SDL_InitSubSystem() failed: %s", SDL_GetError());
1586 if (Mix_OpenAudio(DEFAULT_AUDIO_SAMPLE_RATE, MIX_DEFAULT_FORMAT,
1587 AUDIO_NUM_CHANNELS_STEREO,
1588 setup.system.audio_fragment_size) < 0)
1590 Error(ERR_WARN, "Mix_OpenAudio() failed: %s", SDL_GetError());
1594 audio.sound_available = TRUE;
1595 audio.music_available = TRUE;
1596 audio.loops_available = TRUE;
1597 audio.sound_enabled = TRUE;
1599 /* set number of available mixer channels */
1600 audio.num_channels = Mix_AllocateChannels(NUM_MIXER_CHANNELS);
1601 audio.music_channel = MUSIC_CHANNEL;
1602 audio.first_sound_channel = FIRST_SOUND_CHANNEL;
1604 Mixer_InitChannels();
1607 void SDLCloseAudio(void)
1610 Mix_HaltChannel(-1);
1613 SDL_QuitSubSystem(SDL_INIT_AUDIO);
1617 /* ========================================================================= */
1618 /* event functions */
1619 /* ========================================================================= */
1621 void SDLNextEvent(Event *event)
1623 SDL_WaitEvent(event);
1625 if (event->type == EVENT_BUTTONPRESS ||
1626 event->type == EVENT_BUTTONRELEASE)
1628 if (((ButtonEvent *)event)->x > video_xoffset)
1629 ((ButtonEvent *)event)->x -= video_xoffset;
1631 ((ButtonEvent *)event)->x = 0;
1632 if (((ButtonEvent *)event)->y > video_yoffset)
1633 ((ButtonEvent *)event)->y -= video_yoffset;
1635 ((ButtonEvent *)event)->y = 0;
1637 else if (event->type == EVENT_MOTIONNOTIFY)
1639 if (((MotionEvent *)event)->x > video_xoffset)
1640 ((MotionEvent *)event)->x -= video_xoffset;
1642 ((MotionEvent *)event)->x = 0;
1643 if (((MotionEvent *)event)->y > video_yoffset)
1644 ((MotionEvent *)event)->y -= video_yoffset;
1646 ((MotionEvent *)event)->y = 0;
1651 /* ========================================================================= */
1652 /* joystick functions */
1653 /* ========================================================================= */
1655 static SDL_Joystick *sdl_joystick[MAX_PLAYERS] = { NULL, NULL, NULL, NULL };
1656 static int sdl_js_axis[MAX_PLAYERS][2] = { {0, 0}, {0, 0}, {0, 0}, {0, 0} };
1657 static int sdl_js_button[MAX_PLAYERS][2] = { {0, 0}, {0, 0}, {0, 0}, {0, 0} };
1659 static boolean SDLOpenJoystick(int nr)
1661 if (nr < 0 || nr > MAX_PLAYERS)
1664 return ((sdl_joystick[nr] = SDL_JoystickOpen(nr)) == NULL ? FALSE : TRUE);
1667 static void SDLCloseJoystick(int nr)
1669 if (nr < 0 || nr > MAX_PLAYERS)
1672 SDL_JoystickClose(sdl_joystick[nr]);
1675 static boolean SDLCheckJoystickOpened(int nr)
1677 if (nr < 0 || nr > MAX_PLAYERS)
1680 return (SDL_JoystickOpened(nr) ? TRUE : FALSE);
1683 void HandleJoystickEvent(Event *event)
1687 case SDL_JOYAXISMOTION:
1688 if (event->jaxis.axis < 2)
1689 sdl_js_axis[event->jaxis.which][event->jaxis.axis]= event->jaxis.value;
1692 case SDL_JOYBUTTONDOWN:
1693 if (event->jbutton.button < 2)
1694 sdl_js_button[event->jbutton.which][event->jbutton.button] = TRUE;
1697 case SDL_JOYBUTTONUP:
1698 if (event->jbutton.button < 2)
1699 sdl_js_button[event->jbutton.which][event->jbutton.button] = FALSE;
1707 void SDLInitJoysticks()
1709 static boolean sdl_joystick_subsystem_initialized = FALSE;
1710 boolean print_warning = !sdl_joystick_subsystem_initialized;
1713 if (!sdl_joystick_subsystem_initialized)
1715 sdl_joystick_subsystem_initialized = TRUE;
1717 if (SDL_Init(SDL_INIT_JOYSTICK) < 0)
1719 Error(ERR_EXIT, "SDL_Init() failed: %s", SDL_GetError());
1724 for (i = 0; i < MAX_PLAYERS; i++)
1726 /* get configured joystick for this player */
1727 char *device_name = setup.input[i].joy.device_name;
1728 int joystick_nr = getJoystickNrFromDeviceName(device_name);
1730 if (joystick_nr >= SDL_NumJoysticks())
1732 if (setup.input[i].use_joystick && print_warning)
1733 Error(ERR_WARN, "cannot find joystick %d", joystick_nr);
1738 /* misuse joystick file descriptor variable to store joystick number */
1739 joystick.fd[i] = joystick_nr;
1741 if (joystick_nr == -1)
1744 /* this allows subsequent calls to 'InitJoysticks' for re-initialization */
1745 if (SDLCheckJoystickOpened(joystick_nr))
1746 SDLCloseJoystick(joystick_nr);
1748 if (!setup.input[i].use_joystick)
1751 if (!SDLOpenJoystick(joystick_nr))
1754 Error(ERR_WARN, "cannot open joystick %d", joystick_nr);
1759 joystick.status = JOYSTICK_ACTIVATED;
1763 boolean SDLReadJoystick(int nr, int *x, int *y, boolean *b1, boolean *b2)
1765 if (nr < 0 || nr >= MAX_PLAYERS)
1769 *x = sdl_js_axis[nr][0];
1771 *y = sdl_js_axis[nr][1];
1774 *b1 = sdl_js_button[nr][0];
1776 *b2 = sdl_js_button[nr][1];
1781 #endif /* TARGET_SDL */