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&copy_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