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 ***********************************************************/
20 #if defined(TARGET_SDL)
22 /* ========================================================================= */
24 /* ========================================================================= */
26 /* functions from SGE library */
27 void sge_Line(SDL_Surface *, Sint16, Sint16, Sint16, Sint16, Uint32);
29 /* stuff needed to work around SDL/Windows fullscreen drawing bug */
30 static int fullscreen_width;
31 static int fullscreen_height;
32 static int fullscreen_xoffset;
33 static int fullscreen_yoffset;
34 static int video_xoffset;
35 static int video_yoffset;
37 static void setFullscreenParameters()
39 struct ScreenModeInfo *fullscreen_mode;
42 fullscreen_mode = get_screen_mode_from_string(setup.fullscreen_mode);
44 for (i = 0; video.fullscreen_modes[i].width != -1; i++)
46 if (fullscreen_mode->width == video.fullscreen_modes[i].width &&
47 fullscreen_mode->height == video.fullscreen_modes[i].height)
49 fullscreen_width = fullscreen_mode->width;
50 fullscreen_height = fullscreen_mode->height;
52 fullscreen_xoffset = (fullscreen_width - video.width) / 2;
53 fullscreen_yoffset = (fullscreen_height - video.height) / 2;
60 void SDLInitVideoDisplay(void)
62 putenv("SDL_VIDEO_CENTERED=1");
64 /* initialize SDL video */
65 if (SDL_InitSubSystem(SDL_INIT_VIDEO) < 0)
66 Error(ERR_EXIT, "SDL_InitSubSystem() failed: %s", SDL_GetError());
68 /* set default SDL depth */
69 video.default_depth = SDL_GetVideoInfo()->vfmt->BitsPerPixel;
72 void SDLInitVideoBuffer(DrawBuffer **backbuffer, DrawWindow **window,
75 static int screen_xy[][2] =
85 /* default: normal game window size */
86 fullscreen_width = video.width;
87 fullscreen_height = video.height;
88 fullscreen_xoffset = 0;
89 fullscreen_yoffset = 0;
91 for (i = 0; screen_xy[i][0] != -1; i++)
93 if (screen_xy[i][0] >= video.width && screen_xy[i][1] >= video.height)
95 fullscreen_width = screen_xy[i][0];
96 fullscreen_height = screen_xy[i][1];
102 fullscreen_xoffset = (fullscreen_width - video.width) / 2;
103 fullscreen_yoffset = (fullscreen_height - video.height) / 2;
105 /* get available hardware supported fullscreen modes */
106 modes = SDL_ListModes(NULL, SDL_FULLSCREEN | SDL_HWSURFACE);
110 /* no screen modes available => no fullscreen mode support */
111 video.fullscreen_available = FALSE;
113 else if (modes == (SDL_Rect **)-1)
115 /* fullscreen resolution is not restricted -- all resolutions available */
116 video.fullscreen_modes = checked_calloc(2 * sizeof(struct ScreenModeInfo));
118 /* use native video buffer size for fullscreen mode */
119 video.fullscreen_modes[0].width = video.width;
120 video.fullscreen_modes[0].height = video.height;
122 video.fullscreen_modes[1].width = -1;
123 video.fullscreen_modes[1].height = -1;
127 /* in this case, a certain number of screen modes is available */
130 for(i = 0; modes[i] != NULL; i++)
132 boolean found_mode = FALSE;
134 /* screen mode is smaller than video buffer size -- skip it */
135 if (modes[i]->w < video.width || modes[i]->h < video.height)
138 if (video.fullscreen_modes != NULL)
139 for (j = 0; video.fullscreen_modes[j].width != -1; j++)
140 if (modes[i]->w == video.fullscreen_modes[j].width &&
141 modes[i]->h == video.fullscreen_modes[j].height)
144 if (found_mode) /* screen mode already stored -- skip it */
147 /* new mode found; add it to list of available fullscreen modes */
151 video.fullscreen_modes = checked_realloc(video.fullscreen_modes,
153 sizeof(struct ScreenModeInfo));
155 video.fullscreen_modes[num_modes - 1].width = modes[i]->w;
156 video.fullscreen_modes[num_modes - 1].height = modes[i]->h;
158 video.fullscreen_modes[num_modes].width = -1;
159 video.fullscreen_modes[num_modes].height = -1;
164 /* no appropriate screen modes available => no fullscreen mode support */
165 video.fullscreen_available = FALSE;
169 /* open SDL video output device (window or fullscreen mode) */
170 if (!SDLSetVideoMode(backbuffer, fullscreen))
171 Error(ERR_EXIT, "setting video mode failed");
173 /* set window and icon title */
174 SDL_WM_SetCaption(program.window_title, program.window_title);
176 /* SDL cannot directly draw to the visible video framebuffer like X11,
177 but always uses a backbuffer, which is then blitted to the visible
178 video framebuffer with 'SDL_UpdateRect' (or replaced with the current
179 visible video framebuffer with 'SDL_Flip', if the hardware supports
180 this). Therefore do not use an additional backbuffer for drawing, but
181 use a symbolic buffer (distinguishable from the SDL backbuffer) called
182 'window', which indicates that the SDL backbuffer should be updated to
183 the visible video framebuffer when attempting to blit to it.
185 For convenience, it seems to be a good idea to create this symbolic
186 buffer 'window' at the same size as the SDL backbuffer. Although it
187 should never be drawn to directly, it would do no harm nevertheless. */
189 /* create additional (symbolic) buffer for double-buffering */
190 *window = CreateBitmap(video.width, video.height, video.depth);
193 boolean SDLSetVideoMode(DrawBuffer **backbuffer, boolean fullscreen)
195 boolean success = TRUE;
196 int surface_flags_fullscreen = SURFACE_FLAGS | SDL_FULLSCREEN;
197 int surface_flags_window = SURFACE_FLAGS;
198 SDL_Surface *new_surface = NULL;
200 if (*backbuffer == NULL)
201 *backbuffer = CreateBitmapStruct();
203 if (fullscreen && !video.fullscreen_enabled && video.fullscreen_available)
205 setFullscreenParameters();
207 video_xoffset = fullscreen_xoffset;
208 video_yoffset = fullscreen_yoffset;
210 /* switch display to fullscreen mode, if available */
211 if ((new_surface = SDL_SetVideoMode(fullscreen_width, fullscreen_height,
212 video.depth, surface_flags_fullscreen))
215 /* switching display to fullscreen mode failed */
216 Error(ERR_WARN, "SDL_SetVideoMode() failed: %s", SDL_GetError());
218 /* do not try it again */
219 video.fullscreen_available = FALSE;
224 (*backbuffer)->surface = new_surface;
226 video.fullscreen_enabled = TRUE;
231 if ((!fullscreen && video.fullscreen_enabled) || new_surface == NULL)
236 /* switch display to window mode */
237 if ((new_surface = SDL_SetVideoMode(video.width, video.height,
238 video.depth, surface_flags_window))
241 /* switching display to window mode failed -- should not happen */
242 Error(ERR_WARN, "SDL_SetVideoMode() failed: %s", SDL_GetError());
248 (*backbuffer)->surface = new_surface;
250 video.fullscreen_enabled = FALSE;
258 void SDLCreateBitmapContent(Bitmap *new_bitmap, int width, int height,
261 SDL_Surface *surface_tmp, *surface_native;
263 if ((surface_tmp = SDL_CreateRGBSurface(SURFACE_FLAGS, width, height, depth,
266 Error(ERR_EXIT, "SDL_CreateRGBSurface() failed: %s", SDL_GetError());
268 if ((surface_native = SDL_DisplayFormat(surface_tmp)) == NULL)
269 Error(ERR_EXIT, "SDL_DisplayFormat() failed: %s", SDL_GetError());
271 SDL_FreeSurface(surface_tmp);
273 new_bitmap->surface = surface_native;
276 void SDLFreeBitmapPointers(Bitmap *bitmap)
279 SDL_FreeSurface(bitmap->surface);
280 if (bitmap->surface_masked)
281 SDL_FreeSurface(bitmap->surface_masked);
282 bitmap->surface = NULL;
283 bitmap->surface_masked = NULL;
286 void SDLCopyArea(Bitmap *src_bitmap, Bitmap *dst_bitmap,
287 int src_x, int src_y, int width, int height,
288 int dst_x, int dst_y, int mask_mode)
290 Bitmap *real_dst_bitmap = (dst_bitmap == window ? backbuffer : dst_bitmap);
291 SDL_Rect src_rect, dst_rect;
293 if (src_bitmap == backbuffer)
295 src_x += video_xoffset;
296 src_y += video_yoffset;
304 if (dst_bitmap == backbuffer || dst_bitmap == window)
306 dst_x += video_xoffset;
307 dst_y += video_yoffset;
315 if (src_bitmap != backbuffer || dst_bitmap != window)
316 SDL_BlitSurface((mask_mode == BLIT_MASKED ?
317 src_bitmap->surface_masked : src_bitmap->surface),
318 &src_rect, real_dst_bitmap->surface, &dst_rect);
320 if (dst_bitmap == window)
321 SDL_UpdateRect(backbuffer->surface, dst_x, dst_y, width, height);
324 void SDLFillRectangle(Bitmap *dst_bitmap, int x, int y,
325 int width, int height, Uint32 color)
327 Bitmap *real_dst_bitmap = (dst_bitmap == window ? backbuffer : dst_bitmap);
330 if (dst_bitmap == backbuffer || dst_bitmap == window)
341 SDL_FillRect(real_dst_bitmap->surface, &rect, color);
343 if (dst_bitmap == window)
344 SDL_UpdateRect(backbuffer->surface, x, y, width, height);
347 void SDLFadeScreen(Bitmap *bitmap_cross, int fade_mode, int fade_delay,
350 static boolean initialization_needed = TRUE;
351 static SDL_Surface *surface_screen_copy = NULL;
352 static SDL_Surface *surface_black = NULL;
353 SDL_Surface *surface_screen = backbuffer->surface;
354 SDL_Surface *surface_cross; /* initialized later */
355 SDL_Rect src_rect, dst_rect;
356 int src_x = 0, src_y = 0;
357 int dst_x = 0, dst_y = 0;
358 boolean fade_reverse = (fade_mode == FADE_MODE_FADE_IN ? TRUE : FALSE);
359 unsigned int time_last, time_current;
365 src_rect.w = video.width;
366 src_rect.h = video.height;
368 dst_x += video_xoffset;
369 dst_y += video_yoffset;
373 dst_rect.w = video.width;
374 dst_rect.h = video.height;
377 if (!initialization_needed)
379 /* check if screen size has changed (can happen when toggling fullscreen) */
380 if (surface_screen_copy->w != surface_screen->w ||
381 surface_screen_copy->h != surface_screen->h)
383 SDL_FreeSurface(surface_screen_copy);
384 SDL_FreeSurface(surface_black);
386 initialization_needed = TRUE;
391 if (initialization_needed)
393 unsigned int flags = SDL_SRCALPHA;
395 /* use same surface type as screen surface */
396 if ((surface_screen->flags & SDL_HWSURFACE))
397 flags |= SDL_HWSURFACE;
399 flags |= SDL_SWSURFACE;
401 /* create surface for temporary copy of screen buffer */
402 if ((surface_screen_copy =
403 SDL_CreateRGBSurface(flags,
411 surface_screen->format->BitsPerPixel,
412 surface_screen->format->Rmask,
413 surface_screen->format->Gmask,
414 surface_screen->format->Bmask,
415 surface_screen->format->Amask)) == NULL)
416 Error(ERR_EXIT, "SDL_CreateRGBSurface( ) failed: %s", SDL_GetError());
418 /* create black surface for fading from/to black */
420 SDL_CreateRGBSurface(flags,
428 surface_screen->format->BitsPerPixel,
429 surface_screen->format->Rmask,
430 surface_screen->format->Gmask,
431 surface_screen->format->Bmask,
432 surface_screen->format->Amask)) == NULL)
433 Error(ERR_EXIT, "SDL_CreateRGBSurface( ) failed: %s", SDL_GetError());
435 /* completely fill the surface with black color pixels */
436 SDL_FillRect(surface_black, NULL,
437 SDL_MapRGB(surface_screen->format, 0, 0, 0));
439 initialization_needed = FALSE;
442 /* copy the current screen backbuffer to the temporary screen copy buffer */
443 SDL_BlitSurface(surface_screen, &dst_rect, surface_screen_copy, &src_rect);
445 surface_cross = (fade_mode == FADE_MODE_CROSSFADE ? bitmap_cross->surface :
448 time_current = SDL_GetTicks();
450 for (alpha = 0.0; alpha < 255.0;)
452 time_last = time_current;
453 time_current = SDL_GetTicks();
454 alpha += 255 * ((float)(time_current - time_last) / fade_delay);
455 alpha_final = (int)(fade_reverse ? 255.0 - alpha : alpha);
456 alpha_final = MIN(MAX(0, alpha_final), 255);
458 /* draw existing image to screen buffer */
459 SDL_BlitSurface(surface_screen_copy, &src_rect, surface_screen, &dst_rect);
461 /* draw new image to screen buffer using alpha blending */
462 SDL_SetAlpha(surface_cross, SDL_SRCALPHA, alpha_final);
463 SDL_BlitSurface(surface_cross, &src_rect, surface_screen, &dst_rect);
465 /* draw screen buffer to visible display */
466 SDL_Flip(surface_screen);
472 void SDLDrawSimpleLine(Bitmap *dst_bitmap, int from_x, int from_y,
473 int to_x, int to_y, Uint32 color)
475 SDL_Surface *surface = dst_bitmap->surface;
479 swap_numbers(&from_x, &to_x);
482 swap_numbers(&from_y, &to_y);
486 rect.w = (to_x - from_x + 1);
487 rect.h = (to_y - from_y + 1);
489 if (dst_bitmap == backbuffer || dst_bitmap == window)
491 rect.x += video_xoffset;
492 rect.y += video_yoffset;
495 SDL_FillRect(surface, &rect, color);
498 void SDLDrawLine(Bitmap *dst_bitmap, int from_x, int from_y,
499 int to_x, int to_y, Uint32 color)
501 if (dst_bitmap == backbuffer || dst_bitmap == window)
503 from_x += video_xoffset;
504 from_y += video_yoffset;
505 to_x += video_xoffset;
506 to_y += video_yoffset;
509 sge_Line(dst_bitmap->surface, from_x, from_y, to_x, to_y, color);
513 void SDLDrawLines(SDL_Surface *surface, struct XY *points,
514 int num_points, Uint32 color)
519 for (i = 0; i < num_points - 1; i++)
521 for (x = 0; x < line_width; x++)
523 for (y = 0; y < line_width; y++)
525 int dx = x - line_width / 2;
526 int dy = y - line_width / 2;
528 if ((x == 0 && y == 0) ||
529 (x == 0 && y == line_width - 1) ||
530 (x == line_width - 1 && y == 0) ||
531 (x == line_width - 1 && y == line_width - 1))
534 sge_Line(surface, points[i].x + dx, points[i].y + dy,
535 points[i+1].x + dx, points[i+1].y + dy, color);
542 Pixel SDLGetPixel(Bitmap *src_bitmap, int x, int y)
544 SDL_Surface *surface = src_bitmap->surface;
546 if (src_bitmap == backbuffer || src_bitmap == window)
552 switch (surface->format->BytesPerPixel)
554 case 1: /* assuming 8-bpp */
556 return *((Uint8 *)surface->pixels + y * surface->pitch + x);
560 case 2: /* probably 15-bpp or 16-bpp */
562 return *((Uint16 *)surface->pixels + y * surface->pitch / 2 + x);
566 case 3: /* slow 24-bpp mode; usually not used */
568 /* does this work? */
569 Uint8 *pix = (Uint8 *)surface->pixels + y * surface->pitch + x * 3;
573 shift = surface->format->Rshift;
574 color |= *(pix + shift / 8) >> shift;
575 shift = surface->format->Gshift;
576 color |= *(pix + shift / 8) >> shift;
577 shift = surface->format->Bshift;
578 color |= *(pix + shift / 8) >> shift;
584 case 4: /* probably 32-bpp */
586 return *((Uint32 *)surface->pixels + y * surface->pitch / 4 + x);
595 /* ========================================================================= */
596 /* The following functions were taken from the SGE library */
597 /* (SDL Graphics Extension Library) by Anders Lindström */
598 /* http://www.etek.chalmers.se/~e8cal1/sge/index.html */
599 /* ========================================================================= */
601 void _PutPixel(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
603 if (x >= 0 && x <= surface->w - 1 && y >= 0 && y <= surface->h - 1)
605 switch (surface->format->BytesPerPixel)
610 *((Uint8 *)surface->pixels + y*surface->pitch + x) = color;
616 /* Probably 15-bpp or 16-bpp */
617 *((Uint16 *)surface->pixels + y*surface->pitch/2 + x) = color;
623 /* Slow 24-bpp mode, usually not used */
627 /* Gack - slow, but endian correct */
628 pix = (Uint8 *)surface->pixels + y * surface->pitch + x*3;
629 shift = surface->format->Rshift;
630 *(pix+shift/8) = color>>shift;
631 shift = surface->format->Gshift;
632 *(pix+shift/8) = color>>shift;
633 shift = surface->format->Bshift;
634 *(pix+shift/8) = color>>shift;
640 /* Probably 32-bpp */
641 *((Uint32 *)surface->pixels + y*surface->pitch/4 + x) = color;
648 void _PutPixelRGB(SDL_Surface *surface, Sint16 x, Sint16 y,
649 Uint8 R, Uint8 G, Uint8 B)
651 _PutPixel(surface, x, y, SDL_MapRGB(surface->format, R, G, B));
654 void _PutPixel8(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
656 *((Uint8 *)surface->pixels + y*surface->pitch + x) = color;
659 void _PutPixel16(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
661 *((Uint16 *)surface->pixels + y*surface->pitch/2 + x) = color;
664 void _PutPixel24(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
669 /* Gack - slow, but endian correct */
670 pix = (Uint8 *)surface->pixels + y * surface->pitch + x*3;
671 shift = surface->format->Rshift;
672 *(pix+shift/8) = color>>shift;
673 shift = surface->format->Gshift;
674 *(pix+shift/8) = color>>shift;
675 shift = surface->format->Bshift;
676 *(pix+shift/8) = color>>shift;
679 void _PutPixel32(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
681 *((Uint32 *)surface->pixels + y*surface->pitch/4 + x) = color;
684 void _PutPixelX(SDL_Surface *dest,Sint16 x,Sint16 y,Uint32 color)
686 switch (dest->format->BytesPerPixel)
689 *((Uint8 *)dest->pixels + y*dest->pitch + x) = color;
693 *((Uint16 *)dest->pixels + y*dest->pitch/2 + x) = color;
697 _PutPixel24(dest,x,y,color);
701 *((Uint32 *)dest->pixels + y*dest->pitch/4 + x) = color;
706 void sge_PutPixel(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
708 if (SDL_MUSTLOCK(surface))
710 if (SDL_LockSurface(surface) < 0)
716 _PutPixel(surface, x, y, color);
718 if (SDL_MUSTLOCK(surface))
720 SDL_UnlockSurface(surface);
724 void sge_PutPixelRGB(SDL_Surface *surface, Sint16 x, Sint16 y,
725 Uint8 r, Uint8 g, Uint8 b)
727 sge_PutPixel(surface, x, y, SDL_MapRGB(surface->format, r, g, b));
730 Sint32 sge_CalcYPitch(SDL_Surface *dest, Sint16 y)
732 if (y >= 0 && y <= dest->h - 1)
734 switch (dest->format->BytesPerPixel)
737 return y*dest->pitch;
741 return y*dest->pitch/2;
745 return y*dest->pitch;
749 return y*dest->pitch/4;
757 void sge_pPutPixel(SDL_Surface *surface, Sint16 x, Sint32 ypitch, Uint32 color)
759 if (x >= 0 && x <= surface->w - 1 && ypitch >= 0)
761 switch (surface->format->BytesPerPixel)
766 *((Uint8 *)surface->pixels + ypitch + x) = color;
772 /* Probably 15-bpp or 16-bpp */
773 *((Uint16 *)surface->pixels + ypitch + x) = color;
779 /* Slow 24-bpp mode, usually not used */
783 /* Gack - slow, but endian correct */
784 pix = (Uint8 *)surface->pixels + ypitch + x*3;
785 shift = surface->format->Rshift;
786 *(pix+shift/8) = color>>shift;
787 shift = surface->format->Gshift;
788 *(pix+shift/8) = color>>shift;
789 shift = surface->format->Bshift;
790 *(pix+shift/8) = color>>shift;
796 /* Probably 32-bpp */
797 *((Uint32 *)surface->pixels + ypitch + x) = color;
804 void sge_HLine(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y,
809 if (SDL_MUSTLOCK(Surface))
811 if (SDL_LockSurface(Surface) < 0)
824 /* Do the clipping */
825 if (y < 0 || y > Surface->h - 1 || x1 > Surface->w - 1 || x2 < 0)
829 if (x2 > Surface->w - 1)
837 SDL_FillRect(Surface, &l, Color);
839 if (SDL_MUSTLOCK(Surface))
841 SDL_UnlockSurface(Surface);
845 void sge_HLineRGB(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y,
846 Uint8 R, Uint8 G, Uint8 B)
848 sge_HLine(Surface, x1, x2, y, SDL_MapRGB(Surface->format, R, G, B));
851 void _HLine(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y, Uint32 Color)
862 /* Do the clipping */
863 if (y < 0 || y > Surface->h - 1 || x1 > Surface->w - 1 || x2 < 0)
867 if (x2 > Surface->w - 1)
875 SDL_FillRect(Surface, &l, Color);
878 void sge_VLine(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2,
883 if (SDL_MUSTLOCK(Surface))
885 if (SDL_LockSurface(Surface) < 0)
898 /* Do the clipping */
899 if (x < 0 || x > Surface->w - 1 || y1 > Surface->h - 1 || y2 < 0)
903 if (y2 > Surface->h - 1)
911 SDL_FillRect(Surface, &l, Color);
913 if (SDL_MUSTLOCK(Surface))
915 SDL_UnlockSurface(Surface);
919 void sge_VLineRGB(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2,
920 Uint8 R, Uint8 G, Uint8 B)
922 sge_VLine(Surface, x, y1, y2, SDL_MapRGB(Surface->format, R, G, B));
925 void _VLine(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2, Uint32 Color)
936 /* Do the clipping */
937 if (x < 0 || x > Surface->w - 1 || y1 > Surface->h - 1 || y2 < 0)
941 if (y2 > Surface->h - 1)
949 SDL_FillRect(Surface, &l, Color);
952 void sge_DoLine(SDL_Surface *Surface, Sint16 x1, Sint16 y1,
953 Sint16 x2, Sint16 y2, Uint32 Color,
954 void Callback(SDL_Surface *Surf, Sint16 X, Sint16 Y,
957 Sint16 dx, dy, sdx, sdy, x, y, px, py;
962 sdx = (dx < 0) ? -1 : 1;
963 sdy = (dy < 0) ? -1 : 1;
975 for (x = 0; x < dx; x++)
977 Callback(Surface, px, py, Color);
991 for (y = 0; y < dy; y++)
993 Callback(Surface, px, py, Color);
1007 void sge_DoLineRGB(SDL_Surface *Surface, Sint16 X1, Sint16 Y1,
1008 Sint16 X2, Sint16 Y2, Uint8 R, Uint8 G, Uint8 B,
1009 void Callback(SDL_Surface *Surf, Sint16 X, Sint16 Y,
1012 sge_DoLine(Surface, X1, Y1, X2, Y2,
1013 SDL_MapRGB(Surface->format, R, G, B), Callback);
1016 void sge_Line(SDL_Surface *Surface, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2,
1019 if (SDL_MUSTLOCK(Surface))
1021 if (SDL_LockSurface(Surface) < 0)
1026 sge_DoLine(Surface, x1, y1, x2, y2, Color, _PutPixel);
1028 /* unlock the display */
1029 if (SDL_MUSTLOCK(Surface))
1031 SDL_UnlockSurface(Surface);
1035 void sge_LineRGB(SDL_Surface *Surface, Sint16 x1, Sint16 y1, Sint16 x2,
1036 Sint16 y2, Uint8 R, Uint8 G, Uint8 B)
1038 sge_Line(Surface, x1, y1, x2, y2, SDL_MapRGB(Surface->format, R, G, B));
1041 void SDLPutPixel(Bitmap *dst_bitmap, int x, int y, Pixel pixel)
1043 if (dst_bitmap == backbuffer || dst_bitmap == window)
1049 sge_PutPixel(dst_bitmap->surface, x, y, pixel);
1054 -----------------------------------------------------------------------------
1055 quick (no, it's slow) and dirty hack to "invert" rectangle inside SDL surface
1056 -----------------------------------------------------------------------------
1059 void SDLInvertArea(Bitmap *bitmap, int src_x, int src_y,
1060 int width, int height, Uint32 color)
1064 for (y = src_y; y < src_y + height; y++)
1066 for (x = src_x; x < src_x + width; x++)
1068 Uint32 pixel = SDLGetPixel(bitmap, x, y);
1070 SDLPutPixel(bitmap, x, y, pixel == BLACK_PIXEL ? color : BLACK_PIXEL);
1075 void SDLCopyInverseMasked(Bitmap *src_bitmap, Bitmap *dst_bitmap,
1076 int src_x, int src_y, int width, int height,
1077 int dst_x, int dst_y)
1081 for (y = 0; y < height; y++)
1083 for (x = 0; x < width; x++)
1085 Uint32 pixel = SDLGetPixel(src_bitmap, src_x + x, src_y + y);
1087 if (pixel != BLACK_PIXEL)
1088 SDLPutPixel(dst_bitmap, dst_x + x, dst_y + y, BLACK_PIXEL);
1094 /* ========================================================================= */
1095 /* The following functions were taken from the SDL_gfx library version 2.0.3 */
1096 /* (Rotozoomer) by Andreas Schiffler */
1097 /* http://www.ferzkopp.net/Software/SDL_gfx-2.0/index.html */
1098 /* ========================================================================= */
1101 -----------------------------------------------------------------------------
1104 zoomes 32bit RGBA/ABGR 'src' surface to 'dst' surface.
1105 -----------------------------------------------------------------------------
1116 int zoomSurfaceRGBA_scaleDownBy2(SDL_Surface *src, SDL_Surface *dst)
1119 tColorRGBA *sp, *csp, *dp;
1123 sp = csp = (tColorRGBA *) src->pixels;
1124 dp = (tColorRGBA *) dst->pixels;
1125 sgap = src->pitch - src->w * 4;
1126 dgap = dst->pitch - dst->w * 4;
1128 for (y = 0; y < dst->h; y++)
1132 for (x = 0; x < dst->w; x++)
1134 tColorRGBA *sp0 = sp;
1135 tColorRGBA *sp1 = (tColorRGBA *) ((Uint8 *) sp + src->pitch);
1136 tColorRGBA *sp00 = &sp0[0];
1137 tColorRGBA *sp01 = &sp0[1];
1138 tColorRGBA *sp10 = &sp1[0];
1139 tColorRGBA *sp11 = &sp1[1];
1142 /* create new color pixel from all four source color pixels */
1143 new.r = (sp00->r + sp01->r + sp10->r + sp11->r) / 4;
1144 new.g = (sp00->g + sp01->g + sp10->g + sp11->g) / 4;
1145 new.b = (sp00->b + sp01->b + sp10->b + sp11->b) / 4;
1146 new.a = (sp00->a + sp01->a + sp10->a + sp11->a) / 4;
1151 /* advance source pointers */
1154 /* advance destination pointer */
1158 /* advance source pointer */
1159 csp = (tColorRGBA *) ((Uint8 *) csp + 2 * src->pitch);
1161 /* advance destination pointers */
1162 dp = (tColorRGBA *) ((Uint8 *) dp + dgap);
1168 int zoomSurfaceRGBA(SDL_Surface *src, SDL_Surface *dst)
1170 int x, y, sx, sy, *sax, *say, *csax, *csay, csx, csy;
1171 tColorRGBA *sp, *csp, *dp;
1174 /* use specialized zoom function when scaling down to exactly half size */
1175 if (src->w == 2 * dst->w &&
1176 src->h == 2 * dst->h)
1177 return zoomSurfaceRGBA_scaleDownBy2(src, dst);
1179 /* variable setup */
1180 sx = (int) (65536.0 * (float) src->w / (float) dst->w);
1181 sy = (int) (65536.0 * (float) src->h / (float) dst->h);
1183 /* allocate memory for row increments */
1184 sax = (int *)checked_malloc((dst->w + 1) * sizeof(Uint32));
1185 say = (int *)checked_malloc((dst->h + 1) * sizeof(Uint32));
1187 /* precalculate row increments */
1190 for (x = 0; x <= dst->w; x++)
1200 for (y = 0; y <= dst->h; y++)
1209 sp = csp = (tColorRGBA *) src->pixels;
1210 dp = (tColorRGBA *) dst->pixels;
1211 sgap = src->pitch - src->w * 4;
1212 dgap = dst->pitch - dst->w * 4;
1215 for (y = 0; y < dst->h; y++)
1220 for (x = 0; x < dst->w; x++)
1225 /* advance source pointers */
1227 sp += (*csax >> 16);
1229 /* advance destination pointer */
1233 /* advance source pointer */
1235 csp = (tColorRGBA *) ((Uint8 *) csp + (*csay >> 16) * src->pitch);
1237 /* advance destination pointers */
1238 dp = (tColorRGBA *) ((Uint8 *) dp + dgap);
1248 -----------------------------------------------------------------------------
1251 zoomes 8 bit palette/Y 'src' surface to 'dst' surface
1252 -----------------------------------------------------------------------------
1255 int zoomSurfaceY(SDL_Surface * src, SDL_Surface * dst)
1257 Uint32 x, y, sx, sy, *sax, *say, *csax, *csay, csx, csy;
1258 Uint8 *sp, *dp, *csp;
1261 /* variable setup */
1262 sx = (Uint32) (65536.0 * (float) src->w / (float) dst->w);
1263 sy = (Uint32) (65536.0 * (float) src->h / (float) dst->h);
1265 /* allocate memory for row increments */
1266 sax = (Uint32 *)checked_malloc(dst->w * sizeof(Uint32));
1267 say = (Uint32 *)checked_malloc(dst->h * sizeof(Uint32));
1269 /* precalculate row increments */
1272 for (x = 0; x < dst->w; x++)
1275 *csax = (csx >> 16);
1282 for (y = 0; y < dst->h; y++)
1285 *csay = (csy >> 16);
1292 for (x = 0; x < dst->w; x++)
1300 for (y = 0; y < dst->h; y++)
1307 sp = csp = (Uint8 *) src->pixels;
1308 dp = (Uint8 *) dst->pixels;
1309 dgap = dst->pitch - dst->w;
1313 for (y = 0; y < dst->h; y++)
1317 for (x = 0; x < dst->w; x++)
1322 /* advance source pointers */
1326 /* advance destination pointer */
1330 /* advance source pointer (for row) */
1331 csp += ((*csay) * src->pitch);
1334 /* advance destination pointers */
1345 -----------------------------------------------------------------------------
1348 Zooms a 32bit or 8bit 'src' surface to newly created 'dst' surface.
1349 'zoomx' and 'zoomy' are scaling factors for width and height.
1350 If the surface is not 8bit or 32bit RGBA/ABGR it will be converted
1351 into a 32bit RGBA format on the fly.
1352 -----------------------------------------------------------------------------
1355 SDL_Surface *zoomSurface(SDL_Surface *src, int dst_width, int dst_height)
1357 SDL_Surface *zoom_src = NULL;
1358 SDL_Surface *zoom_dst = NULL;
1359 boolean is_converted = FALSE;
1366 /* determine if source surface is 32 bit or 8 bit */
1367 is_32bit = (src->format->BitsPerPixel == 32);
1369 if (is_32bit || src->format->BitsPerPixel == 8)
1371 /* use source surface 'as is' */
1376 /* new source surface is 32 bit with a defined RGB ordering */
1377 zoom_src = SDL_CreateRGBSurface(SDL_SWSURFACE, src->w, src->h, 32,
1378 0x000000ff, 0x0000ff00, 0x00ff0000, 0);
1379 SDL_BlitSurface(src, NULL, zoom_src, NULL);
1381 is_converted = TRUE;
1384 /* allocate surface to completely contain the zoomed surface */
1387 /* target surface is 32 bit with source RGBA/ABGR ordering */
1388 zoom_dst = SDL_CreateRGBSurface(SDL_SWSURFACE, dst_width, dst_height, 32,
1389 zoom_src->format->Rmask,
1390 zoom_src->format->Gmask,
1391 zoom_src->format->Bmask, 0);
1395 /* target surface is 8 bit */
1396 zoom_dst = SDL_CreateRGBSurface(SDL_SWSURFACE, dst_width, dst_height, 8,
1400 /* lock source surface */
1401 SDL_LockSurface(zoom_src);
1403 /* check which kind of surface we have */
1406 /* call the 32 bit transformation routine to do the zooming */
1407 zoomSurfaceRGBA(zoom_src, zoom_dst);
1412 for (i = 0; i < zoom_src->format->palette->ncolors; i++)
1413 zoom_dst->format->palette->colors[i] =
1414 zoom_src->format->palette->colors[i];
1415 zoom_dst->format->palette->ncolors = zoom_src->format->palette->ncolors;
1417 /* call the 8 bit transformation routine to do the zooming */
1418 zoomSurfaceY(zoom_src, zoom_dst);
1421 /* unlock source surface */
1422 SDL_UnlockSurface(zoom_src);
1424 /* free temporary surface */
1426 SDL_FreeSurface(zoom_src);
1428 /* return destination surface */
1432 void SDLZoomBitmap(Bitmap *src_bitmap, Bitmap *dst_bitmap)
1434 SDL_Surface *sdl_surface_tmp;
1435 int dst_width = dst_bitmap->width;
1436 int dst_height = dst_bitmap->height;
1438 /* throw away old destination surface */
1439 SDL_FreeSurface(dst_bitmap->surface);
1441 /* create zoomed temporary surface from source surface */
1442 sdl_surface_tmp = zoomSurface(src_bitmap->surface, dst_width, dst_height);
1444 /* create native format destination surface from zoomed temporary surface */
1445 dst_bitmap->surface = SDL_DisplayFormat(sdl_surface_tmp);
1447 /* free temporary surface */
1448 SDL_FreeSurface(sdl_surface_tmp);
1452 /* ========================================================================= */
1453 /* load image to bitmap */
1454 /* ========================================================================= */
1456 Bitmap *SDLLoadImage(char *filename)
1458 Bitmap *new_bitmap = CreateBitmapStruct();
1459 SDL_Surface *sdl_image_tmp;
1461 /* load image to temporary surface */
1462 if ((sdl_image_tmp = IMG_Load(filename)) == NULL)
1464 SetError("IMG_Load(): %s", SDL_GetError());
1468 /* create native non-transparent surface for current image */
1469 if ((new_bitmap->surface = SDL_DisplayFormat(sdl_image_tmp)) == NULL)
1471 SetError("SDL_DisplayFormat(): %s", SDL_GetError());
1475 /* create native transparent surface for current image */
1476 SDL_SetColorKey(sdl_image_tmp, SDL_SRCCOLORKEY,
1477 SDL_MapRGB(sdl_image_tmp->format, 0x00, 0x00, 0x00));
1478 if ((new_bitmap->surface_masked = SDL_DisplayFormat(sdl_image_tmp)) == NULL)
1480 SetError("SDL_DisplayFormat(): %s", SDL_GetError());
1484 /* free temporary surface */
1485 SDL_FreeSurface(sdl_image_tmp);
1487 new_bitmap->width = new_bitmap->surface->w;
1488 new_bitmap->height = new_bitmap->surface->h;
1494 /* ------------------------------------------------------------------------- */
1495 /* custom cursor fuctions */
1496 /* ------------------------------------------------------------------------- */
1498 static SDL_Cursor *create_cursor(struct MouseCursorInfo *cursor_info)
1500 return SDL_CreateCursor(cursor_info->data, cursor_info->mask,
1501 cursor_info->width, cursor_info->height,
1502 cursor_info->hot_x, cursor_info->hot_y);
1505 void SDLSetMouseCursor(struct MouseCursorInfo *cursor_info)
1507 static struct MouseCursorInfo *last_cursor_info = NULL;
1508 static struct MouseCursorInfo *last_cursor_info2 = NULL;
1509 static SDL_Cursor *cursor_default = NULL;
1510 static SDL_Cursor *cursor_current = NULL;
1512 /* if invoked for the first time, store the SDL default cursor */
1513 if (cursor_default == NULL)
1514 cursor_default = SDL_GetCursor();
1516 /* only create new cursor if cursor info (custom only) has changed */
1517 if (cursor_info != NULL && cursor_info != last_cursor_info)
1519 cursor_current = create_cursor(cursor_info);
1520 last_cursor_info = cursor_info;
1523 /* only set new cursor if cursor info (custom or NULL) has changed */
1524 if (cursor_info != last_cursor_info2)
1525 SDL_SetCursor(cursor_info ? cursor_current : cursor_default);
1527 last_cursor_info2 = cursor_info;
1531 /* ========================================================================= */
1532 /* audio functions */
1533 /* ========================================================================= */
1535 void SDLOpenAudio(void)
1537 if (!strEqual(setup.system.sdl_audiodriver, ARG_DEFAULT))
1538 putenv(getStringCat2("SDL_AUDIODRIVER=", setup.system.sdl_audiodriver));
1540 if (SDL_InitSubSystem(SDL_INIT_AUDIO) < 0)
1542 Error(ERR_WARN, "SDL_InitSubSystem() failed: %s", SDL_GetError());
1546 if (Mix_OpenAudio(DEFAULT_AUDIO_SAMPLE_RATE, MIX_DEFAULT_FORMAT,
1547 AUDIO_NUM_CHANNELS_STEREO,
1548 setup.system.audio_fragment_size) < 0)
1550 Error(ERR_WARN, "Mix_OpenAudio() failed: %s", SDL_GetError());
1554 audio.sound_available = TRUE;
1555 audio.music_available = TRUE;
1556 audio.loops_available = TRUE;
1557 audio.sound_enabled = TRUE;
1559 /* set number of available mixer channels */
1560 audio.num_channels = Mix_AllocateChannels(NUM_MIXER_CHANNELS);
1561 audio.music_channel = MUSIC_CHANNEL;
1562 audio.first_sound_channel = FIRST_SOUND_CHANNEL;
1564 Mixer_InitChannels();
1567 void SDLCloseAudio(void)
1570 Mix_HaltChannel(-1);
1573 SDL_QuitSubSystem(SDL_INIT_AUDIO);
1577 /* ========================================================================= */
1578 /* event functions */
1579 /* ========================================================================= */
1581 void SDLNextEvent(Event *event)
1583 SDL_WaitEvent(event);
1585 if (event->type == EVENT_BUTTONPRESS ||
1586 event->type == EVENT_BUTTONRELEASE)
1588 if (((ButtonEvent *)event)->x > video_xoffset)
1589 ((ButtonEvent *)event)->x -= video_xoffset;
1591 ((ButtonEvent *)event)->x = 0;
1592 if (((ButtonEvent *)event)->y > video_yoffset)
1593 ((ButtonEvent *)event)->y -= video_yoffset;
1595 ((ButtonEvent *)event)->y = 0;
1597 else if (event->type == EVENT_MOTIONNOTIFY)
1599 if (((MotionEvent *)event)->x > video_xoffset)
1600 ((MotionEvent *)event)->x -= video_xoffset;
1602 ((MotionEvent *)event)->x = 0;
1603 if (((MotionEvent *)event)->y > video_yoffset)
1604 ((MotionEvent *)event)->y -= video_yoffset;
1606 ((MotionEvent *)event)->y = 0;
1611 /* ========================================================================= */
1612 /* joystick functions */
1613 /* ========================================================================= */
1615 static SDL_Joystick *sdl_joystick[MAX_PLAYERS] = { NULL, NULL, NULL, NULL };
1616 static int sdl_js_axis[MAX_PLAYERS][2] = { {0, 0}, {0, 0}, {0, 0}, {0, 0} };
1617 static int sdl_js_button[MAX_PLAYERS][2] = { {0, 0}, {0, 0}, {0, 0}, {0, 0} };
1619 static boolean SDLOpenJoystick(int nr)
1621 if (nr < 0 || nr > MAX_PLAYERS)
1624 return ((sdl_joystick[nr] = SDL_JoystickOpen(nr)) == NULL ? FALSE : TRUE);
1627 static void SDLCloseJoystick(int nr)
1629 if (nr < 0 || nr > MAX_PLAYERS)
1632 SDL_JoystickClose(sdl_joystick[nr]);
1635 static boolean SDLCheckJoystickOpened(int nr)
1637 if (nr < 0 || nr > MAX_PLAYERS)
1640 return (SDL_JoystickOpened(nr) ? TRUE : FALSE);
1643 void HandleJoystickEvent(Event *event)
1647 case SDL_JOYAXISMOTION:
1648 if (event->jaxis.axis < 2)
1649 sdl_js_axis[event->jaxis.which][event->jaxis.axis]= event->jaxis.value;
1652 case SDL_JOYBUTTONDOWN:
1653 if (event->jbutton.button < 2)
1654 sdl_js_button[event->jbutton.which][event->jbutton.button] = TRUE;
1657 case SDL_JOYBUTTONUP:
1658 if (event->jbutton.button < 2)
1659 sdl_js_button[event->jbutton.which][event->jbutton.button] = FALSE;
1667 void SDLInitJoysticks()
1669 static boolean sdl_joystick_subsystem_initialized = FALSE;
1670 boolean print_warning = !sdl_joystick_subsystem_initialized;
1673 if (!sdl_joystick_subsystem_initialized)
1675 sdl_joystick_subsystem_initialized = TRUE;
1677 if (SDL_Init(SDL_INIT_JOYSTICK) < 0)
1679 Error(ERR_EXIT, "SDL_Init() failed: %s", SDL_GetError());
1684 for (i = 0; i < MAX_PLAYERS; i++)
1686 /* get configured joystick for this player */
1687 char *device_name = setup.input[i].joy.device_name;
1688 int joystick_nr = getJoystickNrFromDeviceName(device_name);
1690 if (joystick_nr >= SDL_NumJoysticks())
1692 if (setup.input[i].use_joystick && print_warning)
1693 Error(ERR_WARN, "cannot find joystick %d", joystick_nr);
1698 /* misuse joystick file descriptor variable to store joystick number */
1699 joystick.fd[i] = joystick_nr;
1701 if (joystick_nr == -1)
1704 /* this allows subsequent calls to 'InitJoysticks' for re-initialization */
1705 if (SDLCheckJoystickOpened(joystick_nr))
1706 SDLCloseJoystick(joystick_nr);
1708 if (!setup.input[i].use_joystick)
1711 if (!SDLOpenJoystick(joystick_nr))
1714 Error(ERR_WARN, "cannot open joystick %d", joystick_nr);
1719 joystick.status = JOYSTICK_ACTIVATED;
1723 boolean SDLReadJoystick(int nr, int *x, int *y, boolean *b1, boolean *b2)
1725 if (nr < 0 || nr >= MAX_PLAYERS)
1729 *x = sdl_js_axis[nr][0];
1731 *y = sdl_js_axis[nr][1];
1734 *b1 = sdl_js_button[nr][0];
1736 *b2 = sdl_js_button[nr][1];
1741 #endif /* TARGET_SDL */