1 /**
2 * Graphics
3
4 * Copyright (C) 2007, 2008, 2009 Sylvain Beucler
5
6 * This file is part of GNU FreeDink
7
8 * GNU FreeDink is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License as
10 * published by the Free Software Foundation; either version 3 of the
11 * License, or (at your option) any later version.
12
13 * GNU FreeDink is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * General Public License for more details.
17
18 * You should have received a copy of the GNU General Public License
19 * along with this program. If not, see
20 * <http://www.gnu.org/licenses/>.
21 */
22
23 #ifdef HAVE_CONFIG_H
24 #include <config.h>
25 #endif
26
27 #include <stdlib.h> /* putenv */
28 #include <string.h>
29 #include <math.h>
30
31 #include "SDL.h"
32 #include "SDL_image.h"
33 #include "SDL_rotozoom.h"
34
35 #include "freedink_xpm.h"
36 #include "io_util.h"
37 #include "gfx.h"
38 #include "gfx_fade.h"
39 #include "gfx_fonts.h"
40 #include "gfx_palette.h"
41 #include "gfx_sprites.h"
42 #include "gfx_tiles.h"
43 #include "init.h"
44 #include "paths.h"
45 #include "log.h"
46
47
48 /* Is the screen depth more than 8bit? */
49 int truecolor = 0;
50
51 // // DELETEME
52 // LPDIRECTDRAW lpDD = NULL; // DirectDraw object
53 // //LPDIxRECTDRAWSURFACE lpDDSOne; // Offscreen surface 1
54
55 // LPDIRECTDRAWSURFACE lpDDSPrimary = NULL; // DirectDraw primary surface
56 // LPDIRECTDRAWSURFACE lpDDSBack = NULL; // DirectDraw back surface
57
58 // LPDIRECTDRAWSURFACE lpDDSTwo = NULL; // Offscreen surface 2
59 // LPDIRECTDRAWSURFACE lpDDSTrick = NULL; // Offscreen surface 2
60 // LPDIRECTDRAWSURFACE lpDDSTrick2 = NULL; // Offscreen surface 2
61
62
63 SDL_Surface *GFX_lpDDSBack = NULL; /* Backbuffer and link to physical
64 screen*/
65
66 /* GFX_lpDDSTwo: holds the base scene */
67 /* Rationale attempt :*/
68 /* lpDDSTwo contains the background, which is reused for each new
69 frame. It is overwritten when switching to another screen. However,
70 it can change during a screen: 1) animated tiles (water & fire) 2)
71 when a sprite is written on the background (eg when an enemy dies)
72 3) with various hacks such as fill_screen() (and maybe
73 copy_bmp_to_screen()). */
74 /* Those changes may conflict with each other (eg: an animated tile
75 overwrites half the carcass of a dead enemy). We might want to fix
76 that. */
77 /* After the background is done, all the other operations are applied
78 on lpDDSBack, the double buffer which is directly used by the
79 physical screen. */
80 SDL_Surface *GFX_lpDDSTwo = NULL;
81
82 /* Beuc: apparently used for the scrolling screen transition and more
83 generaly as temporary buffers. Only used by the game, not the
84 editor. */
85 /* Used in freedink.cpp only + as a local/independent temporary buffer
86 in show_bmp©_bmp&process_show_bmp&load_sprite* */
87 SDL_Surface *GFX_lpDDSTrick = NULL;
88 /* Used in freedink.cpp and update_frame.cpp */
89 SDL_Surface *GFX_lpDDSTrick2 = NULL;
90
91
92 /* Reference palette: this is the canonical Dink palette, loaded from
93 TS01.bmp (for freedink) and esplash.bmp (for freedinkedit). The
94 physical screen may be changed (e.g. show_bmp()), but this
95 canonical palette will stay constant. */
96 /* PALETTEENTRY real_pal[256]; */
97 SDL_Color GFX_real_pal[256];
98
99
100 /* True color fade in [0,256]; 0 is completely dark, 256 is unaltered */
101 double truecolor_fade_brightness = 256;
102 /* Time elapsed since last fade computation; -1 is disabled */
103 Uint32 truecolor_fade_lasttick = -1;
104
105
106 static int cur_video_flags = 0;
107
108 /**
109 * Check if the graphics system is initialized, so we know if we can
110 * use it to display error messages to the user
111 */
112 static enum gfx_init_state init_state = GFX_NOT_INITIALIZED;
gfx_get_init_state()113 enum gfx_init_state gfx_get_init_state()
114 {
115 return init_state;
116 }
117
118
gfx_dumpflags(Uint32 flags)119 void gfx_dumpflags(Uint32 flags)
120 {
121 char buf[256]; // enough to display all flags
122
123 sprintf(buf, "0x%8.8x", flags);
124
125 strcat(buf, " ");
126 char c[2] = "x";
127 int i = 32-1;
128 for (; i >= 0; i--)
129 {
130 unsigned int b = flags >> i;
131 c[0] = '0' + (b & 0x1);
132 strcat(buf, c);
133 }
134
135 if (flags & SDL_HWSURFACE)
136 strcat(buf, " SDL_HWSURFACE");
137 else
138 strcat(buf, " SDL_SWSURFACE");
139
140 if (flags & SDL_HWPALETTE)
141 strcat(buf, " | SDL_HWPALETTE");
142
143 if (flags & SDL_FULLSCREEN)
144 strcat(buf, " | SDL_FULLSCREEN");
145
146 if (flags & SDL_DOUBLEBUF)
147 strcat(buf, " | SDL_DOUBLEBUF");
148
149 if (flags & SDL_SRCCOLORKEY)
150 strcat(buf, " | SDL_SRCCOLORKEY");
151
152 if (flags & SDL_SRCALPHA)
153 strcat(buf, " | SDL_SRCALPHA");
154
155 if (flags & SDL_RLEACCEL)
156 strcat(buf, " | SDL_RLEACCEL");
157
158 if (flags & SDL_RLEACCELOK)
159 strcat(buf, " | SDL_RLEACCELOK");
160
161 log_info(buf);
162 }
163
164 /**
165 * Graphics subsystem initalization
166 */
gfx_init(enum gfx_windowed_state windowed,char * splash_path)167 int gfx_init(enum gfx_windowed_state windowed, char* splash_path)
168 {
169 /* Initialization in progress */
170 init_state = GFX_INITIALIZING_VIDEO;
171
172 /* Init graphics subsystem */
173 if (SDL_WasInit(SDL_INIT_VIDEO) == 0 && SDL_InitSubSystem(SDL_INIT_VIDEO) == -1)
174 {
175 init_set_error_msg("Video initialization error: %s", SDL_GetError());
176 return -1;
177 }
178
179 const SDL_VideoInfo* info = SDL_GetVideoInfo();
180
181 if (info->wm_available)
182 {
183 SDL_Surface *icon = NULL;
184 SDL_WM_SetCaption(PACKAGE_STRING, NULL);
185
186 if ((icon = IMG_ReadXPMFromArray(freedink_xpm)) == NULL)
187 {
188 log_error("Error loading icon: %s", IMG_GetError());
189 }
190 else
191 {
192 SDL_WM_SetIcon(icon, NULL);
193 SDL_FreeSurface(icon);
194 }
195 }
196
197
198 /* SDL_HWSURFACE gives direct 2D memory access if that's possible */
199 /* SDL_DOUBLEBUF is supposed to enable hardware double-buffering
200 and is a pre-requisite for SDL_Flip to use hardware, see
201 http://www.libsdl.org/cgi/docwiki.cgi/FAQ_20Hardware_20Surfaces_20Flickering */
202 int flags = SDL_HWSURFACE | SDL_DOUBLEBUF;
203
204 if (windowed != GFX_WINDOWED)
205 flags |= SDL_FULLSCREEN;
206
207
208 int bits_per_pixel = 8;
209 if (truecolor)
210 {
211 /* Recommended depth: */
212 log_info("Recommended depth is %d", info->vfmt->BitsPerPixel);
213 bits_per_pixel = info->vfmt->BitsPerPixel;
214
215 if (bits_per_pixel < 15)
216 {
217 /* Running truecolor mode in 8bit resolution? Let's emulate,
218 the user must know what he's doing. */
219 bits_per_pixel = 15;
220 log_info("Emulating truecolor mode within 8bit mode");
221 }
222 }
223 else
224 {
225 /* SDL_HWPALETTE makes sure we can use all the colors we need
226 (override system palette reserved colors?) */
227 flags |= SDL_HWPALETTE;
228 }
229 log_info("Requesting depth %d", bits_per_pixel);
230
231 putenv("SDL_VIDEO_CENTERED=1");
232 putenv("SDL_ASPECT_RATIO=4:3"); /* used by PSP to keep aspect ratio */
233 if (GFX_lpDDSBack == NULL)
234 {
235 /* Hardware mode */
236 log_info("Requesting video flags: "); gfx_dumpflags(flags);
237 GFX_lpDDSBack = SDL_SetVideoMode(640, 480, bits_per_pixel, flags);
238 if (GFX_lpDDSBack == NULL)
239 log_warn("Unable to use hardware mode: %s", SDL_GetError());
240 }
241 if (GFX_lpDDSBack == NULL)
242 {
243 /* Software mode - in theory SDL automatically fallbacks to
244 software mode if hardware mode isn't available, but some
245 architectures need to do it explicitely, e.g. PSP's
246 640x480stretch mode that only work with
247 SDL_SWSURFACE|SDL_FULLSCREEN */
248 flags &= ~SDL_HWSURFACE;
249 flags &= ~SDL_DOUBLEBUF;
250 flags |= SDL_SWSURFACE;
251 log_info("Requesting video flags: "); gfx_dumpflags(flags);
252 GFX_lpDDSBack = SDL_SetVideoMode(640, 480, bits_per_pixel, flags);
253 if (GFX_lpDDSBack == NULL)
254 log_error("Unable to use software fullscreen mode: %s", SDL_GetError());
255 }
256 if (GFX_lpDDSBack == NULL)
257 {
258 init_set_error_msg("Unable to set 640x480 video: %s\n", SDL_GetError());
259 return -1;
260 }
261 log_info("Obtained video flags: "); gfx_dumpflags(flags);
262 cur_video_flags = flags;
263 log_info("Video format: %d-bit R=0x%08x G=0x%08x B=0x%08x A=0x%08x",
264 GFX_lpDDSBack->format->BitsPerPixel,
265 GFX_lpDDSBack->format->Rmask, GFX_lpDDSBack->format->Gmask,
266 GFX_lpDDSBack->format->Bmask, GFX_lpDDSBack->format->Amask);
267
268 char buf[1024];
269 if (SDL_VideoDriverName(buf, 1024) != NULL)
270 log_info("INFO: Video driver is '%s'", buf);
271 else
272 log_info("INFO: Unable to determine video driver name");
273 if (GFX_lpDDSBack->flags & SDL_HWSURFACE)
274 log_info("INFO: Using hardware video mode.");
275 else
276 log_info("INFO: Not using a hardware video mode.");
277 log_info("INFO: SDL depth is %d", bits_per_pixel);
278
279
280 /* Hide mouse */
281 SDL_ShowCursor(SDL_DISABLE);
282
283 /* Disable Alt-Tab and any other window-manager shortcuts */
284 /* SDL_WM_GrabInput(SDL_GRAB_ON); */
285
286
287 /* Default palette (may be used by early init error messages) */
288 gfx_palette_reset();
289
290 /* Create and set the physical palette */
291 if (gfx_palette_set_from_bmp("Tiles/Ts01.bmp") < 0)
292 log_error("Failed to load default palette from Tiles/Ts01.bmp");
293
294 /* Set the reference palette */
295 gfx_palette_get_phys(GFX_real_pal);
296
297 /* Initialize graphic buffers */
298 /* When a new image is loaded in DX, it's color-converted using the
299 main palette (possibly altering the colors to match the palette);
300 currently we emulate that by wrapping SDL_LoadBMP, converting
301 image to the internal palette at load time - and we never change
302 the buffer's palette again, so we're sure there isn't any
303 conversion even if we change the screen palette: */
304 if (!truecolor)
305 SDL_SetPalette(GFX_lpDDSBack, SDL_LOGPAL, GFX_real_pal, 0, 256);
306 GFX_lpDDSTwo = SDL_DisplayFormat(GFX_lpDDSBack);
307 GFX_lpDDSTrick = SDL_DisplayFormat(GFX_lpDDSBack);
308 GFX_lpDDSTrick2 = SDL_DisplayFormat(GFX_lpDDSBack);
309
310
311 /* Display splash picture, as early as possible */
312 {
313 char* fullpath = paths_dmodfile(splash_path);
314 if (!exist(fullpath))
315 {
316 free(fullpath);
317 fullpath = paths_fallbackfile(splash_path);
318 }
319 SDL_Surface* splash = load_bmp(fullpath);
320 free(fullpath);
321 if (splash == NULL)
322 {
323 log_error("Cannot load base graphics %s", splash_path);
324 }
325 else
326 {
327 /* Copy splash to the background buffer so that D-Mod can
328 start an effect from it (e.g. Pilgrim Quest's burning
329 splash screen effect) */
330 SDL_BlitSurface(splash, NULL, GFX_lpDDSTwo, NULL);
331 SDL_FreeSurface(splash);
332 }
333
334 /* Copy splash screen (again) to the screen during loading time */
335 SDL_BlitSurface(GFX_lpDDSTwo, NULL, GFX_lpDDSBack, NULL);
336
337 flip_it();
338 }
339
340
341 /* Fonts system, default fonts */
342 init_state = GFX_INITIALIZING_FONTS;
343 if (gfx_fonts_init() < 0)
344 return -1; /* error message set in gfx_fonts_init */
345
346 /* Compute fade cache if necessary */
347 gfx_fade_init();
348
349 /* Mouse */
350 /* Center mouse and reset relative positionning */
351 SDL_WarpMouse(320, 240);
352 SDL_PumpEvents();
353 SDL_GetRelativeMouseState(NULL, NULL);
354
355
356 /* SDL_MouseMotionEvent: If the cursor is hidden (SDL_ShowCursor(0))
357 and the input is grabbed (SDL_WM_GrabInput(SDL_GRAB_ON)), then
358 the mouse will give relative motion events even when the cursor
359 reaches the edge of the screen. This is currently only
360 implemented on Windows and Linux/Unix-alikes. */
361 /* So it's not portable and it blocks Alt+Tab, so let's try
362 something else - maybe enable it as a command line option. */
363 /* SDL_WM_GrabInput(SDL_GRAB_ON); */
364
365 /* make all pointers to NULL */
366 memset(&gfx_tiles, 0, sizeof(gfx_tiles));
367 memset(&k, 0, sizeof(k));
368 memset(&GFX_k, 0, sizeof(GFX_k));
369 memset(&seq, 0, sizeof(seq));
370
371 /* Load the tiles from the BMPs */
372 tiles_load_default();
373
374 init_state = GFX_INITIALIZED;
375 return 0;
376 }
377
378 /**
379 * Failsafe graphics mode to display initialization error messages
380 */
gfx_init_failsafe()381 int gfx_init_failsafe()
382 {
383 /* Init graphics subsystem */
384 if (SDL_WasInit(SDL_INIT_VIDEO) == 0 && SDL_InitSubSystem(SDL_INIT_VIDEO) == -1)
385 {
386 log_fatal("Unable to init failsafe video: %s", SDL_GetError());
387 return -1;
388 }
389
390 const SDL_VideoInfo* info = SDL_GetVideoInfo();
391 if (info->wm_available)
392 {
393 SDL_WM_SetCaption(PACKAGE_STRING " - Initialization error", NULL);
394 SDL_Surface *icon = IMG_ReadXPMFromArray(freedink_xpm);
395 if (icon != NULL)
396 {
397 SDL_WM_SetIcon(icon, NULL);
398 SDL_FreeSurface(icon);
399 }
400 }
401
402 putenv("SDL_VIDEO_CENTERED=1");
403 putenv("SDL_ASPECT_RATIO=4:3"); /* used by PSP to keep aspect ratio */
404 #ifdef _PSP
405 //GFX_lpDDSBack = SDL_SetVideoMode(480, 272, 32, SDL_HWSURFACE | SDL_FULLSCREEN);
406 GFX_lpDDSBack = SDL_SetVideoMode(640, 480, 32, SDL_SWSURFACE | SDL_FULLSCREEN);
407 #else
408 GFX_lpDDSBack = SDL_SetVideoMode(640, 480, 0, SDL_DOUBLEBUF);
409 #endif
410 if (GFX_lpDDSBack == NULL)
411 {
412 log_fatal("Unable to set failsafe video mode: %s", SDL_GetError());
413 return -1;
414 }
415
416 if (GFX_lpDDSBack->format->BitsPerPixel > 8)
417 truecolor = 1;
418
419 /* Default physical and reference palettes */
420 gfx_palette_reset();
421 gfx_palette_get_phys(GFX_real_pal);
422
423 /* Set palette immediately (don't wait for flip_it()) */
424 SDL_SetPalette(GFX_lpDDSBack, SDL_PHYSPAL|SDL_LOGPAL, GFX_real_pal, 0, 256);
425
426 return gfx_fonts_init_failsafe();
427 }
428
429 /**
430 * Unload graphics subsystem
431 */
gfx_quit()432 void gfx_quit()
433 {
434 init_state = GFX_QUITTING;
435
436 gfx_fade_quit();
437
438 gfx_fonts_quit();
439
440 tiles_unload_all();
441 sprites_unload();
442
443 if (GFX_lpDDSBack != NULL) SDL_FreeSurface(GFX_lpDDSBack);
444 if (GFX_lpDDSTwo != NULL) SDL_FreeSurface(GFX_lpDDSTwo);
445 if (GFX_lpDDSTrick != NULL) SDL_FreeSurface(GFX_lpDDSTrick);
446 if (GFX_lpDDSTrick2 != NULL) SDL_FreeSurface(GFX_lpDDSTrick2);
447
448 GFX_lpDDSBack = NULL;
449 GFX_lpDDSTwo = NULL;
450 GFX_lpDDSTrick = NULL;
451 GFX_lpDDSTrick2 = NULL;
452
453 init_state = GFX_NOT_INITIALIZED;
454 SDL_QuitSubSystem(SDL_INIT_VIDEO);
455 }
456
457
458 /* LoadBMP wrapper. Load a new graphic from file, and apply the
459 reference palette so that all subsequent blits are faster (color
460 convertion is avoided) - although the initial loading time will be
461 somewhat longer. */
load_bmp_internal(char * filename,SDL_RWops * rw,int from_mem)462 static SDL_Surface* load_bmp_internal(char *filename, SDL_RWops *rw, int from_mem) {
463 SDL_Surface *image;
464
465 if (from_mem == 1)
466 {
467 image = IMG_Load_RW(rw, 1);
468 }
469 else
470 {
471 ciconvert(filename);
472 image = IMG_Load(filename);
473 }
474
475 if (image == NULL)
476 {
477 /* fprintf(stderr, "load_bmp_internal: %s\n", SDL_GetError()); */
478 /* Maybe it's just because we're at the end of a sequence */
479 return NULL;
480 }
481
482 if (!truecolor)
483 {
484 /* Make a copy of the surface using the screen format (in
485 particular: same color depth, which is needed when importing
486 24bit graphics in 8bit mode). */
487 /* This copy is also necessary to make a palette conversion from
488 the Dink palette (the one from the .bmp) to the
489 'DX-bug-messed' Dink palette (GFX_real_pal with overwritten
490 indexes 0 and 255). */
491 /* converted = SDL_ConvertSurface(image, image->format, image->flags); */
492 SDL_Surface *converted = SDL_DisplayFormat(image);
493
494 /* TODO: the following is probably unnecessary, I think that's
495 exactly what SDL_DisplayFormat does: convert the surface to
496 the screen's logical palette. Cf. test/sdl/paltest.c. */
497 {
498 /* In the end, the image must use the reference palette: that
499 way no mistaken color conversion will occur during blits to
500 other surfaces/buffers. Blits should also be faster(?).
501 Alternatively we could replace SDL_BlitSurface with a
502 wrapper that sets identical palettes before the blits. */
503 SDL_SetPalette(converted, SDL_LOGPAL, GFX_real_pal, 0, 256);
504
505 /* Blit the copy back to the original, with a potentially
506 different palette, which triggers color conversion to
507 image's palette. */
508 SDL_BlitSurface(image, NULL, converted, NULL);
509 }
510 SDL_FreeSurface(image);
511 image = NULL;
512
513 return converted;
514 }
515 else
516 {
517 /* In truecolor mode, converting a 8bit image to truecolor does
518 not bring noticeable performance increase or decrease, but
519 does increase memory usage by at least 10MB so let's use the
520 loaded image as-is. No need for palette conversion either. */
521 return image;
522 }
523
524 }
525
526 /* LoadBMP wrapper, from file */
load_bmp(char * filename)527 SDL_Surface* load_bmp(char *filename)
528 {
529 return load_bmp_internal(filename, NULL, 0);
530 }
531
532 /* LoadBMP wrapper, from FILE pointer */
load_bmp_from_fp(FILE * in)533 SDL_Surface* load_bmp_from_fp(FILE* in)
534 {
535 if (in == NULL)
536 return NULL;
537 SDL_RWops *rw = SDL_RWFromFP(in, /*autoclose=*/1);
538 return load_bmp_internal(NULL, rw, 1);
539 }
540
541 /* LoadBMP wrapper, from memory */
load_bmp_from_mem(SDL_RWops * rw)542 SDL_Surface* load_bmp_from_mem(SDL_RWops *rw)
543 {
544 return load_bmp_internal(NULL, rw, 1);
545 }
546
547
548 /**
549 * Temporary disable src's transparency and blit it to dst
550 */
gfx_blit_nocolorkey(SDL_Surface * src,SDL_Rect * src_rect,SDL_Surface * dst,SDL_Rect * dst_rect)551 int gfx_blit_nocolorkey(SDL_Surface *src, SDL_Rect *src_rect,
552 SDL_Surface *dst, SDL_Rect *dst_rect)
553 {
554 int retval = -1;
555
556 Uint32 colorkey_flags, colorkey, alpha_flags, alpha;
557 colorkey_flags = src->flags & (SDL_SRCCOLORKEY|SDL_RLEACCEL);
558 #if SDL_VERSION_ATLEAST(1, 3, 0)
559 SDL_GetColorKey(src, &colorkey);
560 /* 1.3 TODO: alpha */
561 #else
562 colorkey = src->format->colorkey;
563 alpha_flags = src->flags & (SDL_SRCALPHA|SDL_RLEACCEL);
564 alpha = src->format->alpha;
565 #endif
566 SDL_SetColorKey(src, 0, -1);
567 SDL_SetAlpha(src, 0, -1);
568
569 retval = SDL_BlitSurface(src, src_rect, dst, dst_rect);
570
571 SDL_SetColorKey(src, colorkey_flags, colorkey);
572 SDL_SetAlpha(src, alpha_flags, alpha);
573
574 return retval;
575 }
576
577 /**
578 * Blit and resize so that 'src' fits in 'dst_rect'
579 */
gfx_blit_stretch(SDL_Surface * src_surf,SDL_Rect * src_rect,SDL_Surface * dst_surf,SDL_Rect * dst_rect)580 int gfx_blit_stretch(SDL_Surface *src_surf, SDL_Rect *src_rect,
581 SDL_Surface *dst_surf, SDL_Rect *dst_rect)
582 {
583 int retval = -1;
584
585 SDL_Rect src_rect_if_null;
586 if (src_rect == NULL)
587 {
588 src_rect = &src_rect_if_null;
589 src_rect->x = 0;
590 src_rect->y = 0;
591 src_rect->w = src_surf->w;
592 src_rect->h = src_surf->h;
593 }
594
595 double sx = 1.0 * dst_rect->w / src_rect->w;
596 double sy = 1.0 * dst_rect->h / src_rect->h;
597 /* In principle, double's are precise up to 15 decimal digits */
598 if (fabs(sx-1) > 1e-10 || fabs(sy-1) > 1e-10)
599 {
600 SDL_Surface *scaled = zoomSurface(src_surf, sx, sy, SMOOTHING_OFF);
601
602 /* Keep the same transparency / alpha parameters (SDL_gfx bug,
603 report submitted to the author: SDL_gfx adds transparency to
604 non-transparent surfaces) */
605 int colorkey_flag = src_surf->flags & SDL_SRCCOLORKEY;
606 Uint8 r, g, b, a;
607 #if SDL_VERSION_ATLEAST(1, 3, 0)
608 Uint32 colorkey;
609 SDL_GetColorKey(src_surf, &colorkey);
610 # else
611 Uint32 colorkey = src_surf->format->colorkey;
612 #endif
613 SDL_GetRGBA(colorkey, src_surf->format, &r, &g, &b, &a);
614
615 SDL_SetColorKey(scaled, colorkey_flag,
616 SDL_MapRGBA(scaled->format, r, g, b, a));
617 /* Don't mess with alpha transparency, though: */
618 /* int alpha_flag = src->flags & SDL_SRCALPHA; */
619 /* int alpha = src->format->alpha; */
620 /* SDL_SetAlpha(scaled, alpha_flag, alpha); */
621
622 src_rect->x = (int) round(src_rect->x * sx);
623 src_rect->y = (int) round(src_rect->y * sy);
624 src_rect->w = (int) round(src_rect->w * sx);
625 src_rect->h = (int) round(src_rect->h * sy);
626 retval = SDL_BlitSurface(scaled, src_rect, dst_surf, dst_rect);
627 SDL_FreeSurface(scaled);
628 }
629 else
630 {
631 /* No scaling */
632 retval = SDL_BlitSurface(src_surf, src_rect, dst_surf, dst_rect);
633 }
634 return retval;
635 }
636
637
638 /**
639 * Refresh the physical screen, and apply a new palette or fade effect
640 * if needed
641 */
flip_it(void)642 void flip_it(void)
643 {
644 /* We work directly on either lpDDSBack (no lpDDSPrimary as in
645 the original game): the double buffer (Back) is directly
646 managed by SDL; SDL_Flip is used to refresh the physical
647 screen. */
648
649 if (!truecolor)
650 gfx_palette_apply_phys();
651
652 if (truecolor_fade_brightness < 256)
653 gfx_fade_apply(truecolor_fade_brightness);
654
655 SDL_Flip(GFX_lpDDSBack);
656 }
657
658 /* Like SDL_WM_ToggleFullScreen(), except that it works under more
659 platforms */
gfx_toggle_fullscreen(void)660 void gfx_toggle_fullscreen(void)
661 {
662 if ((cur_video_flags & SDL_FULLSCREEN) == SDL_FULLSCREEN)
663 cur_video_flags &= ~SDL_FULLSCREEN;
664 else
665 cur_video_flags |= SDL_FULLSCREEN;
666 GFX_lpDDSBack = SDL_SetVideoMode(640, 480, GFX_lpDDSBack->format->BitsPerPixel, cur_video_flags);
667
668 /* Palette was lost in the process */
669 if (!truecolor)
670 SDL_SetPalette(GFX_lpDDSBack, SDL_LOGPAL, GFX_real_pal, 0, 256);
671 gfx_palette_restore_phys();
672 }
673
674 /**
675 * Print GFX memory usage
676 */
gfx_log_meminfo()677 void gfx_log_meminfo()
678 {
679 int total = 0;
680
681 {
682 int sum = 0;
683 sum = GFX_lpDDSBack->h * GFX_lpDDSBack->pitch;
684 log_debug("GFX screen = %8d", sum);
685 total += sum;
686 }
687
688 {
689 int sum = 0;
690 SDL_Surface* s = NULL;
691 s = GFX_lpDDSTwo;
692 sum += s->h * s->pitch;
693 s = GFX_lpDDSTrick;
694 sum += s->h * s->pitch;
695 s = GFX_lpDDSTrick2;
696 sum += s->h * s->pitch;
697 log_debug("GFX buf = %8d", sum);
698 total += sum;
699 }
700
701 {
702 int sum = 0;
703 int i = 0;
704 SDL_Surface* s = NULL;
705 for (; i < MAX_SPRITES; i++)
706 {
707 s = GFX_k[i].k;
708 if (s != NULL)
709 sum += s->h * s->pitch;
710 // Note: this does not take SDL_RLEACCEL into account
711 }
712 log_debug("GFX bmp = %8d", sum);
713 total += sum;
714 }
715
716 {
717 int sum = 0;
718 int i = 0;
719 SDL_Surface* s = NULL;
720 for (; i < GFX_TILES_NB_SETS+1; i++)
721 {
722 s = gfx_tiles[i];
723 if (s != NULL)
724 sum += s->h * s->pitch;
725 }
726 log_debug("GFX tiles = %8d", sum);
727 total += sum;
728 }
729
730 log_debug("GFX total = %8d (+ ~150kB fonts)", total);
731 }
732