1 /***********************************************************
2 * Artsoft Retro-Game Library *
3 *----------------------------------------------------------*
4 * (c) 1994-2006 Artsoft Entertainment *
5 * Holger Schemel *
6 * Detmolder Strasse 189 *
7 * 33604 Bielefeld *
8 * Germany *
9 * e-mail: info@artsoft.org *
10 *----------------------------------------------------------*
11 * sdl.c *
12 ***********************************************************/
13
14 #include "system.h"
15 #include "sound.h"
16 #include "joystick.h"
17 #include "misc.h"
18 #include "setup.h"
19
20
21 #if defined(TARGET_SDL)
22
23 /* ========================================================================= */
24 /* video functions */
25 /* ========================================================================= */
26
27 /* functions from SGE library */
28 void sge_Line(SDL_Surface *, Sint16, Sint16, Sint16, Sint16, Uint32);
29
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;
37
setFullscreenParameters(char * fullscreen_mode_string)38 static void setFullscreenParameters(char *fullscreen_mode_string)
39 {
40 struct ScreenModeInfo *fullscreen_mode;
41 int i;
42
43 fullscreen_mode = get_screen_mode_from_string(fullscreen_mode_string);
44
45 if (fullscreen_mode == NULL)
46 return;
47
48 for (i = 0; video.fullscreen_modes[i].width != -1; i++)
49 {
50 if (fullscreen_mode->width == video.fullscreen_modes[i].width &&
51 fullscreen_mode->height == video.fullscreen_modes[i].height)
52 {
53 fullscreen_width = fullscreen_mode->width;
54 fullscreen_height = fullscreen_mode->height;
55
56 fullscreen_xoffset = (fullscreen_width - video.width) / 2;
57 fullscreen_yoffset = (fullscreen_height - video.height) / 2;
58
59 break;
60 }
61 }
62 }
63
SDLSetWindowIcon(char * basename)64 static void SDLSetWindowIcon(char *basename)
65 {
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) */
68
69 #if !defined(PLATFORM_MACOSX)
70 char *filename = getCustomImageFilename(basename);
71 SDL_Surface *surface;
72
73 if (filename == NULL)
74 {
75 Error(ERR_WARN, "SDLSetWindowIcon(): cannot find file '%s'", basename);
76
77 return;
78 }
79
80 if ((surface = IMG_Load(filename)) == NULL)
81 {
82 Error(ERR_WARN, "IMG_Load() failed: %s", SDL_GetError());
83
84 return;
85 }
86
87 /* set transparent color */
88 SDL_SetColorKey(surface, SDL_SRCCOLORKEY,
89 SDL_MapRGB(surface->format, 0x00, 0x00, 0x00));
90
91 SDL_WM_SetIcon(surface, NULL);
92 #endif
93 }
94
SDLInitVideoDisplay(void)95 void SDLInitVideoDisplay(void)
96 {
97 if (!strEqual(setup.system.sdl_videodriver, ARG_DEFAULT))
98 SDL_putenv(getStringCat2("SDL_VIDEODRIVER=", setup.system.sdl_videodriver));
99
100 SDL_putenv("SDL_VIDEO_CENTERED=1");
101
102 /* initialize SDL video */
103 if (SDL_InitSubSystem(SDL_INIT_VIDEO) < 0)
104 Error(ERR_EXIT, "SDL_InitSubSystem() failed: %s", SDL_GetError());
105
106 /* set default SDL depth */
107 video.default_depth = SDL_GetVideoInfo()->vfmt->BitsPerPixel;
108 }
109
SDLInitVideoBuffer(DrawBuffer ** backbuffer,DrawWindow ** window,boolean fullscreen)110 void SDLInitVideoBuffer(DrawBuffer **backbuffer, DrawWindow **window,
111 boolean fullscreen)
112 {
113 static int screen_xy[][2] =
114 {
115 { 640, 480 },
116 { 800, 600 },
117 { 1024, 768 },
118 { -1, -1 }
119 };
120 SDL_Rect **modes;
121 int i, j;
122
123 /* default: normal game window size */
124 fullscreen_width = video.width;
125 fullscreen_height = video.height;
126 fullscreen_xoffset = 0;
127 fullscreen_yoffset = 0;
128
129 for (i = 0; screen_xy[i][0] != -1; i++)
130 {
131 if (screen_xy[i][0] >= video.width && screen_xy[i][1] >= video.height)
132 {
133 fullscreen_width = screen_xy[i][0];
134 fullscreen_height = screen_xy[i][1];
135
136 break;
137 }
138 }
139
140 fullscreen_xoffset = (fullscreen_width - video.width) / 2;
141 fullscreen_yoffset = (fullscreen_height - video.height) / 2;
142
143 #if 1
144 checked_free(video.fullscreen_modes);
145
146 video.fullscreen_modes = NULL;
147 video.fullscreen_mode_current = NULL;
148 #endif
149
150 /* get available hardware supported fullscreen modes */
151 modes = SDL_ListModes(NULL, SDL_FULLSCREEN | SDL_HWSURFACE);
152
153 if (modes == NULL)
154 {
155 /* no screen modes available => no fullscreen mode support */
156 video.fullscreen_available = FALSE;
157 }
158 else if (modes == (SDL_Rect **)-1)
159 {
160 /* fullscreen resolution is not restricted -- all resolutions available */
161 video.fullscreen_modes = checked_calloc(2 * sizeof(struct ScreenModeInfo));
162
163 /* use native video buffer size for fullscreen mode */
164 video.fullscreen_modes[0].width = video.width;
165 video.fullscreen_modes[0].height = video.height;
166
167 video.fullscreen_modes[1].width = -1;
168 video.fullscreen_modes[1].height = -1;
169 }
170 else
171 {
172 /* in this case, a certain number of screen modes is available */
173 int num_modes = 0;
174
175 for(i = 0; modes[i] != NULL; i++)
176 {
177 boolean found_mode = FALSE;
178
179 /* screen mode is smaller than video buffer size -- skip it */
180 if (modes[i]->w < video.width || modes[i]->h < video.height)
181 continue;
182
183 if (video.fullscreen_modes != NULL)
184 for (j = 0; video.fullscreen_modes[j].width != -1; j++)
185 if (modes[i]->w == video.fullscreen_modes[j].width &&
186 modes[i]->h == video.fullscreen_modes[j].height)
187 found_mode = TRUE;
188
189 if (found_mode) /* screen mode already stored -- skip it */
190 continue;
191
192 /* new mode found; add it to list of available fullscreen modes */
193
194 num_modes++;
195
196 video.fullscreen_modes = checked_realloc(video.fullscreen_modes,
197 (num_modes + 1) *
198 sizeof(struct ScreenModeInfo));
199
200 video.fullscreen_modes[num_modes - 1].width = modes[i]->w;
201 video.fullscreen_modes[num_modes - 1].height = modes[i]->h;
202
203 video.fullscreen_modes[num_modes].width = -1;
204 video.fullscreen_modes[num_modes].height = -1;
205 }
206
207 if (num_modes == 0)
208 {
209 /* no appropriate screen modes available => no fullscreen mode support */
210 video.fullscreen_available = FALSE;
211 }
212 }
213
214 /* set window icon */
215 SDLSetWindowIcon(program.sdl_icon_filename);
216
217 /* open SDL video output device (window or fullscreen mode) */
218 if (!SDLSetVideoMode(backbuffer, fullscreen))
219 Error(ERR_EXIT, "setting video mode failed");
220
221 /* set window and icon title */
222 SDL_WM_SetCaption(program.window_title, program.window_title);
223
224 /* SDL cannot directly draw to the visible video framebuffer like X11,
225 but always uses a backbuffer, which is then blitted to the visible
226 video framebuffer with 'SDL_UpdateRect' (or replaced with the current
227 visible video framebuffer with 'SDL_Flip', if the hardware supports
228 this). Therefore do not use an additional backbuffer for drawing, but
229 use a symbolic buffer (distinguishable from the SDL backbuffer) called
230 'window', which indicates that the SDL backbuffer should be updated to
231 the visible video framebuffer when attempting to blit to it.
232
233 For convenience, it seems to be a good idea to create this symbolic
234 buffer 'window' at the same size as the SDL backbuffer. Although it
235 should never be drawn to directly, it would do no harm nevertheless. */
236
237 /* create additional (symbolic) buffer for double-buffering */
238 #if 1
239 ReCreateBitmap(window, video.width, video.height, video.depth);
240 #else
241 *window = CreateBitmap(video.width, video.height, video.depth);
242 #endif
243 }
244
SDLSetVideoMode(DrawBuffer ** backbuffer,boolean fullscreen)245 boolean SDLSetVideoMode(DrawBuffer **backbuffer, boolean fullscreen)
246 {
247 boolean success = TRUE;
248 int surface_flags_fullscreen = SURFACE_FLAGS | SDL_FULLSCREEN;
249 int surface_flags_window = SURFACE_FLAGS;
250 SDL_Surface *new_surface = NULL;
251
252 if (*backbuffer == NULL)
253 *backbuffer = CreateBitmapStruct();
254
255 /* (real bitmap might be larger in fullscreen mode with video offsets) */
256 (*backbuffer)->width = video.width;
257 (*backbuffer)->height = video.height;
258
259 if (fullscreen && !video.fullscreen_enabled && video.fullscreen_available)
260 {
261 setFullscreenParameters(setup.fullscreen_mode);
262
263 video_xoffset = fullscreen_xoffset;
264 video_yoffset = fullscreen_yoffset;
265
266 /* switch display to fullscreen mode, if available */
267 if ((new_surface = SDL_SetVideoMode(fullscreen_width, fullscreen_height,
268 video.depth, surface_flags_fullscreen))
269 == NULL)
270 {
271 /* switching display to fullscreen mode failed */
272 Error(ERR_WARN, "SDL_SetVideoMode() failed: %s", SDL_GetError());
273
274 /* do not try it again */
275 video.fullscreen_available = FALSE;
276
277 success = FALSE;
278 }
279 else
280 {
281 (*backbuffer)->surface = new_surface;
282
283 video.fullscreen_enabled = TRUE;
284 video.fullscreen_mode_current = setup.fullscreen_mode;
285
286 success = TRUE;
287 }
288 }
289
290 if ((!fullscreen && video.fullscreen_enabled) || new_surface == NULL)
291 {
292 video_xoffset = 0;
293 video_yoffset = 0;
294
295 /* switch display to window mode */
296 if ((new_surface = SDL_SetVideoMode(video.width, video.height,
297 video.depth, surface_flags_window))
298 == NULL)
299 {
300 /* switching display to window mode failed -- should not happen */
301 Error(ERR_WARN, "SDL_SetVideoMode() failed: %s", SDL_GetError());
302
303 success = FALSE;
304 }
305 else
306 {
307 (*backbuffer)->surface = new_surface;
308
309 video.fullscreen_enabled = FALSE;
310
311 success = TRUE;
312 }
313 }
314
315 #if 1
316 SDL_EventState(SDL_SYSWMEVENT, SDL_ENABLE);
317
318 #if defined(PLATFORM_WIN32)
319 {
320 SDL_SysWMinfo wminfo;
321 HWND hwnd;
322
323 SDL_VERSION(&wminfo.version);
324 SDL_GetWMInfo(&wminfo);
325
326 hwnd = wminfo.window;
327
328 DragAcceptFiles(hwnd, TRUE);
329 }
330 #endif
331 #endif
332
333
334 return success;
335 }
336
SDLCreateBitmapContent(Bitmap * new_bitmap,int width,int height,int depth)337 void SDLCreateBitmapContent(Bitmap *new_bitmap, int width, int height,
338 int depth)
339 {
340 SDL_Surface *surface_tmp, *surface_native;
341
342 if ((surface_tmp = SDL_CreateRGBSurface(SURFACE_FLAGS, width, height, depth,
343 0, 0, 0, 0))
344 == NULL)
345 Error(ERR_EXIT, "SDL_CreateRGBSurface() failed: %s", SDL_GetError());
346
347 if ((surface_native = SDL_DisplayFormat(surface_tmp)) == NULL)
348 Error(ERR_EXIT, "SDL_DisplayFormat() failed: %s", SDL_GetError());
349
350 SDL_FreeSurface(surface_tmp);
351
352 new_bitmap->surface = surface_native;
353 }
354
SDLFreeBitmapPointers(Bitmap * bitmap)355 void SDLFreeBitmapPointers(Bitmap *bitmap)
356 {
357 if (bitmap->surface)
358 SDL_FreeSurface(bitmap->surface);
359 if (bitmap->surface_masked)
360 SDL_FreeSurface(bitmap->surface_masked);
361 bitmap->surface = NULL;
362 bitmap->surface_masked = NULL;
363 }
364
SDLCopyArea(Bitmap * src_bitmap,Bitmap * dst_bitmap,int src_x,int src_y,int width,int height,int dst_x,int dst_y,int mask_mode)365 void SDLCopyArea(Bitmap *src_bitmap, Bitmap *dst_bitmap,
366 int src_x, int src_y, int width, int height,
367 int dst_x, int dst_y, int mask_mode)
368 {
369 Bitmap *real_dst_bitmap = (dst_bitmap == window ? backbuffer : dst_bitmap);
370 SDL_Rect src_rect, dst_rect;
371
372 if (src_bitmap == backbuffer)
373 {
374 src_x += video_xoffset;
375 src_y += video_yoffset;
376 }
377
378 src_rect.x = src_x;
379 src_rect.y = src_y;
380 src_rect.w = width;
381 src_rect.h = height;
382
383 if (dst_bitmap == backbuffer || dst_bitmap == window)
384 {
385 dst_x += video_xoffset;
386 dst_y += video_yoffset;
387 }
388
389 dst_rect.x = dst_x;
390 dst_rect.y = dst_y;
391 dst_rect.w = width;
392 dst_rect.h = height;
393
394 if (src_bitmap != backbuffer || dst_bitmap != window)
395 SDL_BlitSurface((mask_mode == BLIT_MASKED ?
396 src_bitmap->surface_masked : src_bitmap->surface),
397 &src_rect, real_dst_bitmap->surface, &dst_rect);
398
399 if (dst_bitmap == window)
400 SDL_UpdateRect(backbuffer->surface, dst_x, dst_y, width, height);
401 }
402
SDLFillRectangle(Bitmap * dst_bitmap,int x,int y,int width,int height,Uint32 color)403 void SDLFillRectangle(Bitmap *dst_bitmap, int x, int y, int width, int height,
404 Uint32 color)
405 {
406 Bitmap *real_dst_bitmap = (dst_bitmap == window ? backbuffer : dst_bitmap);
407 SDL_Rect rect;
408
409 if (dst_bitmap == backbuffer || dst_bitmap == window)
410 {
411 x += video_xoffset;
412 y += video_yoffset;
413 }
414
415 rect.x = x;
416 rect.y = y;
417 rect.w = width;
418 rect.h = height;
419
420 SDL_FillRect(real_dst_bitmap->surface, &rect, color);
421
422 if (dst_bitmap == window)
423 SDL_UpdateRect(backbuffer->surface, x, y, width, height);
424 }
425
SDLFadeRectangle(Bitmap * bitmap_cross,int x,int y,int width,int height,int fade_mode,int fade_delay,int post_delay,void (* draw_border_function)(void))426 void SDLFadeRectangle(Bitmap *bitmap_cross, int x, int y, int width, int height,
427 int fade_mode, int fade_delay, int post_delay,
428 void (*draw_border_function)(void))
429 {
430 static boolean initialization_needed = TRUE;
431 static SDL_Surface *surface_source = NULL;
432 static SDL_Surface *surface_target = NULL;
433 static SDL_Surface *surface_black = NULL;
434 SDL_Surface *surface_screen = backbuffer->surface;
435 SDL_Surface *surface_cross = (bitmap_cross ? bitmap_cross->surface : NULL);
436 SDL_Rect src_rect, dst_rect;
437 int src_x = x, src_y = y;
438 int dst_x = x, dst_y = y;
439 unsigned int time_last, time_current;
440
441 /* check if screen size has changed */
442 if (surface_source != NULL && (video.width != surface_source->w ||
443 video.height != surface_source->h))
444 {
445 SDL_FreeSurface(surface_source);
446 SDL_FreeSurface(surface_target);
447 SDL_FreeSurface(surface_black);
448
449 initialization_needed = TRUE;
450 }
451
452 src_rect.x = src_x;
453 src_rect.y = src_y;
454 src_rect.w = width;
455 src_rect.h = height;
456
457 dst_x += video_xoffset;
458 dst_y += video_yoffset;
459
460 dst_rect.x = dst_x;
461 dst_rect.y = dst_y;
462 dst_rect.w = width; /* (ignored) */
463 dst_rect.h = height; /* (ignored) */
464
465 if (initialization_needed)
466 {
467 unsigned int flags = SDL_SRCALPHA;
468
469 /* use same surface type as screen surface */
470 if ((surface_screen->flags & SDL_HWSURFACE))
471 flags |= SDL_HWSURFACE;
472 else
473 flags |= SDL_SWSURFACE;
474
475 /* create surface for temporary copy of screen buffer (source) */
476 if ((surface_source =
477 SDL_CreateRGBSurface(flags,
478 video.width,
479 video.height,
480 surface_screen->format->BitsPerPixel,
481 surface_screen->format->Rmask,
482 surface_screen->format->Gmask,
483 surface_screen->format->Bmask,
484 surface_screen->format->Amask)) == NULL)
485 Error(ERR_EXIT, "SDL_CreateRGBSurface() failed: %s", SDL_GetError());
486
487 /* create surface for cross-fading screen buffer (target) */
488 if ((surface_target =
489 SDL_CreateRGBSurface(flags,
490 video.width,
491 video.height,
492 surface_screen->format->BitsPerPixel,
493 surface_screen->format->Rmask,
494 surface_screen->format->Gmask,
495 surface_screen->format->Bmask,
496 surface_screen->format->Amask)) == NULL)
497 Error(ERR_EXIT, "SDL_CreateRGBSurface() failed: %s", SDL_GetError());
498
499 /* create black surface for fading from/to black */
500 if ((surface_black =
501 SDL_CreateRGBSurface(flags,
502 video.width,
503 video.height,
504 surface_screen->format->BitsPerPixel,
505 surface_screen->format->Rmask,
506 surface_screen->format->Gmask,
507 surface_screen->format->Bmask,
508 surface_screen->format->Amask)) == NULL)
509 Error(ERR_EXIT, "SDL_CreateRGBSurface() failed: %s", SDL_GetError());
510
511 /* completely fill the surface with black color pixels */
512 SDL_FillRect(surface_black, NULL,
513 SDL_MapRGB(surface_screen->format, 0, 0, 0));
514
515 initialization_needed = FALSE;
516 }
517
518 /* copy source and target surfaces to temporary surfaces for fading */
519 if (fade_mode & FADE_TYPE_TRANSFORM)
520 {
521 SDL_BlitSurface(surface_cross, &src_rect, surface_source, &src_rect);
522 SDL_BlitSurface(surface_screen, &dst_rect, surface_target, &src_rect);
523 }
524 else if (fade_mode & FADE_TYPE_FADE_IN)
525 {
526 SDL_BlitSurface(surface_black, &src_rect, surface_source, &src_rect);
527 SDL_BlitSurface(surface_screen, &dst_rect, surface_target, &src_rect);
528 }
529 else /* FADE_TYPE_FADE_OUT */
530 {
531 SDL_BlitSurface(surface_screen, &dst_rect, surface_source, &src_rect);
532 SDL_BlitSurface(surface_black, &src_rect, surface_target, &src_rect);
533 }
534
535 time_current = SDL_GetTicks();
536
537 if (fade_mode == FADE_MODE_MELT)
538 {
539 boolean done = FALSE;
540 int melt_pixels = 2;
541 int melt_columns = width / melt_pixels;
542 int ypos[melt_columns];
543 int max_steps = height / 8 + 32;
544 int steps_done = 0;
545 float steps = 0;
546 int i;
547
548 SDL_BlitSurface(surface_source, &src_rect, surface_screen, &dst_rect);
549 SDL_SetAlpha(surface_target, 0, 0); /* disable alpha blending */
550
551 ypos[0] = -GetSimpleRandom(16);
552
553 for (i = 1 ; i < melt_columns; i++)
554 {
555 int r = GetSimpleRandom(3) - 1; /* randomly choose from { -1, 0, -1 } */
556
557 ypos[i] = ypos[i - 1] + r;
558
559 if (ypos[i] > 0)
560 ypos[i] = 0;
561 else
562 if (ypos[i] == -16)
563 ypos[i] = -15;
564 }
565
566 while (!done)
567 {
568 int steps_final;
569
570 time_last = time_current;
571 time_current = SDL_GetTicks();
572 steps += max_steps * ((float)(time_current - time_last) / fade_delay);
573 steps_final = MIN(MAX(0, steps), max_steps);
574
575 steps_done++;
576
577 done = (steps_done >= steps_final);
578
579 for (i = 0 ; i < melt_columns; i++)
580 {
581 if (ypos[i] < 0)
582 {
583 ypos[i]++;
584
585 done = FALSE;
586 }
587 else if (ypos[i] < height)
588 {
589 int y1 = 16;
590 int y2 = 8;
591 int y3 = 8;
592 int dy = (ypos[i] < y1) ? ypos[i] + 1 : y2 + GetSimpleRandom(y3);
593
594 if (ypos[i] + dy >= height)
595 dy = height - ypos[i];
596
597 /* copy part of (appearing) target surface to upper area */
598 src_rect.x = src_x + i * melt_pixels;
599 // src_rect.y = src_y + ypos[i];
600 src_rect.y = src_y;
601 src_rect.w = melt_pixels;
602 // src_rect.h = dy;
603 src_rect.h = ypos[i] + dy;
604
605 dst_rect.x = dst_x + i * melt_pixels;
606 // dst_rect.y = dst_y + ypos[i];
607 dst_rect.y = dst_y;
608
609 if (steps_done >= steps_final)
610 SDL_BlitSurface(surface_target, &src_rect,
611 surface_screen, &dst_rect);
612
613 ypos[i] += dy;
614
615 /* copy part of (disappearing) source surface to lower area */
616 src_rect.x = src_x + i * melt_pixels;
617 src_rect.y = src_y;
618 src_rect.w = melt_pixels;
619 src_rect.h = height - ypos[i];
620
621 dst_rect.x = dst_x + i * melt_pixels;
622 dst_rect.y = dst_y + ypos[i];
623
624 if (steps_done >= steps_final)
625 SDL_BlitSurface(surface_source, &src_rect,
626 surface_screen, &dst_rect);
627
628 done = FALSE;
629 }
630 else
631 {
632 src_rect.x = src_x + i * melt_pixels;
633 src_rect.y = src_y;
634 src_rect.w = melt_pixels;
635 src_rect.h = height;
636
637 dst_rect.x = dst_x + i * melt_pixels;
638 dst_rect.y = dst_y;
639
640 if (steps_done >= steps_final)
641 SDL_BlitSurface(surface_target, &src_rect,
642 surface_screen, &dst_rect);
643 }
644 }
645
646 if (steps_done >= steps_final)
647 {
648 if (draw_border_function != NULL)
649 draw_border_function();
650
651 SDL_UpdateRect(surface_screen, dst_x, dst_y, width, height);
652 }
653 }
654 }
655 else
656 {
657 float alpha;
658 int alpha_final;
659
660 for (alpha = 0.0; alpha < 255.0;)
661 {
662 time_last = time_current;
663 time_current = SDL_GetTicks();
664 alpha += 255 * ((float)(time_current - time_last) / fade_delay);
665 alpha_final = MIN(MAX(0, alpha), 255);
666
667 /* draw existing (source) image to screen buffer */
668 SDL_BlitSurface(surface_source, &src_rect, surface_screen, &dst_rect);
669
670 /* draw new (target) image to screen buffer using alpha blending */
671 SDL_SetAlpha(surface_target, SDL_SRCALPHA, alpha_final);
672 SDL_BlitSurface(surface_target, &src_rect, surface_screen, &dst_rect);
673
674 if (draw_border_function != NULL)
675 draw_border_function();
676
677 #if 1
678 /* only update the region of the screen that is affected from fading */
679 SDL_UpdateRect(surface_screen, dst_x, dst_y, width, height);
680 #else
681 SDL_Flip(surface_screen);
682 #endif
683 }
684 }
685
686 Delay(post_delay);
687 }
688
SDLDrawSimpleLine(Bitmap * dst_bitmap,int from_x,int from_y,int to_x,int to_y,Uint32 color)689 void SDLDrawSimpleLine(Bitmap *dst_bitmap, int from_x, int from_y,
690 int to_x, int to_y, Uint32 color)
691 {
692 SDL_Surface *surface = dst_bitmap->surface;
693 SDL_Rect rect;
694
695 if (from_x > to_x)
696 swap_numbers(&from_x, &to_x);
697
698 if (from_y > to_y)
699 swap_numbers(&from_y, &to_y);
700
701 rect.x = from_x;
702 rect.y = from_y;
703 rect.w = (to_x - from_x + 1);
704 rect.h = (to_y - from_y + 1);
705
706 if (dst_bitmap == backbuffer || dst_bitmap == window)
707 {
708 rect.x += video_xoffset;
709 rect.y += video_yoffset;
710 }
711
712 SDL_FillRect(surface, &rect, color);
713 }
714
SDLDrawLine(Bitmap * dst_bitmap,int from_x,int from_y,int to_x,int to_y,Uint32 color)715 void SDLDrawLine(Bitmap *dst_bitmap, int from_x, int from_y,
716 int to_x, int to_y, Uint32 color)
717 {
718 if (dst_bitmap == backbuffer || dst_bitmap == window)
719 {
720 from_x += video_xoffset;
721 from_y += video_yoffset;
722 to_x += video_xoffset;
723 to_y += video_yoffset;
724 }
725
726 sge_Line(dst_bitmap->surface, from_x, from_y, to_x, to_y, color);
727 }
728
729 #if 0
730 void SDLDrawLines(SDL_Surface *surface, struct XY *points,
731 int num_points, Uint32 color)
732 {
733 int i, x, y;
734 int line_width = 4;
735
736 for (i = 0; i < num_points - 1; i++)
737 {
738 for (x = 0; x < line_width; x++)
739 {
740 for (y = 0; y < line_width; y++)
741 {
742 int dx = x - line_width / 2;
743 int dy = y - line_width / 2;
744
745 if ((x == 0 && y == 0) ||
746 (x == 0 && y == line_width - 1) ||
747 (x == line_width - 1 && y == 0) ||
748 (x == line_width - 1 && y == line_width - 1))
749 continue;
750
751 sge_Line(surface, points[i].x + dx, points[i].y + dy,
752 points[i+1].x + dx, points[i+1].y + dy, color);
753 }
754 }
755 }
756 }
757 #endif
758
SDLGetPixel(Bitmap * src_bitmap,int x,int y)759 Pixel SDLGetPixel(Bitmap *src_bitmap, int x, int y)
760 {
761 SDL_Surface *surface = src_bitmap->surface;
762
763 if (src_bitmap == backbuffer || src_bitmap == window)
764 {
765 x += video_xoffset;
766 y += video_yoffset;
767 }
768
769 switch (surface->format->BytesPerPixel)
770 {
771 case 1: /* assuming 8-bpp */
772 {
773 return *((Uint8 *)surface->pixels + y * surface->pitch + x);
774 }
775 break;
776
777 case 2: /* probably 15-bpp or 16-bpp */
778 {
779 return *((Uint16 *)surface->pixels + y * surface->pitch / 2 + x);
780 }
781 break;
782
783 case 3: /* slow 24-bpp mode; usually not used */
784 {
785 /* does this work? */
786 Uint8 *pix = (Uint8 *)surface->pixels + y * surface->pitch + x * 3;
787 Uint32 color = 0;
788 int shift;
789
790 shift = surface->format->Rshift;
791 color |= *(pix + shift / 8) >> shift;
792 shift = surface->format->Gshift;
793 color |= *(pix + shift / 8) >> shift;
794 shift = surface->format->Bshift;
795 color |= *(pix + shift / 8) >> shift;
796
797 return color;
798 }
799 break;
800
801 case 4: /* probably 32-bpp */
802 {
803 return *((Uint32 *)surface->pixels + y * surface->pitch / 4 + x);
804 }
805 break;
806 }
807
808 return 0;
809 }
810
811
812 /* ========================================================================= */
813 /* The following functions were taken from the SGE library */
814 /* (SDL Graphics Extension Library) by Anders Lindstr�m */
815 /* http://www.etek.chalmers.se/~e8cal1/sge/index.html */
816 /* ========================================================================= */
817
_PutPixel(SDL_Surface * surface,Sint16 x,Sint16 y,Uint32 color)818 void _PutPixel(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
819 {
820 if (x >= 0 && x <= surface->w - 1 && y >= 0 && y <= surface->h - 1)
821 {
822 switch (surface->format->BytesPerPixel)
823 {
824 case 1:
825 {
826 /* Assuming 8-bpp */
827 *((Uint8 *)surface->pixels + y*surface->pitch + x) = color;
828 }
829 break;
830
831 case 2:
832 {
833 /* Probably 15-bpp or 16-bpp */
834 *((Uint16 *)surface->pixels + y*surface->pitch/2 + x) = color;
835 }
836 break;
837
838 case 3:
839 {
840 /* Slow 24-bpp mode, usually not used */
841 Uint8 *pix;
842 int shift;
843
844 /* Gack - slow, but endian correct */
845 pix = (Uint8 *)surface->pixels + y * surface->pitch + x*3;
846 shift = surface->format->Rshift;
847 *(pix+shift/8) = color>>shift;
848 shift = surface->format->Gshift;
849 *(pix+shift/8) = color>>shift;
850 shift = surface->format->Bshift;
851 *(pix+shift/8) = color>>shift;
852 }
853 break;
854
855 case 4:
856 {
857 /* Probably 32-bpp */
858 *((Uint32 *)surface->pixels + y*surface->pitch/4 + x) = color;
859 }
860 break;
861 }
862 }
863 }
864
_PutPixelRGB(SDL_Surface * surface,Sint16 x,Sint16 y,Uint8 R,Uint8 G,Uint8 B)865 void _PutPixelRGB(SDL_Surface *surface, Sint16 x, Sint16 y,
866 Uint8 R, Uint8 G, Uint8 B)
867 {
868 _PutPixel(surface, x, y, SDL_MapRGB(surface->format, R, G, B));
869 }
870
_PutPixel8(SDL_Surface * surface,Sint16 x,Sint16 y,Uint32 color)871 void _PutPixel8(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
872 {
873 *((Uint8 *)surface->pixels + y*surface->pitch + x) = color;
874 }
875
_PutPixel16(SDL_Surface * surface,Sint16 x,Sint16 y,Uint32 color)876 void _PutPixel16(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
877 {
878 *((Uint16 *)surface->pixels + y*surface->pitch/2 + x) = color;
879 }
880
_PutPixel24(SDL_Surface * surface,Sint16 x,Sint16 y,Uint32 color)881 void _PutPixel24(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
882 {
883 Uint8 *pix;
884 int shift;
885
886 /* Gack - slow, but endian correct */
887 pix = (Uint8 *)surface->pixels + y * surface->pitch + x*3;
888 shift = surface->format->Rshift;
889 *(pix+shift/8) = color>>shift;
890 shift = surface->format->Gshift;
891 *(pix+shift/8) = color>>shift;
892 shift = surface->format->Bshift;
893 *(pix+shift/8) = color>>shift;
894 }
895
_PutPixel32(SDL_Surface * surface,Sint16 x,Sint16 y,Uint32 color)896 void _PutPixel32(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
897 {
898 *((Uint32 *)surface->pixels + y*surface->pitch/4 + x) = color;
899 }
900
_PutPixelX(SDL_Surface * dest,Sint16 x,Sint16 y,Uint32 color)901 void _PutPixelX(SDL_Surface *dest,Sint16 x,Sint16 y,Uint32 color)
902 {
903 switch (dest->format->BytesPerPixel)
904 {
905 case 1:
906 *((Uint8 *)dest->pixels + y*dest->pitch + x) = color;
907 break;
908
909 case 2:
910 *((Uint16 *)dest->pixels + y*dest->pitch/2 + x) = color;
911 break;
912
913 case 3:
914 _PutPixel24(dest,x,y,color);
915 break;
916
917 case 4:
918 *((Uint32 *)dest->pixels + y*dest->pitch/4 + x) = color;
919 break;
920 }
921 }
922
sge_PutPixel(SDL_Surface * surface,Sint16 x,Sint16 y,Uint32 color)923 void sge_PutPixel(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
924 {
925 if (SDL_MUSTLOCK(surface))
926 {
927 if (SDL_LockSurface(surface) < 0)
928 {
929 return;
930 }
931 }
932
933 _PutPixel(surface, x, y, color);
934
935 if (SDL_MUSTLOCK(surface))
936 {
937 SDL_UnlockSurface(surface);
938 }
939 }
940
sge_PutPixelRGB(SDL_Surface * surface,Sint16 x,Sint16 y,Uint8 r,Uint8 g,Uint8 b)941 void sge_PutPixelRGB(SDL_Surface *surface, Sint16 x, Sint16 y,
942 Uint8 r, Uint8 g, Uint8 b)
943 {
944 sge_PutPixel(surface, x, y, SDL_MapRGB(surface->format, r, g, b));
945 }
946
sge_CalcYPitch(SDL_Surface * dest,Sint16 y)947 Sint32 sge_CalcYPitch(SDL_Surface *dest, Sint16 y)
948 {
949 if (y >= 0 && y <= dest->h - 1)
950 {
951 switch (dest->format->BytesPerPixel)
952 {
953 case 1:
954 return y*dest->pitch;
955 break;
956
957 case 2:
958 return y*dest->pitch/2;
959 break;
960
961 case 3:
962 return y*dest->pitch;
963 break;
964
965 case 4:
966 return y*dest->pitch/4;
967 break;
968 }
969 }
970
971 return -1;
972 }
973
sge_pPutPixel(SDL_Surface * surface,Sint16 x,Sint32 ypitch,Uint32 color)974 void sge_pPutPixel(SDL_Surface *surface, Sint16 x, Sint32 ypitch, Uint32 color)
975 {
976 if (x >= 0 && x <= surface->w - 1 && ypitch >= 0)
977 {
978 switch (surface->format->BytesPerPixel)
979 {
980 case 1:
981 {
982 /* Assuming 8-bpp */
983 *((Uint8 *)surface->pixels + ypitch + x) = color;
984 }
985 break;
986
987 case 2:
988 {
989 /* Probably 15-bpp or 16-bpp */
990 *((Uint16 *)surface->pixels + ypitch + x) = color;
991 }
992 break;
993
994 case 3:
995 {
996 /* Slow 24-bpp mode, usually not used */
997 Uint8 *pix;
998 int shift;
999
1000 /* Gack - slow, but endian correct */
1001 pix = (Uint8 *)surface->pixels + ypitch + x*3;
1002 shift = surface->format->Rshift;
1003 *(pix+shift/8) = color>>shift;
1004 shift = surface->format->Gshift;
1005 *(pix+shift/8) = color>>shift;
1006 shift = surface->format->Bshift;
1007 *(pix+shift/8) = color>>shift;
1008 }
1009 break;
1010
1011 case 4:
1012 {
1013 /* Probably 32-bpp */
1014 *((Uint32 *)surface->pixels + ypitch + x) = color;
1015 }
1016 break;
1017 }
1018 }
1019 }
1020
sge_HLine(SDL_Surface * Surface,Sint16 x1,Sint16 x2,Sint16 y,Uint32 Color)1021 void sge_HLine(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y,
1022 Uint32 Color)
1023 {
1024 SDL_Rect l;
1025
1026 if (SDL_MUSTLOCK(Surface))
1027 {
1028 if (SDL_LockSurface(Surface) < 0)
1029 {
1030 return;
1031 }
1032 }
1033
1034 if (x1 > x2)
1035 {
1036 Sint16 tmp = x1;
1037 x1 = x2;
1038 x2 = tmp;
1039 }
1040
1041 /* Do the clipping */
1042 if (y < 0 || y > Surface->h - 1 || x1 > Surface->w - 1 || x2 < 0)
1043 return;
1044 if (x1 < 0)
1045 x1 = 0;
1046 if (x2 > Surface->w - 1)
1047 x2 = Surface->w - 1;
1048
1049 l.x = x1;
1050 l.y = y;
1051 l.w = x2 - x1 + 1;
1052 l.h = 1;
1053
1054 SDL_FillRect(Surface, &l, Color);
1055
1056 if (SDL_MUSTLOCK(Surface))
1057 {
1058 SDL_UnlockSurface(Surface);
1059 }
1060 }
1061
sge_HLineRGB(SDL_Surface * Surface,Sint16 x1,Sint16 x2,Sint16 y,Uint8 R,Uint8 G,Uint8 B)1062 void sge_HLineRGB(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y,
1063 Uint8 R, Uint8 G, Uint8 B)
1064 {
1065 sge_HLine(Surface, x1, x2, y, SDL_MapRGB(Surface->format, R, G, B));
1066 }
1067
_HLine(SDL_Surface * Surface,Sint16 x1,Sint16 x2,Sint16 y,Uint32 Color)1068 void _HLine(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y, Uint32 Color)
1069 {
1070 SDL_Rect l;
1071
1072 if (x1 > x2)
1073 {
1074 Sint16 tmp = x1;
1075 x1 = x2;
1076 x2 = tmp;
1077 }
1078
1079 /* Do the clipping */
1080 if (y < 0 || y > Surface->h - 1 || x1 > Surface->w - 1 || x2 < 0)
1081 return;
1082 if (x1 < 0)
1083 x1 = 0;
1084 if (x2 > Surface->w - 1)
1085 x2 = Surface->w - 1;
1086
1087 l.x = x1;
1088 l.y = y;
1089 l.w = x2 - x1 + 1;
1090 l.h = 1;
1091
1092 SDL_FillRect(Surface, &l, Color);
1093 }
1094
sge_VLine(SDL_Surface * Surface,Sint16 x,Sint16 y1,Sint16 y2,Uint32 Color)1095 void sge_VLine(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2,
1096 Uint32 Color)
1097 {
1098 SDL_Rect l;
1099
1100 if (SDL_MUSTLOCK(Surface))
1101 {
1102 if (SDL_LockSurface(Surface) < 0)
1103 {
1104 return;
1105 }
1106 }
1107
1108 if (y1 > y2)
1109 {
1110 Sint16 tmp = y1;
1111 y1 = y2;
1112 y2 = tmp;
1113 }
1114
1115 /* Do the clipping */
1116 if (x < 0 || x > Surface->w - 1 || y1 > Surface->h - 1 || y2 < 0)
1117 return;
1118 if (y1 < 0)
1119 y1 = 0;
1120 if (y2 > Surface->h - 1)
1121 y2 = Surface->h - 1;
1122
1123 l.x = x;
1124 l.y = y1;
1125 l.w = 1;
1126 l.h = y2 - y1 + 1;
1127
1128 SDL_FillRect(Surface, &l, Color);
1129
1130 if (SDL_MUSTLOCK(Surface))
1131 {
1132 SDL_UnlockSurface(Surface);
1133 }
1134 }
1135
sge_VLineRGB(SDL_Surface * Surface,Sint16 x,Sint16 y1,Sint16 y2,Uint8 R,Uint8 G,Uint8 B)1136 void sge_VLineRGB(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2,
1137 Uint8 R, Uint8 G, Uint8 B)
1138 {
1139 sge_VLine(Surface, x, y1, y2, SDL_MapRGB(Surface->format, R, G, B));
1140 }
1141
_VLine(SDL_Surface * Surface,Sint16 x,Sint16 y1,Sint16 y2,Uint32 Color)1142 void _VLine(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2, Uint32 Color)
1143 {
1144 SDL_Rect l;
1145
1146 if (y1 > y2)
1147 {
1148 Sint16 tmp = y1;
1149 y1 = y2;
1150 y2 = tmp;
1151 }
1152
1153 /* Do the clipping */
1154 if (x < 0 || x > Surface->w - 1 || y1 > Surface->h - 1 || y2 < 0)
1155 return;
1156 if (y1 < 0)
1157 y1 = 0;
1158 if (y2 > Surface->h - 1)
1159 y2 = Surface->h - 1;
1160
1161 l.x = x;
1162 l.y = y1;
1163 l.w = 1;
1164 l.h = y2 - y1 + 1;
1165
1166 SDL_FillRect(Surface, &l, Color);
1167 }
1168
sge_DoLine(SDL_Surface * Surface,Sint16 x1,Sint16 y1,Sint16 x2,Sint16 y2,Uint32 Color,void Callback (SDL_Surface * Surf,Sint16 X,Sint16 Y,Uint32 Color))1169 void sge_DoLine(SDL_Surface *Surface, Sint16 x1, Sint16 y1,
1170 Sint16 x2, Sint16 y2, Uint32 Color,
1171 void Callback(SDL_Surface *Surf, Sint16 X, Sint16 Y,
1172 Uint32 Color))
1173 {
1174 Sint16 dx, dy, sdx, sdy, x, y, px, py;
1175
1176 dx = x2 - x1;
1177 dy = y2 - y1;
1178
1179 sdx = (dx < 0) ? -1 : 1;
1180 sdy = (dy < 0) ? -1 : 1;
1181
1182 dx = sdx * dx + 1;
1183 dy = sdy * dy + 1;
1184
1185 x = y = 0;
1186
1187 px = x1;
1188 py = y1;
1189
1190 if (dx >= dy)
1191 {
1192 for (x = 0; x < dx; x++)
1193 {
1194 Callback(Surface, px, py, Color);
1195
1196 y += dy;
1197 if (y >= dx)
1198 {
1199 y -= dx;
1200 py += sdy;
1201 }
1202
1203 px += sdx;
1204 }
1205 }
1206 else
1207 {
1208 for (y = 0; y < dy; y++)
1209 {
1210 Callback(Surface, px, py, Color);
1211
1212 x += dx;
1213 if (x >= dy)
1214 {
1215 x -= dy;
1216 px += sdx;
1217 }
1218
1219 py += sdy;
1220 }
1221 }
1222 }
1223
sge_DoLineRGB(SDL_Surface * Surface,Sint16 X1,Sint16 Y1,Sint16 X2,Sint16 Y2,Uint8 R,Uint8 G,Uint8 B,void Callback (SDL_Surface * Surf,Sint16 X,Sint16 Y,Uint32 Color))1224 void sge_DoLineRGB(SDL_Surface *Surface, Sint16 X1, Sint16 Y1,
1225 Sint16 X2, Sint16 Y2, Uint8 R, Uint8 G, Uint8 B,
1226 void Callback(SDL_Surface *Surf, Sint16 X, Sint16 Y,
1227 Uint32 Color))
1228 {
1229 sge_DoLine(Surface, X1, Y1, X2, Y2,
1230 SDL_MapRGB(Surface->format, R, G, B), Callback);
1231 }
1232
sge_Line(SDL_Surface * Surface,Sint16 x1,Sint16 y1,Sint16 x2,Sint16 y2,Uint32 Color)1233 void sge_Line(SDL_Surface *Surface, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2,
1234 Uint32 Color)
1235 {
1236 if (SDL_MUSTLOCK(Surface))
1237 {
1238 if (SDL_LockSurface(Surface) < 0)
1239 return;
1240 }
1241
1242 /* Draw the line */
1243 sge_DoLine(Surface, x1, y1, x2, y2, Color, _PutPixel);
1244
1245 /* unlock the display */
1246 if (SDL_MUSTLOCK(Surface))
1247 {
1248 SDL_UnlockSurface(Surface);
1249 }
1250 }
1251
sge_LineRGB(SDL_Surface * Surface,Sint16 x1,Sint16 y1,Sint16 x2,Sint16 y2,Uint8 R,Uint8 G,Uint8 B)1252 void sge_LineRGB(SDL_Surface *Surface, Sint16 x1, Sint16 y1, Sint16 x2,
1253 Sint16 y2, Uint8 R, Uint8 G, Uint8 B)
1254 {
1255 sge_Line(Surface, x1, y1, x2, y2, SDL_MapRGB(Surface->format, R, G, B));
1256 }
1257
SDLPutPixel(Bitmap * dst_bitmap,int x,int y,Pixel pixel)1258 void SDLPutPixel(Bitmap *dst_bitmap, int x, int y, Pixel pixel)
1259 {
1260 if (dst_bitmap == backbuffer || dst_bitmap == window)
1261 {
1262 x += video_xoffset;
1263 y += video_yoffset;
1264 }
1265
1266 sge_PutPixel(dst_bitmap->surface, x, y, pixel);
1267 }
1268
1269
1270 /*
1271 -----------------------------------------------------------------------------
1272 quick (no, it's slow) and dirty hack to "invert" rectangle inside SDL surface
1273 -----------------------------------------------------------------------------
1274 */
1275
SDLInvertArea(Bitmap * bitmap,int src_x,int src_y,int width,int height,Uint32 color)1276 void SDLInvertArea(Bitmap *bitmap, int src_x, int src_y,
1277 int width, int height, Uint32 color)
1278 {
1279 int x, y;
1280
1281 for (y = src_y; y < src_y + height; y++)
1282 {
1283 for (x = src_x; x < src_x + width; x++)
1284 {
1285 Uint32 pixel = SDLGetPixel(bitmap, x, y);
1286
1287 SDLPutPixel(bitmap, x, y, pixel == BLACK_PIXEL ? color : BLACK_PIXEL);
1288 }
1289 }
1290 }
1291
SDLCopyInverseMasked(Bitmap * src_bitmap,Bitmap * dst_bitmap,int src_x,int src_y,int width,int height,int dst_x,int dst_y)1292 void SDLCopyInverseMasked(Bitmap *src_bitmap, Bitmap *dst_bitmap,
1293 int src_x, int src_y, int width, int height,
1294 int dst_x, int dst_y)
1295 {
1296 int x, y;
1297
1298 for (y = 0; y < height; y++)
1299 {
1300 for (x = 0; x < width; x++)
1301 {
1302 Uint32 pixel = SDLGetPixel(src_bitmap, src_x + x, src_y + y);
1303
1304 if (pixel != BLACK_PIXEL)
1305 SDLPutPixel(dst_bitmap, dst_x + x, dst_y + y, BLACK_PIXEL);
1306 }
1307 }
1308 }
1309
1310
1311 /* ========================================================================= */
1312 /* The following functions were taken from the SDL_gfx library version 2.0.3 */
1313 /* (Rotozoomer) by Andreas Schiffler */
1314 /* http://www.ferzkopp.net/Software/SDL_gfx-2.0/index.html */
1315 /* ========================================================================= */
1316
1317 /*
1318 -----------------------------------------------------------------------------
1319 32 bit zoomer
1320
1321 zoomes 32bit RGBA/ABGR 'src' surface to 'dst' surface.
1322 -----------------------------------------------------------------------------
1323 */
1324
1325 typedef struct
1326 {
1327 Uint8 r;
1328 Uint8 g;
1329 Uint8 b;
1330 Uint8 a;
1331 } tColorRGBA;
1332
zoomSurfaceRGBA_scaleDownBy2(SDL_Surface * src,SDL_Surface * dst)1333 int zoomSurfaceRGBA_scaleDownBy2(SDL_Surface *src, SDL_Surface *dst)
1334 {
1335 int x, y;
1336 tColorRGBA *sp, *csp, *dp;
1337 #if 0
1338 int sgap;
1339 #endif
1340 int dgap;
1341
1342 /* pointer setup */
1343 sp = csp = (tColorRGBA *) src->pixels;
1344 dp = (tColorRGBA *) dst->pixels;
1345 #if 0
1346 sgap = src->pitch - src->w * 4;
1347 #endif
1348 dgap = dst->pitch - dst->w * 4;
1349
1350 for (y = 0; y < dst->h; y++)
1351 {
1352 sp = csp;
1353
1354 for (x = 0; x < dst->w; x++)
1355 {
1356 tColorRGBA *sp0 = sp;
1357 tColorRGBA *sp1 = (tColorRGBA *) ((Uint8 *) sp + src->pitch);
1358 tColorRGBA *sp00 = &sp0[0];
1359 tColorRGBA *sp01 = &sp0[1];
1360 tColorRGBA *sp10 = &sp1[0];
1361 tColorRGBA *sp11 = &sp1[1];
1362 tColorRGBA new;
1363
1364 /* create new color pixel from all four source color pixels */
1365 new.r = (sp00->r + sp01->r + sp10->r + sp11->r) / 4;
1366 new.g = (sp00->g + sp01->g + sp10->g + sp11->g) / 4;
1367 new.b = (sp00->b + sp01->b + sp10->b + sp11->b) / 4;
1368 new.a = (sp00->a + sp01->a + sp10->a + sp11->a) / 4;
1369
1370 /* draw */
1371 *dp = new;
1372
1373 /* advance source pointers */
1374 sp += 2;
1375
1376 /* advance destination pointer */
1377 dp++;
1378 }
1379
1380 /* advance source pointer */
1381 csp = (tColorRGBA *) ((Uint8 *) csp + 2 * src->pitch);
1382
1383 /* advance destination pointers */
1384 dp = (tColorRGBA *) ((Uint8 *) dp + dgap);
1385 }
1386
1387 return 0;
1388 }
1389
zoomSurfaceRGBA(SDL_Surface * src,SDL_Surface * dst)1390 int zoomSurfaceRGBA(SDL_Surface *src, SDL_Surface *dst)
1391 {
1392 int x, y, sx, sy, *sax, *say, *csax, *csay, csx, csy;
1393 tColorRGBA *sp, *csp, *dp;
1394 #if 0
1395 int sgap;
1396 #endif
1397 int dgap;
1398
1399 /* use specialized zoom function when scaling down to exactly half size */
1400 if (src->w == 2 * dst->w &&
1401 src->h == 2 * dst->h)
1402 return zoomSurfaceRGBA_scaleDownBy2(src, dst);
1403
1404 /* variable setup */
1405 sx = (int) (65536.0 * (float) src->w / (float) dst->w);
1406 sy = (int) (65536.0 * (float) src->h / (float) dst->h);
1407
1408 /* allocate memory for row increments */
1409 sax = (int *)checked_malloc((dst->w + 1) * sizeof(Uint32));
1410 say = (int *)checked_malloc((dst->h + 1) * sizeof(Uint32));
1411
1412 /* precalculate row increments */
1413 csx = 0;
1414 csax = sax;
1415 for (x = 0; x <= dst->w; x++)
1416 {
1417 *csax = csx;
1418 csax++;
1419 csx &= 0xffff;
1420 csx += sx;
1421 }
1422
1423 csy = 0;
1424 csay = say;
1425 for (y = 0; y <= dst->h; y++)
1426 {
1427 *csay = csy;
1428 csay++;
1429 csy &= 0xffff;
1430 csy += sy;
1431 }
1432
1433 /* pointer setup */
1434 sp = csp = (tColorRGBA *) src->pixels;
1435 dp = (tColorRGBA *) dst->pixels;
1436 #if 0
1437 sgap = src->pitch - src->w * 4;
1438 #endif
1439 dgap = dst->pitch - dst->w * 4;
1440
1441 csay = say;
1442 for (y = 0; y < dst->h; y++)
1443 {
1444 sp = csp;
1445 csax = sax;
1446
1447 for (x = 0; x < dst->w; x++)
1448 {
1449 /* draw */
1450 *dp = *sp;
1451
1452 /* advance source pointers */
1453 csax++;
1454 sp += (*csax >> 16);
1455
1456 /* advance destination pointer */
1457 dp++;
1458 }
1459
1460 /* advance source pointer */
1461 csay++;
1462 csp = (tColorRGBA *) ((Uint8 *) csp + (*csay >> 16) * src->pitch);
1463
1464 /* advance destination pointers */
1465 dp = (tColorRGBA *) ((Uint8 *) dp + dgap);
1466 }
1467
1468 free(sax);
1469 free(say);
1470
1471 return 0;
1472 }
1473
1474 /*
1475 -----------------------------------------------------------------------------
1476 8 bit zoomer
1477
1478 zoomes 8 bit palette/Y 'src' surface to 'dst' surface
1479 -----------------------------------------------------------------------------
1480 */
1481
zoomSurfaceY(SDL_Surface * src,SDL_Surface * dst)1482 int zoomSurfaceY(SDL_Surface * src, SDL_Surface * dst)
1483 {
1484 Uint32 x, y, sx, sy, *sax, *say, *csax, *csay, csx, csy;
1485 Uint8 *sp, *dp, *csp;
1486 int dgap;
1487
1488 /* variable setup */
1489 sx = (Uint32) (65536.0 * (float) src->w / (float) dst->w);
1490 sy = (Uint32) (65536.0 * (float) src->h / (float) dst->h);
1491
1492 /* allocate memory for row increments */
1493 sax = (Uint32 *)checked_malloc(dst->w * sizeof(Uint32));
1494 say = (Uint32 *)checked_malloc(dst->h * sizeof(Uint32));
1495
1496 /* precalculate row increments */
1497 csx = 0;
1498 csax = sax;
1499 for (x = 0; x < dst->w; x++)
1500 {
1501 csx += sx;
1502 *csax = (csx >> 16);
1503 csx &= 0xffff;
1504 csax++;
1505 }
1506
1507 csy = 0;
1508 csay = say;
1509 for (y = 0; y < dst->h; y++)
1510 {
1511 csy += sy;
1512 *csay = (csy >> 16);
1513 csy &= 0xffff;
1514 csay++;
1515 }
1516
1517 csx = 0;
1518 csax = sax;
1519 for (x = 0; x < dst->w; x++)
1520 {
1521 csx += (*csax);
1522 csax++;
1523 }
1524
1525 csy = 0;
1526 csay = say;
1527 for (y = 0; y < dst->h; y++)
1528 {
1529 csy += (*csay);
1530 csay++;
1531 }
1532
1533 /* pointer setup */
1534 sp = csp = (Uint8 *) src->pixels;
1535 dp = (Uint8 *) dst->pixels;
1536 dgap = dst->pitch - dst->w;
1537
1538 /* draw */
1539 csay = say;
1540 for (y = 0; y < dst->h; y++)
1541 {
1542 csax = sax;
1543 sp = csp;
1544 for (x = 0; x < dst->w; x++)
1545 {
1546 /* draw */
1547 *dp = *sp;
1548
1549 /* advance source pointers */
1550 sp += (*csax);
1551 csax++;
1552
1553 /* advance destination pointer */
1554 dp++;
1555 }
1556
1557 /* advance source pointer (for row) */
1558 csp += ((*csay) * src->pitch);
1559 csay++;
1560
1561 /* advance destination pointers */
1562 dp += dgap;
1563 }
1564
1565 free(sax);
1566 free(say);
1567
1568 return 0;
1569 }
1570
1571 /*
1572 -----------------------------------------------------------------------------
1573 zoomSurface()
1574
1575 Zooms a 32bit or 8bit 'src' surface to newly created 'dst' surface.
1576 'zoomx' and 'zoomy' are scaling factors for width and height.
1577 If the surface is not 8bit or 32bit RGBA/ABGR it will be converted
1578 into a 32bit RGBA format on the fly.
1579 -----------------------------------------------------------------------------
1580 */
1581
zoomSurface(SDL_Surface * src,int dst_width,int dst_height)1582 SDL_Surface *zoomSurface(SDL_Surface *src, int dst_width, int dst_height)
1583 {
1584 SDL_Surface *zoom_src = NULL;
1585 SDL_Surface *zoom_dst = NULL;
1586 boolean is_converted = FALSE;
1587 boolean is_32bit;
1588 int i;
1589
1590 if (src == NULL)
1591 return NULL;
1592
1593 /* determine if source surface is 32 bit or 8 bit */
1594 is_32bit = (src->format->BitsPerPixel == 32);
1595
1596 if (is_32bit || src->format->BitsPerPixel == 8)
1597 {
1598 /* use source surface 'as is' */
1599 zoom_src = src;
1600 }
1601 else
1602 {
1603 /* new source surface is 32 bit with a defined RGB ordering */
1604 zoom_src = SDL_CreateRGBSurface(SDL_SWSURFACE, src->w, src->h, 32,
1605 0x000000ff, 0x0000ff00, 0x00ff0000, 0);
1606 SDL_BlitSurface(src, NULL, zoom_src, NULL);
1607 is_32bit = TRUE;
1608 is_converted = TRUE;
1609 }
1610
1611 /* allocate surface to completely contain the zoomed surface */
1612 if (is_32bit)
1613 {
1614 /* target surface is 32 bit with source RGBA/ABGR ordering */
1615 zoom_dst = SDL_CreateRGBSurface(SDL_SWSURFACE, dst_width, dst_height, 32,
1616 zoom_src->format->Rmask,
1617 zoom_src->format->Gmask,
1618 zoom_src->format->Bmask, 0);
1619 }
1620 else
1621 {
1622 /* target surface is 8 bit */
1623 zoom_dst = SDL_CreateRGBSurface(SDL_SWSURFACE, dst_width, dst_height, 8,
1624 0, 0, 0, 0);
1625 }
1626
1627 /* lock source surface */
1628 SDL_LockSurface(zoom_src);
1629
1630 /* check which kind of surface we have */
1631 if (is_32bit)
1632 {
1633 /* call the 32 bit transformation routine to do the zooming */
1634 zoomSurfaceRGBA(zoom_src, zoom_dst);
1635 }
1636 else
1637 {
1638 /* copy palette */
1639 for (i = 0; i < zoom_src->format->palette->ncolors; i++)
1640 zoom_dst->format->palette->colors[i] =
1641 zoom_src->format->palette->colors[i];
1642 zoom_dst->format->palette->ncolors = zoom_src->format->palette->ncolors;
1643
1644 /* call the 8 bit transformation routine to do the zooming */
1645 zoomSurfaceY(zoom_src, zoom_dst);
1646 }
1647
1648 /* unlock source surface */
1649 SDL_UnlockSurface(zoom_src);
1650
1651 /* free temporary surface */
1652 if (is_converted)
1653 SDL_FreeSurface(zoom_src);
1654
1655 /* return destination surface */
1656 return zoom_dst;
1657 }
1658
SDLZoomBitmap(Bitmap * src_bitmap,Bitmap * dst_bitmap)1659 void SDLZoomBitmap(Bitmap *src_bitmap, Bitmap *dst_bitmap)
1660 {
1661 SDL_Surface *sdl_surface_tmp;
1662 int dst_width = dst_bitmap->width;
1663 int dst_height = dst_bitmap->height;
1664
1665 /* throw away old destination surface */
1666 SDL_FreeSurface(dst_bitmap->surface);
1667
1668 /* create zoomed temporary surface from source surface */
1669 sdl_surface_tmp = zoomSurface(src_bitmap->surface, dst_width, dst_height);
1670
1671 /* create native format destination surface from zoomed temporary surface */
1672 dst_bitmap->surface = SDL_DisplayFormat(sdl_surface_tmp);
1673
1674 /* free temporary surface */
1675 SDL_FreeSurface(sdl_surface_tmp);
1676 }
1677
1678
1679 /* ========================================================================= */
1680 /* load image to bitmap */
1681 /* ========================================================================= */
1682
SDLLoadImage(char * filename)1683 Bitmap *SDLLoadImage(char *filename)
1684 {
1685 Bitmap *new_bitmap = CreateBitmapStruct();
1686 SDL_Surface *sdl_image_tmp;
1687
1688 /* load image to temporary surface */
1689 if ((sdl_image_tmp = IMG_Load(filename)) == NULL)
1690 {
1691 SetError("IMG_Load(): %s", SDL_GetError());
1692
1693 return NULL;
1694 }
1695
1696 UPDATE_BUSY_STATE();
1697
1698 /* create native non-transparent surface for current image */
1699 if ((new_bitmap->surface = SDL_DisplayFormat(sdl_image_tmp)) == NULL)
1700 {
1701 SetError("SDL_DisplayFormat(): %s", SDL_GetError());
1702
1703 return NULL;
1704 }
1705
1706 UPDATE_BUSY_STATE();
1707
1708 /* create native transparent surface for current image */
1709 SDL_SetColorKey(sdl_image_tmp, SDL_SRCCOLORKEY,
1710 SDL_MapRGB(sdl_image_tmp->format, 0x00, 0x00, 0x00));
1711 if ((new_bitmap->surface_masked = SDL_DisplayFormat(sdl_image_tmp)) == NULL)
1712 {
1713 SetError("SDL_DisplayFormat(): %s", SDL_GetError());
1714
1715 return NULL;
1716 }
1717
1718 UPDATE_BUSY_STATE();
1719
1720 /* free temporary surface */
1721 SDL_FreeSurface(sdl_image_tmp);
1722
1723 new_bitmap->width = new_bitmap->surface->w;
1724 new_bitmap->height = new_bitmap->surface->h;
1725
1726 return new_bitmap;
1727 }
1728
1729
1730 /* ------------------------------------------------------------------------- */
1731 /* custom cursor fuctions */
1732 /* ------------------------------------------------------------------------- */
1733
create_cursor(struct MouseCursorInfo * cursor_info)1734 static SDL_Cursor *create_cursor(struct MouseCursorInfo *cursor_info)
1735 {
1736 return SDL_CreateCursor(cursor_info->data, cursor_info->mask,
1737 cursor_info->width, cursor_info->height,
1738 cursor_info->hot_x, cursor_info->hot_y);
1739 }
1740
SDLSetMouseCursor(struct MouseCursorInfo * cursor_info)1741 void SDLSetMouseCursor(struct MouseCursorInfo *cursor_info)
1742 {
1743 static struct MouseCursorInfo *last_cursor_info = NULL;
1744 static struct MouseCursorInfo *last_cursor_info2 = NULL;
1745 static SDL_Cursor *cursor_default = NULL;
1746 static SDL_Cursor *cursor_current = NULL;
1747
1748 /* if invoked for the first time, store the SDL default cursor */
1749 if (cursor_default == NULL)
1750 cursor_default = SDL_GetCursor();
1751
1752 /* only create new cursor if cursor info (custom only) has changed */
1753 if (cursor_info != NULL && cursor_info != last_cursor_info)
1754 {
1755 cursor_current = create_cursor(cursor_info);
1756 last_cursor_info = cursor_info;
1757 }
1758
1759 /* only set new cursor if cursor info (custom or NULL) has changed */
1760 if (cursor_info != last_cursor_info2)
1761 SDL_SetCursor(cursor_info ? cursor_current : cursor_default);
1762
1763 last_cursor_info2 = cursor_info;
1764 }
1765
1766
1767 /* ========================================================================= */
1768 /* audio functions */
1769 /* ========================================================================= */
1770
SDLOpenAudio(void)1771 void SDLOpenAudio(void)
1772 {
1773 if (!strEqual(setup.system.sdl_audiodriver, ARG_DEFAULT))
1774 SDL_putenv(getStringCat2("SDL_AUDIODRIVER=", setup.system.sdl_audiodriver));
1775
1776 if (SDL_InitSubSystem(SDL_INIT_AUDIO) < 0)
1777 {
1778 Error(ERR_WARN, "SDL_InitSubSystem() failed: %s", SDL_GetError());
1779 return;
1780 }
1781
1782 if (Mix_OpenAudio(DEFAULT_AUDIO_SAMPLE_RATE, MIX_DEFAULT_FORMAT,
1783 AUDIO_NUM_CHANNELS_STEREO,
1784 setup.system.audio_fragment_size) < 0)
1785 {
1786 Error(ERR_WARN, "Mix_OpenAudio() failed: %s", SDL_GetError());
1787 return;
1788 }
1789
1790 audio.sound_available = TRUE;
1791 audio.music_available = TRUE;
1792 audio.loops_available = TRUE;
1793 audio.sound_enabled = TRUE;
1794
1795 /* set number of available mixer channels */
1796 audio.num_channels = Mix_AllocateChannels(NUM_MIXER_CHANNELS);
1797 audio.music_channel = MUSIC_CHANNEL;
1798 audio.first_sound_channel = FIRST_SOUND_CHANNEL;
1799
1800 Mixer_InitChannels();
1801 }
1802
SDLCloseAudio(void)1803 void SDLCloseAudio(void)
1804 {
1805 Mix_HaltMusic();
1806 Mix_HaltChannel(-1);
1807
1808 Mix_CloseAudio();
1809 SDL_QuitSubSystem(SDL_INIT_AUDIO);
1810 }
1811
1812
1813 /* ========================================================================= */
1814 /* event functions */
1815 /* ========================================================================= */
1816
SDLNextEvent(Event * event)1817 void SDLNextEvent(Event *event)
1818 {
1819 SDL_WaitEvent(event);
1820
1821 if (event->type == EVENT_BUTTONPRESS ||
1822 event->type == EVENT_BUTTONRELEASE)
1823 {
1824 if (((ButtonEvent *)event)->x > video_xoffset)
1825 ((ButtonEvent *)event)->x -= video_xoffset;
1826 else
1827 ((ButtonEvent *)event)->x = 0;
1828 if (((ButtonEvent *)event)->y > video_yoffset)
1829 ((ButtonEvent *)event)->y -= video_yoffset;
1830 else
1831 ((ButtonEvent *)event)->y = 0;
1832 }
1833 else if (event->type == EVENT_MOTIONNOTIFY)
1834 {
1835 if (((MotionEvent *)event)->x > video_xoffset)
1836 ((MotionEvent *)event)->x -= video_xoffset;
1837 else
1838 ((MotionEvent *)event)->x = 0;
1839 if (((MotionEvent *)event)->y > video_yoffset)
1840 ((MotionEvent *)event)->y -= video_yoffset;
1841 else
1842 ((MotionEvent *)event)->y = 0;
1843 }
1844 }
1845
SDLHandleWindowManagerEvent(Event * event)1846 void SDLHandleWindowManagerEvent(Event *event)
1847 {
1848 #if defined(PLATFORM_WIN32)
1849 SDL_SysWMEvent *syswmevent = (SDL_SysWMEvent *)event;
1850 SDL_SysWMmsg *syswmmsg = (SDL_SysWMmsg *)(syswmevent->msg);
1851
1852 if (syswmmsg->msg == WM_DROPFILES)
1853 {
1854 HDROP hdrop = (HDROP)syswmmsg->wParam;
1855 int i, num_files;
1856
1857 printf("::: SDL_SYSWMEVENT:\n");
1858
1859 num_files = DragQueryFile(hdrop, 0xffffffff, NULL, 0);
1860
1861 for (i = 0; i < num_files; i++)
1862 {
1863 int buffer_len = DragQueryFile(hdrop, i, NULL, 0);
1864 char buffer[buffer_len + 1];
1865
1866 DragQueryFile(hdrop, i, buffer, buffer_len + 1);
1867
1868 printf("::: - '%s'\n", buffer);
1869 }
1870
1871 DragFinish((HDROP)syswmmsg->wParam);
1872 }
1873 #endif
1874 }
1875
1876
1877 /* ========================================================================= */
1878 /* joystick functions */
1879 /* ========================================================================= */
1880
1881 static SDL_Joystick *sdl_joystick[MAX_PLAYERS] = { NULL, NULL, NULL, NULL };
1882 static int sdl_js_axis[MAX_PLAYERS][2] = { {0, 0}, {0, 0}, {0, 0}, {0, 0} };
1883 static int sdl_js_button[MAX_PLAYERS][2] = { {0, 0}, {0, 0}, {0, 0}, {0, 0} };
1884
SDLOpenJoystick(int nr)1885 static boolean SDLOpenJoystick(int nr)
1886 {
1887 if (nr < 0 || nr > MAX_PLAYERS)
1888 return FALSE;
1889
1890 return ((sdl_joystick[nr] = SDL_JoystickOpen(nr)) == NULL ? FALSE : TRUE);
1891 }
1892
SDLCloseJoystick(int nr)1893 static void SDLCloseJoystick(int nr)
1894 {
1895 if (nr < 0 || nr > MAX_PLAYERS)
1896 return;
1897
1898 SDL_JoystickClose(sdl_joystick[nr]);
1899 }
1900
SDLCheckJoystickOpened(int nr)1901 static boolean SDLCheckJoystickOpened(int nr)
1902 {
1903 if (nr < 0 || nr > MAX_PLAYERS)
1904 return FALSE;
1905
1906 return (SDL_JoystickOpened(nr) ? TRUE : FALSE);
1907 }
1908
HandleJoystickEvent(Event * event)1909 void HandleJoystickEvent(Event *event)
1910 {
1911 switch(event->type)
1912 {
1913 case SDL_JOYAXISMOTION:
1914 if (event->jaxis.axis < 2)
1915 sdl_js_axis[event->jaxis.which][event->jaxis.axis]= event->jaxis.value;
1916 break;
1917
1918 case SDL_JOYBUTTONDOWN:
1919 if (event->jbutton.button < 2)
1920 sdl_js_button[event->jbutton.which][event->jbutton.button] = TRUE;
1921 break;
1922
1923 case SDL_JOYBUTTONUP:
1924 if (event->jbutton.button < 2)
1925 sdl_js_button[event->jbutton.which][event->jbutton.button] = FALSE;
1926 break;
1927
1928 default:
1929 break;
1930 }
1931 }
1932
SDLInitJoysticks()1933 void SDLInitJoysticks()
1934 {
1935 static boolean sdl_joystick_subsystem_initialized = FALSE;
1936 boolean print_warning = !sdl_joystick_subsystem_initialized;
1937 int i;
1938
1939 if (!sdl_joystick_subsystem_initialized)
1940 {
1941 sdl_joystick_subsystem_initialized = TRUE;
1942
1943 if (SDL_Init(SDL_INIT_JOYSTICK) < 0)
1944 {
1945 Error(ERR_EXIT, "SDL_Init() failed: %s", SDL_GetError());
1946 return;
1947 }
1948 }
1949
1950 for (i = 0; i < MAX_PLAYERS; i++)
1951 {
1952 /* get configured joystick for this player */
1953 char *device_name = setup.input[i].joy.device_name;
1954 int joystick_nr = getJoystickNrFromDeviceName(device_name);
1955
1956 if (joystick_nr >= SDL_NumJoysticks())
1957 {
1958 if (setup.input[i].use_joystick && print_warning)
1959 Error(ERR_WARN, "cannot find joystick %d", joystick_nr);
1960
1961 joystick_nr = -1;
1962 }
1963
1964 /* misuse joystick file descriptor variable to store joystick number */
1965 joystick.fd[i] = joystick_nr;
1966
1967 if (joystick_nr == -1)
1968 continue;
1969
1970 /* this allows subsequent calls to 'InitJoysticks' for re-initialization */
1971 if (SDLCheckJoystickOpened(joystick_nr))
1972 SDLCloseJoystick(joystick_nr);
1973
1974 if (!setup.input[i].use_joystick)
1975 continue;
1976
1977 if (!SDLOpenJoystick(joystick_nr))
1978 {
1979 if (print_warning)
1980 Error(ERR_WARN, "cannot open joystick %d", joystick_nr);
1981
1982 continue;
1983 }
1984
1985 joystick.status = JOYSTICK_ACTIVATED;
1986 }
1987 }
1988
SDLReadJoystick(int nr,int * x,int * y,boolean * b1,boolean * b2)1989 boolean SDLReadJoystick(int nr, int *x, int *y, boolean *b1, boolean *b2)
1990 {
1991 if (nr < 0 || nr >= MAX_PLAYERS)
1992 return FALSE;
1993
1994 if (x != NULL)
1995 *x = sdl_js_axis[nr][0];
1996 if (y != NULL)
1997 *y = sdl_js_axis[nr][1];
1998
1999 if (b1 != NULL)
2000 *b1 = sdl_js_button[nr][0];
2001 if (b2 != NULL)
2002 *b2 = sdl_js_button[nr][1];
2003
2004 return TRUE;
2005 }
2006
2007 #endif /* TARGET_SDL */
2008