added optional button to restart game (door, panel and touch variants)
[rocksndiamonds.git] / src / libgame / sdl.c
index d34feb4cd2b93af6c4319b210a13520313bf669a..0b3ec7f623383a26e07efc560938295438ae74dc 100644 (file)
@@ -62,19 +62,33 @@ static void FinalizeScreen(int draw_target)
   if (gfx.draw_global_anim_function != NULL)
     gfx.draw_global_anim_function(draw_target, DRAW_GLOBAL_ANIM_STAGE_2);
 
-  // copy tile selection cursor to render target buffer, if defined (above all)
+  // copy tile selection cursor to render target buffer, if defined (part 1)
   if (gfx.draw_tile_cursor_function != NULL)
-    gfx.draw_tile_cursor_function(draw_target);
+    gfx.draw_tile_cursor_function(draw_target, TRUE);
+
+  // copy envelope request to render target buffer, if needed (above all)
+  if (gfx.draw_envelope_request_function != NULL)
+    gfx.draw_envelope_request_function(draw_target);
+
+  // copy tile selection cursor to render target buffer, if defined (part 2)
+  if (gfx.draw_tile_cursor_function != NULL)
+    gfx.draw_tile_cursor_function(draw_target, FALSE);
+
+  // copy global animations to render target buffer, if defined (mouse pointer)
+  if (gfx.draw_global_anim_function != NULL)
+    gfx.draw_global_anim_function(draw_target, DRAW_GLOBAL_ANIM_STAGE_3);
 }
 
 static void UpdateScreenExt(SDL_Rect *rect, boolean with_frame_delay)
 {
-  static unsigned int update_screen_delay = 0;
-  unsigned int update_screen_delay_value = 50;         // (milliseconds)
+  if (program.headless)
+    return;
+
+  static DelayCounter update_screen_delay = { 50 };    // (milliseconds)
   SDL_Surface *screen = backbuffer->surface;
 
   if (limit_screen_updates &&
-      !DelayReached(&update_screen_delay, update_screen_delay_value))
+      !DelayReached(&update_screen_delay))
     return;
 
   LimitScreenUpdates(FALSE);
@@ -84,8 +98,8 @@ static void UpdateScreenExt(SDL_Rect *rect, boolean with_frame_delay)
     static int LastFrameCounter = 0;
     boolean changed = (FrameCounter != LastFrameCounter);
 
-    printf("::: FrameCounter == %d [%s]\n", FrameCounter,
-          (changed ? "-" : "SAME FRAME UPDATED"));
+    Debug("internal:frame", "FrameCounter == %d [%s]", FrameCounter,
+         (changed ? "-" : "SAME FRAME UPDATED"));
 
     LastFrameCounter = FrameCounter;
 
@@ -151,28 +165,31 @@ static void UpdateScreenExt(SDL_Rect *rect, boolean with_frame_delay)
     dst_rect1 = &dst_rect_screen;
 
 #if defined(HAS_SCREEN_KEYBOARD)
-  if (video.shifted_up || video.shifted_up_delay)
+  SDL_Rect src_rect_up = { 0, 0,  video.width, video.height };
+  SDL_Rect dst_rect_up = dst_rect_screen;
+
+  if (video.shifted_up || video.shifted_up_delay.count)
   {
     int time_current = SDL_GetTicks();
     int pos = video.shifted_up_pos;
     int pos_last = video.shifted_up_pos_last;
 
-    if (!DelayReachedExt(&video.shifted_up_delay, video.shifted_up_delay_value,
-                        time_current))
+    if (!DelayReachedExt(&video.shifted_up_delay, time_current))
     {
-      int delay = time_current - video.shifted_up_delay;
-      int delay_value = video.shifted_up_delay_value;
+      int delay_count = time_current - video.shifted_up_delay.count;
+      int delay_value = video.shifted_up_delay.value;
 
-      pos = pos_last + (pos - pos_last) * delay / delay_value;
+      pos = pos_last + (pos - pos_last) * delay_count / delay_value;
     }
     else
     {
       video.shifted_up_pos_last = pos;
-      video.shifted_up_delay = 0;
+      video.shifted_up_delay.count = 0;
     }
 
-    SDL_Rect src_rect_up = { 0,    pos,  video.width, video.height - pos };
-    SDL_Rect dst_rect_up = { xoff, yoff, video.width, video.height - pos };
+    src_rect_up.y = pos;
+    src_rect_up.h = video.height - pos;
+    dst_rect_up.h = video.height - pos;
 
     if (video.screen_rendering_mode == SPECIAL_RENDERING_TARGET ||
        video.screen_rendering_mode == SPECIAL_RENDERING_DOUBLE)
@@ -221,7 +238,7 @@ static void UpdateScreenExt(SDL_Rect *rect, boolean with_frame_delay)
 
   // global synchronization point of the game to align video frame delay
   if (with_frame_delay)
-    WaitUntilDelayReached(&video.frame_delay, video.frame_delay_value);
+    WaitUntilDelayReached(&video.frame_delay);
 
   video.frame_counter++;
 
@@ -260,20 +277,20 @@ static void SDLSetWindowIcon(char *basename)
   // (setting the window icon on Mac OS X would replace the high-quality
   // dock icon with the currently smaller (and uglier) icon from file)
 
-#if !defined(PLATFORM_MACOSX)
+#if !defined(PLATFORM_MAC)
   char *filename = getCustomImageFilename(basename);
   SDL_Surface *surface;
 
   if (filename == NULL)
   {
-    Error(ERR_WARN, "SDLSetWindowIcon(): cannot find file '%s'", basename);
+    Warn("SDLSetWindowIcon(): cannot find file '%s'", basename);
 
     return;
   }
 
   if ((surface = IMG_Load(filename)) == NULL)
   {
-    Error(ERR_WARN, "IMG_Load('%s') failed: %s", basename, SDL_GetError());
+    Warn("IMG_Load('%s') failed: %s", basename, SDL_GetError());
 
     return;
   }
@@ -297,19 +314,35 @@ static boolean equalSDLPixelFormat(SDL_PixelFormat *format1,
          format1->Bmask         == format2->Bmask);
 }
 
-static Pixel SDLGetColorKey(SDL_Surface *surface)
+static void SDLCopyColorKey(SDL_Surface *src_surface, SDL_Surface *dst_surface)
 {
   Pixel color_key;
+  Uint8 r, g, b;
+
+  // check if source surface has a color key
+  if (SDL_GetColorKey(src_surface, &color_key) == 0)
+  {
+    // get RGB values of color key of source surface
+    SDL_GetRGB(color_key, src_surface->format, &r, &g, &b);
 
-  if (SDL_GetColorKey(surface, &color_key) != 0)
-    return -1;
+    // get color key from RGB values in destination surface format
+    color_key = SDL_MapRGB(dst_surface->format, r, g, b);
 
-  return color_key;
+    // set color key in destination surface
+    SDL_SetColorKey(dst_surface, SET_TRANSPARENT_PIXEL, color_key);
+  }
+  else
+  {
+    // unset color key in destination surface
+    SDL_SetColorKey(dst_surface, UNSET_TRANSPARENT_PIXEL, 0);
+  }
 }
 
 static boolean SDLHasColorKey(SDL_Surface *surface)
 {
-  return (SDLGetColorKey(surface) != -1);
+  Pixel color_key;
+
+  return (SDL_GetColorKey(surface, &color_key) == 0);
 }
 
 static boolean SDLHasAlpha(SDL_Surface *surface)
@@ -322,7 +355,7 @@ static boolean SDLHasAlpha(SDL_Surface *surface)
   return (blend_mode == SDL_BLENDMODE_BLEND);
 }
 
-static void SDLSetAlpha(SDL_Surface *surface, boolean set, int alpha)
+static void SDLSetSurfaceAlpha(SDL_Surface *surface, boolean set, int alpha)
 {
   SDL_BlendMode blend_mode = (set ? SDL_BLENDMODE_BLEND : SDL_BLENDMODE_NONE);
 
@@ -330,6 +363,49 @@ static void SDLSetAlpha(SDL_Surface *surface, boolean set, int alpha)
   SDL_SetSurfaceAlphaMod(surface, alpha);
 }
 
+static void SDLSetTextureAlpha(SDL_Texture *texture, boolean set, int alpha)
+{
+  SDL_BlendMode blend_mode = (set ? SDL_BLENDMODE_BLEND : SDL_BLENDMODE_NONE);
+
+  SDL_SetTextureBlendMode(texture, blend_mode);
+  SDL_SetTextureAlphaMod(texture, alpha);
+}
+
+static void SDLSetBitmapAlpha(Bitmap *bitmap, boolean is_texture,
+                             boolean is_masked)
+{
+  int alpha_next_blit = bitmap->alpha_next_blit;
+
+  // alpha value must be requested every time before blitting, if needed
+  bitmap->alpha_next_blit = -1;
+
+  // nothing to do if requested alpha value is already set
+  if (bitmap->alpha[is_texture][is_masked] == alpha_next_blit)
+    return;
+
+  // store requested alpha value for masked/unmasked surface/texture
+  bitmap->alpha[is_texture][is_masked] = alpha_next_blit;
+
+  // set blend mode if bitmap is masked or if alpha value is defined
+  boolean set_blend_mode = (is_masked || alpha_next_blit != -1);
+
+  // if alpha value is undefined, use default (opaque) alpha value
+  if (alpha_next_blit == -1)
+    alpha_next_blit = SDL_ALPHA_OPAQUE;
+
+  if (is_texture)
+    SDLSetTextureAlpha(is_masked ? bitmap->texture_masked : bitmap->texture,
+                      set_blend_mode, alpha_next_blit);
+  else
+    SDLSetSurfaceAlpha(is_masked ? bitmap->surface_masked : bitmap->surface,
+                      set_blend_mode, alpha_next_blit);
+}
+
+void SDLSetAlpha(SDL_Surface *surface, boolean set, int alpha)
+{
+  SDLSetSurfaceAlpha(surface, set, alpha);
+}
+
 const char *SDLGetRendererName(void)
 {
   static SDL_RendererInfo renderer_info;
@@ -360,12 +436,11 @@ SDL_Surface *SDLGetNativeSurface(SDL_Surface *surface)
   new_surface = SDL_ConvertSurface(surface, &format, 0);
 
   if (new_surface == NULL)
-    Error(ERR_EXIT, "SDL_ConvertSurface() failed: %s", SDL_GetError());
+    Fail("SDL_ConvertSurface() failed: %s", SDL_GetError());
 
   // workaround for a bug in SDL 2.0.12 (which does not convert the color key)
   if (SDLHasColorKey(surface) && !SDLHasColorKey(new_surface))
-    SDL_SetColorKey(new_surface, SET_TRANSPARENT_PIXEL,
-                   SDLGetColorKey(surface));
+    SDLCopyColorKey(surface, new_surface);
 
   return new_surface;
 }
@@ -401,8 +476,7 @@ static SDL_Texture *SDLCreateTextureFromSurface(SDL_Surface *surface)
   SDL_Texture *texture = SDL_CreateTextureFromSurface(sdl_renderer, surface);
 
   if (texture == NULL)
-    Error(ERR_EXIT, "SDL_CreateTextureFromSurface() failed: %s",
-         SDL_GetError());
+    Fail("SDL_CreateTextureFromSurface() failed: %s", SDL_GetError());
 
   return texture;
 }
@@ -443,7 +517,7 @@ void SDLInitVideoDisplay(void)
 
   // initialize SDL video
   if (SDL_InitSubSystem(SDL_INIT_VIDEO) < 0)
-    Error(ERR_EXIT, "SDL_InitSubSystem() failed: %s", SDL_GetError());
+    Fail("SDL_InitSubSystem() failed: %s", SDL_GetError());
 
   // set default SDL depth
   video.default_depth = 32;    // (how to determine video depth in SDL2?)
@@ -467,7 +541,7 @@ static void SDLInitVideoBuffer_VideoBuffer(boolean fullscreen)
 
   // open SDL video output device (window or fullscreen mode)
   if (!SDLSetVideoMode(fullscreen))
-    Error(ERR_EXIT, "setting video mode failed");
+    Fail("setting video mode failed");
 
   // !!! SDL2 can only set the window icon if the window already exists !!!
   // set window icon
@@ -537,6 +611,7 @@ static boolean SDLCreateScreen(boolean fullscreen)
   int screen_height = video.screen_height;
   int surface_flags = (fullscreen ? surface_flags_fullscreen :
                       surface_flags_window);
+  int display_nr = options.display_nr;
 
   // default window size is unscaled
   video.window_width  = screen_width;
@@ -572,15 +647,14 @@ static boolean SDLCreateScreen(boolean fullscreen)
 
     if (sdl_window)
     {
-      SDL_DestroyWindow(sdl_window);
-      sdl_window = NULL;
+      SDL_SetWindowSize(sdl_window, video.window_width, video.window_height);
     }
   }
 
   if (sdl_window == NULL)
     sdl_window = SDL_CreateWindow(program.window_title,
-                                 SDL_WINDOWPOS_CENTERED,
-                                 SDL_WINDOWPOS_CENTERED,
+                                 SDL_WINDOWPOS_CENTERED_DISPLAY(display_nr),
+                                 SDL_WINDOWPOS_CENTERED_DISPLAY(display_nr),
                                  video.window_width,
                                  video.window_height,
                                  surface_flags);
@@ -615,21 +689,21 @@ static boolean SDLCreateScreen(boolean fullscreen)
        new_surface = SDL_CreateRGBSurface(0, width, height, 32, 0,0,0, 0);
 
        if (new_surface == NULL)
-         Error(ERR_WARN, "SDL_CreateRGBSurface() failed: %s", SDL_GetError());
+         Warn("SDL_CreateRGBSurface() failed: %s", SDL_GetError());
       }
       else
       {
-       Error(ERR_WARN, "SDL_CreateTexture() failed: %s", SDL_GetError());
+       Warn("SDL_CreateTexture() failed: %s", SDL_GetError());
       }
     }
     else
     {
-      Error(ERR_WARN, "SDL_CreateRenderer() failed: %s", SDL_GetError());
+      Warn("SDL_CreateRenderer() failed: %s", SDL_GetError());
     }
   }
   else
   {
-    Error(ERR_WARN, "SDL_CreateWindow() failed: %s", SDL_GetError());
+    Warn("SDL_CreateWindow() failed: %s", SDL_GetError());
   }
 
   SDLSetScreenProperties();
@@ -780,7 +854,8 @@ void SDLSetWindowFullscreen(boolean fullscreen)
   {
     SDLSetWindowScaling(setup.window_scaling_percent);
     SDL_SetWindowPosition(sdl_window,
-                         SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED);
+                         SDL_WINDOWPOS_CENTERED_DISPLAY(options.display_nr),
+                         SDL_WINDOWPOS_CENTERED_DISPLAY(options.display_nr));
 
     video.fullscreen_initial = FALSE;
   }
@@ -798,7 +873,7 @@ void SDLSetDisplaySize(void)
     video.display_height = h;
 
 #if 0
-    Error(ERR_DEBUG, "SDL renderer size: %d x %d",
+    Debug("video", "SDL renderer size: %d x %d",
          video.display_width, video.display_height);
 #endif
   }
@@ -812,7 +887,7 @@ void SDLSetDisplaySize(void)
     video.display_height = display_bounds.h;
 
 #if 0
-    Error(ERR_DEBUG, "SDL display size: %d x %d",
+    Debug("video", "SDL display size: %d x %d",
          video.display_width, video.display_height);
 #endif
   }
@@ -843,7 +918,7 @@ void SDLSetScreenSizeAndOffsets(int width, int height)
     video.screen_yoffset = (video.screen_height - height) / 2;
 
 #if 0
-    Error(ERR_DEBUG, "Changing screen from %dx%d to %dx%d (%.2f to %.2f)",
+    Debug("video", "Changing screen from %dx%d to %dx%d (%.2f to %.2f)",
          width, height,
          video.screen_width, video.screen_height,
          ratio_video, ratio_display);
@@ -862,6 +937,8 @@ void SDLSetScreenProperties(void)
   SDLSetDisplaySize();
   SDLSetScreenSizeAndOffsets(video.width, video.height);
   SDLSetScreenSizeForRenderer(video.screen_width, video.screen_height);
+
+  SetOverlayGridSizeAndButtons();
 }
 
 void SDLSetScreenRenderingMode(char *screen_rendering_mode)
@@ -877,6 +954,10 @@ void SDLSetScreenRenderingMode(char *screen_rendering_mode)
 
 void SDLSetScreenVsyncMode(char *vsync_mode)
 {
+  // changing vsync mode without re-creating renderer only supported by OpenGL
+  if (!strPrefixLower((char *)SDLGetRendererName(), "opengl"))
+    return;
+
   int interval = VSYNC_MODE_STR_TO_INT(vsync_mode);
   int result = SDL_GL_SetSwapInterval(interval);
 
@@ -909,7 +990,7 @@ void SDLCreateBitmapContent(Bitmap *bitmap, int width, int height,
     SDL_CreateRGBSurface(SURFACE_FLAGS, width, height, depth, 0,0,0, 0);
 
   if (surface == NULL)
-    Error(ERR_EXIT, "SDL_CreateRGBSurface() failed: %s", SDL_GetError());
+    Fail("SDL_CreateRGBSurface() failed: %s", SDL_GetError());
 
   SDLSetNativeSurface(&surface);
 
@@ -935,6 +1016,25 @@ void SDLFreeBitmapPointers(Bitmap *bitmap)
   bitmap->texture_masked = NULL;
 }
 
+void SDLBlitSurface(SDL_Surface *src_surface, SDL_Surface *dst_surface,
+                   int src_x, int src_y, int width, int height,
+                   int dst_x, int dst_y)
+{
+  SDL_Rect src_rect, dst_rect;
+
+  src_rect.x = src_x;
+  src_rect.y = src_y;
+  src_rect.w = width;
+  src_rect.h = height;
+
+  dst_rect.x = dst_x;
+  dst_rect.y = dst_y;
+  dst_rect.w = width;
+  dst_rect.h = height;
+
+  SDL_BlitSurface(src_surface, &src_rect, dst_surface, &dst_rect);
+}
+
 void 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)
@@ -952,6 +1052,8 @@ void SDLCopyArea(Bitmap *src_bitmap, Bitmap *dst_bitmap,
   dst_rect.w = width;
   dst_rect.h = height;
 
+  SDLSetBitmapAlpha(src_bitmap, FALSE, mask_mode == BLIT_MASKED);
+
   // if (src_bitmap != backbuffer || dst_bitmap != window)
   if (!(src_bitmap == backbuffer && dst_bitmap == window))
     SDL_BlitSurface((mask_mode == BLIT_MASKED ?
@@ -986,6 +1088,8 @@ void SDLBlitTexture(Bitmap *bitmap,
   dst_rect.w = width;
   dst_rect.h = height;
 
+  SDLSetBitmapAlpha(bitmap, TRUE, mask_mode == BLIT_MASKED);
+
   SDL_RenderCopy(sdl_renderer, texture, &src_rect, &dst_rect);
 }
 
@@ -1205,6 +1309,9 @@ void SDLFadeRectangle(int x, int y, int width, int height,
          draw_border_function();
 
        UpdateScreen_WithFrameDelay(&dst_rect2);
+
+       if (PendingEscapeKeyEvent())
+         break;
       }
     }
   }
@@ -1261,6 +1368,9 @@ void SDLFadeRectangle(int x, int y, int width, int height,
 
       // only update the region of the screen that is affected from fading
       UpdateScreen_WithFrameDelay(&dst_rect2);
+
+      if (PendingEscapeKeyEvent())
+       break;
     }
   }
   else         // fading in, fading out or cross-fading
@@ -1287,6 +1397,9 @@ void SDLFadeRectangle(int x, int y, int width, int height,
 
       // only update the region of the screen that is affected from fading
       UpdateScreen_WithFrameDelay(&dst_rect);
+
+      if (PendingEscapeKeyEvent())
+       break;
     }
   }
 
@@ -1419,14 +1532,14 @@ static void _PutPixel(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
       case 1:
       {
        // Assuming 8-bpp
-       *((Uint8 *)surface->pixels + y*surface->pitch + x) = color;
+       *((Uint8 *)surface->pixels + y * surface->pitch + x) = color;
       }
       break;
 
       case 2:
       {
        // Probably 15-bpp or 16-bpp
-       *((Uint16 *)surface->pixels + y*surface->pitch/2 + x) = color;
+       *((Uint16 *)surface->pixels + y * surface->pitch / 2 + x) = color;
       }
       break;
 
@@ -1437,20 +1550,20 @@ static void _PutPixel(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
        int shift;
 
        // Gack - slow, but endian correct
-       pix = (Uint8 *)surface->pixels + y * surface->pitch + x*3;
+       pix = (Uint8 *)surface->pixels + y * surface->pitch + x * 3;
        shift = surface->format->Rshift;
-       *(pix+shift/8) = color>>shift;
+       *(pix + shift / 8) = color>>shift;
        shift = surface->format->Gshift;
-       *(pix+shift/8) = color>>shift;
+       *(pix + shift / 8) = color>>shift;
        shift = surface->format->Bshift;
-       *(pix+shift/8) = color>>shift;
+       *(pix + shift / 8) = color>>shift;
       }
       break;
 
       case 4:
       {
        // Probably 32-bpp
-       *((Uint32 *)surface->pixels + y*surface->pitch/4 + x) = color;
+       *((Uint32 *)surface->pixels + y * surface->pitch / 4 + x) = color;
       }
       break;
     }
@@ -1466,12 +1579,12 @@ static void _PutPixelRGB(SDL_Surface *surface, Sint16 x, Sint16 y,
 
 static void _PutPixel8(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
 {
-  *((Uint8 *)surface->pixels + y*surface->pitch + x) = color;
+  *((Uint8 *)surface->pixels + y * surface->pitch + x) = color;
 }
 
 static void _PutPixel16(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
 {
-  *((Uint16 *)surface->pixels + y*surface->pitch/2 + x) = color;
+  *((Uint16 *)surface->pixels + y * surface->pitch / 2 + x) = color;
 }
 
 static void _PutPixel24(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
@@ -1480,38 +1593,38 @@ static void _PutPixel24(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
   int shift;
 
   // Gack - slow, but endian correct
-  pix = (Uint8 *)surface->pixels + y * surface->pitch + x*3;
+  pix = (Uint8 *)surface->pixels + y * surface->pitch + x * 3;
   shift = surface->format->Rshift;
-  *(pix+shift/8) = color>>shift;
+  *(pix + shift / 8) = color>>shift;
   shift = surface->format->Gshift;
-  *(pix+shift/8) = color>>shift;
+  *(pix + shift / 8) = color>>shift;
   shift = surface->format->Bshift;
-  *(pix+shift/8) = color>>shift;
+  *(pix + shift / 8) = color>>shift;
 }
 
 static void _PutPixel32(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
 {
-  *((Uint32 *)surface->pixels + y*surface->pitch/4 + x) = color;
+  *((Uint32 *)surface->pixels + y * surface->pitch / 4 + x) = color;
 }
 
-static void _PutPixelX(SDL_Surface *dest,Sint16 x,Sint16 y,Uint32 color)
+static void _PutPixelX(SDL_Surface *dest, Sint16 x, Sint16 y, Uint32 color)
 {
   switch (dest->format->BytesPerPixel)
   {
     case 1:
-      *((Uint8 *)dest->pixels + y*dest->pitch + x) = color;
+      *((Uint8 *)dest->pixels + y * dest->pitch + x) = color;
       break;
 
     case 2:
-      *((Uint16 *)dest->pixels + y*dest->pitch/2 + x) = color;
+      *((Uint16 *)dest->pixels + y * dest->pitch / 2 + x) = color;
       break;
 
     case 3:
-      _PutPixel24(dest,x,y,color);
+      _PutPixel24(dest, x, y, color);
       break;
 
     case 4:
-      *((Uint32 *)dest->pixels + y*dest->pitch/4 + x) = color;
+      *((Uint32 *)dest->pixels + y * dest->pitch / 4 + x) = color;
       break;
   }
 }
@@ -1549,19 +1662,19 @@ static Sint32 sge_CalcYPitch(SDL_Surface *dest, Sint16 y)
     switch (dest->format->BytesPerPixel)
     {
       case 1:
-       return y*dest->pitch;
+       return y * dest->pitch;
        break;
 
       case 2:
-       return y*dest->pitch/2;
+       return y * dest->pitch / 2;
        break;
 
       case 3:
-       return y*dest->pitch;
+       return y * dest->pitch;
        break;
 
       case 4:
-       return y*dest->pitch/4;
+       return y * dest->pitch / 4;
        break;
     }
   }
@@ -1597,13 +1710,13 @@ static void sge_pPutPixel(SDL_Surface *surface, Sint16 x, Sint32 ypitch,
        int shift;
 
        // Gack - slow, but endian correct
-       pix = (Uint8 *)surface->pixels + ypitch + x*3;
+       pix = (Uint8 *)surface->pixels + ypitch + x * 3;
        shift = surface->format->Rshift;
-       *(pix+shift/8) = color>>shift;
+       *(pix + shift / 8) = color>>shift;
        shift = surface->format->Gshift;
-       *(pix+shift/8) = color>>shift;
+       *(pix + shift / 8) = color>>shift;
        shift = surface->format->Bshift;
-       *(pix+shift/8) = color>>shift;
+       *(pix + shift / 8) = color>>shift;
       }
       break;
 
@@ -1871,22 +1984,6 @@ void SDLPutPixel(Bitmap *dst_bitmap, int x, int y, Pixel pixel)
 // quick (no, it's slow) and dirty hack to "invert" rectangle inside SDL surface
 // ----------------------------------------------------------------------------
 
-void SDLInvertArea(Bitmap *bitmap, int src_x, int src_y,
-                  int width, int height, Uint32 color)
-{
-  int x, y;
-
-  for (y = src_y; y < src_y + height; y++)
-  {
-    for (x = src_x; x < src_x + width; x++)
-    {
-      Uint32 pixel = SDLGetPixel(bitmap, x, y);
-
-      SDLPutPixel(bitmap, x, y, pixel == BLACK_PIXEL ? color : BLACK_PIXEL);
-    }
-  }
-}
-
 void SDLCopyInverseMasked(Bitmap *src_bitmap, Bitmap *dst_bitmap,
                          int src_x, int src_y, int width, int height,
                          int dst_x, int dst_y)
@@ -2233,7 +2330,7 @@ static SDL_Surface *SDLGetOpaqueSurface(SDL_Surface *surface)
     return NULL;
 
   if ((new_surface = SDLGetNativeSurface(surface)) == NULL)
-    Error(ERR_EXIT, "SDLGetNativeSurface() failed");
+    Fail("SDLGetNativeSurface() failed");
 
   // remove alpha channel from native non-transparent surface, if defined
   SDLSetAlpha(new_surface, FALSE, 0);
@@ -2264,8 +2361,7 @@ Bitmap *SDLZoomBitmap(Bitmap *src_bitmap, int dst_width, int dst_height)
 
   // set color key for zoomed surface from source surface, if defined
   if (SDLHasColorKey(src_surface))
-    SDL_SetColorKey(dst_surface, SET_TRANSPARENT_PIXEL,
-                   SDLGetColorKey(src_surface));
+    SDLCopyColorKey(src_surface, dst_surface);
 
   // create native non-transparent surface for opaque blitting
   dst_bitmap->surface = SDLGetOpaqueSurface(dst_surface);
@@ -2300,8 +2396,7 @@ Bitmap *SDLLoadImage(char *filename)
 
   // load image to temporary surface
   if ((sdl_image_tmp = IMG_Load(filename)) == NULL)
-    Error(ERR_EXIT, "IMG_Load('%s') failed: %s", getBaseNamePtr(filename),
-         SDL_GetError());
+    Fail("IMG_Load('%s') failed: %s", getBaseNamePtr(filename), SDL_GetError());
 
   print_timestamp_time("IMG_Load");
 
@@ -2309,7 +2404,7 @@ Bitmap *SDLLoadImage(char *filename)
 
   // create native non-transparent surface for current image
   if ((new_bitmap->surface = SDLGetOpaqueSurface(sdl_image_tmp)) == NULL)
-    Error(ERR_EXIT, "SDLGetOpaqueSurface() failed");
+    Fail("SDLGetOpaqueSurface() failed");
 
   print_timestamp_time("SDLGetNativeSurface (opaque)");
 
@@ -2323,7 +2418,7 @@ Bitmap *SDLLoadImage(char *filename)
 
   // create native transparent surface for current image
   if ((new_bitmap->surface_masked = SDLGetNativeSurface(sdl_image_tmp)) == NULL)
-    Error(ERR_EXIT, "SDLGetNativeSurface() failed");
+    Fail("SDLGetNativeSurface() failed");
 
   print_timestamp_time("SDLGetNativeSurface (masked)");
 
@@ -2389,7 +2484,8 @@ void SDLOpenAudio(void)
 
   if (SDL_InitSubSystem(SDL_INIT_AUDIO) < 0)
   {
-    Error(ERR_WARN, "SDL_InitSubSystem() failed: %s", SDL_GetError());
+    Warn("SDL_InitSubSystem() failed: %s", SDL_GetError());
+
     return;
   }
 
@@ -2397,7 +2493,8 @@ void SDLOpenAudio(void)
                    AUDIO_NUM_CHANNELS_STEREO,
                    setup.system.audio_fragment_size) < 0)
   {
-    Error(ERR_WARN, "Mix_OpenAudio() failed: %s", SDL_GetError());
+    Warn("Mix_OpenAudio() failed: %s", SDL_GetError());
+
     return;
   }
 
@@ -2488,7 +2585,7 @@ boolean SDLOpenJoystick(int nr)
   sdl_is_controller[nr] = SDL_IsGameController(nr);
 
 #if DEBUG_JOYSTICKS
-  Error(ERR_DEBUG, "opening joystick %d (%s)",
+  Debug("joystick", "opening joystick %d (%s)",
        nr, (sdl_is_controller[nr] ? "game controller" : "joystick"));
 #endif
 
@@ -2506,7 +2603,7 @@ void SDLCloseJoystick(int nr)
     return;
 
 #if DEBUG_JOYSTICKS
-  Error(ERR_DEBUG, "closing joystick %d", nr);
+  Debug("joystick", "closing joystick %d", nr);
 #endif
 
   if (sdl_is_controller[nr])
@@ -2592,7 +2689,7 @@ void HandleJoystickEvent(Event *event)
   {
     case SDL_CONTROLLERDEVICEADDED:
 #if DEBUG_JOYSTICKS
-      Error(ERR_DEBUG, "SDL_CONTROLLERDEVICEADDED: device %d added",
+      Debug("joystick", "SDL_CONTROLLERDEVICEADDED: device %d added",
            event->cdevice.which);
 #endif
       InitJoysticks();
@@ -2600,7 +2697,7 @@ void HandleJoystickEvent(Event *event)
 
     case SDL_CONTROLLERDEVICEREMOVED:
 #if DEBUG_JOYSTICKS
-      Error(ERR_DEBUG, "SDL_CONTROLLERDEVICEREMOVED: device %d removed",
+      Debug("joystick", "SDL_CONTROLLERDEVICEREMOVED: device %d removed",
            event->cdevice.which);
 #endif
       InitJoysticks();
@@ -2608,7 +2705,7 @@ void HandleJoystickEvent(Event *event)
 
     case SDL_CONTROLLERAXISMOTION:
 #if DEBUG_JOYSTICKS
-      Error(ERR_DEBUG, "SDL_CONTROLLERAXISMOTION: device %d, axis %d: %d",
+      Debug("joystick", "SDL_CONTROLLERAXISMOTION: device %d, axis %d: %d",
            event->caxis.which, event->caxis.axis, event->caxis.value);
 #endif
       setJoystickAxis(event->caxis.which,
@@ -2618,7 +2715,7 @@ void HandleJoystickEvent(Event *event)
 
     case SDL_CONTROLLERBUTTONDOWN:
 #if DEBUG_JOYSTICKS
-      Error(ERR_DEBUG, "SDL_CONTROLLERBUTTONDOWN: device %d, button %d",
+      Debug("joystick", "SDL_CONTROLLERBUTTONDOWN: device %d, button %d",
            event->cbutton.which, event->cbutton.button);
 #endif
       setJoystickButton(event->cbutton.which,
@@ -2628,7 +2725,7 @@ void HandleJoystickEvent(Event *event)
 
     case SDL_CONTROLLERBUTTONUP:
 #if DEBUG_JOYSTICKS
-      Error(ERR_DEBUG, "SDL_CONTROLLERBUTTONUP: device %d, button %d",
+      Debug("joystick", "SDL_CONTROLLERBUTTONUP: device %d, button %d",
            event->cbutton.which, event->cbutton.button);
 #endif
       setJoystickButton(event->cbutton.which,
@@ -2641,7 +2738,7 @@ void HandleJoystickEvent(Event *event)
        break;
 
 #if DEBUG_JOYSTICKS
-      Error(ERR_DEBUG, "SDL_JOYAXISMOTION: device %d, axis %d: %d",
+      Debug("joystick", "SDL_JOYAXISMOTION: device %d, axis %d: %d",
            event->jaxis.which, event->jaxis.axis, event->jaxis.value);
 #endif
       if (event->jaxis.axis < 4)
@@ -2655,7 +2752,7 @@ void HandleJoystickEvent(Event *event)
        break;
 
 #if DEBUG_JOYSTICKS
-      Error(ERR_DEBUG, "SDL_JOYBUTTONDOWN: device %d, button %d",
+      Debug("joystick", "SDL_JOYBUTTONDOWN: device %d, button %d",
            event->jbutton.which, event->jbutton.button);
 #endif
       if (event->jbutton.button < 4)
@@ -2669,7 +2766,7 @@ void HandleJoystickEvent(Event *event)
        break;
 
 #if DEBUG_JOYSTICKS
-      Error(ERR_DEBUG, "SDL_JOYBUTTONUP: device %d, button %d",
+      Debug("joystick", "SDL_JOYBUTTONUP: device %d, button %d",
            event->jbutton.which, event->jbutton.button);
 #endif
       if (event->jbutton.button < 4)
@@ -2689,7 +2786,7 @@ void SDLInitJoysticks(void)
   boolean print_warning = !sdl_joystick_subsystem_initialized;
   char *mappings_file_base = getPath2(options.conf_directory,
                                      GAMECONTROLLER_BASENAME);
-  char *mappings_file_user = getPath2(getUserGameDataDir(),
+  char *mappings_file_user = getPath2(getMainUserGameDataDir(),
                                      GAMECONTROLLER_BASENAME);
   int num_mappings;
   int i;
@@ -2701,19 +2798,17 @@ void SDLInitJoysticks(void)
     SDL_SetHint(SDL_HINT_ACCELEROMETER_AS_JOYSTICK, "0");
 
     if (SDL_InitSubSystem(SDL_INIT_GAMECONTROLLER) < 0)
-    {
-      Error(ERR_EXIT, "SDL_Init() failed: %s", SDL_GetError());
-      return;
-    }
+      Fail("SDL_Init() failed: %s", SDL_GetError());
 
     num_mappings = SDL_GameControllerAddMappingsFromFile(mappings_file_base);
 
     // the included game controller base mappings should always be found
     if (num_mappings == -1)
-      Error(ERR_WARN, "no game controller base mappings found");
+      Warn("no game controller base mappings found");
 #if DEBUG_JOYSTICKS
     else
-      Error(ERR_INFO, "%d game controller base mapping(s) added", num_mappings);
+      Debug("joystick", "%d game controller base mapping(s) added",
+           num_mappings);
 #endif
 
     num_mappings = SDL_GameControllerAddMappingsFromFile(mappings_file_user);
@@ -2721,11 +2816,12 @@ void SDLInitJoysticks(void)
 #if DEBUG_JOYSTICKS
     // the personal game controller user mappings may or may not be found
     if (num_mappings == -1)
-      Error(ERR_WARN, "no game controller user mappings found");
+      Warn("no game controller user mappings found");
     else
-      Error(ERR_INFO, "%d game controller user mapping(s) added", num_mappings);
+      Debug("joystick", , "%d game controller user mapping(s) added",
+           num_mappings);
 
-    Error(ERR_INFO, "%d joystick(s) found:", SDL_NumJoysticks());
+    Debug("joystick", "%d joystick(s) found:", SDL_NumJoysticks());
 #endif
 
     checked_free(mappings_file_base);
@@ -2747,7 +2843,7 @@ void SDLInitJoysticks(void)
        type = "joystick";
       }
 
-      Error(ERR_INFO, "- joystick %d (%s): '%s'",
+      Debug("joystick", "- joystick %d (%s): '%s'",
            i, type, (name ? name : "(Unknown)"));
     }
 #endif
@@ -2763,7 +2859,7 @@ void SDLInitJoysticks(void)
     if (joystick_nr >= SDL_NumJoysticks())
     {
       if (setup.input[i].use_joystick && print_warning)
-       Error(ERR_WARN, "cannot find joystick %d", joystick_nr);
+       Warn("cannot find joystick %d", joystick_nr);
 
       joystick_nr = -1;
     }
@@ -2782,7 +2878,7 @@ void SDLInitJoysticks(void)
     if (SDLOpenJoystick(i))
       joystick.status = JOYSTICK_ACTIVATED;
     else if (print_warning)
-      Error(ERR_WARN, "cannot open joystick %d", i);
+      Warn("cannot open joystick %d", i);
   }
 
   SDLClearJoystickState();