changed drawing of global borders to more generic approach
[rocksndiamonds.git] / src / libgame / sdl.c
index 0759b549fe643dc5ace17a427b8b38f77b6dbd0c..6b38ce15ba6fd28bcac51149c2629914932f0376 100644 (file)
@@ -53,7 +53,8 @@ void SDLLimitScreenUpdates(boolean enable)
 static void UpdateScreen(SDL_Rect *rect)
 {
   static unsigned int update_screen_delay = 0;
-  unsigned int update_screen_delay_value = 20;         /* (milliseconds) */
+  unsigned int update_screen_delay_value = 50;         /* (milliseconds) */
+  SDL_Surface *screen = backbuffer->surface;
 
   if (limit_screen_updates &&
       !DelayReached(&update_screen_delay, update_screen_delay_value))
@@ -78,10 +79,37 @@ static void UpdateScreen(SDL_Rect *rect)
   }
 #endif
 
+#if USE_FINAL_SCREEN_BITMAP
+  if (gfx.final_screen_bitmap != NULL) // may not be initialized yet
+  {
+    // !!! TEST !!!
+    // draw global animations using bitmaps instead of using textures
+    // to prevent texture scaling artefacts (this is potentially slower)
+
+    BlitBitmap(backbuffer, gfx.final_screen_bitmap, 0, 0,
+              gfx.win_xsize, gfx.win_ysize, 0, 0);
+
+    // copy global animations to render target buffer, if defined (below border)
+    if (gfx.draw_global_anim_function != NULL)
+      gfx.draw_global_anim_function(DRAW_GLOBAL_ANIM_STAGE_1);
+
+    // copy global masked border to render target buffer, if defined
+    if (gfx.draw_global_border_function != NULL)
+      gfx.draw_global_border_function(DRAW_BORDER_TO_SCREEN);
+
+    // copy global animations to render target buffer, if defined (above border)
+    if (gfx.draw_global_anim_function != NULL)
+      gfx.draw_global_anim_function(DRAW_GLOBAL_ANIM_STAGE_2);
+
+    screen = gfx.final_screen_bitmap->surface;
+
+    // force full window redraw
+    rect = NULL;
+  }
+#endif
+
 #if defined(TARGET_SDL2)
 #if USE_RENDERER
-  SDL_Surface *screen = backbuffer->surface;
-
   if (rect)
   {
     int bytes_x = screen->pitch / video.width;
@@ -105,9 +133,19 @@ static void UpdateScreen(SDL_Rect *rect)
   // copy backbuffer to render target buffer
   SDL_RenderCopy(sdl_renderer, sdl_texture, NULL, NULL);
 
-  // copy global animations to render target buffer, if defined
+#if !USE_FINAL_SCREEN_BITMAP
+  // copy global animations to render target buffer, if defined (below border)
   if (gfx.draw_global_anim_function != NULL)
-    gfx.draw_global_anim_function();
+    gfx.draw_global_anim_function(DRAW_GLOBAL_ANIM_STAGE_1);
+
+  // copy global masked border to render target buffer, if defined
+  if (gfx.draw_global_border_function != NULL)
+    gfx.draw_global_border_function(DRAW_BORDER_TO_SCREEN);
+
+  // copy global animations to render target buffer, if defined (above border)
+  if (gfx.draw_global_anim_function != NULL)
+    gfx.draw_global_anim_function(DRAW_GLOBAL_ANIM_STAGE_2);
+#endif
 
   // show render target buffer on screen
   SDL_RenderPresent(sdl_renderer);
@@ -122,9 +160,9 @@ static void UpdateScreen(SDL_Rect *rect)
 
 #else  // TARGET_SDL
   if (rect)
-    SDL_UpdateRects(backbuffer->surface, 1, rect);
+    SDL_UpdateRects(screen, 1, rect);
   else
-    SDL_UpdateRect(backbuffer->surface, 0, 0, 0, 0);
+    SDL_UpdateRect(screen, 0, 0, 0, 0);
 #endif
 }
 
@@ -240,15 +278,23 @@ boolean SDLSetNativeSurface(SDL_Surface **surface)
 
 SDL_Surface *SDLGetNativeSurface(SDL_Surface *surface)
 {
+  SDL_PixelFormat format;
   SDL_Surface *new_surface;
 
   if (surface == NULL)
     return NULL;
 
   if (backbuffer && backbuffer->surface)
-    new_surface = SDL_ConvertSurface(surface, backbuffer->surface->format, 0);
+  {
+    format = *backbuffer->surface->format;
+    format.Amask = surface->format->Amask;     // keep alpha channel
+  }
   else
-    new_surface = SDL_ConvertSurface(surface, surface->format, 0);
+  {
+    format = *surface->format;
+  }
+
+  new_surface = SDL_ConvertSurface(surface, &format, 0);
 
   if (new_surface == NULL)
     Error(ERR_EXIT, "SDL_ConvertSurface() failed: %s", SDL_GetError());
@@ -327,6 +373,22 @@ void SDLCreateBitmapTextures(Bitmap *bitmap)
 #endif
 }
 
+void SDLFreeBitmapTextures(Bitmap *bitmap)
+{
+#if defined(TARGET_SDL2)
+  if (bitmap == NULL)
+    return;
+
+  if (bitmap->texture)
+    SDL_DestroyTexture(bitmap->texture);
+  if (bitmap->texture_masked)
+    SDL_DestroyTexture(bitmap->texture_masked);
+
+  bitmap->texture = NULL;
+  bitmap->texture_masked = NULL;
+#endif
+}
+
 void SDLInitVideoDisplay(void)
 {
 #if !defined(TARGET_SDL2)
@@ -1048,10 +1110,9 @@ void 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))
 {
-  static boolean initialization_needed = TRUE;
-  static SDL_Surface *surface_source = NULL;
-  static SDL_Surface *surface_target = NULL;
-  static SDL_Surface *surface_black = NULL;
+  SDL_Surface *surface_source = gfx.fade_bitmap_source->surface;
+  SDL_Surface *surface_target = gfx.fade_bitmap_target->surface;
+  SDL_Surface *surface_black  = gfx.fade_bitmap_black->surface;
   SDL_Surface *surface_screen = backbuffer->surface;
   SDL_Surface *surface_cross = (bitmap_cross ? bitmap_cross->surface : NULL);
   SDL_Rect src_rect, dst_rect;
@@ -1060,16 +1121,12 @@ void SDLFadeRectangle(Bitmap *bitmap_cross, int x, int y, int width, int height,
   int dst_x = x, dst_y = y;
   unsigned int time_last, time_current;
 
-  /* check if screen size has changed */
-  if (surface_source != NULL && (video.width  != surface_source->w ||
-                                video.height != surface_source->h))
-  {
-    SDL_FreeSurface(surface_source);
-    SDL_FreeSurface(surface_target);
-    SDL_FreeSurface(surface_black);
+  // store function for drawing global masked border
+  void (*draw_global_border_function)(int) = gfx.draw_global_border_function;
 
-    initialization_needed = TRUE;
-  }
+  // deactivate drawing of global border while fading, if needed
+  if (draw_border_function == NULL)
+    gfx.draw_global_border_function = NULL;
 
   src_rect.x = src_x;
   src_rect.y = src_y;
@@ -1086,63 +1143,6 @@ void SDLFadeRectangle(Bitmap *bitmap_cross, int x, int y, int width, int height,
 
   dst_rect2 = dst_rect;
 
-  if (initialization_needed)
-  {
-#if defined(TARGET_SDL2)
-    unsigned int flags = 0;
-#else
-    unsigned int flags = SDL_SRCALPHA;
-
-    /* use same surface type as screen surface */
-    if ((surface_screen->flags & SDL_HWSURFACE))
-      flags |= SDL_HWSURFACE;
-    else
-      flags |= SDL_SWSURFACE;
-#endif
-
-    /* create surface for temporary copy of screen buffer (source) */
-    if ((surface_source =
-        SDL_CreateRGBSurface(flags,
-                             video.width,
-                             video.height,
-                             surface_screen->format->BitsPerPixel,
-                             surface_screen->format->Rmask,
-                             surface_screen->format->Gmask,
-                             surface_screen->format->Bmask,
-                             surface_screen->format->Amask)) == NULL)
-      Error(ERR_EXIT, "SDL_CreateRGBSurface() failed: %s", SDL_GetError());
-
-    /* create surface for cross-fading screen buffer (target) */
-    if ((surface_target =
-        SDL_CreateRGBSurface(flags,
-                             video.width,
-                             video.height,
-                             surface_screen->format->BitsPerPixel,
-                             surface_screen->format->Rmask,
-                             surface_screen->format->Gmask,
-                             surface_screen->format->Bmask,
-                             surface_screen->format->Amask)) == NULL)
-      Error(ERR_EXIT, "SDL_CreateRGBSurface() failed: %s", SDL_GetError());
-
-    /* create black surface for fading from/to black */
-    if ((surface_black =
-        SDL_CreateRGBSurface(flags,
-                             video.width,
-                             video.height,
-                             surface_screen->format->BitsPerPixel,
-                             surface_screen->format->Rmask,
-                             surface_screen->format->Gmask,
-                             surface_screen->format->Bmask,
-                             surface_screen->format->Amask)) == NULL)
-      Error(ERR_EXIT, "SDL_CreateRGBSurface() failed: %s", SDL_GetError());
-
-    /* completely fill the surface with black color pixels */
-    SDL_FillRect(surface_black, NULL,
-                SDL_MapRGB(surface_screen->format, 0, 0, 0));
-
-    initialization_needed = FALSE;
-  }
-
   /* copy source and target surfaces to temporary surfaces for fading */
   if (fade_mode & FADE_TYPE_TRANSFORM)
   {
@@ -1374,7 +1374,27 @@ void SDLFadeRectangle(Bitmap *bitmap_cross, int x, int y, int width, int height,
     }
   }
 
-  Delay(post_delay);
+  if (post_delay > 0)
+  {
+    unsigned int time_post_delay;
+
+    time_current = SDL_GetTicks();
+    time_post_delay = time_current + post_delay;
+
+    while (time_current < time_post_delay)
+    {
+      // do not wait longer than 10 ms at a time to be able to ...
+      Delay(MIN(10, time_post_delay - time_current));
+
+      // ... continue drawing global animations during post delay
+      UpdateScreen(NULL);
+
+      time_current = SDL_GetTicks();
+    }
+  }
+
+  // restore function for drawing global masked border
+  gfx.draw_global_border_function = draw_global_border_function;
 }
 
 void SDLDrawSimpleLine(Bitmap *dst_bitmap, int from_x, int from_y,
@@ -2381,8 +2401,9 @@ Bitmap *SDLLoadImage(char *filename)
   UPDATE_BUSY_STATE();
 
   /* create native transparent surface for current image */
-  SDL_SetColorKey(sdl_image_tmp, SET_TRANSPARENT_PIXEL,
-                 SDL_MapRGB(sdl_image_tmp->format, 0x00, 0x00, 0x00));
+  if (sdl_image_tmp->format->Amask == 0)
+    SDL_SetColorKey(sdl_image_tmp, SET_TRANSPARENT_PIXEL,
+                   SDL_MapRGB(sdl_image_tmp->format, 0x00, 0x00, 0x00));
 
   if ((new_bitmap->surface_masked = SDLGetNativeSurface(sdl_image_tmp)) == NULL)
   {