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(char *fullscreen_mode_string)
40 struct ScreenModeInfo *fullscreen_mode;
43 fullscreen_mode = get_screen_mode_from_string(fullscreen_mode_string);
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(setup.fullscreen_mode);
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;
263 (*backbuffer)->surface = new_surface;
265 video.fullscreen_enabled = TRUE;
266 video.fullscreen_mode_current = setup.fullscreen_mode;
272 if ((!fullscreen && video.fullscreen_enabled) || new_surface == NULL)
277 /* switch display to window mode */
278 if ((new_surface = SDL_SetVideoMode(video.width, video.height,
279 video.depth, surface_flags_window))
282 /* switching display to window mode failed -- should not happen */
283 Error(ERR_WARN, "SDL_SetVideoMode() failed: %s", SDL_GetError());
289 (*backbuffer)->surface = new_surface;
291 video.fullscreen_enabled = FALSE;
299 void SDLCreateBitmapContent(Bitmap *new_bitmap, int width, int height,
302 SDL_Surface *surface_tmp, *surface_native;
304 if ((surface_tmp = SDL_CreateRGBSurface(SURFACE_FLAGS, width, height, depth,
307 Error(ERR_EXIT, "SDL_CreateRGBSurface() failed: %s", SDL_GetError());
309 if ((surface_native = SDL_DisplayFormat(surface_tmp)) == NULL)
310 Error(ERR_EXIT, "SDL_DisplayFormat() failed: %s", SDL_GetError());
312 SDL_FreeSurface(surface_tmp);
314 new_bitmap->surface = surface_native;
317 void SDLFreeBitmapPointers(Bitmap *bitmap)
320 SDL_FreeSurface(bitmap->surface);
321 if (bitmap->surface_masked)
322 SDL_FreeSurface(bitmap->surface_masked);
323 bitmap->surface = NULL;
324 bitmap->surface_masked = NULL;
327 void SDLCopyArea(Bitmap *src_bitmap, Bitmap *dst_bitmap,
328 int src_x, int src_y, int width, int height,
329 int dst_x, int dst_y, int mask_mode)
331 Bitmap *real_dst_bitmap = (dst_bitmap == window ? backbuffer : dst_bitmap);
332 SDL_Rect src_rect, dst_rect;
334 if (src_bitmap == backbuffer)
336 src_x += video_xoffset;
337 src_y += video_yoffset;
345 if (dst_bitmap == backbuffer || dst_bitmap == window)
347 dst_x += video_xoffset;
348 dst_y += video_yoffset;
356 if (src_bitmap != backbuffer || dst_bitmap != window)
357 SDL_BlitSurface((mask_mode == BLIT_MASKED ?
358 src_bitmap->surface_masked : src_bitmap->surface),
359 &src_rect, real_dst_bitmap->surface, &dst_rect);
361 if (dst_bitmap == window)
362 SDL_UpdateRect(backbuffer->surface, dst_x, dst_y, width, height);
365 void SDLFillRectangle(Bitmap *dst_bitmap, int x, int y, int width, int height,
368 Bitmap *real_dst_bitmap = (dst_bitmap == window ? backbuffer : dst_bitmap);
371 if (dst_bitmap == backbuffer || dst_bitmap == window)
382 SDL_FillRect(real_dst_bitmap->surface, &rect, color);
384 if (dst_bitmap == window)
385 SDL_UpdateRect(backbuffer->surface, x, y, width, height);
388 void SDLFadeRectangle(Bitmap *bitmap_cross, int x, int y, int width, int height,
389 int fade_mode, int fade_delay, int post_delay,
390 void (*draw_border_function)(void))
392 static boolean initialization_needed = TRUE;
393 static SDL_Surface *surface_source = NULL;
394 static SDL_Surface *surface_target = NULL;
395 static SDL_Surface *surface_black = NULL;
396 SDL_Surface *surface_screen = backbuffer->surface;
397 SDL_Surface *surface_cross = (bitmap_cross ? bitmap_cross->surface : NULL);
398 SDL_Rect src_rect, dst_rect;
399 int src_x = x, src_y = y;
400 int dst_x = x, dst_y = y;
401 unsigned int time_last, time_current;
410 dst_x += video_xoffset;
411 dst_y += video_yoffset;
418 if (initialization_needed)
420 unsigned int flags = SDL_SRCALPHA;
422 /* use same surface type as screen surface */
423 if ((surface_screen->flags & SDL_HWSURFACE))
424 flags |= SDL_HWSURFACE;
426 flags |= SDL_SWSURFACE;
428 /* create surface for temporary copy of screen buffer (source) */
429 if ((surface_source =
430 SDL_CreateRGBSurface(flags,
433 surface_screen->format->BitsPerPixel,
434 surface_screen->format->Rmask,
435 surface_screen->format->Gmask,
436 surface_screen->format->Bmask,
437 surface_screen->format->Amask)) == NULL)
438 Error(ERR_EXIT, "SDL_CreateRGBSurface() failed: %s", SDL_GetError());
440 /* create surface for cross-fading screen buffer (target) */
441 if ((surface_target =
442 SDL_CreateRGBSurface(flags,
445 surface_screen->format->BitsPerPixel,
446 surface_screen->format->Rmask,
447 surface_screen->format->Gmask,
448 surface_screen->format->Bmask,
449 surface_screen->format->Amask)) == NULL)
450 Error(ERR_EXIT, "SDL_CreateRGBSurface() failed: %s", SDL_GetError());
452 /* create black surface for fading from/to black */
454 SDL_CreateRGBSurface(flags,
457 surface_screen->format->BitsPerPixel,
458 surface_screen->format->Rmask,
459 surface_screen->format->Gmask,
460 surface_screen->format->Bmask,
461 surface_screen->format->Amask)) == NULL)
462 Error(ERR_EXIT, "SDL_CreateRGBSurface() failed: %s", SDL_GetError());
464 /* completely fill the surface with black color pixels */
465 SDL_FillRect(surface_black, NULL,
466 SDL_MapRGB(surface_screen->format, 0, 0, 0));
468 initialization_needed = FALSE;
471 /* copy source and target surfaces to temporary surfaces for fading */
472 if (fade_mode == FADE_MODE_CROSSFADE)
474 SDL_BlitSurface(surface_cross, &src_rect, surface_source, &src_rect);
475 SDL_BlitSurface(surface_screen, &dst_rect, surface_target, &src_rect);
477 else if (fade_mode == FADE_MODE_FADE_IN)
479 SDL_BlitSurface(surface_black, &src_rect, surface_source, &src_rect);
480 SDL_BlitSurface(surface_screen, &dst_rect, surface_target, &src_rect);
482 else /* FADE_MODE_FADE_OUT */
484 SDL_BlitSurface(surface_screen, &dst_rect, surface_source, &src_rect);
485 SDL_BlitSurface(surface_black, &src_rect, surface_target, &src_rect);
488 time_current = SDL_GetTicks();
490 for (alpha = 0.0; alpha < 255.0;)
492 time_last = time_current;
493 time_current = SDL_GetTicks();
494 alpha += 255 * ((float)(time_current - time_last) / fade_delay);
495 alpha_final = MIN(MAX(0, alpha), 255);
497 /* draw existing (source) image to screen buffer */
498 SDL_BlitSurface(surface_source, &src_rect, surface_screen, &dst_rect);
500 /* draw new (target) image to screen buffer using alpha blending */
501 SDL_SetAlpha(surface_target, SDL_SRCALPHA, alpha_final);
502 SDL_BlitSurface(surface_target, &src_rect, surface_screen, &dst_rect);
504 if (draw_border_function != NULL)
505 draw_border_function();
508 /* only update the region of the screen that is affected from fading */
509 SDL_UpdateRect(surface_screen, dst_x, dst_y, width, height);
511 SDL_Flip(surface_screen);
518 void SDLDrawSimpleLine(Bitmap *dst_bitmap, int from_x, int from_y,
519 int to_x, int to_y, Uint32 color)
521 SDL_Surface *surface = dst_bitmap->surface;
525 swap_numbers(&from_x, &to_x);
528 swap_numbers(&from_y, &to_y);
532 rect.w = (to_x - from_x + 1);
533 rect.h = (to_y - from_y + 1);
535 if (dst_bitmap == backbuffer || dst_bitmap == window)
537 rect.x += video_xoffset;
538 rect.y += video_yoffset;
541 SDL_FillRect(surface, &rect, color);
544 void SDLDrawLine(Bitmap *dst_bitmap, int from_x, int from_y,
545 int to_x, int to_y, Uint32 color)
547 if (dst_bitmap == backbuffer || dst_bitmap == window)
549 from_x += video_xoffset;
550 from_y += video_yoffset;
551 to_x += video_xoffset;
552 to_y += video_yoffset;
555 sge_Line(dst_bitmap->surface, from_x, from_y, to_x, to_y, color);
559 void SDLDrawLines(SDL_Surface *surface, struct XY *points,
560 int num_points, Uint32 color)
565 for (i = 0; i < num_points - 1; i++)
567 for (x = 0; x < line_width; x++)
569 for (y = 0; y < line_width; y++)
571 int dx = x - line_width / 2;
572 int dy = y - line_width / 2;
574 if ((x == 0 && y == 0) ||
575 (x == 0 && y == line_width - 1) ||
576 (x == line_width - 1 && y == 0) ||
577 (x == line_width - 1 && y == line_width - 1))
580 sge_Line(surface, points[i].x + dx, points[i].y + dy,
581 points[i+1].x + dx, points[i+1].y + dy, color);
588 Pixel SDLGetPixel(Bitmap *src_bitmap, int x, int y)
590 SDL_Surface *surface = src_bitmap->surface;
592 if (src_bitmap == backbuffer || src_bitmap == window)
598 switch (surface->format->BytesPerPixel)
600 case 1: /* assuming 8-bpp */
602 return *((Uint8 *)surface->pixels + y * surface->pitch + x);
606 case 2: /* probably 15-bpp or 16-bpp */
608 return *((Uint16 *)surface->pixels + y * surface->pitch / 2 + x);
612 case 3: /* slow 24-bpp mode; usually not used */
614 /* does this work? */
615 Uint8 *pix = (Uint8 *)surface->pixels + y * surface->pitch + x * 3;
619 shift = surface->format->Rshift;
620 color |= *(pix + shift / 8) >> shift;
621 shift = surface->format->Gshift;
622 color |= *(pix + shift / 8) >> shift;
623 shift = surface->format->Bshift;
624 color |= *(pix + shift / 8) >> shift;
630 case 4: /* probably 32-bpp */
632 return *((Uint32 *)surface->pixels + y * surface->pitch / 4 + x);
641 /* ========================================================================= */
642 /* The following functions were taken from the SGE library */
643 /* (SDL Graphics Extension Library) by Anders Lindström */
644 /* http://www.etek.chalmers.se/~e8cal1/sge/index.html */
645 /* ========================================================================= */
647 void _PutPixel(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
649 if (x >= 0 && x <= surface->w - 1 && y >= 0 && y <= surface->h - 1)
651 switch (surface->format->BytesPerPixel)
656 *((Uint8 *)surface->pixels + y*surface->pitch + x) = color;
662 /* Probably 15-bpp or 16-bpp */
663 *((Uint16 *)surface->pixels + y*surface->pitch/2 + x) = color;
669 /* Slow 24-bpp mode, usually not used */
673 /* Gack - slow, but endian correct */
674 pix = (Uint8 *)surface->pixels + y * surface->pitch + x*3;
675 shift = surface->format->Rshift;
676 *(pix+shift/8) = color>>shift;
677 shift = surface->format->Gshift;
678 *(pix+shift/8) = color>>shift;
679 shift = surface->format->Bshift;
680 *(pix+shift/8) = color>>shift;
686 /* Probably 32-bpp */
687 *((Uint32 *)surface->pixels + y*surface->pitch/4 + x) = color;
694 void _PutPixelRGB(SDL_Surface *surface, Sint16 x, Sint16 y,
695 Uint8 R, Uint8 G, Uint8 B)
697 _PutPixel(surface, x, y, SDL_MapRGB(surface->format, R, G, B));
700 void _PutPixel8(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
702 *((Uint8 *)surface->pixels + y*surface->pitch + x) = color;
705 void _PutPixel16(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
707 *((Uint16 *)surface->pixels + y*surface->pitch/2 + x) = color;
710 void _PutPixel24(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
715 /* Gack - slow, but endian correct */
716 pix = (Uint8 *)surface->pixels + y * surface->pitch + x*3;
717 shift = surface->format->Rshift;
718 *(pix+shift/8) = color>>shift;
719 shift = surface->format->Gshift;
720 *(pix+shift/8) = color>>shift;
721 shift = surface->format->Bshift;
722 *(pix+shift/8) = color>>shift;
725 void _PutPixel32(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
727 *((Uint32 *)surface->pixels + y*surface->pitch/4 + x) = color;
730 void _PutPixelX(SDL_Surface *dest,Sint16 x,Sint16 y,Uint32 color)
732 switch (dest->format->BytesPerPixel)
735 *((Uint8 *)dest->pixels + y*dest->pitch + x) = color;
739 *((Uint16 *)dest->pixels + y*dest->pitch/2 + x) = color;
743 _PutPixel24(dest,x,y,color);
747 *((Uint32 *)dest->pixels + y*dest->pitch/4 + x) = color;
752 void sge_PutPixel(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
754 if (SDL_MUSTLOCK(surface))
756 if (SDL_LockSurface(surface) < 0)
762 _PutPixel(surface, x, y, color);
764 if (SDL_MUSTLOCK(surface))
766 SDL_UnlockSurface(surface);
770 void sge_PutPixelRGB(SDL_Surface *surface, Sint16 x, Sint16 y,
771 Uint8 r, Uint8 g, Uint8 b)
773 sge_PutPixel(surface, x, y, SDL_MapRGB(surface->format, r, g, b));
776 Sint32 sge_CalcYPitch(SDL_Surface *dest, Sint16 y)
778 if (y >= 0 && y <= dest->h - 1)
780 switch (dest->format->BytesPerPixel)
783 return y*dest->pitch;
787 return y*dest->pitch/2;
791 return y*dest->pitch;
795 return y*dest->pitch/4;
803 void sge_pPutPixel(SDL_Surface *surface, Sint16 x, Sint32 ypitch, Uint32 color)
805 if (x >= 0 && x <= surface->w - 1 && ypitch >= 0)
807 switch (surface->format->BytesPerPixel)
812 *((Uint8 *)surface->pixels + ypitch + x) = color;
818 /* Probably 15-bpp or 16-bpp */
819 *((Uint16 *)surface->pixels + ypitch + x) = color;
825 /* Slow 24-bpp mode, usually not used */
829 /* Gack - slow, but endian correct */
830 pix = (Uint8 *)surface->pixels + ypitch + x*3;
831 shift = surface->format->Rshift;
832 *(pix+shift/8) = color>>shift;
833 shift = surface->format->Gshift;
834 *(pix+shift/8) = color>>shift;
835 shift = surface->format->Bshift;
836 *(pix+shift/8) = color>>shift;
842 /* Probably 32-bpp */
843 *((Uint32 *)surface->pixels + ypitch + x) = color;
850 void sge_HLine(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y,
855 if (SDL_MUSTLOCK(Surface))
857 if (SDL_LockSurface(Surface) < 0)
870 /* Do the clipping */
871 if (y < 0 || y > Surface->h - 1 || x1 > Surface->w - 1 || x2 < 0)
875 if (x2 > Surface->w - 1)
883 SDL_FillRect(Surface, &l, Color);
885 if (SDL_MUSTLOCK(Surface))
887 SDL_UnlockSurface(Surface);
891 void sge_HLineRGB(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y,
892 Uint8 R, Uint8 G, Uint8 B)
894 sge_HLine(Surface, x1, x2, y, SDL_MapRGB(Surface->format, R, G, B));
897 void _HLine(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y, Uint32 Color)
908 /* Do the clipping */
909 if (y < 0 || y > Surface->h - 1 || x1 > Surface->w - 1 || x2 < 0)
913 if (x2 > Surface->w - 1)
921 SDL_FillRect(Surface, &l, Color);
924 void sge_VLine(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2,
929 if (SDL_MUSTLOCK(Surface))
931 if (SDL_LockSurface(Surface) < 0)
944 /* Do the clipping */
945 if (x < 0 || x > Surface->w - 1 || y1 > Surface->h - 1 || y2 < 0)
949 if (y2 > Surface->h - 1)
957 SDL_FillRect(Surface, &l, Color);
959 if (SDL_MUSTLOCK(Surface))
961 SDL_UnlockSurface(Surface);
965 void sge_VLineRGB(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2,
966 Uint8 R, Uint8 G, Uint8 B)
968 sge_VLine(Surface, x, y1, y2, SDL_MapRGB(Surface->format, R, G, B));
971 void _VLine(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2, Uint32 Color)
982 /* Do the clipping */
983 if (x < 0 || x > Surface->w - 1 || y1 > Surface->h - 1 || y2 < 0)
987 if (y2 > Surface->h - 1)
995 SDL_FillRect(Surface, &l, Color);
998 void sge_DoLine(SDL_Surface *Surface, Sint16 x1, Sint16 y1,
999 Sint16 x2, Sint16 y2, Uint32 Color,
1000 void Callback(SDL_Surface *Surf, Sint16 X, Sint16 Y,
1003 Sint16 dx, dy, sdx, sdy, x, y, px, py;
1008 sdx = (dx < 0) ? -1 : 1;
1009 sdy = (dy < 0) ? -1 : 1;
1021 for (x = 0; x < dx; x++)
1023 Callback(Surface, px, py, Color);
1037 for (y = 0; y < dy; y++)
1039 Callback(Surface, px, py, Color);
1053 void sge_DoLineRGB(SDL_Surface *Surface, Sint16 X1, Sint16 Y1,
1054 Sint16 X2, Sint16 Y2, Uint8 R, Uint8 G, Uint8 B,
1055 void Callback(SDL_Surface *Surf, Sint16 X, Sint16 Y,
1058 sge_DoLine(Surface, X1, Y1, X2, Y2,
1059 SDL_MapRGB(Surface->format, R, G, B), Callback);
1062 void sge_Line(SDL_Surface *Surface, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2,
1065 if (SDL_MUSTLOCK(Surface))
1067 if (SDL_LockSurface(Surface) < 0)
1072 sge_DoLine(Surface, x1, y1, x2, y2, Color, _PutPixel);
1074 /* unlock the display */
1075 if (SDL_MUSTLOCK(Surface))
1077 SDL_UnlockSurface(Surface);
1081 void sge_LineRGB(SDL_Surface *Surface, Sint16 x1, Sint16 y1, Sint16 x2,
1082 Sint16 y2, Uint8 R, Uint8 G, Uint8 B)
1084 sge_Line(Surface, x1, y1, x2, y2, SDL_MapRGB(Surface->format, R, G, B));
1087 void SDLPutPixel(Bitmap *dst_bitmap, int x, int y, Pixel pixel)
1089 if (dst_bitmap == backbuffer || dst_bitmap == window)
1095 sge_PutPixel(dst_bitmap->surface, x, y, pixel);
1100 -----------------------------------------------------------------------------
1101 quick (no, it's slow) and dirty hack to "invert" rectangle inside SDL surface
1102 -----------------------------------------------------------------------------
1105 void SDLInvertArea(Bitmap *bitmap, int src_x, int src_y,
1106 int width, int height, Uint32 color)
1110 for (y = src_y; y < src_y + height; y++)
1112 for (x = src_x; x < src_x + width; x++)
1114 Uint32 pixel = SDLGetPixel(bitmap, x, y);
1116 SDLPutPixel(bitmap, x, y, pixel == BLACK_PIXEL ? color : BLACK_PIXEL);
1121 void SDLCopyInverseMasked(Bitmap *src_bitmap, Bitmap *dst_bitmap,
1122 int src_x, int src_y, int width, int height,
1123 int dst_x, int dst_y)
1127 for (y = 0; y < height; y++)
1129 for (x = 0; x < width; x++)
1131 Uint32 pixel = SDLGetPixel(src_bitmap, src_x + x, src_y + y);
1133 if (pixel != BLACK_PIXEL)
1134 SDLPutPixel(dst_bitmap, dst_x + x, dst_y + y, BLACK_PIXEL);
1140 /* ========================================================================= */
1141 /* The following functions were taken from the SDL_gfx library version 2.0.3 */
1142 /* (Rotozoomer) by Andreas Schiffler */
1143 /* http://www.ferzkopp.net/Software/SDL_gfx-2.0/index.html */
1144 /* ========================================================================= */
1147 -----------------------------------------------------------------------------
1150 zoomes 32bit RGBA/ABGR 'src' surface to 'dst' surface.
1151 -----------------------------------------------------------------------------
1162 int zoomSurfaceRGBA_scaleDownBy2(SDL_Surface *src, SDL_Surface *dst)
1165 tColorRGBA *sp, *csp, *dp;
1169 sp = csp = (tColorRGBA *) src->pixels;
1170 dp = (tColorRGBA *) dst->pixels;
1171 sgap = src->pitch - src->w * 4;
1172 dgap = dst->pitch - dst->w * 4;
1174 for (y = 0; y < dst->h; y++)
1178 for (x = 0; x < dst->w; x++)
1180 tColorRGBA *sp0 = sp;
1181 tColorRGBA *sp1 = (tColorRGBA *) ((Uint8 *) sp + src->pitch);
1182 tColorRGBA *sp00 = &sp0[0];
1183 tColorRGBA *sp01 = &sp0[1];
1184 tColorRGBA *sp10 = &sp1[0];
1185 tColorRGBA *sp11 = &sp1[1];
1188 /* create new color pixel from all four source color pixels */
1189 new.r = (sp00->r + sp01->r + sp10->r + sp11->r) / 4;
1190 new.g = (sp00->g + sp01->g + sp10->g + sp11->g) / 4;
1191 new.b = (sp00->b + sp01->b + sp10->b + sp11->b) / 4;
1192 new.a = (sp00->a + sp01->a + sp10->a + sp11->a) / 4;
1197 /* advance source pointers */
1200 /* advance destination pointer */
1204 /* advance source pointer */
1205 csp = (tColorRGBA *) ((Uint8 *) csp + 2 * src->pitch);
1207 /* advance destination pointers */
1208 dp = (tColorRGBA *) ((Uint8 *) dp + dgap);
1214 int zoomSurfaceRGBA(SDL_Surface *src, SDL_Surface *dst)
1216 int x, y, sx, sy, *sax, *say, *csax, *csay, csx, csy;
1217 tColorRGBA *sp, *csp, *dp;
1220 /* use specialized zoom function when scaling down to exactly half size */
1221 if (src->w == 2 * dst->w &&
1222 src->h == 2 * dst->h)
1223 return zoomSurfaceRGBA_scaleDownBy2(src, dst);
1225 /* variable setup */
1226 sx = (int) (65536.0 * (float) src->w / (float) dst->w);
1227 sy = (int) (65536.0 * (float) src->h / (float) dst->h);
1229 /* allocate memory for row increments */
1230 sax = (int *)checked_malloc((dst->w + 1) * sizeof(Uint32));
1231 say = (int *)checked_malloc((dst->h + 1) * sizeof(Uint32));
1233 /* precalculate row increments */
1236 for (x = 0; x <= dst->w; x++)
1246 for (y = 0; y <= dst->h; y++)
1255 sp = csp = (tColorRGBA *) src->pixels;
1256 dp = (tColorRGBA *) dst->pixels;
1257 sgap = src->pitch - src->w * 4;
1258 dgap = dst->pitch - dst->w * 4;
1261 for (y = 0; y < dst->h; y++)
1266 for (x = 0; x < dst->w; x++)
1271 /* advance source pointers */
1273 sp += (*csax >> 16);
1275 /* advance destination pointer */
1279 /* advance source pointer */
1281 csp = (tColorRGBA *) ((Uint8 *) csp + (*csay >> 16) * src->pitch);
1283 /* advance destination pointers */
1284 dp = (tColorRGBA *) ((Uint8 *) dp + dgap);
1294 -----------------------------------------------------------------------------
1297 zoomes 8 bit palette/Y 'src' surface to 'dst' surface
1298 -----------------------------------------------------------------------------
1301 int zoomSurfaceY(SDL_Surface * src, SDL_Surface * dst)
1303 Uint32 x, y, sx, sy, *sax, *say, *csax, *csay, csx, csy;
1304 Uint8 *sp, *dp, *csp;
1307 /* variable setup */
1308 sx = (Uint32) (65536.0 * (float) src->w / (float) dst->w);
1309 sy = (Uint32) (65536.0 * (float) src->h / (float) dst->h);
1311 /* allocate memory for row increments */
1312 sax = (Uint32 *)checked_malloc(dst->w * sizeof(Uint32));
1313 say = (Uint32 *)checked_malloc(dst->h * sizeof(Uint32));
1315 /* precalculate row increments */
1318 for (x = 0; x < dst->w; x++)
1321 *csax = (csx >> 16);
1328 for (y = 0; y < dst->h; y++)
1331 *csay = (csy >> 16);
1338 for (x = 0; x < dst->w; x++)
1346 for (y = 0; y < dst->h; y++)
1353 sp = csp = (Uint8 *) src->pixels;
1354 dp = (Uint8 *) dst->pixels;
1355 dgap = dst->pitch - dst->w;
1359 for (y = 0; y < dst->h; y++)
1363 for (x = 0; x < dst->w; x++)
1368 /* advance source pointers */
1372 /* advance destination pointer */
1376 /* advance source pointer (for row) */
1377 csp += ((*csay) * src->pitch);
1380 /* advance destination pointers */
1391 -----------------------------------------------------------------------------
1394 Zooms a 32bit or 8bit 'src' surface to newly created 'dst' surface.
1395 'zoomx' and 'zoomy' are scaling factors for width and height.
1396 If the surface is not 8bit or 32bit RGBA/ABGR it will be converted
1397 into a 32bit RGBA format on the fly.
1398 -----------------------------------------------------------------------------
1401 SDL_Surface *zoomSurface(SDL_Surface *src, int dst_width, int dst_height)
1403 SDL_Surface *zoom_src = NULL;
1404 SDL_Surface *zoom_dst = NULL;
1405 boolean is_converted = FALSE;
1412 /* determine if source surface is 32 bit or 8 bit */
1413 is_32bit = (src->format->BitsPerPixel == 32);
1415 if (is_32bit || src->format->BitsPerPixel == 8)
1417 /* use source surface 'as is' */
1422 /* new source surface is 32 bit with a defined RGB ordering */
1423 zoom_src = SDL_CreateRGBSurface(SDL_SWSURFACE, src->w, src->h, 32,
1424 0x000000ff, 0x0000ff00, 0x00ff0000, 0);
1425 SDL_BlitSurface(src, NULL, zoom_src, NULL);
1427 is_converted = TRUE;
1430 /* allocate surface to completely contain the zoomed surface */
1433 /* target surface is 32 bit with source RGBA/ABGR ordering */
1434 zoom_dst = SDL_CreateRGBSurface(SDL_SWSURFACE, dst_width, dst_height, 32,
1435 zoom_src->format->Rmask,
1436 zoom_src->format->Gmask,
1437 zoom_src->format->Bmask, 0);
1441 /* target surface is 8 bit */
1442 zoom_dst = SDL_CreateRGBSurface(SDL_SWSURFACE, dst_width, dst_height, 8,
1446 /* lock source surface */
1447 SDL_LockSurface(zoom_src);
1449 /* check which kind of surface we have */
1452 /* call the 32 bit transformation routine to do the zooming */
1453 zoomSurfaceRGBA(zoom_src, zoom_dst);
1458 for (i = 0; i < zoom_src->format->palette->ncolors; i++)
1459 zoom_dst->format->palette->colors[i] =
1460 zoom_src->format->palette->colors[i];
1461 zoom_dst->format->palette->ncolors = zoom_src->format->palette->ncolors;
1463 /* call the 8 bit transformation routine to do the zooming */
1464 zoomSurfaceY(zoom_src, zoom_dst);
1467 /* unlock source surface */
1468 SDL_UnlockSurface(zoom_src);
1470 /* free temporary surface */
1472 SDL_FreeSurface(zoom_src);
1474 /* return destination surface */
1478 void SDLZoomBitmap(Bitmap *src_bitmap, Bitmap *dst_bitmap)
1480 SDL_Surface *sdl_surface_tmp;
1481 int dst_width = dst_bitmap->width;
1482 int dst_height = dst_bitmap->height;
1484 /* throw away old destination surface */
1485 SDL_FreeSurface(dst_bitmap->surface);
1487 /* create zoomed temporary surface from source surface */
1488 sdl_surface_tmp = zoomSurface(src_bitmap->surface, dst_width, dst_height);
1490 /* create native format destination surface from zoomed temporary surface */
1491 dst_bitmap->surface = SDL_DisplayFormat(sdl_surface_tmp);
1493 /* free temporary surface */
1494 SDL_FreeSurface(sdl_surface_tmp);
1498 /* ========================================================================= */
1499 /* load image to bitmap */
1500 /* ========================================================================= */
1502 Bitmap *SDLLoadImage(char *filename)
1504 Bitmap *new_bitmap = CreateBitmapStruct();
1505 SDL_Surface *sdl_image_tmp;
1507 /* load image to temporary surface */
1508 if ((sdl_image_tmp = IMG_Load(filename)) == NULL)
1510 SetError("IMG_Load(): %s", SDL_GetError());
1515 /* create native non-transparent surface for current image */
1516 if ((new_bitmap->surface = SDL_DisplayFormat(sdl_image_tmp)) == NULL)
1518 SetError("SDL_DisplayFormat(): %s", SDL_GetError());
1523 /* create native transparent surface for current image */
1524 SDL_SetColorKey(sdl_image_tmp, SDL_SRCCOLORKEY,
1525 SDL_MapRGB(sdl_image_tmp->format, 0x00, 0x00, 0x00));
1526 if ((new_bitmap->surface_masked = SDL_DisplayFormat(sdl_image_tmp)) == NULL)
1528 SetError("SDL_DisplayFormat(): %s", SDL_GetError());
1533 /* free temporary surface */
1534 SDL_FreeSurface(sdl_image_tmp);
1536 new_bitmap->width = new_bitmap->surface->w;
1537 new_bitmap->height = new_bitmap->surface->h;
1543 /* ------------------------------------------------------------------------- */
1544 /* custom cursor fuctions */
1545 /* ------------------------------------------------------------------------- */
1547 static SDL_Cursor *create_cursor(struct MouseCursorInfo *cursor_info)
1549 return SDL_CreateCursor(cursor_info->data, cursor_info->mask,
1550 cursor_info->width, cursor_info->height,
1551 cursor_info->hot_x, cursor_info->hot_y);
1554 void SDLSetMouseCursor(struct MouseCursorInfo *cursor_info)
1556 static struct MouseCursorInfo *last_cursor_info = NULL;
1557 static struct MouseCursorInfo *last_cursor_info2 = NULL;
1558 static SDL_Cursor *cursor_default = NULL;
1559 static SDL_Cursor *cursor_current = NULL;
1561 /* if invoked for the first time, store the SDL default cursor */
1562 if (cursor_default == NULL)
1563 cursor_default = SDL_GetCursor();
1565 /* only create new cursor if cursor info (custom only) has changed */
1566 if (cursor_info != NULL && cursor_info != last_cursor_info)
1568 cursor_current = create_cursor(cursor_info);
1569 last_cursor_info = cursor_info;
1572 /* only set new cursor if cursor info (custom or NULL) has changed */
1573 if (cursor_info != last_cursor_info2)
1574 SDL_SetCursor(cursor_info ? cursor_current : cursor_default);
1576 last_cursor_info2 = cursor_info;
1580 /* ========================================================================= */
1581 /* audio functions */
1582 /* ========================================================================= */
1584 void SDLOpenAudio(void)
1586 if (!strEqual(setup.system.sdl_audiodriver, ARG_DEFAULT))
1587 putenv(getStringCat2("SDL_AUDIODRIVER=", setup.system.sdl_audiodriver));
1589 if (SDL_InitSubSystem(SDL_INIT_AUDIO) < 0)
1591 Error(ERR_WARN, "SDL_InitSubSystem() failed: %s", SDL_GetError());
1595 if (Mix_OpenAudio(DEFAULT_AUDIO_SAMPLE_RATE, MIX_DEFAULT_FORMAT,
1596 AUDIO_NUM_CHANNELS_STEREO,
1597 setup.system.audio_fragment_size) < 0)
1599 Error(ERR_WARN, "Mix_OpenAudio() failed: %s", SDL_GetError());
1603 audio.sound_available = TRUE;
1604 audio.music_available = TRUE;
1605 audio.loops_available = TRUE;
1606 audio.sound_enabled = TRUE;
1608 /* set number of available mixer channels */
1609 audio.num_channels = Mix_AllocateChannels(NUM_MIXER_CHANNELS);
1610 audio.music_channel = MUSIC_CHANNEL;
1611 audio.first_sound_channel = FIRST_SOUND_CHANNEL;
1613 Mixer_InitChannels();
1616 void SDLCloseAudio(void)
1619 Mix_HaltChannel(-1);
1622 SDL_QuitSubSystem(SDL_INIT_AUDIO);
1626 /* ========================================================================= */
1627 /* event functions */
1628 /* ========================================================================= */
1630 void SDLNextEvent(Event *event)
1632 SDL_WaitEvent(event);
1634 if (event->type == EVENT_BUTTONPRESS ||
1635 event->type == EVENT_BUTTONRELEASE)
1637 if (((ButtonEvent *)event)->x > video_xoffset)
1638 ((ButtonEvent *)event)->x -= video_xoffset;
1640 ((ButtonEvent *)event)->x = 0;
1641 if (((ButtonEvent *)event)->y > video_yoffset)
1642 ((ButtonEvent *)event)->y -= video_yoffset;
1644 ((ButtonEvent *)event)->y = 0;
1646 else if (event->type == EVENT_MOTIONNOTIFY)
1648 if (((MotionEvent *)event)->x > video_xoffset)
1649 ((MotionEvent *)event)->x -= video_xoffset;
1651 ((MotionEvent *)event)->x = 0;
1652 if (((MotionEvent *)event)->y > video_yoffset)
1653 ((MotionEvent *)event)->y -= video_yoffset;
1655 ((MotionEvent *)event)->y = 0;
1660 /* ========================================================================= */
1661 /* joystick functions */
1662 /* ========================================================================= */
1664 static SDL_Joystick *sdl_joystick[MAX_PLAYERS] = { NULL, NULL, NULL, NULL };
1665 static int sdl_js_axis[MAX_PLAYERS][2] = { {0, 0}, {0, 0}, {0, 0}, {0, 0} };
1666 static int sdl_js_button[MAX_PLAYERS][2] = { {0, 0}, {0, 0}, {0, 0}, {0, 0} };
1668 static boolean SDLOpenJoystick(int nr)
1670 if (nr < 0 || nr > MAX_PLAYERS)
1673 return ((sdl_joystick[nr] = SDL_JoystickOpen(nr)) == NULL ? FALSE : TRUE);
1676 static void SDLCloseJoystick(int nr)
1678 if (nr < 0 || nr > MAX_PLAYERS)
1681 SDL_JoystickClose(sdl_joystick[nr]);
1684 static boolean SDLCheckJoystickOpened(int nr)
1686 if (nr < 0 || nr > MAX_PLAYERS)
1689 return (SDL_JoystickOpened(nr) ? TRUE : FALSE);
1692 void HandleJoystickEvent(Event *event)
1696 case SDL_JOYAXISMOTION:
1697 if (event->jaxis.axis < 2)
1698 sdl_js_axis[event->jaxis.which][event->jaxis.axis]= event->jaxis.value;
1701 case SDL_JOYBUTTONDOWN:
1702 if (event->jbutton.button < 2)
1703 sdl_js_button[event->jbutton.which][event->jbutton.button] = TRUE;
1706 case SDL_JOYBUTTONUP:
1707 if (event->jbutton.button < 2)
1708 sdl_js_button[event->jbutton.which][event->jbutton.button] = FALSE;
1716 void SDLInitJoysticks()
1718 static boolean sdl_joystick_subsystem_initialized = FALSE;
1719 boolean print_warning = !sdl_joystick_subsystem_initialized;
1722 if (!sdl_joystick_subsystem_initialized)
1724 sdl_joystick_subsystem_initialized = TRUE;
1726 if (SDL_Init(SDL_INIT_JOYSTICK) < 0)
1728 Error(ERR_EXIT, "SDL_Init() failed: %s", SDL_GetError());
1733 for (i = 0; i < MAX_PLAYERS; i++)
1735 /* get configured joystick for this player */
1736 char *device_name = setup.input[i].joy.device_name;
1737 int joystick_nr = getJoystickNrFromDeviceName(device_name);
1739 if (joystick_nr >= SDL_NumJoysticks())
1741 if (setup.input[i].use_joystick && print_warning)
1742 Error(ERR_WARN, "cannot find joystick %d", joystick_nr);
1747 /* misuse joystick file descriptor variable to store joystick number */
1748 joystick.fd[i] = joystick_nr;
1750 if (joystick_nr == -1)
1753 /* this allows subsequent calls to 'InitJoysticks' for re-initialization */
1754 if (SDLCheckJoystickOpened(joystick_nr))
1755 SDLCloseJoystick(joystick_nr);
1757 if (!setup.input[i].use_joystick)
1760 if (!SDLOpenJoystick(joystick_nr))
1763 Error(ERR_WARN, "cannot open joystick %d", joystick_nr);
1768 joystick.status = JOYSTICK_ACTIVATED;
1772 boolean SDLReadJoystick(int nr, int *x, int *y, boolean *b1, boolean *b2)
1774 if (nr < 0 || nr >= MAX_PLAYERS)
1778 *x = sdl_js_axis[nr][0];
1780 *y = sdl_js_axis[nr][1];
1783 *b1 = sdl_js_button[nr][0];
1785 *b2 = sdl_js_button[nr][1];
1790 #endif /* TARGET_SDL */