rnd-20030403-2-src
[rocksndiamonds.git] / src / libgame / system.c
index cc7dc2aa33fb4111ff5f737ca76a4a731437960c..7d25d4cd26962497585b0f605433fc2c609fc5ef 100644 (file)
@@ -66,10 +66,31 @@ int                 FrameCounter = 0;
 /* init/close functions                                                      */
 /* ========================================================================= */
 
-void InitCommandName(char *argv0)
+void InitProgramInfo(char *argv0,
+                    char *userdata_directory, char *program_title,
+                    char *window_title, char *icon_title,
+                    char *x11_icon_filename, char *x11_iconmask_filename,
+                    char *msdos_pointer_filename,
+                    char *cookie_prefix, char *filename_prefix,
+                    int program_version)
 {
   program.command_basename =
     (strrchr(argv0, '/') ? strrchr(argv0, '/') + 1 : argv0);
+
+  program.userdata_directory = userdata_directory;
+  program.program_title = program_title;
+  program.window_title = window_title;
+  program.icon_title = icon_title;
+  program.x11_icon_filename = x11_icon_filename;
+  program.x11_iconmask_filename = x11_iconmask_filename;
+  program.msdos_pointer_filename = msdos_pointer_filename;
+
+  program.cookie_prefix = cookie_prefix;
+  program.filename_prefix = filename_prefix;
+
+  program.version_major = VERSION_MAJOR(program_version);
+  program.version_minor = VERSION_MINOR(program_version);
+  program.version_patch = VERSION_PATCH(program_version);
 }
 
 void InitExitFunction(void (*exit_function)(int))
@@ -90,10 +111,6 @@ void InitPlatformDependantStuff(void)
 {
 #if defined(PLATFORM_MSDOS)
   _fmode = O_BINARY;
-#endif
-
-#if !defined(PLATFORM_UNIX)
-  program.userdata_directory = "userdata";
   initErrorFile();
 #endif
 
@@ -105,42 +122,15 @@ void InitPlatformDependantStuff(void)
 
 void ClosePlatformDependantStuff(void)
 {
-#if !defined(PLATFORM_UNIX)
+#if defined(PLATFORM_MSDOS)
   dumpErrorFile();
 #endif
 }
 
-void InitProgramInfo(char *unix_userdata_directory, char *program_title,
-                    char *window_title, char *icon_title,
-                    char *x11_icon_filename, char *x11_iconmask_filename,
-                    char *msdos_pointer_filename,
-                    char *cookie_prefix, char *filename_prefix,
-                    int program_version)
-{
-#if defined(PLATFORM_UNIX)
-  program.userdata_directory = unix_userdata_directory;
-#else
-  program.userdata_directory = "userdata";
-#endif
-
-  program.program_title = program_title;
-  program.window_title = window_title;
-  program.icon_title = icon_title;
-  program.x11_icon_filename = x11_icon_filename;
-  program.x11_iconmask_filename = x11_iconmask_filename;
-  program.msdos_pointer_filename = msdos_pointer_filename;
-
-  program.cookie_prefix = cookie_prefix;
-  program.filename_prefix = filename_prefix;
-
-  program.version_major = VERSION_MAJOR(program_version);
-  program.version_minor = VERSION_MINOR(program_version);
-  program.version_patch = VERSION_PATCH(program_version);
-}
-
 void InitGfxFieldInfo(int sx, int sy, int sxsize, int sysize,
                      int real_sx, int real_sy,
-                     int full_sxsize, int full_sysize)
+                     int full_sxsize, int full_sysize,
+                     Bitmap *field_save_buffer)
 {
   gfx.sx = sx;
   gfx.sy = sy;
@@ -151,7 +141,13 @@ void InitGfxFieldInfo(int sx, int sy, int sxsize, int sysize,
   gfx.full_sxsize = full_sxsize;
   gfx.full_sysize = full_sysize;
 
+  gfx.field_save_buffer = field_save_buffer;
+
+  gfx.background_bitmap = NULL;
+  gfx.background_bitmap_mask = REDRAW_NONE;
+
   SetDrawDeactivationMask(REDRAW_NONE);                /* do not deactivate drawing */
+  SetDrawBackgroundMask(REDRAW_NONE);          /* deactivate masked drawing */
 }
 
 void InitGfxDoor1Info(int dx, int dy, int dxsize, int dysize)
@@ -182,6 +178,90 @@ void SetDrawDeactivationMask(int draw_deactivation_mask)
   gfx.draw_deactivation_mask = draw_deactivation_mask;
 }
 
+void SetDrawBackgroundMask(int draw_background_mask)
+{
+  gfx.draw_background_mask = draw_background_mask;
+}
+
+static void DrawBitmapFromTile(Bitmap *bitmap, Bitmap *tile,
+                              int dest_x, int dest_y, int width, int height)
+{
+  int bitmap_xsize = width;
+  int bitmap_ysize = height;
+  int tile_xsize = tile->width;
+  int tile_ysize = tile->height;
+  int tile_xsteps = (bitmap_xsize + tile_xsize - 1) / tile_xsize;
+  int tile_ysteps = (bitmap_ysize + tile_ysize - 1) / tile_ysize;
+  int x, y;
+
+  for (y=0; y < tile_ysteps; y++)
+  {
+    for (x=0; x < tile_xsteps; x++)
+    {
+      int draw_x = dest_x + x * tile_xsize;
+      int draw_y = dest_y + y * tile_ysize;
+      int draw_xsize = MIN(tile_xsize, bitmap_xsize - x * tile_xsize);
+      int draw_ysize = MIN(tile_ysize, bitmap_ysize - y * tile_ysize);
+
+      BlitBitmap(tile, bitmap, 0, 0, draw_xsize, draw_ysize, draw_x, draw_y);
+    }
+  }
+}
+
+void SetBackgroundBitmap(Bitmap *background_bitmap_tile, int mask)
+{
+  static Bitmap *main_bitmap_tile = NULL;
+  static Bitmap *door_bitmap_tile = NULL;
+
+  if (mask == REDRAW_FIELD)
+  {
+    if (background_bitmap_tile == main_bitmap_tile)
+      return;          /* main background tile has not changed */
+
+    main_bitmap_tile = background_bitmap_tile;
+  }
+  else if (mask == REDRAW_DOOR_1)
+  {
+    if (background_bitmap_tile == door_bitmap_tile)
+      return;  /* main background tile has not changed */
+
+    door_bitmap_tile = background_bitmap_tile;
+  }
+  else         /* should not happen */
+    return;
+
+  if (background_bitmap_tile)
+    gfx.background_bitmap_mask |= mask;
+  else
+    gfx.background_bitmap_mask &= ~mask;
+
+  if (gfx.background_bitmap == NULL)
+    gfx.background_bitmap = CreateBitmap(video.width, video.height,
+                                        DEFAULT_DEPTH);
+
+  if (background_bitmap_tile == NULL)  /* empty background requested */
+    return;
+
+  if (mask == REDRAW_FIELD)
+    DrawBitmapFromTile(gfx.background_bitmap, background_bitmap_tile,
+                      gfx.real_sx, gfx.real_sy,
+                      gfx.full_sxsize, gfx.full_sysize);
+  else
+    DrawBitmapFromTile(gfx.background_bitmap, background_bitmap_tile,
+                      gfx.dx, gfx.dy,
+                      gfx.dxsize, gfx.dysize);
+}
+
+void SetMainBackgroundBitmap(Bitmap *background_bitmap_tile)
+{
+  SetBackgroundBitmap(background_bitmap_tile, REDRAW_FIELD);
+}
+
+void SetDoorBackgroundBitmap(Bitmap *background_bitmap_tile)
+{
+  SetBackgroundBitmap(background_bitmap_tile, REDRAW_DOOR_1);
+}
+
 
 /* ========================================================================= */
 /* video functions                                                           */
@@ -278,6 +358,9 @@ inline Bitmap *CreateBitmap(int width, int height, int depth)
   new_bitmap->line_gc[1] = window->line_gc[1];
 #endif
 
+  new_bitmap->width = width;
+  new_bitmap->height = height;
+
   return new_bitmap;
 }
 
@@ -295,7 +378,7 @@ inline static void FreeBitmapPointers(Bitmap *bitmap)
   bitmap->surface_masked = NULL;
 #else
   /* The X11 version seems to have a memory leak here -- although
-     "XFreePixmap()" is called, the correspondig memory seems not
+     "XFreePixmap()" is called, the corresponding memory seems not
      to be freed (according to "ps"). The SDL version apparently
      does not have this problem. */
 
@@ -350,28 +433,38 @@ inline void CloseWindow(DrawWindow *window)
 #endif
 }
 
-inline boolean DrawingDeactivated(int x, int y, int width, int height)
+static inline boolean CheckDrawingArea(int x, int y, int width, int height,
+                                      int draw_mask)
 {
-  if (gfx.draw_deactivation_mask != REDRAW_NONE)
-  {
-    if ((gfx.draw_deactivation_mask & REDRAW_FIELD) &&
-       x < gfx.sx + gfx.sxsize)
-      return TRUE;
-    else if ((gfx.draw_deactivation_mask & REDRAW_DOORS) &&
-            x > gfx.dx)
-    {
-      if ((gfx.draw_deactivation_mask & REDRAW_DOOR_1) &&
-         y < gfx.dy + gfx.dysize)
-       return TRUE;
-      else if ((gfx.draw_deactivation_mask & REDRAW_DOOR_2) &&
-              y > gfx.vy)
-       return TRUE;
-    }
-  }
+  if (draw_mask == REDRAW_NONE)
+    return FALSE;
+
+  if (draw_mask & REDRAW_ALL)
+    return TRUE;
+
+  if ((draw_mask & REDRAW_FIELD) && x < gfx.real_sx + gfx.full_sxsize)
+    return TRUE;
+
+  if ((draw_mask & REDRAW_DOOR_1) && x >= gfx.dx && y < gfx.dy + gfx.dysize)
+    return TRUE;
+
+  if ((draw_mask & REDRAW_DOOR_2) && x >= gfx.dx && y >= gfx.vy)
+    return TRUE;
 
   return FALSE;
 }
 
+inline boolean DrawingDeactivated(int x, int y, int width, int height)
+{
+  return CheckDrawingArea(x, y, width, height, gfx.draw_deactivation_mask);
+}
+
+inline boolean DrawingOnBackground(int x, int y)
+{
+  return ((gfx.draw_background_mask & gfx.background_bitmap_mask) &&
+         CheckDrawingArea(x, y, 1, 1, gfx.draw_background_mask));
+}
+
 inline void BlitBitmap(Bitmap *src_bitmap, Bitmap *dst_bitmap,
                       int src_x, int src_y,
                       int width, int height,
@@ -389,6 +482,31 @@ inline void BlitBitmap(Bitmap *src_bitmap, Bitmap *dst_bitmap,
 #endif
 }
 
+inline void DrawRectangle(Bitmap *bitmap, int x, int y, int width, int height,
+                         Pixel color)
+{
+  if (DrawingDeactivated(x, y, width, height))
+    return;
+
+#ifdef TARGET_SDL
+  SDLFillRectangle(bitmap, x, y, width, height, color);
+#else
+  XSetForeground(display, bitmap->gc, color);
+  XFillRectangle(display, bitmap->drawable, bitmap->gc, x, y, width, height);
+  XSetForeground(display, bitmap->gc, BlackPixel(display, screen));
+#endif
+}
+
+#if 1
+inline void ClearRectangle(Bitmap *bitmap, int x, int y, int width, int height)
+{
+#ifdef TARGET_SDL
+  DrawRectangle(bitmap, x, y, width, height, 0x000000);
+#else
+  DrawRectangle(bitmap, x, y, width, height, 0x000000);
+#endif
+}
+#else
 inline void ClearRectangle(Bitmap *bitmap, int x, int y, int width, int height)
 {
   if (DrawingDeactivated(x, y, width, height))
@@ -400,6 +518,16 @@ inline void ClearRectangle(Bitmap *bitmap, int x, int y, int width, int height)
   XFillRectangle(display, bitmap->drawable, bitmap->gc, x, y, width, height);
 #endif
 }
+#endif
+
+inline void ClearRectangleOnBackground(Bitmap *bitmap, int x, int y,
+                                      int width, int height)
+{
+  if (DrawingOnBackground(x, y))
+    BlitBitmap(gfx.background_bitmap, bitmap, x, y, width, height, x, y);
+  else
+    ClearRectangle(bitmap, x, y, width, height);
+}
 
 #if 0
 #ifndef TARGET_SDL
@@ -452,6 +580,28 @@ inline void BlitBitmapMasked(Bitmap *src_bitmap, Bitmap *dst_bitmap,
 #endif
 }
 
+inline void BlitBitmapOnBackground(Bitmap *src_bitmap, Bitmap *dst_bitmap,
+                                  int src_x, int src_y,
+                                  int width, int height,
+                                  int dst_x, int dst_y)
+{
+  if (DrawingOnBackground(dst_x, dst_y))
+  {
+    /* draw background */
+    BlitBitmap(gfx.background_bitmap, dst_bitmap, dst_x, dst_y, width, height,
+              dst_x, dst_y);
+
+    /* draw foreground */
+    SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
+                 dst_x - src_x, dst_y - src_y);
+    BlitBitmapMasked(src_bitmap, dst_bitmap, src_x, src_y, width, height,
+                    dst_x, dst_y);
+  }
+  else
+    BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, width, height,
+              dst_x, dst_y);
+}
+
 inline void DrawSimpleWhiteLine(Bitmap *bitmap, int from_x, int from_y,
                                int to_x, int to_y)
 {
@@ -718,7 +868,8 @@ void ReloadCustomImage(Bitmap *bitmap, char *basename)
   if (bitmap->width != new_bitmap->width ||
       bitmap->height != new_bitmap->height)
   {
-    Error(ERR_WARN, "ReloadCustomImage: new image has wrong dimensions");
+    Error(ERR_WARN, "ReloadCustomImage: new image '%s' has wrong dimensions",
+         filename);
     FreeBitmap(new_bitmap);
     return;
   }
@@ -727,6 +878,58 @@ void ReloadCustomImage(Bitmap *bitmap, char *basename)
   free(new_bitmap);
 }
 
+Bitmap *ZoomBitmap(Bitmap *src_bitmap, int zoom_width, int zoom_height)
+{
+  Bitmap *dst_bitmap = CreateBitmap(zoom_width, zoom_height, DEFAULT_DEPTH);
+
+#if defined(TARGET_SDL)
+  SDLZoomBitmap(src_bitmap, dst_bitmap);
+#else
+  X11ZoomBitmap(src_bitmap, dst_bitmap);
+#endif
+
+  return dst_bitmap;
+}
+
+void CreateBitmapWithSmallBitmaps(Bitmap *src_bitmap)
+{
+  Bitmap *tmp_bitmap, *tmp_bitmap_2, *tmp_bitmap_8;
+  int src_width, src_height;
+  int tmp_width, tmp_height;
+
+  src_width  = src_bitmap->width;
+  src_height = src_bitmap->height;
+
+  tmp_width  = src_width;
+  tmp_height = src_height + src_height / 2;
+
+  tmp_bitmap = CreateBitmap(tmp_width, tmp_height, DEFAULT_DEPTH);
+
+  tmp_bitmap_2 = ZoomBitmap(src_bitmap, src_width / 2, src_height / 2);
+  tmp_bitmap_8 = ZoomBitmap(src_bitmap, src_width / 8, src_height / 8);
+
+  BlitBitmap(src_bitmap, tmp_bitmap, 0, 0, src_width, src_height, 0, 0);
+  BlitBitmap(tmp_bitmap_2, tmp_bitmap, 0, 0, src_width / 2, src_height / 2,
+            0, src_height);
+  BlitBitmap(tmp_bitmap_8, tmp_bitmap, 0, 0, src_width / 8, src_height / 8,
+            3 * src_width / 4, src_height);
+
+  FreeBitmap(tmp_bitmap_2);
+  FreeBitmap(tmp_bitmap_8);
+
+#ifdef TARGET_SDL
+  src_bitmap->surface = tmp_bitmap->surface;
+  tmp_bitmap->surface = NULL;
+#else
+  src_bitmap->drawable = tmp_bitmap->drawable;
+  tmp_bitmap->drawable = None;
+#endif
+
+  src_bitmap->height = tmp_bitmap->height;
+
+  FreeBitmap(tmp_bitmap);
+}
+
 
 /* ========================================================================= */
 /* audio functions                                                           */
@@ -743,7 +946,7 @@ inline void OpenAudio(void)
   audio.sound_deactivated = FALSE;
 
   audio.mixer_pipe[0] = audio.mixer_pipe[1] = 0;
-  audio.mixer_pid = -1;
+  audio.mixer_pid = 0;
   audio.device_name = NULL;
   audio.device_fd = -1;