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,
358 int width, int height, Uint32 color)
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 SDLFadeScreen(Bitmap *bitmap_cross, int fade_mode, int fade_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 = 0, src_y = 0;
390 int dst_x = 0, dst_y = 0;
391 boolean fade_reverse = (fade_mode == FADE_MODE_FADE_IN ? TRUE : FALSE);
392 unsigned int time_last, time_current;
398 src_rect.w = video.width;
399 src_rect.h = video.height;
401 dst_x += video_xoffset;
402 dst_y += video_yoffset;
406 dst_rect.w = video.width;
407 dst_rect.h = video.height;
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 */
499 SDL_Flip(surface_screen);
505 void SDLDrawSimpleLine(Bitmap *dst_bitmap, int from_x, int from_y,
506 int to_x, int to_y, Uint32 color)
508 SDL_Surface *surface = dst_bitmap->surface;
512 swap_numbers(&from_x, &to_x);
515 swap_numbers(&from_y, &to_y);
519 rect.w = (to_x - from_x + 1);
520 rect.h = (to_y - from_y + 1);
522 if (dst_bitmap == backbuffer || dst_bitmap == window)
524 rect.x += video_xoffset;
525 rect.y += video_yoffset;
528 SDL_FillRect(surface, &rect, color);
531 void SDLDrawLine(Bitmap *dst_bitmap, int from_x, int from_y,
532 int to_x, int to_y, Uint32 color)
534 if (dst_bitmap == backbuffer || dst_bitmap == window)
536 from_x += video_xoffset;
537 from_y += video_yoffset;
538 to_x += video_xoffset;
539 to_y += video_yoffset;
542 sge_Line(dst_bitmap->surface, from_x, from_y, to_x, to_y, color);
546 void SDLDrawLines(SDL_Surface *surface, struct XY *points,
547 int num_points, Uint32 color)
552 for (i = 0; i < num_points - 1; i++)
554 for (x = 0; x < line_width; x++)
556 for (y = 0; y < line_width; y++)
558 int dx = x - line_width / 2;
559 int dy = y - line_width / 2;
561 if ((x == 0 && y == 0) ||
562 (x == 0 && y == line_width - 1) ||
563 (x == line_width - 1 && y == 0) ||
564 (x == line_width - 1 && y == line_width - 1))
567 sge_Line(surface, points[i].x + dx, points[i].y + dy,
568 points[i+1].x + dx, points[i+1].y + dy, color);
575 Pixel SDLGetPixel(Bitmap *src_bitmap, int x, int y)
577 SDL_Surface *surface = src_bitmap->surface;
579 if (src_bitmap == backbuffer || src_bitmap == window)
585 switch (surface->format->BytesPerPixel)
587 case 1: /* assuming 8-bpp */
589 return *((Uint8 *)surface->pixels + y * surface->pitch + x);
593 case 2: /* probably 15-bpp or 16-bpp */
595 return *((Uint16 *)surface->pixels + y * surface->pitch / 2 + x);
599 case 3: /* slow 24-bpp mode; usually not used */
601 /* does this work? */
602 Uint8 *pix = (Uint8 *)surface->pixels + y * surface->pitch + x * 3;
606 shift = surface->format->Rshift;
607 color |= *(pix + shift / 8) >> shift;
608 shift = surface->format->Gshift;
609 color |= *(pix + shift / 8) >> shift;
610 shift = surface->format->Bshift;
611 color |= *(pix + shift / 8) >> shift;
617 case 4: /* probably 32-bpp */
619 return *((Uint32 *)surface->pixels + y * surface->pitch / 4 + x);
628 /* ========================================================================= */
629 /* The following functions were taken from the SGE library */
630 /* (SDL Graphics Extension Library) by Anders Lindström */
631 /* http://www.etek.chalmers.se/~e8cal1/sge/index.html */
632 /* ========================================================================= */
634 void _PutPixel(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
636 if (x >= 0 && x <= surface->w - 1 && y >= 0 && y <= surface->h - 1)
638 switch (surface->format->BytesPerPixel)
643 *((Uint8 *)surface->pixels + y*surface->pitch + x) = color;
649 /* Probably 15-bpp or 16-bpp */
650 *((Uint16 *)surface->pixels + y*surface->pitch/2 + x) = color;
656 /* Slow 24-bpp mode, usually not used */
660 /* Gack - slow, but endian correct */
661 pix = (Uint8 *)surface->pixels + y * surface->pitch + x*3;
662 shift = surface->format->Rshift;
663 *(pix+shift/8) = color>>shift;
664 shift = surface->format->Gshift;
665 *(pix+shift/8) = color>>shift;
666 shift = surface->format->Bshift;
667 *(pix+shift/8) = color>>shift;
673 /* Probably 32-bpp */
674 *((Uint32 *)surface->pixels + y*surface->pitch/4 + x) = color;
681 void _PutPixelRGB(SDL_Surface *surface, Sint16 x, Sint16 y,
682 Uint8 R, Uint8 G, Uint8 B)
684 _PutPixel(surface, x, y, SDL_MapRGB(surface->format, R, G, B));
687 void _PutPixel8(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
689 *((Uint8 *)surface->pixels + y*surface->pitch + x) = color;
692 void _PutPixel16(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
694 *((Uint16 *)surface->pixels + y*surface->pitch/2 + x) = color;
697 void _PutPixel24(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
702 /* Gack - slow, but endian correct */
703 pix = (Uint8 *)surface->pixels + y * surface->pitch + x*3;
704 shift = surface->format->Rshift;
705 *(pix+shift/8) = color>>shift;
706 shift = surface->format->Gshift;
707 *(pix+shift/8) = color>>shift;
708 shift = surface->format->Bshift;
709 *(pix+shift/8) = color>>shift;
712 void _PutPixel32(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
714 *((Uint32 *)surface->pixels + y*surface->pitch/4 + x) = color;
717 void _PutPixelX(SDL_Surface *dest,Sint16 x,Sint16 y,Uint32 color)
719 switch (dest->format->BytesPerPixel)
722 *((Uint8 *)dest->pixels + y*dest->pitch + x) = color;
726 *((Uint16 *)dest->pixels + y*dest->pitch/2 + x) = color;
730 _PutPixel24(dest,x,y,color);
734 *((Uint32 *)dest->pixels + y*dest->pitch/4 + x) = color;
739 void sge_PutPixel(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
741 if (SDL_MUSTLOCK(surface))
743 if (SDL_LockSurface(surface) < 0)
749 _PutPixel(surface, x, y, color);
751 if (SDL_MUSTLOCK(surface))
753 SDL_UnlockSurface(surface);
757 void sge_PutPixelRGB(SDL_Surface *surface, Sint16 x, Sint16 y,
758 Uint8 r, Uint8 g, Uint8 b)
760 sge_PutPixel(surface, x, y, SDL_MapRGB(surface->format, r, g, b));
763 Sint32 sge_CalcYPitch(SDL_Surface *dest, Sint16 y)
765 if (y >= 0 && y <= dest->h - 1)
767 switch (dest->format->BytesPerPixel)
770 return y*dest->pitch;
774 return y*dest->pitch/2;
778 return y*dest->pitch;
782 return y*dest->pitch/4;
790 void sge_pPutPixel(SDL_Surface *surface, Sint16 x, Sint32 ypitch, Uint32 color)
792 if (x >= 0 && x <= surface->w - 1 && ypitch >= 0)
794 switch (surface->format->BytesPerPixel)
799 *((Uint8 *)surface->pixels + ypitch + x) = color;
805 /* Probably 15-bpp or 16-bpp */
806 *((Uint16 *)surface->pixels + ypitch + x) = color;
812 /* Slow 24-bpp mode, usually not used */
816 /* Gack - slow, but endian correct */
817 pix = (Uint8 *)surface->pixels + ypitch + x*3;
818 shift = surface->format->Rshift;
819 *(pix+shift/8) = color>>shift;
820 shift = surface->format->Gshift;
821 *(pix+shift/8) = color>>shift;
822 shift = surface->format->Bshift;
823 *(pix+shift/8) = color>>shift;
829 /* Probably 32-bpp */
830 *((Uint32 *)surface->pixels + ypitch + x) = color;
837 void sge_HLine(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y,
842 if (SDL_MUSTLOCK(Surface))
844 if (SDL_LockSurface(Surface) < 0)
857 /* Do the clipping */
858 if (y < 0 || y > Surface->h - 1 || x1 > Surface->w - 1 || x2 < 0)
862 if (x2 > Surface->w - 1)
870 SDL_FillRect(Surface, &l, Color);
872 if (SDL_MUSTLOCK(Surface))
874 SDL_UnlockSurface(Surface);
878 void sge_HLineRGB(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y,
879 Uint8 R, Uint8 G, Uint8 B)
881 sge_HLine(Surface, x1, x2, y, SDL_MapRGB(Surface->format, R, G, B));
884 void _HLine(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y, Uint32 Color)
895 /* Do the clipping */
896 if (y < 0 || y > Surface->h - 1 || x1 > Surface->w - 1 || x2 < 0)
900 if (x2 > Surface->w - 1)
908 SDL_FillRect(Surface, &l, Color);
911 void sge_VLine(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2,
916 if (SDL_MUSTLOCK(Surface))
918 if (SDL_LockSurface(Surface) < 0)
931 /* Do the clipping */
932 if (x < 0 || x > Surface->w - 1 || y1 > Surface->h - 1 || y2 < 0)
936 if (y2 > Surface->h - 1)
944 SDL_FillRect(Surface, &l, Color);
946 if (SDL_MUSTLOCK(Surface))
948 SDL_UnlockSurface(Surface);
952 void sge_VLineRGB(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2,
953 Uint8 R, Uint8 G, Uint8 B)
955 sge_VLine(Surface, x, y1, y2, SDL_MapRGB(Surface->format, R, G, B));
958 void _VLine(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2, Uint32 Color)
969 /* Do the clipping */
970 if (x < 0 || x > Surface->w - 1 || y1 > Surface->h - 1 || y2 < 0)
974 if (y2 > Surface->h - 1)
982 SDL_FillRect(Surface, &l, Color);
985 void sge_DoLine(SDL_Surface *Surface, Sint16 x1, Sint16 y1,
986 Sint16 x2, Sint16 y2, Uint32 Color,
987 void Callback(SDL_Surface *Surf, Sint16 X, Sint16 Y,
990 Sint16 dx, dy, sdx, sdy, x, y, px, py;
995 sdx = (dx < 0) ? -1 : 1;
996 sdy = (dy < 0) ? -1 : 1;
1008 for (x = 0; x < dx; x++)
1010 Callback(Surface, px, py, Color);
1024 for (y = 0; y < dy; y++)
1026 Callback(Surface, px, py, Color);
1040 void sge_DoLineRGB(SDL_Surface *Surface, Sint16 X1, Sint16 Y1,
1041 Sint16 X2, Sint16 Y2, Uint8 R, Uint8 G, Uint8 B,
1042 void Callback(SDL_Surface *Surf, Sint16 X, Sint16 Y,
1045 sge_DoLine(Surface, X1, Y1, X2, Y2,
1046 SDL_MapRGB(Surface->format, R, G, B), Callback);
1049 void sge_Line(SDL_Surface *Surface, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2,
1052 if (SDL_MUSTLOCK(Surface))
1054 if (SDL_LockSurface(Surface) < 0)
1059 sge_DoLine(Surface, x1, y1, x2, y2, Color, _PutPixel);
1061 /* unlock the display */
1062 if (SDL_MUSTLOCK(Surface))
1064 SDL_UnlockSurface(Surface);
1068 void sge_LineRGB(SDL_Surface *Surface, Sint16 x1, Sint16 y1, Sint16 x2,
1069 Sint16 y2, Uint8 R, Uint8 G, Uint8 B)
1071 sge_Line(Surface, x1, y1, x2, y2, SDL_MapRGB(Surface->format, R, G, B));
1074 void SDLPutPixel(Bitmap *dst_bitmap, int x, int y, Pixel pixel)
1076 if (dst_bitmap == backbuffer || dst_bitmap == window)
1082 sge_PutPixel(dst_bitmap->surface, x, y, pixel);
1087 -----------------------------------------------------------------------------
1088 quick (no, it's slow) and dirty hack to "invert" rectangle inside SDL surface
1089 -----------------------------------------------------------------------------
1092 void SDLInvertArea(Bitmap *bitmap, int src_x, int src_y,
1093 int width, int height, Uint32 color)
1097 for (y = src_y; y < src_y + height; y++)
1099 for (x = src_x; x < src_x + width; x++)
1101 Uint32 pixel = SDLGetPixel(bitmap, x, y);
1103 SDLPutPixel(bitmap, x, y, pixel == BLACK_PIXEL ? color : BLACK_PIXEL);
1108 void SDLCopyInverseMasked(Bitmap *src_bitmap, Bitmap *dst_bitmap,
1109 int src_x, int src_y, int width, int height,
1110 int dst_x, int dst_y)
1114 for (y = 0; y < height; y++)
1116 for (x = 0; x < width; x++)
1118 Uint32 pixel = SDLGetPixel(src_bitmap, src_x + x, src_y + y);
1120 if (pixel != BLACK_PIXEL)
1121 SDLPutPixel(dst_bitmap, dst_x + x, dst_y + y, BLACK_PIXEL);
1127 /* ========================================================================= */
1128 /* The following functions were taken from the SDL_gfx library version 2.0.3 */
1129 /* (Rotozoomer) by Andreas Schiffler */
1130 /* http://www.ferzkopp.net/Software/SDL_gfx-2.0/index.html */
1131 /* ========================================================================= */
1134 -----------------------------------------------------------------------------
1137 zoomes 32bit RGBA/ABGR 'src' surface to 'dst' surface.
1138 -----------------------------------------------------------------------------
1149 int zoomSurfaceRGBA_scaleDownBy2(SDL_Surface *src, SDL_Surface *dst)
1152 tColorRGBA *sp, *csp, *dp;
1156 sp = csp = (tColorRGBA *) src->pixels;
1157 dp = (tColorRGBA *) dst->pixels;
1158 sgap = src->pitch - src->w * 4;
1159 dgap = dst->pitch - dst->w * 4;
1161 for (y = 0; y < dst->h; y++)
1165 for (x = 0; x < dst->w; x++)
1167 tColorRGBA *sp0 = sp;
1168 tColorRGBA *sp1 = (tColorRGBA *) ((Uint8 *) sp + src->pitch);
1169 tColorRGBA *sp00 = &sp0[0];
1170 tColorRGBA *sp01 = &sp0[1];
1171 tColorRGBA *sp10 = &sp1[0];
1172 tColorRGBA *sp11 = &sp1[1];
1175 /* create new color pixel from all four source color pixels */
1176 new.r = (sp00->r + sp01->r + sp10->r + sp11->r) / 4;
1177 new.g = (sp00->g + sp01->g + sp10->g + sp11->g) / 4;
1178 new.b = (sp00->b + sp01->b + sp10->b + sp11->b) / 4;
1179 new.a = (sp00->a + sp01->a + sp10->a + sp11->a) / 4;
1184 /* advance source pointers */
1187 /* advance destination pointer */
1191 /* advance source pointer */
1192 csp = (tColorRGBA *) ((Uint8 *) csp + 2 * src->pitch);
1194 /* advance destination pointers */
1195 dp = (tColorRGBA *) ((Uint8 *) dp + dgap);
1201 int zoomSurfaceRGBA(SDL_Surface *src, SDL_Surface *dst)
1203 int x, y, sx, sy, *sax, *say, *csax, *csay, csx, csy;
1204 tColorRGBA *sp, *csp, *dp;
1207 /* use specialized zoom function when scaling down to exactly half size */
1208 if (src->w == 2 * dst->w &&
1209 src->h == 2 * dst->h)
1210 return zoomSurfaceRGBA_scaleDownBy2(src, dst);
1212 /* variable setup */
1213 sx = (int) (65536.0 * (float) src->w / (float) dst->w);
1214 sy = (int) (65536.0 * (float) src->h / (float) dst->h);
1216 /* allocate memory for row increments */
1217 sax = (int *)checked_malloc((dst->w + 1) * sizeof(Uint32));
1218 say = (int *)checked_malloc((dst->h + 1) * sizeof(Uint32));
1220 /* precalculate row increments */
1223 for (x = 0; x <= dst->w; x++)
1233 for (y = 0; y <= dst->h; y++)
1242 sp = csp = (tColorRGBA *) src->pixels;
1243 dp = (tColorRGBA *) dst->pixels;
1244 sgap = src->pitch - src->w * 4;
1245 dgap = dst->pitch - dst->w * 4;
1248 for (y = 0; y < dst->h; y++)
1253 for (x = 0; x < dst->w; x++)
1258 /* advance source pointers */
1260 sp += (*csax >> 16);
1262 /* advance destination pointer */
1266 /* advance source pointer */
1268 csp = (tColorRGBA *) ((Uint8 *) csp + (*csay >> 16) * src->pitch);
1270 /* advance destination pointers */
1271 dp = (tColorRGBA *) ((Uint8 *) dp + dgap);
1281 -----------------------------------------------------------------------------
1284 zoomes 8 bit palette/Y 'src' surface to 'dst' surface
1285 -----------------------------------------------------------------------------
1288 int zoomSurfaceY(SDL_Surface * src, SDL_Surface * dst)
1290 Uint32 x, y, sx, sy, *sax, *say, *csax, *csay, csx, csy;
1291 Uint8 *sp, *dp, *csp;
1294 /* variable setup */
1295 sx = (Uint32) (65536.0 * (float) src->w / (float) dst->w);
1296 sy = (Uint32) (65536.0 * (float) src->h / (float) dst->h);
1298 /* allocate memory for row increments */
1299 sax = (Uint32 *)checked_malloc(dst->w * sizeof(Uint32));
1300 say = (Uint32 *)checked_malloc(dst->h * sizeof(Uint32));
1302 /* precalculate row increments */
1305 for (x = 0; x < dst->w; x++)
1308 *csax = (csx >> 16);
1315 for (y = 0; y < dst->h; y++)
1318 *csay = (csy >> 16);
1325 for (x = 0; x < dst->w; x++)
1333 for (y = 0; y < dst->h; y++)
1340 sp = csp = (Uint8 *) src->pixels;
1341 dp = (Uint8 *) dst->pixels;
1342 dgap = dst->pitch - dst->w;
1346 for (y = 0; y < dst->h; y++)
1350 for (x = 0; x < dst->w; x++)
1355 /* advance source pointers */
1359 /* advance destination pointer */
1363 /* advance source pointer (for row) */
1364 csp += ((*csay) * src->pitch);
1367 /* advance destination pointers */
1378 -----------------------------------------------------------------------------
1381 Zooms a 32bit or 8bit 'src' surface to newly created 'dst' surface.
1382 'zoomx' and 'zoomy' are scaling factors for width and height.
1383 If the surface is not 8bit or 32bit RGBA/ABGR it will be converted
1384 into a 32bit RGBA format on the fly.
1385 -----------------------------------------------------------------------------
1388 SDL_Surface *zoomSurface(SDL_Surface *src, int dst_width, int dst_height)
1390 SDL_Surface *zoom_src = NULL;
1391 SDL_Surface *zoom_dst = NULL;
1392 boolean is_converted = FALSE;
1399 /* determine if source surface is 32 bit or 8 bit */
1400 is_32bit = (src->format->BitsPerPixel == 32);
1402 if (is_32bit || src->format->BitsPerPixel == 8)
1404 /* use source surface 'as is' */
1409 /* new source surface is 32 bit with a defined RGB ordering */
1410 zoom_src = SDL_CreateRGBSurface(SDL_SWSURFACE, src->w, src->h, 32,
1411 0x000000ff, 0x0000ff00, 0x00ff0000, 0);
1412 SDL_BlitSurface(src, NULL, zoom_src, NULL);
1414 is_converted = TRUE;
1417 /* allocate surface to completely contain the zoomed surface */
1420 /* target surface is 32 bit with source RGBA/ABGR ordering */
1421 zoom_dst = SDL_CreateRGBSurface(SDL_SWSURFACE, dst_width, dst_height, 32,
1422 zoom_src->format->Rmask,
1423 zoom_src->format->Gmask,
1424 zoom_src->format->Bmask, 0);
1428 /* target surface is 8 bit */
1429 zoom_dst = SDL_CreateRGBSurface(SDL_SWSURFACE, dst_width, dst_height, 8,
1433 /* lock source surface */
1434 SDL_LockSurface(zoom_src);
1436 /* check which kind of surface we have */
1439 /* call the 32 bit transformation routine to do the zooming */
1440 zoomSurfaceRGBA(zoom_src, zoom_dst);
1445 for (i = 0; i < zoom_src->format->palette->ncolors; i++)
1446 zoom_dst->format->palette->colors[i] =
1447 zoom_src->format->palette->colors[i];
1448 zoom_dst->format->palette->ncolors = zoom_src->format->palette->ncolors;
1450 /* call the 8 bit transformation routine to do the zooming */
1451 zoomSurfaceY(zoom_src, zoom_dst);
1454 /* unlock source surface */
1455 SDL_UnlockSurface(zoom_src);
1457 /* free temporary surface */
1459 SDL_FreeSurface(zoom_src);
1461 /* return destination surface */
1465 void SDLZoomBitmap(Bitmap *src_bitmap, Bitmap *dst_bitmap)
1467 SDL_Surface *sdl_surface_tmp;
1468 int dst_width = dst_bitmap->width;
1469 int dst_height = dst_bitmap->height;
1471 /* throw away old destination surface */
1472 SDL_FreeSurface(dst_bitmap->surface);
1474 /* create zoomed temporary surface from source surface */
1475 sdl_surface_tmp = zoomSurface(src_bitmap->surface, dst_width, dst_height);
1477 /* create native format destination surface from zoomed temporary surface */
1478 dst_bitmap->surface = SDL_DisplayFormat(sdl_surface_tmp);
1480 /* free temporary surface */
1481 SDL_FreeSurface(sdl_surface_tmp);
1485 /* ========================================================================= */
1486 /* load image to bitmap */
1487 /* ========================================================================= */
1489 Bitmap *SDLLoadImage(char *filename)
1491 Bitmap *new_bitmap = CreateBitmapStruct();
1492 SDL_Surface *sdl_image_tmp;
1494 /* load image to temporary surface */
1495 if ((sdl_image_tmp = IMG_Load(filename)) == NULL)
1497 SetError("IMG_Load(): %s", SDL_GetError());
1502 /* create native non-transparent surface for current image */
1503 if ((new_bitmap->surface = SDL_DisplayFormat(sdl_image_tmp)) == NULL)
1505 SetError("SDL_DisplayFormat(): %s", SDL_GetError());
1510 /* create native transparent surface for current image */
1511 SDL_SetColorKey(sdl_image_tmp, SDL_SRCCOLORKEY,
1512 SDL_MapRGB(sdl_image_tmp->format, 0x00, 0x00, 0x00));
1513 if ((new_bitmap->surface_masked = SDL_DisplayFormat(sdl_image_tmp)) == NULL)
1515 SetError("SDL_DisplayFormat(): %s", SDL_GetError());
1520 /* free temporary surface */
1521 SDL_FreeSurface(sdl_image_tmp);
1523 new_bitmap->width = new_bitmap->surface->w;
1524 new_bitmap->height = new_bitmap->surface->h;
1530 /* ------------------------------------------------------------------------- */
1531 /* custom cursor fuctions */
1532 /* ------------------------------------------------------------------------- */
1534 static SDL_Cursor *create_cursor(struct MouseCursorInfo *cursor_info)
1536 return SDL_CreateCursor(cursor_info->data, cursor_info->mask,
1537 cursor_info->width, cursor_info->height,
1538 cursor_info->hot_x, cursor_info->hot_y);
1541 void SDLSetMouseCursor(struct MouseCursorInfo *cursor_info)
1543 static struct MouseCursorInfo *last_cursor_info = NULL;
1544 static struct MouseCursorInfo *last_cursor_info2 = NULL;
1545 static SDL_Cursor *cursor_default = NULL;
1546 static SDL_Cursor *cursor_current = NULL;
1548 /* if invoked for the first time, store the SDL default cursor */
1549 if (cursor_default == NULL)
1550 cursor_default = SDL_GetCursor();
1552 /* only create new cursor if cursor info (custom only) has changed */
1553 if (cursor_info != NULL && cursor_info != last_cursor_info)
1555 cursor_current = create_cursor(cursor_info);
1556 last_cursor_info = cursor_info;
1559 /* only set new cursor if cursor info (custom or NULL) has changed */
1560 if (cursor_info != last_cursor_info2)
1561 SDL_SetCursor(cursor_info ? cursor_current : cursor_default);
1563 last_cursor_info2 = cursor_info;
1567 /* ========================================================================= */
1568 /* audio functions */
1569 /* ========================================================================= */
1571 void SDLOpenAudio(void)
1573 if (!strEqual(setup.system.sdl_audiodriver, ARG_DEFAULT))
1574 putenv(getStringCat2("SDL_AUDIODRIVER=", setup.system.sdl_audiodriver));
1576 if (SDL_InitSubSystem(SDL_INIT_AUDIO) < 0)
1578 Error(ERR_WARN, "SDL_InitSubSystem() failed: %s", SDL_GetError());
1582 if (Mix_OpenAudio(DEFAULT_AUDIO_SAMPLE_RATE, MIX_DEFAULT_FORMAT,
1583 AUDIO_NUM_CHANNELS_STEREO,
1584 setup.system.audio_fragment_size) < 0)
1586 Error(ERR_WARN, "Mix_OpenAudio() failed: %s", SDL_GetError());
1590 audio.sound_available = TRUE;
1591 audio.music_available = TRUE;
1592 audio.loops_available = TRUE;
1593 audio.sound_enabled = TRUE;
1595 /* set number of available mixer channels */
1596 audio.num_channels = Mix_AllocateChannels(NUM_MIXER_CHANNELS);
1597 audio.music_channel = MUSIC_CHANNEL;
1598 audio.first_sound_channel = FIRST_SOUND_CHANNEL;
1600 Mixer_InitChannels();
1603 void SDLCloseAudio(void)
1606 Mix_HaltChannel(-1);
1609 SDL_QuitSubSystem(SDL_INIT_AUDIO);
1613 /* ========================================================================= */
1614 /* event functions */
1615 /* ========================================================================= */
1617 void SDLNextEvent(Event *event)
1619 SDL_WaitEvent(event);
1621 if (event->type == EVENT_BUTTONPRESS ||
1622 event->type == EVENT_BUTTONRELEASE)
1624 if (((ButtonEvent *)event)->x > video_xoffset)
1625 ((ButtonEvent *)event)->x -= video_xoffset;
1627 ((ButtonEvent *)event)->x = 0;
1628 if (((ButtonEvent *)event)->y > video_yoffset)
1629 ((ButtonEvent *)event)->y -= video_yoffset;
1631 ((ButtonEvent *)event)->y = 0;
1633 else if (event->type == EVENT_MOTIONNOTIFY)
1635 if (((MotionEvent *)event)->x > video_xoffset)
1636 ((MotionEvent *)event)->x -= video_xoffset;
1638 ((MotionEvent *)event)->x = 0;
1639 if (((MotionEvent *)event)->y > video_yoffset)
1640 ((MotionEvent *)event)->y -= video_yoffset;
1642 ((MotionEvent *)event)->y = 0;
1647 /* ========================================================================= */
1648 /* joystick functions */
1649 /* ========================================================================= */
1651 static SDL_Joystick *sdl_joystick[MAX_PLAYERS] = { NULL, NULL, NULL, NULL };
1652 static int sdl_js_axis[MAX_PLAYERS][2] = { {0, 0}, {0, 0}, {0, 0}, {0, 0} };
1653 static int sdl_js_button[MAX_PLAYERS][2] = { {0, 0}, {0, 0}, {0, 0}, {0, 0} };
1655 static boolean SDLOpenJoystick(int nr)
1657 if (nr < 0 || nr > MAX_PLAYERS)
1660 return ((sdl_joystick[nr] = SDL_JoystickOpen(nr)) == NULL ? FALSE : TRUE);
1663 static void SDLCloseJoystick(int nr)
1665 if (nr < 0 || nr > MAX_PLAYERS)
1668 SDL_JoystickClose(sdl_joystick[nr]);
1671 static boolean SDLCheckJoystickOpened(int nr)
1673 if (nr < 0 || nr > MAX_PLAYERS)
1676 return (SDL_JoystickOpened(nr) ? TRUE : FALSE);
1679 void HandleJoystickEvent(Event *event)
1683 case SDL_JOYAXISMOTION:
1684 if (event->jaxis.axis < 2)
1685 sdl_js_axis[event->jaxis.which][event->jaxis.axis]= event->jaxis.value;
1688 case SDL_JOYBUTTONDOWN:
1689 if (event->jbutton.button < 2)
1690 sdl_js_button[event->jbutton.which][event->jbutton.button] = TRUE;
1693 case SDL_JOYBUTTONUP:
1694 if (event->jbutton.button < 2)
1695 sdl_js_button[event->jbutton.which][event->jbutton.button] = FALSE;
1703 void SDLInitJoysticks()
1705 static boolean sdl_joystick_subsystem_initialized = FALSE;
1706 boolean print_warning = !sdl_joystick_subsystem_initialized;
1709 if (!sdl_joystick_subsystem_initialized)
1711 sdl_joystick_subsystem_initialized = TRUE;
1713 if (SDL_Init(SDL_INIT_JOYSTICK) < 0)
1715 Error(ERR_EXIT, "SDL_Init() failed: %s", SDL_GetError());
1720 for (i = 0; i < MAX_PLAYERS; i++)
1722 /* get configured joystick for this player */
1723 char *device_name = setup.input[i].joy.device_name;
1724 int joystick_nr = getJoystickNrFromDeviceName(device_name);
1726 if (joystick_nr >= SDL_NumJoysticks())
1728 if (setup.input[i].use_joystick && print_warning)
1729 Error(ERR_WARN, "cannot find joystick %d", joystick_nr);
1734 /* misuse joystick file descriptor variable to store joystick number */
1735 joystick.fd[i] = joystick_nr;
1737 if (joystick_nr == -1)
1740 /* this allows subsequent calls to 'InitJoysticks' for re-initialization */
1741 if (SDLCheckJoystickOpened(joystick_nr))
1742 SDLCloseJoystick(joystick_nr);
1744 if (!setup.input[i].use_joystick)
1747 if (!SDLOpenJoystick(joystick_nr))
1750 Error(ERR_WARN, "cannot open joystick %d", joystick_nr);
1755 joystick.status = JOYSTICK_ACTIVATED;
1759 boolean SDLReadJoystick(int nr, int *x, int *y, boolean *b1, boolean *b2)
1761 if (nr < 0 || nr >= MAX_PLAYERS)
1765 *x = sdl_js_axis[nr][0];
1767 *y = sdl_js_axis[nr][1];
1770 *b1 = sdl_js_button[nr][0];
1772 *b2 = sdl_js_button[nr][1];
1777 #endif /* TARGET_SDL */