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 if (fullscreen_mode == NULL)
47 for (i = 0; video.fullscreen_modes[i].width != -1; i++)
49 if (fullscreen_mode->width == video.fullscreen_modes[i].width &&
50 fullscreen_mode->height == video.fullscreen_modes[i].height)
52 fullscreen_width = fullscreen_mode->width;
53 fullscreen_height = fullscreen_mode->height;
55 fullscreen_xoffset = (fullscreen_width - video.width) / 2;
56 fullscreen_yoffset = (fullscreen_height - video.height) / 2;
63 void SDLInitVideoDisplay(void)
65 putenv("SDL_VIDEO_CENTERED=1");
67 /* initialize SDL video */
68 if (SDL_InitSubSystem(SDL_INIT_VIDEO) < 0)
69 Error(ERR_EXIT, "SDL_InitSubSystem() failed: %s", SDL_GetError());
71 /* set default SDL depth */
72 video.default_depth = SDL_GetVideoInfo()->vfmt->BitsPerPixel;
75 void SDLInitVideoBuffer(DrawBuffer **backbuffer, DrawWindow **window,
78 static int screen_xy[][2] =
88 /* default: normal game window size */
89 fullscreen_width = video.width;
90 fullscreen_height = video.height;
91 fullscreen_xoffset = 0;
92 fullscreen_yoffset = 0;
94 for (i = 0; screen_xy[i][0] != -1; i++)
96 if (screen_xy[i][0] >= video.width && screen_xy[i][1] >= video.height)
98 fullscreen_width = screen_xy[i][0];
99 fullscreen_height = screen_xy[i][1];
105 fullscreen_xoffset = (fullscreen_width - video.width) / 2;
106 fullscreen_yoffset = (fullscreen_height - video.height) / 2;
108 /* get available hardware supported fullscreen modes */
109 modes = SDL_ListModes(NULL, SDL_FULLSCREEN | SDL_HWSURFACE);
113 /* no screen modes available => no fullscreen mode support */
114 video.fullscreen_available = FALSE;
116 else if (modes == (SDL_Rect **)-1)
118 /* fullscreen resolution is not restricted -- all resolutions available */
119 video.fullscreen_modes = checked_calloc(2 * sizeof(struct ScreenModeInfo));
121 /* use native video buffer size for fullscreen mode */
122 video.fullscreen_modes[0].width = video.width;
123 video.fullscreen_modes[0].height = video.height;
125 video.fullscreen_modes[1].width = -1;
126 video.fullscreen_modes[1].height = -1;
130 /* in this case, a certain number of screen modes is available */
133 for(i = 0; modes[i] != NULL; i++)
135 boolean found_mode = FALSE;
137 /* screen mode is smaller than video buffer size -- skip it */
138 if (modes[i]->w < video.width || modes[i]->h < video.height)
141 if (video.fullscreen_modes != NULL)
142 for (j = 0; video.fullscreen_modes[j].width != -1; j++)
143 if (modes[i]->w == video.fullscreen_modes[j].width &&
144 modes[i]->h == video.fullscreen_modes[j].height)
147 if (found_mode) /* screen mode already stored -- skip it */
150 /* new mode found; add it to list of available fullscreen modes */
154 video.fullscreen_modes = checked_realloc(video.fullscreen_modes,
156 sizeof(struct ScreenModeInfo));
158 video.fullscreen_modes[num_modes - 1].width = modes[i]->w;
159 video.fullscreen_modes[num_modes - 1].height = modes[i]->h;
161 video.fullscreen_modes[num_modes].width = -1;
162 video.fullscreen_modes[num_modes].height = -1;
167 /* no appropriate screen modes available => no fullscreen mode support */
168 video.fullscreen_available = FALSE;
172 /* open SDL video output device (window or fullscreen mode) */
173 if (!SDLSetVideoMode(backbuffer, fullscreen))
174 Error(ERR_EXIT, "setting video mode failed");
176 /* set window and icon title */
177 SDL_WM_SetCaption(program.window_title, program.window_title);
179 /* SDL cannot directly draw to the visible video framebuffer like X11,
180 but always uses a backbuffer, which is then blitted to the visible
181 video framebuffer with 'SDL_UpdateRect' (or replaced with the current
182 visible video framebuffer with 'SDL_Flip', if the hardware supports
183 this). Therefore do not use an additional backbuffer for drawing, but
184 use a symbolic buffer (distinguishable from the SDL backbuffer) called
185 'window', which indicates that the SDL backbuffer should be updated to
186 the visible video framebuffer when attempting to blit to it.
188 For convenience, it seems to be a good idea to create this symbolic
189 buffer 'window' at the same size as the SDL backbuffer. Although it
190 should never be drawn to directly, it would do no harm nevertheless. */
192 /* create additional (symbolic) buffer for double-buffering */
193 *window = CreateBitmap(video.width, video.height, video.depth);
196 boolean SDLSetVideoMode(DrawBuffer **backbuffer, boolean fullscreen)
198 boolean success = TRUE;
199 int surface_flags_fullscreen = SURFACE_FLAGS | SDL_FULLSCREEN;
200 int surface_flags_window = SURFACE_FLAGS;
201 SDL_Surface *new_surface = NULL;
203 if (*backbuffer == NULL)
204 *backbuffer = CreateBitmapStruct();
206 if (fullscreen && !video.fullscreen_enabled && video.fullscreen_available)
208 setFullscreenParameters();
210 video_xoffset = fullscreen_xoffset;
211 video_yoffset = fullscreen_yoffset;
213 /* switch display to fullscreen mode, if available */
214 if ((new_surface = SDL_SetVideoMode(fullscreen_width, fullscreen_height,
215 video.depth, surface_flags_fullscreen))
218 /* switching display to fullscreen mode failed */
219 Error(ERR_WARN, "SDL_SetVideoMode() failed: %s", SDL_GetError());
221 /* do not try it again */
222 video.fullscreen_available = FALSE;
227 (*backbuffer)->surface = new_surface;
229 video.fullscreen_enabled = TRUE;
234 if ((!fullscreen && video.fullscreen_enabled) || new_surface == NULL)
239 /* switch display to window mode */
240 if ((new_surface = SDL_SetVideoMode(video.width, video.height,
241 video.depth, surface_flags_window))
244 /* switching display to window mode failed -- should not happen */
245 Error(ERR_WARN, "SDL_SetVideoMode() failed: %s", SDL_GetError());
251 (*backbuffer)->surface = new_surface;
253 video.fullscreen_enabled = FALSE;
261 void SDLCreateBitmapContent(Bitmap *new_bitmap, int width, int height,
264 SDL_Surface *surface_tmp, *surface_native;
266 if ((surface_tmp = SDL_CreateRGBSurface(SURFACE_FLAGS, width, height, depth,
269 Error(ERR_EXIT, "SDL_CreateRGBSurface() failed: %s", SDL_GetError());
271 if ((surface_native = SDL_DisplayFormat(surface_tmp)) == NULL)
272 Error(ERR_EXIT, "SDL_DisplayFormat() failed: %s", SDL_GetError());
274 SDL_FreeSurface(surface_tmp);
276 new_bitmap->surface = surface_native;
279 void SDLFreeBitmapPointers(Bitmap *bitmap)
282 SDL_FreeSurface(bitmap->surface);
283 if (bitmap->surface_masked)
284 SDL_FreeSurface(bitmap->surface_masked);
285 bitmap->surface = NULL;
286 bitmap->surface_masked = NULL;
289 void SDLCopyArea(Bitmap *src_bitmap, Bitmap *dst_bitmap,
290 int src_x, int src_y, int width, int height,
291 int dst_x, int dst_y, int mask_mode)
293 Bitmap *real_dst_bitmap = (dst_bitmap == window ? backbuffer : dst_bitmap);
294 SDL_Rect src_rect, dst_rect;
296 if (src_bitmap == backbuffer)
298 src_x += video_xoffset;
299 src_y += video_yoffset;
307 if (dst_bitmap == backbuffer || dst_bitmap == window)
309 dst_x += video_xoffset;
310 dst_y += video_yoffset;
318 if (src_bitmap != backbuffer || dst_bitmap != window)
319 SDL_BlitSurface((mask_mode == BLIT_MASKED ?
320 src_bitmap->surface_masked : src_bitmap->surface),
321 &src_rect, real_dst_bitmap->surface, &dst_rect);
323 if (dst_bitmap == window)
324 SDL_UpdateRect(backbuffer->surface, dst_x, dst_y, width, height);
327 void SDLFillRectangle(Bitmap *dst_bitmap, int x, int y,
328 int width, int height, Uint32 color)
330 Bitmap *real_dst_bitmap = (dst_bitmap == window ? backbuffer : dst_bitmap);
333 if (dst_bitmap == backbuffer || dst_bitmap == window)
344 SDL_FillRect(real_dst_bitmap->surface, &rect, color);
346 if (dst_bitmap == window)
347 SDL_UpdateRect(backbuffer->surface, x, y, width, height);
350 void SDLFadeScreen(Bitmap *bitmap_cross, int fade_mode, int fade_delay,
353 static boolean initialization_needed = TRUE;
354 static SDL_Surface *surface_screen_copy = NULL;
355 static SDL_Surface *surface_black = NULL;
356 SDL_Surface *surface_screen = backbuffer->surface;
357 SDL_Surface *surface_cross; /* initialized later */
358 SDL_Rect src_rect, dst_rect;
359 int src_x = 0, src_y = 0;
360 int dst_x = 0, dst_y = 0;
361 boolean fade_reverse = (fade_mode == FADE_MODE_FADE_IN ? TRUE : FALSE);
362 unsigned int time_last, time_current;
368 src_rect.w = video.width;
369 src_rect.h = video.height;
371 dst_x += video_xoffset;
372 dst_y += video_yoffset;
376 dst_rect.w = video.width;
377 dst_rect.h = video.height;
380 if (!initialization_needed)
382 /* check if screen size has changed (can happen when toggling fullscreen) */
383 if (surface_screen_copy->w != surface_screen->w ||
384 surface_screen_copy->h != surface_screen->h)
386 SDL_FreeSurface(surface_screen_copy);
387 SDL_FreeSurface(surface_black);
389 initialization_needed = TRUE;
394 if (initialization_needed)
396 unsigned int flags = SDL_SRCALPHA;
398 /* use same surface type as screen surface */
399 if ((surface_screen->flags & SDL_HWSURFACE))
400 flags |= SDL_HWSURFACE;
402 flags |= SDL_SWSURFACE;
404 /* create surface for temporary copy of screen buffer */
405 if ((surface_screen_copy =
406 SDL_CreateRGBSurface(flags,
414 surface_screen->format->BitsPerPixel,
415 surface_screen->format->Rmask,
416 surface_screen->format->Gmask,
417 surface_screen->format->Bmask,
418 surface_screen->format->Amask)) == NULL)
419 Error(ERR_EXIT, "SDL_CreateRGBSurface( ) failed: %s", SDL_GetError());
421 /* create black surface for fading from/to black */
423 SDL_CreateRGBSurface(flags,
431 surface_screen->format->BitsPerPixel,
432 surface_screen->format->Rmask,
433 surface_screen->format->Gmask,
434 surface_screen->format->Bmask,
435 surface_screen->format->Amask)) == NULL)
436 Error(ERR_EXIT, "SDL_CreateRGBSurface( ) failed: %s", SDL_GetError());
438 /* completely fill the surface with black color pixels */
439 SDL_FillRect(surface_black, NULL,
440 SDL_MapRGB(surface_screen->format, 0, 0, 0));
442 initialization_needed = FALSE;
445 /* copy the current screen backbuffer to the temporary screen copy buffer */
446 SDL_BlitSurface(surface_screen, &dst_rect, surface_screen_copy, &src_rect);
448 surface_cross = (fade_mode == FADE_MODE_CROSSFADE ? bitmap_cross->surface :
451 time_current = SDL_GetTicks();
453 for (alpha = 0.0; alpha < 255.0;)
455 time_last = time_current;
456 time_current = SDL_GetTicks();
457 alpha += 255 * ((float)(time_current - time_last) / fade_delay);
458 alpha_final = (int)(fade_reverse ? 255.0 - alpha : alpha);
459 alpha_final = MIN(MAX(0, alpha_final), 255);
461 /* draw existing image to screen buffer */
462 SDL_BlitSurface(surface_screen_copy, &src_rect, surface_screen, &dst_rect);
464 /* draw new image to screen buffer using alpha blending */
465 SDL_SetAlpha(surface_cross, SDL_SRCALPHA, alpha_final);
466 SDL_BlitSurface(surface_cross, &src_rect, surface_screen, &dst_rect);
468 /* draw screen buffer to visible display */
469 SDL_Flip(surface_screen);
475 void SDLDrawSimpleLine(Bitmap *dst_bitmap, int from_x, int from_y,
476 int to_x, int to_y, Uint32 color)
478 SDL_Surface *surface = dst_bitmap->surface;
482 swap_numbers(&from_x, &to_x);
485 swap_numbers(&from_y, &to_y);
489 rect.w = (to_x - from_x + 1);
490 rect.h = (to_y - from_y + 1);
492 if (dst_bitmap == backbuffer || dst_bitmap == window)
494 rect.x += video_xoffset;
495 rect.y += video_yoffset;
498 SDL_FillRect(surface, &rect, color);
501 void SDLDrawLine(Bitmap *dst_bitmap, int from_x, int from_y,
502 int to_x, int to_y, Uint32 color)
504 if (dst_bitmap == backbuffer || dst_bitmap == window)
506 from_x += video_xoffset;
507 from_y += video_yoffset;
508 to_x += video_xoffset;
509 to_y += video_yoffset;
512 sge_Line(dst_bitmap->surface, from_x, from_y, to_x, to_y, color);
516 void SDLDrawLines(SDL_Surface *surface, struct XY *points,
517 int num_points, Uint32 color)
522 for (i = 0; i < num_points - 1; i++)
524 for (x = 0; x < line_width; x++)
526 for (y = 0; y < line_width; y++)
528 int dx = x - line_width / 2;
529 int dy = y - line_width / 2;
531 if ((x == 0 && y == 0) ||
532 (x == 0 && y == line_width - 1) ||
533 (x == line_width - 1 && y == 0) ||
534 (x == line_width - 1 && y == line_width - 1))
537 sge_Line(surface, points[i].x + dx, points[i].y + dy,
538 points[i+1].x + dx, points[i+1].y + dy, color);
545 Pixel SDLGetPixel(Bitmap *src_bitmap, int x, int y)
547 SDL_Surface *surface = src_bitmap->surface;
549 if (src_bitmap == backbuffer || src_bitmap == window)
555 switch (surface->format->BytesPerPixel)
557 case 1: /* assuming 8-bpp */
559 return *((Uint8 *)surface->pixels + y * surface->pitch + x);
563 case 2: /* probably 15-bpp or 16-bpp */
565 return *((Uint16 *)surface->pixels + y * surface->pitch / 2 + x);
569 case 3: /* slow 24-bpp mode; usually not used */
571 /* does this work? */
572 Uint8 *pix = (Uint8 *)surface->pixels + y * surface->pitch + x * 3;
576 shift = surface->format->Rshift;
577 color |= *(pix + shift / 8) >> shift;
578 shift = surface->format->Gshift;
579 color |= *(pix + shift / 8) >> shift;
580 shift = surface->format->Bshift;
581 color |= *(pix + shift / 8) >> shift;
587 case 4: /* probably 32-bpp */
589 return *((Uint32 *)surface->pixels + y * surface->pitch / 4 + x);
598 /* ========================================================================= */
599 /* The following functions were taken from the SGE library */
600 /* (SDL Graphics Extension Library) by Anders Lindström */
601 /* http://www.etek.chalmers.se/~e8cal1/sge/index.html */
602 /* ========================================================================= */
604 void _PutPixel(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
606 if (x >= 0 && x <= surface->w - 1 && y >= 0 && y <= surface->h - 1)
608 switch (surface->format->BytesPerPixel)
613 *((Uint8 *)surface->pixels + y*surface->pitch + x) = color;
619 /* Probably 15-bpp or 16-bpp */
620 *((Uint16 *)surface->pixels + y*surface->pitch/2 + x) = color;
626 /* Slow 24-bpp mode, usually not used */
630 /* Gack - slow, but endian correct */
631 pix = (Uint8 *)surface->pixels + y * surface->pitch + x*3;
632 shift = surface->format->Rshift;
633 *(pix+shift/8) = color>>shift;
634 shift = surface->format->Gshift;
635 *(pix+shift/8) = color>>shift;
636 shift = surface->format->Bshift;
637 *(pix+shift/8) = color>>shift;
643 /* Probably 32-bpp */
644 *((Uint32 *)surface->pixels + y*surface->pitch/4 + x) = color;
651 void _PutPixelRGB(SDL_Surface *surface, Sint16 x, Sint16 y,
652 Uint8 R, Uint8 G, Uint8 B)
654 _PutPixel(surface, x, y, SDL_MapRGB(surface->format, R, G, B));
657 void _PutPixel8(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
659 *((Uint8 *)surface->pixels + y*surface->pitch + x) = color;
662 void _PutPixel16(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
664 *((Uint16 *)surface->pixels + y*surface->pitch/2 + x) = color;
667 void _PutPixel24(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
672 /* Gack - slow, but endian correct */
673 pix = (Uint8 *)surface->pixels + y * surface->pitch + x*3;
674 shift = surface->format->Rshift;
675 *(pix+shift/8) = color>>shift;
676 shift = surface->format->Gshift;
677 *(pix+shift/8) = color>>shift;
678 shift = surface->format->Bshift;
679 *(pix+shift/8) = color>>shift;
682 void _PutPixel32(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
684 *((Uint32 *)surface->pixels + y*surface->pitch/4 + x) = color;
687 void _PutPixelX(SDL_Surface *dest,Sint16 x,Sint16 y,Uint32 color)
689 switch (dest->format->BytesPerPixel)
692 *((Uint8 *)dest->pixels + y*dest->pitch + x) = color;
696 *((Uint16 *)dest->pixels + y*dest->pitch/2 + x) = color;
700 _PutPixel24(dest,x,y,color);
704 *((Uint32 *)dest->pixels + y*dest->pitch/4 + x) = color;
709 void sge_PutPixel(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
711 if (SDL_MUSTLOCK(surface))
713 if (SDL_LockSurface(surface) < 0)
719 _PutPixel(surface, x, y, color);
721 if (SDL_MUSTLOCK(surface))
723 SDL_UnlockSurface(surface);
727 void sge_PutPixelRGB(SDL_Surface *surface, Sint16 x, Sint16 y,
728 Uint8 r, Uint8 g, Uint8 b)
730 sge_PutPixel(surface, x, y, SDL_MapRGB(surface->format, r, g, b));
733 Sint32 sge_CalcYPitch(SDL_Surface *dest, Sint16 y)
735 if (y >= 0 && y <= dest->h - 1)
737 switch (dest->format->BytesPerPixel)
740 return y*dest->pitch;
744 return y*dest->pitch/2;
748 return y*dest->pitch;
752 return y*dest->pitch/4;
760 void sge_pPutPixel(SDL_Surface *surface, Sint16 x, Sint32 ypitch, Uint32 color)
762 if (x >= 0 && x <= surface->w - 1 && ypitch >= 0)
764 switch (surface->format->BytesPerPixel)
769 *((Uint8 *)surface->pixels + ypitch + x) = color;
775 /* Probably 15-bpp or 16-bpp */
776 *((Uint16 *)surface->pixels + ypitch + x) = color;
782 /* Slow 24-bpp mode, usually not used */
786 /* Gack - slow, but endian correct */
787 pix = (Uint8 *)surface->pixels + ypitch + x*3;
788 shift = surface->format->Rshift;
789 *(pix+shift/8) = color>>shift;
790 shift = surface->format->Gshift;
791 *(pix+shift/8) = color>>shift;
792 shift = surface->format->Bshift;
793 *(pix+shift/8) = color>>shift;
799 /* Probably 32-bpp */
800 *((Uint32 *)surface->pixels + ypitch + x) = color;
807 void sge_HLine(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y,
812 if (SDL_MUSTLOCK(Surface))
814 if (SDL_LockSurface(Surface) < 0)
827 /* Do the clipping */
828 if (y < 0 || y > Surface->h - 1 || x1 > Surface->w - 1 || x2 < 0)
832 if (x2 > Surface->w - 1)
840 SDL_FillRect(Surface, &l, Color);
842 if (SDL_MUSTLOCK(Surface))
844 SDL_UnlockSurface(Surface);
848 void sge_HLineRGB(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y,
849 Uint8 R, Uint8 G, Uint8 B)
851 sge_HLine(Surface, x1, x2, y, SDL_MapRGB(Surface->format, R, G, B));
854 void _HLine(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y, Uint32 Color)
865 /* Do the clipping */
866 if (y < 0 || y > Surface->h - 1 || x1 > Surface->w - 1 || x2 < 0)
870 if (x2 > Surface->w - 1)
878 SDL_FillRect(Surface, &l, Color);
881 void sge_VLine(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2,
886 if (SDL_MUSTLOCK(Surface))
888 if (SDL_LockSurface(Surface) < 0)
901 /* Do the clipping */
902 if (x < 0 || x > Surface->w - 1 || y1 > Surface->h - 1 || y2 < 0)
906 if (y2 > Surface->h - 1)
914 SDL_FillRect(Surface, &l, Color);
916 if (SDL_MUSTLOCK(Surface))
918 SDL_UnlockSurface(Surface);
922 void sge_VLineRGB(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2,
923 Uint8 R, Uint8 G, Uint8 B)
925 sge_VLine(Surface, x, y1, y2, SDL_MapRGB(Surface->format, R, G, B));
928 void _VLine(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2, Uint32 Color)
939 /* Do the clipping */
940 if (x < 0 || x > Surface->w - 1 || y1 > Surface->h - 1 || y2 < 0)
944 if (y2 > Surface->h - 1)
952 SDL_FillRect(Surface, &l, Color);
955 void sge_DoLine(SDL_Surface *Surface, Sint16 x1, Sint16 y1,
956 Sint16 x2, Sint16 y2, Uint32 Color,
957 void Callback(SDL_Surface *Surf, Sint16 X, Sint16 Y,
960 Sint16 dx, dy, sdx, sdy, x, y, px, py;
965 sdx = (dx < 0) ? -1 : 1;
966 sdy = (dy < 0) ? -1 : 1;
978 for (x = 0; x < dx; x++)
980 Callback(Surface, px, py, Color);
994 for (y = 0; y < dy; y++)
996 Callback(Surface, px, py, Color);
1010 void sge_DoLineRGB(SDL_Surface *Surface, Sint16 X1, Sint16 Y1,
1011 Sint16 X2, Sint16 Y2, Uint8 R, Uint8 G, Uint8 B,
1012 void Callback(SDL_Surface *Surf, Sint16 X, Sint16 Y,
1015 sge_DoLine(Surface, X1, Y1, X2, Y2,
1016 SDL_MapRGB(Surface->format, R, G, B), Callback);
1019 void sge_Line(SDL_Surface *Surface, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2,
1022 if (SDL_MUSTLOCK(Surface))
1024 if (SDL_LockSurface(Surface) < 0)
1029 sge_DoLine(Surface, x1, y1, x2, y2, Color, _PutPixel);
1031 /* unlock the display */
1032 if (SDL_MUSTLOCK(Surface))
1034 SDL_UnlockSurface(Surface);
1038 void sge_LineRGB(SDL_Surface *Surface, Sint16 x1, Sint16 y1, Sint16 x2,
1039 Sint16 y2, Uint8 R, Uint8 G, Uint8 B)
1041 sge_Line(Surface, x1, y1, x2, y2, SDL_MapRGB(Surface->format, R, G, B));
1044 void SDLPutPixel(Bitmap *dst_bitmap, int x, int y, Pixel pixel)
1046 if (dst_bitmap == backbuffer || dst_bitmap == window)
1052 sge_PutPixel(dst_bitmap->surface, x, y, pixel);
1057 -----------------------------------------------------------------------------
1058 quick (no, it's slow) and dirty hack to "invert" rectangle inside SDL surface
1059 -----------------------------------------------------------------------------
1062 void SDLInvertArea(Bitmap *bitmap, int src_x, int src_y,
1063 int width, int height, Uint32 color)
1067 for (y = src_y; y < src_y + height; y++)
1069 for (x = src_x; x < src_x + width; x++)
1071 Uint32 pixel = SDLGetPixel(bitmap, x, y);
1073 SDLPutPixel(bitmap, x, y, pixel == BLACK_PIXEL ? color : BLACK_PIXEL);
1078 void SDLCopyInverseMasked(Bitmap *src_bitmap, Bitmap *dst_bitmap,
1079 int src_x, int src_y, int width, int height,
1080 int dst_x, int dst_y)
1084 for (y = 0; y < height; y++)
1086 for (x = 0; x < width; x++)
1088 Uint32 pixel = SDLGetPixel(src_bitmap, src_x + x, src_y + y);
1090 if (pixel != BLACK_PIXEL)
1091 SDLPutPixel(dst_bitmap, dst_x + x, dst_y + y, BLACK_PIXEL);
1097 /* ========================================================================= */
1098 /* The following functions were taken from the SDL_gfx library version 2.0.3 */
1099 /* (Rotozoomer) by Andreas Schiffler */
1100 /* http://www.ferzkopp.net/Software/SDL_gfx-2.0/index.html */
1101 /* ========================================================================= */
1104 -----------------------------------------------------------------------------
1107 zoomes 32bit RGBA/ABGR 'src' surface to 'dst' surface.
1108 -----------------------------------------------------------------------------
1119 int zoomSurfaceRGBA_scaleDownBy2(SDL_Surface *src, SDL_Surface *dst)
1122 tColorRGBA *sp, *csp, *dp;
1126 sp = csp = (tColorRGBA *) src->pixels;
1127 dp = (tColorRGBA *) dst->pixels;
1128 sgap = src->pitch - src->w * 4;
1129 dgap = dst->pitch - dst->w * 4;
1131 for (y = 0; y < dst->h; y++)
1135 for (x = 0; x < dst->w; x++)
1137 tColorRGBA *sp0 = sp;
1138 tColorRGBA *sp1 = (tColorRGBA *) ((Uint8 *) sp + src->pitch);
1139 tColorRGBA *sp00 = &sp0[0];
1140 tColorRGBA *sp01 = &sp0[1];
1141 tColorRGBA *sp10 = &sp1[0];
1142 tColorRGBA *sp11 = &sp1[1];
1145 /* create new color pixel from all four source color pixels */
1146 new.r = (sp00->r + sp01->r + sp10->r + sp11->r) / 4;
1147 new.g = (sp00->g + sp01->g + sp10->g + sp11->g) / 4;
1148 new.b = (sp00->b + sp01->b + sp10->b + sp11->b) / 4;
1149 new.a = (sp00->a + sp01->a + sp10->a + sp11->a) / 4;
1154 /* advance source pointers */
1157 /* advance destination pointer */
1161 /* advance source pointer */
1162 csp = (tColorRGBA *) ((Uint8 *) csp + 2 * src->pitch);
1164 /* advance destination pointers */
1165 dp = (tColorRGBA *) ((Uint8 *) dp + dgap);
1171 int zoomSurfaceRGBA(SDL_Surface *src, SDL_Surface *dst)
1173 int x, y, sx, sy, *sax, *say, *csax, *csay, csx, csy;
1174 tColorRGBA *sp, *csp, *dp;
1177 /* use specialized zoom function when scaling down to exactly half size */
1178 if (src->w == 2 * dst->w &&
1179 src->h == 2 * dst->h)
1180 return zoomSurfaceRGBA_scaleDownBy2(src, dst);
1182 /* variable setup */
1183 sx = (int) (65536.0 * (float) src->w / (float) dst->w);
1184 sy = (int) (65536.0 * (float) src->h / (float) dst->h);
1186 /* allocate memory for row increments */
1187 sax = (int *)checked_malloc((dst->w + 1) * sizeof(Uint32));
1188 say = (int *)checked_malloc((dst->h + 1) * sizeof(Uint32));
1190 /* precalculate row increments */
1193 for (x = 0; x <= dst->w; x++)
1203 for (y = 0; y <= dst->h; y++)
1212 sp = csp = (tColorRGBA *) src->pixels;
1213 dp = (tColorRGBA *) dst->pixels;
1214 sgap = src->pitch - src->w * 4;
1215 dgap = dst->pitch - dst->w * 4;
1218 for (y = 0; y < dst->h; y++)
1223 for (x = 0; x < dst->w; x++)
1228 /* advance source pointers */
1230 sp += (*csax >> 16);
1232 /* advance destination pointer */
1236 /* advance source pointer */
1238 csp = (tColorRGBA *) ((Uint8 *) csp + (*csay >> 16) * src->pitch);
1240 /* advance destination pointers */
1241 dp = (tColorRGBA *) ((Uint8 *) dp + dgap);
1251 -----------------------------------------------------------------------------
1254 zoomes 8 bit palette/Y 'src' surface to 'dst' surface
1255 -----------------------------------------------------------------------------
1258 int zoomSurfaceY(SDL_Surface * src, SDL_Surface * dst)
1260 Uint32 x, y, sx, sy, *sax, *say, *csax, *csay, csx, csy;
1261 Uint8 *sp, *dp, *csp;
1264 /* variable setup */
1265 sx = (Uint32) (65536.0 * (float) src->w / (float) dst->w);
1266 sy = (Uint32) (65536.0 * (float) src->h / (float) dst->h);
1268 /* allocate memory for row increments */
1269 sax = (Uint32 *)checked_malloc(dst->w * sizeof(Uint32));
1270 say = (Uint32 *)checked_malloc(dst->h * sizeof(Uint32));
1272 /* precalculate row increments */
1275 for (x = 0; x < dst->w; x++)
1278 *csax = (csx >> 16);
1285 for (y = 0; y < dst->h; y++)
1288 *csay = (csy >> 16);
1295 for (x = 0; x < dst->w; x++)
1303 for (y = 0; y < dst->h; y++)
1310 sp = csp = (Uint8 *) src->pixels;
1311 dp = (Uint8 *) dst->pixels;
1312 dgap = dst->pitch - dst->w;
1316 for (y = 0; y < dst->h; y++)
1320 for (x = 0; x < dst->w; x++)
1325 /* advance source pointers */
1329 /* advance destination pointer */
1333 /* advance source pointer (for row) */
1334 csp += ((*csay) * src->pitch);
1337 /* advance destination pointers */
1348 -----------------------------------------------------------------------------
1351 Zooms a 32bit or 8bit 'src' surface to newly created 'dst' surface.
1352 'zoomx' and 'zoomy' are scaling factors for width and height.
1353 If the surface is not 8bit or 32bit RGBA/ABGR it will be converted
1354 into a 32bit RGBA format on the fly.
1355 -----------------------------------------------------------------------------
1358 SDL_Surface *zoomSurface(SDL_Surface *src, int dst_width, int dst_height)
1360 SDL_Surface *zoom_src = NULL;
1361 SDL_Surface *zoom_dst = NULL;
1362 boolean is_converted = FALSE;
1369 /* determine if source surface is 32 bit or 8 bit */
1370 is_32bit = (src->format->BitsPerPixel == 32);
1372 if (is_32bit || src->format->BitsPerPixel == 8)
1374 /* use source surface 'as is' */
1379 /* new source surface is 32 bit with a defined RGB ordering */
1380 zoom_src = SDL_CreateRGBSurface(SDL_SWSURFACE, src->w, src->h, 32,
1381 0x000000ff, 0x0000ff00, 0x00ff0000, 0);
1382 SDL_BlitSurface(src, NULL, zoom_src, NULL);
1384 is_converted = TRUE;
1387 /* allocate surface to completely contain the zoomed surface */
1390 /* target surface is 32 bit with source RGBA/ABGR ordering */
1391 zoom_dst = SDL_CreateRGBSurface(SDL_SWSURFACE, dst_width, dst_height, 32,
1392 zoom_src->format->Rmask,
1393 zoom_src->format->Gmask,
1394 zoom_src->format->Bmask, 0);
1398 /* target surface is 8 bit */
1399 zoom_dst = SDL_CreateRGBSurface(SDL_SWSURFACE, dst_width, dst_height, 8,
1403 /* lock source surface */
1404 SDL_LockSurface(zoom_src);
1406 /* check which kind of surface we have */
1409 /* call the 32 bit transformation routine to do the zooming */
1410 zoomSurfaceRGBA(zoom_src, zoom_dst);
1415 for (i = 0; i < zoom_src->format->palette->ncolors; i++)
1416 zoom_dst->format->palette->colors[i] =
1417 zoom_src->format->palette->colors[i];
1418 zoom_dst->format->palette->ncolors = zoom_src->format->palette->ncolors;
1420 /* call the 8 bit transformation routine to do the zooming */
1421 zoomSurfaceY(zoom_src, zoom_dst);
1424 /* unlock source surface */
1425 SDL_UnlockSurface(zoom_src);
1427 /* free temporary surface */
1429 SDL_FreeSurface(zoom_src);
1431 /* return destination surface */
1435 void SDLZoomBitmap(Bitmap *src_bitmap, Bitmap *dst_bitmap)
1437 SDL_Surface *sdl_surface_tmp;
1438 int dst_width = dst_bitmap->width;
1439 int dst_height = dst_bitmap->height;
1441 /* throw away old destination surface */
1442 SDL_FreeSurface(dst_bitmap->surface);
1444 /* create zoomed temporary surface from source surface */
1445 sdl_surface_tmp = zoomSurface(src_bitmap->surface, dst_width, dst_height);
1447 /* create native format destination surface from zoomed temporary surface */
1448 dst_bitmap->surface = SDL_DisplayFormat(sdl_surface_tmp);
1450 /* free temporary surface */
1451 SDL_FreeSurface(sdl_surface_tmp);
1455 /* ========================================================================= */
1456 /* load image to bitmap */
1457 /* ========================================================================= */
1459 Bitmap *SDLLoadImage(char *filename)
1461 Bitmap *new_bitmap = CreateBitmapStruct();
1462 SDL_Surface *sdl_image_tmp;
1464 /* load image to temporary surface */
1465 if ((sdl_image_tmp = IMG_Load(filename)) == NULL)
1467 SetError("IMG_Load(): %s", SDL_GetError());
1471 /* create native non-transparent surface for current image */
1472 if ((new_bitmap->surface = SDL_DisplayFormat(sdl_image_tmp)) == NULL)
1474 SetError("SDL_DisplayFormat(): %s", SDL_GetError());
1478 /* create native transparent surface for current image */
1479 SDL_SetColorKey(sdl_image_tmp, SDL_SRCCOLORKEY,
1480 SDL_MapRGB(sdl_image_tmp->format, 0x00, 0x00, 0x00));
1481 if ((new_bitmap->surface_masked = SDL_DisplayFormat(sdl_image_tmp)) == NULL)
1483 SetError("SDL_DisplayFormat(): %s", SDL_GetError());
1487 /* free temporary surface */
1488 SDL_FreeSurface(sdl_image_tmp);
1490 new_bitmap->width = new_bitmap->surface->w;
1491 new_bitmap->height = new_bitmap->surface->h;
1497 /* ------------------------------------------------------------------------- */
1498 /* custom cursor fuctions */
1499 /* ------------------------------------------------------------------------- */
1501 static SDL_Cursor *create_cursor(struct MouseCursorInfo *cursor_info)
1503 return SDL_CreateCursor(cursor_info->data, cursor_info->mask,
1504 cursor_info->width, cursor_info->height,
1505 cursor_info->hot_x, cursor_info->hot_y);
1508 void SDLSetMouseCursor(struct MouseCursorInfo *cursor_info)
1510 static struct MouseCursorInfo *last_cursor_info = NULL;
1511 static struct MouseCursorInfo *last_cursor_info2 = NULL;
1512 static SDL_Cursor *cursor_default = NULL;
1513 static SDL_Cursor *cursor_current = NULL;
1515 /* if invoked for the first time, store the SDL default cursor */
1516 if (cursor_default == NULL)
1517 cursor_default = SDL_GetCursor();
1519 /* only create new cursor if cursor info (custom only) has changed */
1520 if (cursor_info != NULL && cursor_info != last_cursor_info)
1522 cursor_current = create_cursor(cursor_info);
1523 last_cursor_info = cursor_info;
1526 /* only set new cursor if cursor info (custom or NULL) has changed */
1527 if (cursor_info != last_cursor_info2)
1528 SDL_SetCursor(cursor_info ? cursor_current : cursor_default);
1530 last_cursor_info2 = cursor_info;
1534 /* ========================================================================= */
1535 /* audio functions */
1536 /* ========================================================================= */
1538 void SDLOpenAudio(void)
1540 if (!strEqual(setup.system.sdl_audiodriver, ARG_DEFAULT))
1541 putenv(getStringCat2("SDL_AUDIODRIVER=", setup.system.sdl_audiodriver));
1543 if (SDL_InitSubSystem(SDL_INIT_AUDIO) < 0)
1545 Error(ERR_WARN, "SDL_InitSubSystem() failed: %s", SDL_GetError());
1549 if (Mix_OpenAudio(DEFAULT_AUDIO_SAMPLE_RATE, MIX_DEFAULT_FORMAT,
1550 AUDIO_NUM_CHANNELS_STEREO,
1551 setup.system.audio_fragment_size) < 0)
1553 Error(ERR_WARN, "Mix_OpenAudio() failed: %s", SDL_GetError());
1557 audio.sound_available = TRUE;
1558 audio.music_available = TRUE;
1559 audio.loops_available = TRUE;
1560 audio.sound_enabled = TRUE;
1562 /* set number of available mixer channels */
1563 audio.num_channels = Mix_AllocateChannels(NUM_MIXER_CHANNELS);
1564 audio.music_channel = MUSIC_CHANNEL;
1565 audio.first_sound_channel = FIRST_SOUND_CHANNEL;
1567 Mixer_InitChannels();
1570 void SDLCloseAudio(void)
1573 Mix_HaltChannel(-1);
1576 SDL_QuitSubSystem(SDL_INIT_AUDIO);
1580 /* ========================================================================= */
1581 /* event functions */
1582 /* ========================================================================= */
1584 void SDLNextEvent(Event *event)
1586 SDL_WaitEvent(event);
1588 if (event->type == EVENT_BUTTONPRESS ||
1589 event->type == EVENT_BUTTONRELEASE)
1591 if (((ButtonEvent *)event)->x > video_xoffset)
1592 ((ButtonEvent *)event)->x -= video_xoffset;
1594 ((ButtonEvent *)event)->x = 0;
1595 if (((ButtonEvent *)event)->y > video_yoffset)
1596 ((ButtonEvent *)event)->y -= video_yoffset;
1598 ((ButtonEvent *)event)->y = 0;
1600 else if (event->type == EVENT_MOTIONNOTIFY)
1602 if (((MotionEvent *)event)->x > video_xoffset)
1603 ((MotionEvent *)event)->x -= video_xoffset;
1605 ((MotionEvent *)event)->x = 0;
1606 if (((MotionEvent *)event)->y > video_yoffset)
1607 ((MotionEvent *)event)->y -= video_yoffset;
1609 ((MotionEvent *)event)->y = 0;
1614 /* ========================================================================= */
1615 /* joystick functions */
1616 /* ========================================================================= */
1618 static SDL_Joystick *sdl_joystick[MAX_PLAYERS] = { NULL, NULL, NULL, NULL };
1619 static int sdl_js_axis[MAX_PLAYERS][2] = { {0, 0}, {0, 0}, {0, 0}, {0, 0} };
1620 static int sdl_js_button[MAX_PLAYERS][2] = { {0, 0}, {0, 0}, {0, 0}, {0, 0} };
1622 static boolean SDLOpenJoystick(int nr)
1624 if (nr < 0 || nr > MAX_PLAYERS)
1627 return ((sdl_joystick[nr] = SDL_JoystickOpen(nr)) == NULL ? FALSE : TRUE);
1630 static void SDLCloseJoystick(int nr)
1632 if (nr < 0 || nr > MAX_PLAYERS)
1635 SDL_JoystickClose(sdl_joystick[nr]);
1638 static boolean SDLCheckJoystickOpened(int nr)
1640 if (nr < 0 || nr > MAX_PLAYERS)
1643 return (SDL_JoystickOpened(nr) ? TRUE : FALSE);
1646 void HandleJoystickEvent(Event *event)
1650 case SDL_JOYAXISMOTION:
1651 if (event->jaxis.axis < 2)
1652 sdl_js_axis[event->jaxis.which][event->jaxis.axis]= event->jaxis.value;
1655 case SDL_JOYBUTTONDOWN:
1656 if (event->jbutton.button < 2)
1657 sdl_js_button[event->jbutton.which][event->jbutton.button] = TRUE;
1660 case SDL_JOYBUTTONUP:
1661 if (event->jbutton.button < 2)
1662 sdl_js_button[event->jbutton.which][event->jbutton.button] = FALSE;
1670 void SDLInitJoysticks()
1672 static boolean sdl_joystick_subsystem_initialized = FALSE;
1673 boolean print_warning = !sdl_joystick_subsystem_initialized;
1676 if (!sdl_joystick_subsystem_initialized)
1678 sdl_joystick_subsystem_initialized = TRUE;
1680 if (SDL_Init(SDL_INIT_JOYSTICK) < 0)
1682 Error(ERR_EXIT, "SDL_Init() failed: %s", SDL_GetError());
1687 for (i = 0; i < MAX_PLAYERS; i++)
1689 /* get configured joystick for this player */
1690 char *device_name = setup.input[i].joy.device_name;
1691 int joystick_nr = getJoystickNrFromDeviceName(device_name);
1693 if (joystick_nr >= SDL_NumJoysticks())
1695 if (setup.input[i].use_joystick && print_warning)
1696 Error(ERR_WARN, "cannot find joystick %d", joystick_nr);
1701 /* misuse joystick file descriptor variable to store joystick number */
1702 joystick.fd[i] = joystick_nr;
1704 if (joystick_nr == -1)
1707 /* this allows subsequent calls to 'InitJoysticks' for re-initialization */
1708 if (SDLCheckJoystickOpened(joystick_nr))
1709 SDLCloseJoystick(joystick_nr);
1711 if (!setup.input[i].use_joystick)
1714 if (!SDLOpenJoystick(joystick_nr))
1717 Error(ERR_WARN, "cannot open joystick %d", joystick_nr);
1722 joystick.status = JOYSTICK_ACTIVATED;
1726 boolean SDLReadJoystick(int nr, int *x, int *y, boolean *b1, boolean *b2)
1728 if (nr < 0 || nr >= MAX_PLAYERS)
1732 *x = sdl_js_axis[nr][0];
1734 *y = sdl_js_axis[nr][1];
1737 *b1 = sdl_js_button[nr][0];
1739 *b2 = sdl_js_button[nr][1];
1744 #endif /* TARGET_SDL */