Merge branch 'global-anims'
authorHolger Schemel <info@artsoft.org>
Fri, 15 Apr 2016 17:51:59 +0000 (19:51 +0200)
committerHolger Schemel <info@artsoft.org>
Fri, 15 Apr 2016 17:51:59 +0000 (19:51 +0200)
32 files changed:
graphics/gfx_classic/RocksScreen.ilbm
src/cartoons.c
src/cartoons.h
src/conf_gfx.c
src/conf_mus.c
src/conf_snd.c
src/config.c
src/editor.c
src/events.c
src/files.c
src/game.c
src/init.c
src/init.h
src/libgame/gadgets.c
src/libgame/image.c
src/libgame/image.h
src/libgame/misc.c
src/libgame/misc.h
src/libgame/sdl.c
src/libgame/sdl.h
src/libgame/sound.c
src/libgame/sound.h
src/libgame/system.c
src/libgame/system.h
src/libgame/toons.c
src/libgame/toons.h
src/main.c
src/main.h
src/network.c
src/screens.c
src/tools.c
src/tools.h

index 7325306b70a50e39f525980dd658153f47867474..274ebec517303a0da040caf3a236c23292bbd769 100644 (file)
Binary files a/graphics/gfx_classic/RocksScreen.ilbm and b/graphics/gfx_classic/RocksScreen.ilbm differ
index a0115cf98dce2b312824186ef95b8ac2afe3c2be..2e74c72b92a5683da4063eb88a88ff1fd6381775 100644 (file)
 #include "tools.h"
 
 
-/* values for toon definition */
-#define MAX_NUM_TOONS                  20
+/* values for global toon animation definition */
+#define NUM_GLOBAL_TOON_ANIMS          1
+#define NUM_GLOBAL_TOON_PARTS          MAX_NUM_TOONS
 
+/* values for global animation definition (including toons) */
+#define NUM_GLOBAL_ANIMS_AND_TOONS     (NUM_GLOBAL_ANIMS +             \
+                                        NUM_GLOBAL_TOON_ANIMS)
+#define NUM_GLOBAL_ANIM_PARTS_AND_TOONS        MAX(NUM_GLOBAL_ANIM_PARTS_ALL,  \
+                                           NUM_GLOBAL_TOON_PARTS)
+
+#define ANIM_CLASS_BIT_TITLE_INITIAL   0
+#define ANIM_CLASS_BIT_TITLE           1
+#define ANIM_CLASS_BIT_MAIN            2
+#define ANIM_CLASS_BIT_SUBMENU         3
+#define ANIM_CLASS_BIT_MENU            4
+#define ANIM_CLASS_BIT_TOONS           5
+
+#define NUM_ANIM_CLASSES               6
+
+#define ANIM_CLASS_NONE                        0
+#define ANIM_CLASS_TITLE_INITIAL       (1 << ANIM_CLASS_BIT_TITLE_INITIAL)
+#define ANIM_CLASS_TITLE               (1 << ANIM_CLASS_BIT_TITLE)
+#define ANIM_CLASS_MAIN                        (1 << ANIM_CLASS_BIT_MAIN)
+#define ANIM_CLASS_SUBMENU             (1 << ANIM_CLASS_BIT_SUBMENU)
+#define ANIM_CLASS_MENU                        (1 << ANIM_CLASS_BIT_MENU)
+#define ANIM_CLASS_TOONS               (1 << ANIM_CLASS_BIT_TOONS)
+
+#define ANIM_CLASS_TOONS_MENU_MAIN     (ANIM_CLASS_TOONS |     \
+                                        ANIM_CLASS_MENU  |     \
+                                        ANIM_CLASS_MAIN)
+
+#define ANIM_CLASS_TOONS_MENU_SUBMENU  (ANIM_CLASS_TOONS |     \
+                                        ANIM_CLASS_MENU  |     \
+                                        ANIM_CLASS_SUBMENU)
+
+struct GlobalAnimPartControlInfo
+{
+  int nr;
+  int anim_nr;
+  int mode_nr;
+
+  int sound;
+  int graphic;
+
+  struct GraphicInfo graphic_info;
+  struct GraphicInfo control_info;
+
+  int viewport_x;
+  int viewport_y;
+  int viewport_width;
+  int viewport_height;
+
+  int x, y;
+  int step_xoffset, step_yoffset;
+
+  unsigned int initial_anim_sync_frame;
+  unsigned int step_delay, step_delay_value;
+
+  int init_delay_counter;
+  int anim_delay_counter;
+  int post_delay_counter;
+
+  int drawing_stage;
+
+  int state;
+  int last_anim_status;
+};
+
+struct GlobalAnimMainControlInfo
+{
+  struct GlobalAnimPartControlInfo base;
+  struct GlobalAnimPartControlInfo part[NUM_GLOBAL_ANIM_PARTS_AND_TOONS];
+
+  int nr;
+  int mode_nr;
+
+  struct GraphicInfo control_info;
+
+  int num_parts;
+  int part_counter;
+  int active_part_nr;
+
+  boolean has_base;
+
+  int init_delay_counter;
+
+  int state;
+
+  int last_state, last_active_part_nr;
+};
+
+struct GlobalAnimControlInfo
+{
+  struct GlobalAnimMainControlInfo anim[NUM_GLOBAL_ANIMS_AND_TOONS];
+
+  int nr;
+  int num_anims;
+};
+
+struct GameModeAnimClass
+{
+  int game_mode;
+  int class;
+} game_mode_anim_classes_list[] =
+{
+  { GAME_MODE_TITLE_INITIAL_1,         ANIM_CLASS_TITLE_INITIAL        },
+  { GAME_MODE_TITLE_INITIAL_2,         ANIM_CLASS_TITLE_INITIAL        },
+  { GAME_MODE_TITLE_INITIAL_3,         ANIM_CLASS_TITLE_INITIAL        },
+  { GAME_MODE_TITLE_INITIAL_4,         ANIM_CLASS_TITLE_INITIAL        },
+  { GAME_MODE_TITLE_INITIAL_5,         ANIM_CLASS_TITLE_INITIAL        },
+  { GAME_MODE_TITLE_1,                 ANIM_CLASS_TITLE                },
+  { GAME_MODE_TITLE_2,                 ANIM_CLASS_TITLE                },
+  { GAME_MODE_TITLE_3,                 ANIM_CLASS_TITLE                },
+  { GAME_MODE_TITLE_4,                 ANIM_CLASS_TITLE                },
+  { GAME_MODE_TITLE_5,                 ANIM_CLASS_TITLE                },
+  { GAME_MODE_LEVELS,                  ANIM_CLASS_TOONS_MENU_SUBMENU   },
+  { GAME_MODE_LEVELNR,                 ANIM_CLASS_TOONS_MENU_SUBMENU   },
+  { GAME_MODE_INFO,                    ANIM_CLASS_TOONS_MENU_SUBMENU   },
+  { GAME_MODE_SETUP,                   ANIM_CLASS_TOONS_MENU_SUBMENU   },
+  { GAME_MODE_PSEUDO_MAINONLY,         ANIM_CLASS_TOONS_MENU_MAIN      },
+  { GAME_MODE_PSEUDO_TYPENAME,         ANIM_CLASS_TOONS_MENU_MAIN      },
+  { GAME_MODE_SCORES,                  ANIM_CLASS_TOONS                },
+
+  { -1,                                        -1                              }
+};
+
+struct AnimClassGameMode
+{
+  int class_bit;
+  int game_mode;
+} anim_class_game_modes_list[] =
+{
+  { ANIM_CLASS_BIT_TITLE_INITIAL,      GAME_MODE_TITLE_INITIAL         },
+  { ANIM_CLASS_BIT_TITLE,              GAME_MODE_TITLE                 },
+  { ANIM_CLASS_BIT_MAIN,               GAME_MODE_MAIN                  },
+  { ANIM_CLASS_BIT_SUBMENU,            GAME_MODE_PSEUDO_SUBMENU        },
+  { ANIM_CLASS_BIT_MENU,               GAME_MODE_PSEUDO_MENU           },
+  { ANIM_CLASS_BIT_TOONS,              GAME_MODE_PSEUDO_TOONS          },
+
+  { -1,                                        -1                              }
+};
+
+/* forward declaration for internal use */
+static void HandleGlobalAnim(int, int);
+static void DoAnimationExt(void);
+
+static struct GlobalAnimControlInfo global_anim_ctrl[NUM_GAME_MODES];
 static struct ToonInfo toons[MAX_NUM_TOONS];
 
+static unsigned int anim_sync_frame = 0;
+static unsigned int anim_sync_frame_delay = 0;
+static unsigned int anim_sync_frame_delay_value = GAME_FRAME_DELAY;
+
+static int game_mode_anim_classes[NUM_GAME_MODES];
+static int anim_class_game_modes[NUM_ANIM_CLASSES];
+
+static int anim_status_last = GAME_MODE_DEFAULT;
+static int anim_classes_last = ANIM_CLASS_NONE;
+
+
+static int getGlobalAnimationPart(struct GlobalAnimMainControlInfo *anim)
+{
+  struct GraphicInfo *c = &anim->control_info;
+  int last_anim_random_frame = gfx.anim_random_frame;
+  int part_nr;
+
+  gfx.anim_random_frame = -1;  // (use simple, ad-hoc random numbers)
+
+  part_nr = getAnimationFrame(anim->num_parts, 1,
+                             c->anim_mode, c->anim_start_frame,
+                             anim->part_counter);
+
+  gfx.anim_random_frame = last_anim_random_frame;
+
+  return part_nr;
+}
+
+static int compareGlobalAnimPartControlInfo(const void *obj1, const void *obj2)
+{
+  const struct GlobalAnimPartControlInfo *o1 =
+    (struct GlobalAnimPartControlInfo *)obj1;
+  const struct GlobalAnimPartControlInfo *o2 =
+    (struct GlobalAnimPartControlInfo *)obj2;
+  int compare_result;
+
+  if (o1->control_info.draw_order != o2->control_info.draw_order)
+    compare_result = o1->control_info.draw_order - o2->control_info.draw_order;
+  else
+    compare_result = o1->nr - o2->nr;
+
+  return compare_result;
+}
+
+static int compareGlobalAnimMainControlInfo(const void *obj1, const void *obj2)
+{
+  const struct GlobalAnimMainControlInfo *o1 =
+    (struct GlobalAnimMainControlInfo *)obj1;
+  const struct GlobalAnimMainControlInfo *o2 =
+    (struct GlobalAnimMainControlInfo *)obj2;
+  int compare_result;
+
+  if (o1->control_info.draw_order != o2->control_info.draw_order)
+    compare_result = o1->control_info.draw_order - o2->control_info.draw_order;
+  else
+    compare_result = o1->nr - o2->nr;
+
+  return compare_result;
+}
+
 static void PrepareBackbuffer()
 {
   if (game_status != GAME_MODE_PLAYING)
@@ -71,3 +275,881 @@ void InitToons()
                 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
                 GAME_FRAME_DELAY);
 }
+
+static void InitToonControls()
+{
+  int mode_nr_toons = GAME_MODE_PSEUDO_TOONS;
+  struct GlobalAnimControlInfo *ctrl = &global_anim_ctrl[mode_nr_toons];
+  struct GlobalAnimMainControlInfo *anim = &ctrl->anim[ctrl->num_anims];
+  int mode_nr, anim_nr, part_nr;
+  int control = IMG_INTERNAL_GLOBAL_TOON_DEFAULT;
+  int num_toons = MAX_NUM_TOONS;
+  int i;
+
+  if (global.num_toons >= 0 && global.num_toons < MAX_NUM_TOONS)
+    num_toons = global.num_toons;
+
+  mode_nr = mode_nr_toons;
+  anim_nr = ctrl->num_anims;
+
+  anim->nr = anim_nr;
+  anim->mode_nr = mode_nr;
+  anim->control_info = graphic_info[control];
+
+  anim->num_parts = 0;
+  anim->part_counter = 0;
+  anim->active_part_nr = 0;
+
+  anim->has_base = FALSE;
+
+  anim->init_delay_counter = 0;
+
+  anim->state = ANIM_STATE_INACTIVE;
+
+  part_nr = 0;
+
+  for (i = 0; i < num_toons; i++)
+  {
+    struct GlobalAnimPartControlInfo *part = &anim->part[part_nr];
+    int sound = SND_UNDEFINED;
+    int graphic = IMG_TOON_1 + i;
+    int control = graphic;
+
+    part->nr = part_nr;
+    part->anim_nr = anim_nr;
+    part->mode_nr = mode_nr;
+    part->sound = sound;
+    part->graphic = graphic;
+    part->graphic_info = graphic_info[graphic];
+    part->control_info = graphic_info[control];
+
+    part->graphic_info.anim_delay *= part->graphic_info.step_delay;
+
+    part->control_info.init_delay_fixed = 0;
+    part->control_info.init_delay_random = 150;
+
+    part->control_info.x = ARG_UNDEFINED_VALUE;
+    part->control_info.y = ARG_UNDEFINED_VALUE;
+
+    part->initial_anim_sync_frame = 0;
+
+    part->step_delay = 0;
+    part->step_delay_value = graphic_info[control].step_delay;
+
+    part->state = ANIM_STATE_INACTIVE;
+    part->last_anim_status = -1;
+
+    anim->num_parts++;
+    part_nr++;
+  }
+
+  ctrl->num_anims++;
+}
+
+void InitGlobalAnimControls()
+{
+  int i, m, a, p;
+  int mode_nr, anim_nr, part_nr;
+  int sound, graphic, control;
+
+  anim_sync_frame = 0;
+
+  ResetDelayCounter(&anim_sync_frame_delay);
+
+  for (m = 0; m < NUM_GAME_MODES; m++)
+  {
+    mode_nr = m;
+
+    struct GlobalAnimControlInfo *ctrl = &global_anim_ctrl[mode_nr];
+
+    ctrl->nr = mode_nr;
+    ctrl->num_anims = 0;
+
+    anim_nr = 0;
+
+    for (a = 0; a < NUM_GLOBAL_ANIMS; a++)
+    {
+      struct GlobalAnimMainControlInfo *anim = &ctrl->anim[anim_nr];
+      int ctrl_id = GLOBAL_ANIM_ID_CONTROL_FIRST + a;
+
+      control = global_anim_info[ctrl_id].graphic[GLOBAL_ANIM_ID_PART_BASE][m];
+
+      // if no base animation parameters defined, use default values
+      if (control == IMG_UNDEFINED)
+       control = IMG_INTERNAL_GLOBAL_ANIM_DEFAULT;
+
+      anim->nr = anim_nr;
+      anim->mode_nr = mode_nr;
+      anim->control_info = graphic_info[control];
+
+      anim->num_parts = 0;
+      anim->part_counter = 0;
+      anim->active_part_nr = 0;
+
+      anim->has_base = FALSE;
+
+      anim->init_delay_counter = 0;
+
+      anim->state = ANIM_STATE_INACTIVE;
+
+      part_nr = 0;
+
+      for (p = 0; p < NUM_GLOBAL_ANIM_PARTS_ALL; p++)
+      {
+       struct GlobalAnimPartControlInfo *part = &anim->part[part_nr];
+
+       sound   = global_anim_info[a].sound[p][m];
+       graphic = global_anim_info[a].graphic[p][m];
+       control = global_anim_info[ctrl_id].graphic[p][m];
+
+       if (graphic == IMG_UNDEFINED || graphic_info[graphic].bitmap == NULL ||
+           control == IMG_UNDEFINED)
+         continue;
+
+#if 0
+       printf("::: mode == %d, anim = %d, part = %d [%d, %d, %d] [%d]\n",
+              m, a, p, mode_nr, anim_nr, part_nr, control);
+#endif
+
+#if 0
+       printf("::: mode == %d, anim = %d, part = %d [%d, %d, %d] [%d]\n",
+              m, a, p, mode_nr, anim_nr, part_nr, sound);
+#endif
+
+       part->nr = part_nr;
+       part->anim_nr = anim_nr;
+       part->mode_nr = mode_nr;
+       part->sound = sound;
+       part->graphic = graphic;
+       part->graphic_info = graphic_info[graphic];
+       part->control_info = graphic_info[control];
+
+       part->initial_anim_sync_frame = 0;
+
+       part->step_delay = 0;
+       part->step_delay_value = graphic_info[control].step_delay;
+
+       part->state = ANIM_STATE_INACTIVE;
+       part->last_anim_status = -1;
+
+       if (p < GLOBAL_ANIM_ID_PART_BASE)
+       {
+         anim->num_parts++;
+         part_nr++;
+       }
+       else
+       {
+         anim->base = *part;
+         anim->has_base = TRUE;
+       }
+      }
+
+      if (anim->num_parts > 0 || anim->has_base)
+      {
+       ctrl->num_anims++;
+       anim_nr++;
+      }
+    }
+  }
+
+  InitToonControls();
+
+  /* sort all animations according to draw_order and animation number */
+  for (m = 0; m < NUM_GAME_MODES; m++)
+  {
+    struct GlobalAnimControlInfo *ctrl = &global_anim_ctrl[m];
+
+    /* sort all main animations for this game mode */
+    qsort(ctrl->anim, ctrl->num_anims,
+         sizeof(struct GlobalAnimMainControlInfo),
+         compareGlobalAnimMainControlInfo);
+
+    for (a = 0; a < ctrl->num_anims; a++)
+    {
+      struct GlobalAnimMainControlInfo *anim = &ctrl->anim[a];
+
+      /* sort all animation parts for this main animation */
+      qsort(anim->part, anim->num_parts,
+           sizeof(struct GlobalAnimPartControlInfo),
+           compareGlobalAnimPartControlInfo);
+    }
+  }
+
+  for (i = 0; i < NUM_GAME_MODES; i++)
+    game_mode_anim_classes[i] = ANIM_CLASS_NONE;
+  for (i = 0; game_mode_anim_classes_list[i].game_mode != -1; i++)
+    game_mode_anim_classes[game_mode_anim_classes_list[i].game_mode] =
+      game_mode_anim_classes_list[i].class;
+
+  for (i = 0; i < NUM_ANIM_CLASSES; i++)
+    anim_class_game_modes[i] = GAME_MODE_DEFAULT;
+  for (i = 0; anim_class_game_modes_list[i].game_mode != -1; i++)
+    anim_class_game_modes[anim_class_game_modes_list[i].class_bit] =
+      anim_class_game_modes_list[i].game_mode;
+
+  anim_status_last = GAME_MODE_LOADING;
+  anim_classes_last = ANIM_CLASS_NONE;
+}
+
+void InitGlobalAnimations()
+{
+  InitGlobalAnimControls();
+}
+
+void DrawGlobalAnimExt(int drawing_stage)
+{
+  int mode_nr;
+
+  if (global.anim_status != anim_status_last)
+  {
+    boolean before_fading = (global.anim_status == GAME_MODE_PSEUDO_FADING);
+    boolean after_fading  = (anim_status_last   == GAME_MODE_PSEUDO_FADING);
+    int anim_classes_next = game_mode_anim_classes[global.anim_status_next];
+    int i;
+
+    // ---------- part 1 ------------------------------------------------------
+    // start or stop global animations by change of game mode
+    // (special handling of animations for "current screen" and "all screens")
+
+    // stop animations for last screen
+    HandleGlobalAnim(ANIM_STOP, anim_status_last);
+
+    // start animations for current screen
+    HandleGlobalAnim(ANIM_START, global.anim_status);
+
+    // start animations for all screens after loading new artwork set
+    if (anim_status_last == GAME_MODE_LOADING)
+      HandleGlobalAnim(ANIM_START, GAME_MODE_DEFAULT);
+
+    // ---------- part 2 ------------------------------------------------------
+    // start or stop global animations by change of animation class
+    // (generic handling of animations for "class of screens")
+
+    for (i = 0; i < NUM_ANIM_CLASSES; i++)
+    {
+      int anim_class_check = (1 << i);
+      int anim_class_game_mode = anim_class_game_modes[i];
+      int anim_class_last = anim_classes_last & anim_class_check;
+      int anim_class_next = anim_classes_next & anim_class_check;
+
+      // stop animations for changed screen class before fading to new screen
+      if (before_fading && anim_class_last && !anim_class_next)
+       HandleGlobalAnim(ANIM_STOP, anim_class_game_mode);
+
+      // start animations for changed screen class after fading to new screen
+      if (after_fading && !anim_class_last && anim_class_next)
+       HandleGlobalAnim(ANIM_START, anim_class_game_mode);
+    }
+
+    if (after_fading)
+      anim_classes_last = anim_classes_next;
+
+    anim_status_last = global.anim_status;
+  }
+
+  if (!setup.toons || global.anim_status == GAME_MODE_LOADING)
+    return;
+
+  if (drawing_stage == DRAW_GLOBAL_ANIM_STAGE_1)
+    DoAnimationExt();
+
+  for (mode_nr = 0; mode_nr < NUM_GAME_MODES; mode_nr++)
+  {
+    struct GlobalAnimControlInfo *ctrl = &global_anim_ctrl[mode_nr];
+    int anim_nr;
+
+#if 0
+    if (mode_nr != GFX_SPECIAL_ARG_DEFAULT &&
+       mode_nr != game_status)
+      continue;
+#endif
+
+    for (anim_nr = 0; anim_nr < ctrl->num_anims; anim_nr++)
+    {
+      struct GlobalAnimMainControlInfo *anim = &ctrl->anim[anim_nr];
+      struct GraphicInfo *c = &anim->control_info;
+      int part_first, part_last;
+      int part_nr;
+
+      if (!(anim->state & ANIM_STATE_RUNNING))
+       continue;
+
+      part_first = part_last = anim->active_part_nr;
+
+      if (c->anim_mode & ANIM_ALL || anim->num_parts == 0)
+      {
+       int num_parts = anim->num_parts + (anim->has_base ? 1 : 0);
+
+       part_first = 0;
+       part_last = num_parts - 1;
+      }
+
+      for (part_nr = part_first; part_nr <= part_last; part_nr++)
+      {
+       struct GlobalAnimPartControlInfo *part = &anim->part[part_nr];
+       struct GraphicInfo *g = &part->graphic_info;
+       Bitmap *src_bitmap;
+       int src_x, src_y;
+       int width  = g->width;
+       int height = g->height;
+       int dst_x = part->x;
+       int dst_y = part->y;
+       int cut_x = 0;
+       int cut_y = 0;
+       int sync_frame;
+       int frame;
+
+       if (!(part->state & ANIM_STATE_RUNNING))
+         continue;
+
+       if (part->drawing_stage != drawing_stage)
+         continue;
+
+       if (part->x < 0)
+       {
+         dst_x = 0;
+         width += part->x;
+         cut_x = -part->x;
+       }
+       else if (part->x > part->viewport_width - g->width)
+         width -= (part->x - (part->viewport_width - g->width));
+
+       if (part->y < 0)
+       {
+         dst_y = 0;
+         height += part->y;
+         cut_y = -part->y;
+       }
+       else if (part->y > part->viewport_height - g->height)
+         height -= (part->y - (part->viewport_height - g->height));
+
+       if (width <= 0 || height <= 0)
+         continue;
+
+       dst_x += part->viewport_x;
+       dst_y += part->viewport_y;
+
+       sync_frame = anim_sync_frame - part->initial_anim_sync_frame;
+       frame = getAnimationFrame(g->anim_frames, g->anim_delay,
+                                 g->anim_mode, g->anim_start_frame,
+                                 sync_frame);
+
+       getFixedGraphicSource(part->graphic, frame, &src_bitmap,
+                             &src_x, &src_y);
+
+       src_x += cut_x;
+       src_y += cut_y;
+
+       BlitToScreenMasked(src_bitmap, src_x, src_y, width, height,
+                          dst_x, dst_y);
+      }
+    }
+  }
+}
+
+void DrawGlobalAnim(int drawing_stage)
+{
+  DrawGlobalAnimExt(drawing_stage);
+}
+
+boolean SetGlobalAnimPart_Viewport(struct GlobalAnimPartControlInfo *part)
+{
+  int viewport_x;
+  int viewport_y;
+  int viewport_width;
+  int viewport_height;
+  boolean changed = FALSE;
+
+  if (part->last_anim_status == global.anim_status)
+    return FALSE;
+
+  part->last_anim_status = global.anim_status;
+
+  part->drawing_stage = DRAW_GLOBAL_ANIM_STAGE_1;
+
+  if (part->control_info.class == get_hash_from_key("window") ||
+      part->control_info.class == get_hash_from_key("border"))
+  {
+    viewport_x = 0;
+    viewport_y = 0;
+    viewport_width  = WIN_XSIZE;
+    viewport_height = WIN_YSIZE;
+
+    part->drawing_stage = DRAW_GLOBAL_ANIM_STAGE_2;
+  }
+  else if (part->control_info.class == get_hash_from_key("door_1"))
+  {
+    viewport_x = DX;
+    viewport_y = DY;
+    viewport_width  = DXSIZE;
+    viewport_height = DYSIZE;
+  }
+  else if (part->control_info.class == get_hash_from_key("door_2"))
+  {
+    viewport_x = VX;
+    viewport_y = VY;
+    viewport_width  = VXSIZE;
+    viewport_height = VYSIZE;
+  }
+  else         // default: "playfield"
+  {
+    viewport_x = REAL_SX;
+    viewport_y = REAL_SY;
+    viewport_width  = FULL_SXSIZE;
+    viewport_height = FULL_SYSIZE;
+  }
+
+  if (viewport_x != part->viewport_x ||
+      viewport_y != part->viewport_y ||
+      viewport_width  != part->viewport_width ||
+      viewport_height != part->viewport_height)
+  {
+    part->viewport_x = viewport_x;
+    part->viewport_y = viewport_y;
+    part->viewport_width  = viewport_width;
+    part->viewport_height = viewport_height;
+
+    changed = TRUE;
+  }
+
+  return changed;
+}
+
+void PlayGlobalAnimSound(struct GlobalAnimPartControlInfo *part)
+{
+  int sound = part->sound;
+
+  if (sound == SND_UNDEFINED)
+    return;
+
+  if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
+      (!setup.sound_loops && IS_LOOP_SOUND(sound)))
+    return;
+
+  // !!! TODO: ADD STEREO POSITION FOR MOVING ANIMATIONS !!!
+  if (IS_LOOP_SOUND(sound))
+    PlaySoundLoop(sound);
+  else
+    PlaySound(sound);
+
+#if 0
+  printf("::: PLAY %d.%d.%d: %d\n",
+        part->anim_nr, part->nr, part->mode_nr, sound);
+#endif
+}
+
+void StopGlobalAnimSound(struct GlobalAnimPartControlInfo *part)
+{
+  int sound = part->sound;
+
+  if (sound == SND_UNDEFINED)
+    return;
+
+  StopSound(sound);
+
+#if 0
+  printf("::: STOP %d.%d.%d: %d\n",
+        part->anim_nr, part->nr, part->mode_nr, sound);
+#endif
+}
+
+int HandleGlobalAnim_Part(struct GlobalAnimPartControlInfo *part, int state)
+{
+  struct GraphicInfo *g = &part->graphic_info;
+  struct GraphicInfo *c = &part->control_info;
+  boolean viewport_changed = SetGlobalAnimPart_Viewport(part);
+
+  if (viewport_changed)
+    state |= ANIM_STATE_RESTART;
+
+  if (state & ANIM_STATE_RESTART)
+  {
+    ResetDelayCounterExt(&part->step_delay, anim_sync_frame);
+
+    part->init_delay_counter =
+      (c->init_delay_fixed + GetSimpleRandom(c->init_delay_random));
+
+    part->anim_delay_counter =
+      (c->anim_delay_fixed + GetSimpleRandom(c->anim_delay_random));
+
+    part->initial_anim_sync_frame =
+      (g->anim_global_sync ? 0 : anim_sync_frame + part->init_delay_counter);
+
+    if (c->direction & MV_HORIZONTAL)
+    {
+      int pos_bottom = part->viewport_height - g->height;
+
+      if (c->position == POS_TOP)
+       part->y = 0;
+      else if (c->position == POS_UPPER)
+       part->y = GetSimpleRandom(pos_bottom / 2);
+      else if (c->position == POS_MIDDLE)
+       part->y = pos_bottom / 2;
+      else if (c->position == POS_LOWER)
+       part->y = pos_bottom / 2 + GetSimpleRandom(pos_bottom / 2);
+      else if (c->position == POS_BOTTOM)
+       part->y = pos_bottom;
+      else
+       part->y = GetSimpleRandom(pos_bottom);
+
+      if (c->direction == MV_RIGHT)
+      {
+       part->step_xoffset = c->step_offset;
+       part->x = -g->width + part->step_xoffset;
+      }
+      else
+      {
+       part->step_xoffset = -c->step_offset;
+       part->x = part->viewport_width + part->step_xoffset;
+      }
+
+      part->step_yoffset = 0;
+    }
+    else if (c->direction & MV_VERTICAL)
+    {
+      int pos_right = part->viewport_width - g->width;
+
+      if (c->position == POS_LEFT)
+       part->x = 0;
+      else if (c->position == POS_RIGHT)
+       part->x = pos_right;
+      else
+       part->x = GetSimpleRandom(pos_right);
+
+      if (c->direction == MV_DOWN)
+      {
+       part->step_yoffset = c->step_offset;
+       part->y = -g->height + part->step_yoffset;
+      }
+      else
+      {
+       part->step_yoffset = -c->step_offset;
+       part->y = part->viewport_height + part->step_yoffset;
+      }
+
+      part->step_xoffset = 0;
+    }
+    else
+    {
+      part->x = 0;
+      part->y = 0;
+
+      part->step_xoffset = 0;
+      part->step_yoffset = 0;
+    }
+
+    if (c->x != ARG_UNDEFINED_VALUE)
+      part->x = c->x;
+    if (c->y != ARG_UNDEFINED_VALUE)
+      part->y = c->y;
+
+    if (c->step_xoffset != ARG_UNDEFINED_VALUE)
+      part->step_xoffset = c->step_xoffset;
+    if (c->step_yoffset != ARG_UNDEFINED_VALUE)
+      part->step_yoffset = c->step_yoffset;
+
+    if (part->init_delay_counter == 0)
+      PlayGlobalAnimSound(part);
+  }
+
+  if (part->init_delay_counter > 0)
+  {
+    part->init_delay_counter--;
+
+    if (part->init_delay_counter == 0)
+      PlayGlobalAnimSound(part);
+
+    return ANIM_STATE_WAITING;
+  }
+
+  // check if moving animation has left the visible screen area
+  if ((part->x <= -g->width              && part->step_xoffset <= 0) ||
+      (part->x >=  part->viewport_width  && part->step_xoffset >= 0) ||
+      (part->y <= -g->height             && part->step_yoffset <= 0) ||
+      (part->y >=  part->viewport_height && part->step_yoffset >= 0))
+  {
+    // do not stop animation before "anim" or "post" counter are finished
+    if (part->anim_delay_counter == 0 &&
+       part->post_delay_counter == 0)
+    {
+      StopGlobalAnimSound(part);
+
+      part->post_delay_counter =
+       (c->post_delay_fixed + GetSimpleRandom(c->post_delay_random));
+
+      if (part->post_delay_counter > 0)
+       return ANIM_STATE_RUNNING;
+
+      // drawing last frame not needed here -- animation not visible anymore
+      return ANIM_STATE_RESTART;
+    }
+  }
+
+  if (part->anim_delay_counter > 0)
+  {
+    part->anim_delay_counter--;
+
+    if (part->anim_delay_counter == 0)
+    {
+      StopGlobalAnimSound(part);
+
+      part->post_delay_counter =
+       (c->post_delay_fixed + GetSimpleRandom(c->post_delay_random));
+
+      if (part->post_delay_counter > 0)
+       return ANIM_STATE_RUNNING;
+
+      // additional state "RUNNING" required to not skip drawing last frame
+      return ANIM_STATE_RESTART | ANIM_STATE_RUNNING;
+    }
+  }
+
+  if (part->post_delay_counter > 0)
+  {
+    part->post_delay_counter--;
+
+    if (part->post_delay_counter == 0)
+      return ANIM_STATE_RESTART;
+
+    return ANIM_STATE_WAITING;
+  }
+
+  if (!DelayReachedExt(&part->step_delay, part->step_delay_value,
+                      anim_sync_frame))
+    return ANIM_STATE_RUNNING;
+
+#if 0
+  {
+    static unsigned int last_counter = -1;
+    unsigned int counter = Counter();
+
+    printf("::: NEXT ANIM PART [%d, %d]\n",
+          anim_sync_frame, counter - last_counter);
+
+    last_counter = counter;
+  }
+#endif
+
+  part->x += part->step_xoffset;
+  part->y += part->step_yoffset;
+
+  return ANIM_STATE_RUNNING;
+}
+
+void HandleGlobalAnim_Main(struct GlobalAnimMainControlInfo *anim, int action)
+{
+  struct GlobalAnimPartControlInfo *part;
+  struct GraphicInfo *c = &anim->control_info;
+  int state, active_part_nr;
+
+#if 0
+  printf("::: HandleGlobalAnim_Main: %d, %d => %d\n",
+        anim->mode_nr, anim->nr, anim->num_parts);
+  printf("::: %d, %d, %d\n", global.num_toons, setup.toons, num_toons);
+#endif
+
+#if 0
+  printf("::: %s(%d): %d, %d, %d [%d]\n",
+        (action == ANIM_START ? "ANIM_START" :
+         action == ANIM_CONTINUE ? "ANIM_CONTINUE" :
+         action == ANIM_STOP ? "ANIM_STOP" : "(should not happen)"),
+        anim->nr,
+        anim->state & ANIM_STATE_RESTART,
+        anim->state & ANIM_STATE_WAITING,
+        anim->state & ANIM_STATE_RUNNING,
+        anim->num_parts);
+#endif
+
+  switch (action)
+  {
+    case ANIM_START:
+      anim->state = anim->last_state = ANIM_STATE_RESTART;
+      anim->active_part_nr = anim->last_active_part_nr = 0;
+      anim->part_counter = 0;
+
+      break;
+
+    case ANIM_CONTINUE:
+      if (anim->state == ANIM_STATE_INACTIVE)
+       return;
+
+      anim->state = anim->last_state;
+      anim->active_part_nr = anim->last_active_part_nr;
+
+      break;
+
+    case ANIM_STOP:
+      anim->state = ANIM_STATE_INACTIVE;
+
+      {
+       int num_parts = anim->num_parts + (anim->has_base ? 1 : 0);
+       int i;
+
+       for (i = 0; i < num_parts; i++)
+         StopGlobalAnimSound(&anim->part[i]);
+      }
+
+      return;
+
+    default:
+      break;
+  }
+
+  if (c->anim_mode & ANIM_ALL || anim->num_parts == 0)
+  {
+    int num_parts = anim->num_parts + (anim->has_base ? 1 : 0);
+    int i;
+
+#if 0
+    printf("::: HandleGlobalAnim_Main: %d, %d => %d\n",
+          anim->mode_nr, anim->nr, num_parts);
+#endif
+
+    for (i = 0; i < num_parts; i++)
+    {
+      part = &anim->part[i];
+
+      switch (action)
+      {
+        case ANIM_START:
+         anim->state = ANIM_STATE_RUNNING;
+         part->state = ANIM_STATE_RESTART;
+
+         break;
+
+        case ANIM_CONTINUE:
+         if (part->state == ANIM_STATE_INACTIVE)
+           continue;
+
+         break;
+
+        case ANIM_STOP:
+         part->state = ANIM_STATE_INACTIVE;
+
+         continue;
+
+        default:
+         break;
+      }
+
+      part->state = HandleGlobalAnim_Part(part, part->state);
+
+      // when animation mode is "once", stop after animation was played once
+      if (c->anim_mode & ANIM_ONCE &&
+         part->state & ANIM_STATE_RESTART)
+       part->state = ANIM_STATE_INACTIVE;
+    }
+
+    anim->last_state = anim->state;
+    anim->last_active_part_nr = anim->active_part_nr;
+
+    return;
+  }
+
+  if (anim->state & ANIM_STATE_RESTART)                // directly after restart
+    anim->active_part_nr = getGlobalAnimationPart(anim);
+
+  part = &anim->part[anim->active_part_nr];
+
+  part->state = ANIM_STATE_RUNNING;
+
+  anim->state = HandleGlobalAnim_Part(part, anim->state);
+
+  if (anim->state & ANIM_STATE_RESTART)
+    anim->part_counter++;
+
+  // when animation mode is "once", stop after all animations were played once
+  if (c->anim_mode & ANIM_ONCE &&
+      anim->part_counter == anim->num_parts)
+    anim->state = ANIM_STATE_INACTIVE;
+
+  state = anim->state;
+  active_part_nr = anim->active_part_nr;
+
+  // while the animation parts are pausing (waiting or inactive), play the base
+  // (main) animation; this corresponds to the "boring player animation" logic
+  // (!!! KLUDGE WARNING: I THINK THIS IS A MESS THAT SHOULD BE CLEANED UP !!!)
+  if (anim->has_base)
+  {
+    if (anim->state == ANIM_STATE_WAITING ||
+       anim->state == ANIM_STATE_INACTIVE)
+    {
+      anim->active_part_nr = anim->num_parts;  // part nr of base animation
+      part = &anim->part[anim->active_part_nr];
+
+      if (anim->state != anim->last_state)
+       part->state = ANIM_STATE_RESTART;
+
+      anim->state = ANIM_STATE_RUNNING;
+      part->state = HandleGlobalAnim_Part(part, part->state);
+    }
+  }
+
+  anim->last_state = state;
+  anim->last_active_part_nr = active_part_nr;
+}
+
+void HandleGlobalAnim_Mode(struct GlobalAnimControlInfo *ctrl, int action)
+{
+  int i;
+
+#if 0
+  printf("::: HandleGlobalAnim_Mode: %d => %d\n",
+        ctrl->nr, ctrl->num_anims);
+#endif
+
+  for (i = 0; i < ctrl->num_anims; i++)
+    HandleGlobalAnim_Main(&ctrl->anim[i], action);
+}
+
+static void HandleGlobalAnim(int action, int game_mode)
+{
+#if 0
+  printf("::: HandleGlobalAnim [mode == %d]\n", game_status);
+#endif
+
+  HandleGlobalAnim_Mode(&global_anim_ctrl[game_mode], action);
+}
+
+void InitAnimation()
+{
+}
+
+void StopAnimation()
+{
+}
+
+static void DoAnimationExt()
+{
+  int i;
+
+#if 0
+  printf("::: DoAnimation [%d, %d]\n", anim_sync_frame, Counter());
+#endif
+
+#if 1
+  WaitUntilDelayReached(&anim_sync_frame_delay, anim_sync_frame_delay_value);
+  anim_sync_frame++;
+#else
+  if (DelayReached(&anim_sync_frame_delay, anim_sync_frame_delay_value))
+    anim_sync_frame++;
+#endif
+
+  for (i = 0; i < NUM_GAME_MODES; i++)
+    HandleGlobalAnim(ANIM_CONTINUE, i);
+
+#if 1
+  // force screen redraw in next frame to continue drawing global animations
+  redraw_mask = REDRAW_ALL;
+#endif
+}
+
+void DoAnimation()
+{
+  // HandleAnimation(ANIM_CONTINUE);
+
+#if 1
+  // force screen redraw in next frame to continue drawing global animations
+  redraw_mask = REDRAW_ALL;
+#endif
+}
index b3c20192d88acb42b7b86424aa3403187619422f..2b7680d113c528660ad15dca189b35c6a5e46153 100644 (file)
 #ifndef CARTOONS_H
 #define CARTOONS_H
 
+
+/* values for global animations */
+#define ANIM_STATE_INACTIVE    0
+#define ANIM_STATE_RESTART     (1 << 0)
+#define ANIM_STATE_WAITING     (1 << 1)
+#define ANIM_STATE_RUNNING     (1 << 2)
+
+
 void InitToons(void);
+void InitGlobalAnimations(void);
+
+void DrawGlobalAnim(int);
+
+void InitAnimation(void);
+void StopAnimation(void);
+void DoAnimation(void);
 
 #endif
index 4766b3fd5aa56cedba3442383af626df8560e9fb..45b4298bb2e1a67b196b27344a7a6b04ffe4a91b 100644 (file)
@@ -45,12 +45,17 @@ struct ConfigTypeInfo image_config_suffix[] =
   { ".diggable_like",                  ARG_UNDEFINED,  TYPE_ELEMENT    },
   { ".border_size",                    ARG_UNDEFINED,  TYPE_INTEGER    },
   { ".step_offset",                    "4",            TYPE_INTEGER    },
+  { ".step_xoffset",                   ARG_UNDEFINED,  TYPE_INTEGER    },
+  { ".step_yoffset",                   ARG_UNDEFINED,  TYPE_INTEGER    },
   { ".step_delay",                     "1",            TYPE_INTEGER    },
   { ".direction",                      ARG_UNDEFINED,  TYPE_STRING     },
   { ".position",                       ARG_UNDEFINED,  TYPE_STRING     },
   { ".draw_xoffset",                   "0",            TYPE_INTEGER    },
   { ".draw_yoffset",                   "0",            TYPE_INTEGER    },
   { ".draw_masked",                    "false",        TYPE_BOOLEAN    },
+  { ".draw_order",                     ARG_UNDEFINED,  TYPE_INTEGER    },
+  { ".init_delay_fixed",               ARG_UNDEFINED,  TYPE_INTEGER    },
+  { ".init_delay_random",              ARG_UNDEFINED,  TYPE_INTEGER    },
   { ".anim_delay_fixed",               ARG_UNDEFINED,  TYPE_INTEGER    },
   { ".anim_delay_random",              ARG_UNDEFINED,  TYPE_INTEGER    },
   { ".post_delay_fixed",               ARG_UNDEFINED,  TYPE_INTEGER    },
@@ -4588,6 +4593,29 @@ struct ConfigInfo image_config[] =
   { "toon_20.direction",                       "down"                  },
   { "toon_20.position",                                "any"                   },
 
+  { "global.anim_1.gfx",                       UNDEFINED_FILENAME      },
+  { "global.anim_2.gfx",                       UNDEFINED_FILENAME      },
+  { "global.anim_3.gfx",                       UNDEFINED_FILENAME      },
+  { "global.anim_4.gfx",                       UNDEFINED_FILENAME      },
+  { "global.anim_5.gfx",                       UNDEFINED_FILENAME      },
+  { "global.anim_6.gfx",                       UNDEFINED_FILENAME      },
+  { "global.anim_7.gfx",                       UNDEFINED_FILENAME      },
+  { "global.anim_8.gfx",                       UNDEFINED_FILENAME      },
+
+  { "global.anim_1",                           UNDEFINED_FILENAME      },
+  { "global.anim_2",                           UNDEFINED_FILENAME      },
+  { "global.anim_3",                           UNDEFINED_FILENAME      },
+  { "global.anim_4",                           UNDEFINED_FILENAME      },
+  { "global.anim_5",                           UNDEFINED_FILENAME      },
+  { "global.anim_6",                           UNDEFINED_FILENAME      },
+  { "global.anim_7",                           UNDEFINED_FILENAME      },
+  { "global.anim_8",                           UNDEFINED_FILENAME      },
+
+  { "internal.global.toon_default",            UNDEFINED_FILENAME      },
+  { "internal.global.toon_default.anim_mode",  "random"                },
+
+  { "internal.global.anim_default",            UNDEFINED_FILENAME      },
+
   { "menu.calibrate_red",                      "RocksElements.png"     },
   { "menu.calibrate_red.xpos",                 "12"                    },
   { "menu.calibrate_red.ypos",                 "8"                     },
@@ -5183,11 +5211,15 @@ struct ConfigInfo image_config[] =
   { "font.option_off.y",                       "160"                   },
   { "font.option_off.width",                   "32"                    },
   { "font.option_off.height",                  "32"                    },
+  { "font.option_off_narrow",                  UNDEFINED_FILENAME      },
+  { "font.option_off_narrow.clone_from",       "font.text_2.LEVELS"    },
   { "font.option_on",                          "RocksFontBig.png"      },
   { "font.option_on.x",                                "0"                     },
   { "font.option_on.y",                                "480"                   },
   { "font.option_on.width",                    "32"                    },
   { "font.option_on.height",                   "32"                    },
+  { "font.option_on_narrow",                   UNDEFINED_FILENAME      },
+  { "font.option_on_narrow.clone_from",                "font.text_4.LEVELS"    },
 
   { "font.value_1",                            "RocksFontBig.png"      },
   { "font.value_1.x",                          "0"                     },
@@ -5204,6 +5236,8 @@ struct ConfigInfo image_config[] =
   { "font.value_old.y",                                "160"                   },
   { "font.value_old.width",                    "32"                    },
   { "font.value_old.height",                   "32"                    },
+  { "font.value_narrow",                       UNDEFINED_FILENAME      },
+  { "font.value_narrow.clone_from",            "font.text_4.LEVELS"    },
 
   { "font.level_number",                       "RocksFontSmall.png"    },
   { "font.level_number.x",                     "0"                     },
index 907537fd5632be45345173637a536f77b095d686..5ecd0775ed39ae0e610a181aa27bc32b5d51e9e7 100644 (file)
@@ -31,6 +31,7 @@ struct ConfigInfo music_config[] =
   { "background.TITLE",                        UNDEFINED_FILENAME              },
   { "background.MAIN",                 UNDEFINED_FILENAME              },
   { "background.LEVELS",               UNDEFINED_FILENAME              },
+  { "background.LEVELNR",              UNDEFINED_FILENAME              },
   { "background.SCORES",               UNDEFINED_FILENAME              },
   { "background.EDITOR",               UNDEFINED_FILENAME              },
   { "background.INFO",                 "rhythmloop.wav"                },
index 9b18ed962ad1cb0f219c76e48b4397efcc898a86..e2d7a5303fa32210790025495d73fd55311656e7 100644 (file)
@@ -264,6 +264,7 @@ struct ConfigInfo sound_config[] =
   { "background.TITLE",                        UNDEFINED_FILENAME              },
   { "background.MAIN",                 UNDEFINED_FILENAME              },
   { "background.LEVELS",               UNDEFINED_FILENAME              },
+  { "background.LEVELNR",              UNDEFINED_FILENAME              },
   { "background.SCORES",               "halloffame.wav"                },
   { "background.SCORES.mode_loop",     "false"                         },
   { "background.EDITOR",               UNDEFINED_FILENAME              },
index 3b75f709207583ab77737813336b30282ff315ec..2e90887055567ac070a36b5527d6ca98697dc473 100644 (file)
@@ -29,9 +29,9 @@ char *getProgramVersionString()
 {
   static char program_version_string[32];
 
-  sprintf(program_version_string, "%d.%d.%d.%d",
+  sprintf(program_version_string, "%d.%d.%d.%d%s",
          PROGRAM_VERSION_MAJOR, PROGRAM_VERSION_MINOR, PROGRAM_VERSION_PATCH,
-         PROGRAM_VERSION_BUILD);
+         PROGRAM_VERSION_BUILD, PROGRAM_VERSION_EXTRA);
 
   return program_version_string;
 }
index 7ed0f977d73c0879885ffca809831064589a560c..04d03e1b24e703b4a0247556e1fa218ff3b1c606 100644 (file)
@@ -6403,10 +6403,8 @@ static void CreateRadiobuttonGadgets()
 
 void CreateLevelEditorGadgets()
 {
-  int old_game_status = game_status;
-
-  /* setting 'game_status' is needed to get the right fonts for the editor */
-  game_status = GAME_MODE_EDITOR;
+  /* force EDITOR font inside level editor */
+  SetFontStatus(GAME_MODE_EDITOR);
 
   /* these values are not constant, but can change at runtime */
   ed_fieldx = MAX_ED_FIELDX - 1;
@@ -6440,7 +6438,7 @@ void CreateLevelEditorGadgets()
   CreateTextbuttonGadgets();
   CreateDrawingAreas();
 
-  game_status = old_game_status;
+  ResetFontStatus();
 }
 
 void FreeLevelEditorGadgets()
@@ -7625,7 +7623,7 @@ void DrawLevelEd()
 {
   int fade_mask = REDRAW_FIELD;
 
-  CloseDoor(DOOR_CLOSE_ALL);
+  FadeSoundsAndMusic();
 
   /* needed if different viewport properties defined for editor */
   ChangeViewportPropertiesIfNeeded();
@@ -12267,12 +12265,31 @@ void RequestExitLevelEditor(boolean ask_if_level_has_changed,
       Request("Level has changed! Exit without saving?",
              REQ_ASK | REQ_STAY_OPEN))
   {
-    SetDoorState(DOOR_CLOSE_2);
+    struct RectWithBorder *vp_door_1 = &viewport.door_1[GAME_MODE_MAIN];
+    struct RectWithBorder *vp_door_2 = &viewport.door_2[GAME_MODE_MAIN];
+
+    /* draw normal door */
+    UndrawSpecialEditorDoor();
+
+    // close editor doors if viewport definition is the same as in main menu
+    if (vp_door_1->x      == DX     &&
+       vp_door_1->y      == DY     &&
+       vp_door_1->width  == DXSIZE &&
+       vp_door_1->height == DYSIZE &&
+       vp_door_2->x      == VX     &&
+       vp_door_2->y      == VY     &&
+       vp_door_2->width  == VXSIZE &&
+       vp_door_2->height == VYSIZE)
+      CloseDoor(DOOR_CLOSE_ALL | DOOR_NO_DELAY);
+    else
+      SetDoorState(DOOR_CLOSE_2);
+
+    BackToFront();
 
     if (quick_quit)
       FadeSkipNextFadeIn();
 
-    game_status = GAME_MODE_MAIN;
+    SetGameStatus(GAME_MODE_MAIN);
 
     DrawMainMenu();
   }
index e82d3667b42958144a01fdce30e24a70a3b8cec9..d9104aa1be04172a8d64bc8be39b3afd8c57fb46 100644 (file)
@@ -19,6 +19,7 @@
 #include "editor.h"
 #include "files.h"
 #include "tape.h"
+#include "cartoons.h"
 #include "network.h"
 
 
@@ -151,115 +152,63 @@ boolean NextValidEvent(Event *event)
   return FALSE;
 }
 
-void EventLoop(void)
+void HandleEvents()
 {
-  while (1)
+  Event event;
+  unsigned int event_frame_delay = 0;
+  unsigned int event_frame_delay_value = GAME_FRAME_DELAY;
+
+  ResetDelayCounter(&event_frame_delay);
+
+  while (NextValidEvent(&event))
   {
-    if (PendingEvent())                /* got event */
+    switch (event.type)
     {
-      Event event;
+      case EVENT_BUTTONPRESS:
+      case EVENT_BUTTONRELEASE:
+       HandleButtonEvent((ButtonEvent *) &event);
+       break;
 
-      while (NextValidEvent(&event))
-      {
-       switch (event.type)
-       {
-         case EVENT_BUTTONPRESS:
-         case EVENT_BUTTONRELEASE:
-           HandleButtonEvent((ButtonEvent *) &event);
-           break;
-  
-         case EVENT_MOTIONNOTIFY:
-           HandleMotionEvent((MotionEvent *) &event);
-           break;
+      case EVENT_MOTIONNOTIFY:
+       HandleMotionEvent((MotionEvent *) &event);
+       break;
 
 #if defined(TARGET_SDL2)
-         case SDL_WINDOWEVENT:
-           HandleWindowEvent((WindowEvent *) &event);
-           break;
-
-         case EVENT_FINGERPRESS:
-         case EVENT_FINGERRELEASE:
-         case EVENT_FINGERMOTION:
-           HandleFingerEvent((FingerEvent *) &event);
-           break;
-
-         case EVENT_TEXTINPUT:
-           HandleTextEvent((TextEvent *) &event);
-           break;
-
-         case SDL_APP_WILLENTERBACKGROUND:
-         case SDL_APP_DIDENTERBACKGROUND:
-         case SDL_APP_WILLENTERFOREGROUND:
-         case SDL_APP_DIDENTERFOREGROUND:
-           HandlePauseResumeEvent((PauseResumeEvent *) &event);
-           break;
-#endif
-
-         case EVENT_KEYPRESS:
-         case EVENT_KEYRELEASE:
-           HandleKeyEvent((KeyEvent *) &event);
-           break;
-
-         default:
-           HandleOtherEvents(&event);
-           break;
-       }
-      }
-    }
-    else
-    {
-      if (game_status == GAME_MODE_TITLE)
-      {
-       /* when showing title screens, hide mouse pointer (if not moved) */
-
-       if (gfx.cursor_mode != CURSOR_NONE &&
-           DelayReached(&special_cursor_delay, special_cursor_delay_value))
-       {
-         SetMouseCursor(CURSOR_NONE);
-       }
-      }
-      else if (game_status == GAME_MODE_PLAYING && (!tape.pausing ||
-                                                   tape.single_step))
-      {
-       /* when playing, display a special mouse pointer inside the playfield */
+      case SDL_WINDOWEVENT:
+       HandleWindowEvent((WindowEvent *) &event);
+       break;
 
-       if (gfx.cursor_mode != CURSOR_PLAYFIELD &&
-           cursor_inside_playfield &&
-           DelayReached(&special_cursor_delay, special_cursor_delay_value))
-       {
-         SetMouseCursor(CURSOR_PLAYFIELD);
-       }
-      }
-      else if (gfx.cursor_mode != CURSOR_DEFAULT)
-      {
-       SetMouseCursor(CURSOR_DEFAULT);
-      }
+      case EVENT_FINGERPRESS:
+      case EVENT_FINGERRELEASE:
+      case EVENT_FINGERMOTION:
+       HandleFingerEvent((FingerEvent *) &event);
+       break;
 
-      /* this is set after all pending events have been processed */
-      cursor_mode_last = gfx.cursor_mode;
-    }
+      case EVENT_TEXTINPUT:
+       HandleTextEvent((TextEvent *) &event);
+       break;
 
-    /* also execute after pending events have been processed before */
-    HandleNoEvent();
+      case SDL_APP_WILLENTERBACKGROUND:
+      case SDL_APP_DIDENTERBACKGROUND:
+      case SDL_APP_WILLENTERFOREGROUND:
+      case SDL_APP_DIDENTERFOREGROUND:
+       HandlePauseResumeEvent((PauseResumeEvent *) &event);
+       break;
+#endif
 
-    /* don't use all CPU time when idle; the main loop while playing
-       has its own synchronization and is CPU friendly, too */
+      case EVENT_KEYPRESS:
+      case EVENT_KEYRELEASE:
+       HandleKeyEvent((KeyEvent *) &event);
+       break;
 
-    if (game_status == GAME_MODE_PLAYING)
-    {
-      HandleGameActions();
-    }
-    else
-    {
-      if (!PendingEvent())     /* delay only if no pending events */
-       Delay(10);
+      default:
+       HandleOtherEvents(&event);
+       break;
     }
 
-    /* refresh window contents from drawing buffer, if needed */
-    BackToFront();
-
-    if (game_status == GAME_MODE_QUIT)
-      return;
+    // do not handle events for longer than standard frame delay period
+    if (DelayReached(&event_frame_delay, event_frame_delay_value))
+      break;
   }
 }
 
@@ -305,6 +254,71 @@ void HandleOtherEvents(Event *event)
   }
 }
 
+void HandleMouseCursor()
+{
+  if (game_status == GAME_MODE_TITLE)
+  {
+    /* when showing title screens, hide mouse pointer (if not moved) */
+
+    if (gfx.cursor_mode != CURSOR_NONE &&
+       DelayReached(&special_cursor_delay, special_cursor_delay_value))
+    {
+      SetMouseCursor(CURSOR_NONE);
+    }
+  }
+  else if (game_status == GAME_MODE_PLAYING && (!tape.pausing ||
+                                               tape.single_step))
+  {
+    /* when playing, display a special mouse pointer inside the playfield */
+
+    if (gfx.cursor_mode != CURSOR_PLAYFIELD &&
+       cursor_inside_playfield &&
+       DelayReached(&special_cursor_delay, special_cursor_delay_value))
+    {
+      SetMouseCursor(CURSOR_PLAYFIELD);
+    }
+  }
+  else if (gfx.cursor_mode != CURSOR_DEFAULT)
+  {
+    SetMouseCursor(CURSOR_DEFAULT);
+  }
+
+  /* this is set after all pending events have been processed */
+  cursor_mode_last = gfx.cursor_mode;
+}
+
+void EventLoop(void)
+{
+  unsigned int sync_frame_delay = 0;
+  unsigned int sync_frame_delay_value = GAME_FRAME_DELAY;
+
+  while (1)
+  {
+    if (PendingEvent())
+      HandleEvents();
+    else
+      HandleMouseCursor();
+
+    /* also execute after pending events have been processed before */
+    HandleNoEvent();
+
+    /* don't use all CPU time when idle; the main loop while playing
+       has its own synchronization and is CPU friendly, too */
+
+    if (game_status == GAME_MODE_PLAYING)
+      HandleGameActions();
+
+    /* refresh window contents from drawing buffer, if needed */
+    BackToFront();
+
+    if (game_status != GAME_MODE_PLAYING)
+      WaitUntilDelayReached(&sync_frame_delay, sync_frame_delay_value);
+
+    if (game_status == GAME_MODE_QUIT)
+      return;
+  }
+}
+
 void ClearEventQueue()
 {
   while (PendingEvent())
@@ -1567,7 +1581,8 @@ void HandleKey(Key key, int key_status)
     default:
       if (key == KSYM_Escape)
       {
-       game_status = GAME_MODE_MAIN;
+       SetGameStatus(GAME_MODE_MAIN);
+
        DrawMainMenu();
 
        return;
index f8b9e8b859c9fe94e2eb09f8a13c2f92e3ddfa31..ebf045cb07aa52367ca0a579bb59051e3690f6e2 100644 (file)
@@ -7909,9 +7909,9 @@ void SaveScore(int nr)
 #define SETUP_TOKEN_SKIP_LEVELS                        15
 #define SETUP_TOKEN_TIME_LIMIT                 16
 #define SETUP_TOKEN_FULLSCREEN                 17
-#define SETUP_TOKEN_FULLSCREEN_MODE            18
-#define SETUP_TOKEN_WINDOW_SCALING_PERCENT     19
-#define SETUP_TOKEN_WINDOW_SCALING_QUALITY     20
+#define SETUP_TOKEN_WINDOW_SCALING_PERCENT     18
+#define SETUP_TOKEN_WINDOW_SCALING_QUALITY     19
+#define SETUP_TOKEN_SCREEN_RENDERING_MODE      20
 #define SETUP_TOKEN_ASK_ON_ESCAPE              21
 #define SETUP_TOKEN_ASK_ON_ESCAPE_EDITOR       22
 #define SETUP_TOKEN_QUICK_SWITCH               23
@@ -8044,8 +8044,10 @@ void SaveScore(int nr)
 #define SETUP_TOKEN_INT_FALLBACK_MUSIC_FILE    12
 #define SETUP_TOKEN_INT_DEFAULT_LEVEL_SERIES   13
 #define SETUP_TOKEN_INT_CHOOSE_FROM_TOP_LEVELDIR 14
+#define SETUP_TOKEN_INT_DEFAULT_WINDOW_WIDTH   15
+#define SETUP_TOKEN_INT_DEFAULT_WINDOW_HEIGHT  16
 
-#define NUM_INTERNAL_SETUP_TOKENS              15
+#define NUM_INTERNAL_SETUP_TOKENS              17
 
 /* options setup */
 #define SETUP_TOKEN_OPTIONS_VERBOSE            0
@@ -8082,9 +8084,9 @@ static struct TokenInfo global_setup_tokens[] =
   { TYPE_SWITCH, &si.skip_levels,             "skip_levels"            },
   { TYPE_SWITCH, &si.time_limit,              "time_limit"             },
   { TYPE_SWITCH, &si.fullscreen,              "fullscreen"             },
-  { TYPE_STRING, &si.fullscreen_mode,         "fullscreen_mode"                },
   { TYPE_INTEGER,&si.window_scaling_percent,  "window_scaling_percent" },
   { TYPE_STRING, &si.window_scaling_quality,  "window_scaling_quality" },
+  { TYPE_STRING, &si.screen_rendering_mode,   "screen_rendering_mode"  },
   { TYPE_SWITCH, &si.ask_on_escape,           "ask_on_escape"          },
   { TYPE_SWITCH, &si.ask_on_escape_editor,    "ask_on_escape_editor"   },
   { TYPE_SWITCH, &si.quick_switch,            "quick_player_switch"    },
@@ -8217,6 +8219,8 @@ static struct TokenInfo internal_setup_tokens[] =
   { TYPE_STRING, &sxi.fallback_music_file,     "fallback_music_file"   },
   { TYPE_STRING, &sxi.default_level_series,    "default_level_series"  },
   { TYPE_BOOLEAN,&sxi.choose_from_top_leveldir,        "choose_from_top_leveldir" },
+  { TYPE_INTEGER,&sxi.default_window_width,    "default_window_width"  },
+  { TYPE_INTEGER,&sxi.default_window_height,   "default_window_height" },
 };
 
 static struct TokenInfo options_setup_tokens[] =
@@ -8262,9 +8266,9 @@ static void setSetupInfoToDefaults(struct SetupInfo *si)
   si->skip_levels = TRUE;
   si->time_limit = TRUE;
   si->fullscreen = FALSE;
-  si->fullscreen_mode = getStringCopy(DEFAULT_FULLSCREEN_MODE);
   si->window_scaling_percent = STD_WINDOW_SCALING_PERCENT;
   si->window_scaling_quality = getStringCopy(SCALING_QUALITY_DEFAULT);
+  si->screen_rendering_mode = getStringCopy(STR_SPECIAL_RENDERING_DEFAULT);
   si->ask_on_escape = TRUE;
   si->ask_on_escape_editor = TRUE;
   si->quick_switch = FALSE;
@@ -8379,6 +8383,9 @@ static void setSetupInfoToDefaults(struct SetupInfo *si)
   si->internal.default_level_series = getStringCopy(UNDEFINED_LEVELSET);
   si->internal.choose_from_top_leveldir = FALSE;
 
+  si->internal.default_window_width  = WIN_XSIZE_DEFAULT;
+  si->internal.default_window_height = WIN_YSIZE_DEFAULT;
+
   si->options.verbose = FALSE;
 
 #if defined(PLATFORM_ANDROID)
index cc6bcdfc33e33cedb876ec0bd0cb63d3f821c5b1..c754fc186f0d08505356b474feb65032b98e6512 100644 (file)
@@ -2446,7 +2446,7 @@ void DisplayGameControlValues()
   /* redraw game control buttons */
   RedrawGameButtons();
 
-  game_status = GAME_MODE_PSEUDO_PANEL;
+  SetGameStatus(GAME_MODE_PSEUDO_PANEL);
 
   for (i = 0; i < NUM_GAME_PANEL_CONTROLS; i++)
   {
@@ -2574,7 +2574,7 @@ void DisplayGameControlValues()
     redraw_mask |= REDRAW_DOOR_1;
   }
 
-  game_status = GAME_MODE_PLAYING;
+  SetGameStatus(GAME_MODE_PLAYING);
 }
 
 void UpdateAndDisplayGameControlValues()
@@ -3097,11 +3097,11 @@ void InitGame()
   // required here to update video display before fading (FIX THIS)
   DrawMaskedBorder(REDRAW_DOOR_2);
 
-  game_status = GAME_MODE_PLAYING;
-
   if (!game.restart_level)
     CloseDoor(DOOR_CLOSE_1);
 
+  SetGameStatus(GAME_MODE_PLAYING);
+
   /* needed if different viewport properties defined for playing */
   ChangeViewportPropertiesIfNeeded();
 
@@ -3113,12 +3113,16 @@ void InitGame()
   if (CheckIfGlobalBorderHasChanged())
     fade_mask = REDRAW_ALL;
 
-  FadeOut(fade_mask);
+  FadeSoundsAndMusic();
 
-  OpenDoor(GetDoorState() | DOOR_NO_DELAY | DOOR_FORCE_REDRAW);
+  ExpireSoundLoops(TRUE);
+
+  FadeOut(fade_mask);
 
   ClearField();
 
+  OpenDoor(GetDoorState() | DOOR_NO_DELAY | DOOR_FORCE_REDRAW);
+
   DrawCompleteVideoDisplay();
 
   InitGameEngine();
@@ -4422,7 +4426,7 @@ void GameEnd()
 
   if (level_editor_test_game)
   {
-    game_status = GAME_MODE_MAIN;
+    SetGameStatus(GAME_MODE_MAIN);
 
     DrawMainMenu();
 
@@ -4431,7 +4435,7 @@ void GameEnd()
 
   if (!local_player->LevelSolved_SaveScore)
   {
-    game_status = GAME_MODE_MAIN;
+    SetGameStatus(GAME_MODE_MAIN);
 
     DrawMainMenu();
 
@@ -4450,7 +4454,7 @@ void GameEnd()
 
   if ((hi_pos = NewHiScore()) >= 0) 
   {
-    game_status = GAME_MODE_SCORES;
+    SetGameStatus(GAME_MODE_SCORES);
 
     DrawHallOfFame(hi_pos);
 
@@ -4462,7 +4466,7 @@ void GameEnd()
   }
   else
   {
-    game_status = GAME_MODE_MAIN;
+    SetGameStatus(GAME_MODE_MAIN);
 
     if (raise_level)
     {
@@ -14470,7 +14474,7 @@ void RequestQuitGameExt(boolean skip_request, boolean quick_quit, char *message)
       if (quick_quit)
        FadeSkipNextFadeIn();
 
-      game_status = GAME_MODE_MAIN;
+      SetGameStatus(GAME_MODE_MAIN);
 
       DrawMainMenu();
     }
index ca820886f380c18d9ca65fc5dfb8a8df0e709d5c..d0422650ab5ee09b34c1b6e5b0d5b57cfd124e6c 100644 (file)
@@ -226,6 +226,35 @@ void InitBitmapPointers()
       graphic_info[i].bitmap = graphic_info[i].bitmaps[IMG_BITMAP_STANDARD];
 }
 
+void InitImageTextures()
+{
+  int i, j, k;
+
+  FreeAllImageTextures();
+
+  for (i = IMG_GLOBAL_BORDER_FIRST; i <= IMG_GLOBAL_BORDER_LAST; i++)
+    CreateImageTextures(i);
+
+  for (i = 0; i < MAX_NUM_TOONS; i++)
+    CreateImageTextures(IMG_TOON_1 + i);
+
+  for (i = 0; i < NUM_GLOBAL_ANIMS; i++)
+  {
+    for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
+    {
+      for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
+      {
+       int graphic = global_anim_info[i].graphic[j][k];
+
+       if (graphic == IMG_UNDEFINED)
+         continue;
+
+       CreateImageTextures(graphic);
+      }
+    }
+  }
+}
+
 #if 1
 /* !!! FIX THIS (CHANGE TO USING NORMAL ELEMENT GRAPHIC DEFINITIONS) !!! */
 void SetBitmaps_EM(Bitmap **em_bitmap)
@@ -505,6 +534,114 @@ void InitFontGraphicInfo()
               getFontBitmapID, getFontFromToken);
 }
 
+void InitGlobalAnimGraphicInfo()
+{
+  struct PropertyMapping *property_mapping = getImageListPropertyMapping();
+  int num_property_mappings = getImageListPropertyMappingSize();
+  int i, j, k;
+
+  if (graphic_info == NULL)            /* still at startup phase */
+    return;
+
+  /* always start with reliable default values (no global animations) */
+  for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
+    for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
+      for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
+       global_anim_info[i].graphic[j][k] = IMG_UNDEFINED;
+
+  /* initialize global animation definitions from static configuration */
+  for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
+  {
+    int j = GLOBAL_ANIM_ID_PART_BASE;
+    int k = GFX_SPECIAL_ARG_DEFAULT;
+
+    global_anim_info[i].graphic[j][k] = IMG_GLOBAL_ANIM_1_GFX + i;
+  }
+
+  /* initialize global animation definitions from dynamic configuration */
+  for (i = 0; i < num_property_mappings; i++)
+  {
+    int anim_nr = property_mapping[i].base_index - MAX_NUM_ELEMENTS - NUM_FONTS;
+    int part_nr = property_mapping[i].ext1_index - ACTION_PART_1;
+    int special = property_mapping[i].ext3_index;
+    int graphic = property_mapping[i].artwork_index;
+
+    if (anim_nr < 0 || anim_nr >= NUM_GLOBAL_ANIM_TOKENS)
+      continue;
+
+    /* set animation part to base part, if not specified */
+    if (!IS_GLOBAL_ANIM_PART(part_nr))
+      part_nr = GLOBAL_ANIM_ID_PART_BASE;
+
+    /* set animation screen to default, if not specified */
+    if (!IS_SPECIAL_GFX_ARG(special))
+      special = GFX_SPECIAL_ARG_DEFAULT;
+
+    global_anim_info[anim_nr].graphic[part_nr][special] = graphic;
+  }
+
+#if 0
+  printf("::: InitGlobalAnimGraphicInfo\n");
+
+  for (i = 0; i < NUM_GLOBAL_ANIMS; i++)
+    for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
+      for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
+       if (global_anim_info[i].graphic[j][k] != IMG_UNDEFINED &&
+           graphic_info[global_anim_info[i].graphic[j][k]].bitmap != NULL)
+         printf("::: - anim %d, part %d, mode %d => %d\n",
+                i, j, k, global_anim_info[i].graphic[j][k]);
+#endif
+}
+
+void InitGlobalAnimSoundInfo()
+{
+  struct PropertyMapping *property_mapping = getSoundListPropertyMapping();
+  int num_property_mappings = getSoundListPropertyMappingSize();
+  int i, j, k;
+
+  /* always start with reliable default values (no global animation sounds) */
+  for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
+    for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
+      for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
+       global_anim_info[i].sound[j][k] = SND_UNDEFINED;
+
+  /* initialize global animation sound definitions from dynamic configuration */
+  for (i = 0; i < num_property_mappings; i++)
+  {
+    int anim_nr = property_mapping[i].base_index - 2 * MAX_NUM_ELEMENTS;
+    int part_nr = property_mapping[i].ext1_index - ACTION_PART_1;
+    int special = property_mapping[i].ext3_index;
+    int sound   = property_mapping[i].artwork_index;
+
+    // sound uses control definition; map it to position of graphic (artwork)
+    anim_nr -= GLOBAL_ANIM_ID_CONTROL_FIRST;
+
+    if (anim_nr < 0 || anim_nr >= NUM_GLOBAL_ANIM_TOKENS)
+      continue;
+
+    /* set animation part to base part, if not specified */
+    if (!IS_GLOBAL_ANIM_PART(part_nr))
+      part_nr = GLOBAL_ANIM_ID_PART_BASE;
+
+    /* set animation screen to default, if not specified */
+    if (!IS_SPECIAL_GFX_ARG(special))
+      special = GFX_SPECIAL_ARG_DEFAULT;
+
+    global_anim_info[anim_nr].sound[part_nr][special] = sound;
+  }
+
+#if 0
+  printf("::: InitGlobalAnimSoundInfo\n");
+
+  for (i = 0; i < NUM_GLOBAL_ANIMS; i++)
+    for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
+      for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
+       if (global_anim_info[i].sound[j][k] != SND_UNDEFINED)
+         printf("::: - anim %d, part %d, mode %d => %d\n",
+                i, j, k, global_anim_info[i].sound[j][k]);
+#endif
+}
+
 void InitElementGraphicInfo()
 {
   struct PropertyMapping *property_mapping = getImageListPropertyMapping();
@@ -1042,10 +1179,13 @@ static void set_graphic_parameters_ext(int graphic, int *parameter,
   g->scale_up_factor = 1;              /* default: no scaling up */
   g->tile_size = TILESIZE;             /* default: standard tile size */
   g->clone_from = -1;                  /* do not use clone graphic */
+  g->init_delay_fixed = 0;
+  g->init_delay_random = 0;
   g->anim_delay_fixed = 0;
   g->anim_delay_random = 0;
   g->post_delay_fixed = 0;
   g->post_delay_random = 0;
+  g->draw_order = 0;
   g->fade_mode = FADE_MODE_DEFAULT;
   g->fade_delay = -1;
   g->post_delay = -1;
@@ -1247,7 +1387,11 @@ static void set_graphic_parameters_ext(int graphic, int *parameter,
   if (parameter[GFX_ARG_BORDER_SIZE] != ARG_UNDEFINED_VALUE)
     g->border_size = parameter[GFX_ARG_BORDER_SIZE];
 
-  /* this is only used for player "boring" and "sleeping" actions */
+  /* used for global animations and player "boring" and "sleeping" actions */
+  if (parameter[GFX_ARG_INIT_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
+    g->init_delay_fixed = parameter[GFX_ARG_INIT_DELAY_FIXED];
+  if (parameter[GFX_ARG_INIT_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
+    g->init_delay_random = parameter[GFX_ARG_INIT_DELAY_RANDOM];
   if (parameter[GFX_ARG_ANIM_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
     g->anim_delay_fixed = parameter[GFX_ARG_ANIM_DELAY_FIXED];
   if (parameter[GFX_ARG_ANIM_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
@@ -1257,9 +1401,15 @@ static void set_graphic_parameters_ext(int graphic, int *parameter,
   if (parameter[GFX_ARG_POST_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
     g->post_delay_random = parameter[GFX_ARG_POST_DELAY_RANDOM];
 
-  /* this is only used for toon animations */
-  g->step_offset = parameter[GFX_ARG_STEP_OFFSET];
-  g->step_delay  = parameter[GFX_ARG_STEP_DELAY];
+  /* used for toon animations and global animations */
+  g->step_offset  = parameter[GFX_ARG_STEP_OFFSET];
+  g->step_xoffset = parameter[GFX_ARG_STEP_XOFFSET];
+  g->step_yoffset = parameter[GFX_ARG_STEP_YOFFSET];
+  g->step_delay   = parameter[GFX_ARG_STEP_DELAY];
+  g->direction    = parameter[GFX_ARG_DIRECTION];
+  g->position     = parameter[GFX_ARG_POSITION];
+  g->x            = parameter[GFX_ARG_X];      // (may be uninitialized,
+  g->y            = parameter[GFX_ARG_Y];      // unlike src_x and src_y)
 
   /* this is only used for drawing font characters */
   g->draw_xoffset = parameter[GFX_ARG_DRAW_XOFFSET];
@@ -1268,6 +1418,10 @@ static void set_graphic_parameters_ext(int graphic, int *parameter,
   /* this is only used for drawing envelope graphics */
   g->draw_masked = parameter[GFX_ARG_DRAW_MASKED];
 
+  /* used for toon animations and global animations */
+  if (parameter[GFX_ARG_DRAW_ORDER] != ARG_UNDEFINED_VALUE)
+    g->draw_order = parameter[GFX_ARG_DRAW_ORDER];
+
   /* optional graphic for cloning all graphics settings */
   if (parameter[GFX_ARG_CLONE_FROM] != ARG_UNDEFINED_VALUE)
     g->clone_from = parameter[GFX_ARG_CLONE_FROM];
@@ -1936,6 +2090,11 @@ static void ReinitializeGraphics()
   print_timestamp_time("InitBitmapPointers");
   InitFontGraphicInfo();               /* initialize text drawing functions */
   print_timestamp_time("InitFontGraphicInfo");
+  InitGlobalAnimGraphicInfo();         /* initialize global animation config */
+  print_timestamp_time("InitGlobalAnimGraphicInfo");
+
+  InitImageTextures();                 /* create textures for certain images */
+  print_timestamp_time("InitImageTextures");
 
   InitGraphicInfo_EM();                        /* graphic mapping for EM engine */
   print_timestamp_time("InitGraphicInfo_EM");
@@ -1963,6 +2122,7 @@ static void ReinitializeSounds()
   InitSoundInfo();             /* sound properties mapping */
   InitElementSoundInfo();      /* element game sound mapping */
   InitGameModeSoundInfo();     /* game mode sound mapping */
+  InitGlobalAnimSoundInfo();   /* global animation sound settings */
 
   InitPlayLevelSound();                /* internal game sound settings */
 }
@@ -4557,7 +4717,8 @@ static void InitGlobal()
 
   global.frames_per_second = 0;
 
-  global.border_status = GAME_MODE_MAIN;
+  global.border_status = GAME_MODE_LOADING;
+  global.anim_status = global.anim_status_next = GAME_MODE_LOADING;
 
   global.use_envelope_request = FALSE;
 }
@@ -4751,94 +4912,6 @@ void Execute_Command(char *command)
 
     exit(0);
   }
-
-#if DEBUG
-#if defined(TARGET_SDL2)
-  else if (strEqual(command, "SDL_ListModes"))
-  {
-    SDL_Init(SDL_INIT_VIDEO);
-
-    int num_displays = SDL_GetNumVideoDisplays();
-
-    // check if there are any displays available
-    if (num_displays < 0)
-    {
-      Print("No displays available: %s\n", SDL_GetError());
-
-      exit(-1);
-    }
-
-    for (i = 0; i < num_displays; i++)
-    {
-      int num_modes = SDL_GetNumDisplayModes(i);
-      int j;
-
-      Print("Available display modes for display %d:\n", i);
-
-      // check if there are any display modes available for this display
-      if (num_modes < 0)
-      {
-       Print("No display modes available for display %d: %s\n",
-             i, SDL_GetError());
-
-       exit(-1);
-      }
-
-      for (j = 0; j < num_modes; j++)
-      {
-       SDL_DisplayMode mode;
-
-       if (SDL_GetDisplayMode(i, j, &mode) < 0)
-       {
-         Print("Cannot get display mode %d for display %d: %s\n",
-               j, i, SDL_GetError());
-
-         exit(-1);
-       }
-
-       Print("- %d x %d\n", mode.w, mode.h);
-      }
-    }
-
-    exit(0);
-  }
-#elif defined(TARGET_SDL)
-  else if (strEqual(command, "SDL_ListModes"))
-  {
-    SDL_Rect **modes;
-    int i;
-
-    SDL_Init(SDL_INIT_VIDEO);
-
-    /* get available fullscreen/hardware modes */
-    modes = SDL_ListModes(NULL, SDL_FULLSCREEN | SDL_HWSURFACE);
-
-    /* check if there are any modes available */
-    if (modes == NULL)
-    {
-      Print("No modes available!\n");
-
-      exit(-1);
-    }
-
-    /* check if our resolution is restricted */
-    if (modes == (SDL_Rect **)-1)
-    {
-      Print("All resolutions available.\n");
-    }
-    else
-    {
-      Print("Available display modes:\n");
-
-      for (i = 0; modes[i]; i++)
-       Print("- %d x %d\n", modes[i]->w, modes[i]->h);
-    }
-
-    exit(0);
-  }
-#endif
-#endif
-
   else
   {
     Error(ERR_EXIT_HELP, "unrecognized command '%s'", command);
@@ -4901,8 +4974,11 @@ static char *get_level_id_suffix(int id_nr)
 
 static void InitArtworkConfig()
 {
-  static char *image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + 1];
-  static char *sound_id_prefix[2 * MAX_NUM_ELEMENTS + 1];
+  static char *image_id_prefix[MAX_NUM_ELEMENTS +
+                              NUM_FONTS +
+                              NUM_GLOBAL_ANIM_TOKENS + 1];
+  static char *sound_id_prefix[2 * MAX_NUM_ELEMENTS +
+                              NUM_GLOBAL_ANIM_TOKENS + 1];
   static char *music_id_prefix[NUM_MUSIC_PREFIXES + 1];
   static char *action_id_suffix[NUM_ACTIONS + 1];
   static char *direction_id_suffix[NUM_DIRECTIONS_FULL + 1];
@@ -4962,14 +5038,20 @@ static void InitArtworkConfig()
     image_id_prefix[i] = element_info[i].token_name;
   for (i = 0; i < NUM_FONTS; i++)
     image_id_prefix[MAX_NUM_ELEMENTS + i] = font_info[i].token_name;
-  image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS] = NULL;
+  for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
+    image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + i] =
+      global_anim_info[i].token_name;
+  image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + NUM_GLOBAL_ANIM_TOKENS] = NULL;
 
   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
     sound_id_prefix[i] = element_info[i].token_name;
   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
     sound_id_prefix[MAX_NUM_ELEMENTS + i] =
       get_string_in_brackets(element_info[i].class_name);
-  sound_id_prefix[2 * MAX_NUM_ELEMENTS] = NULL;
+  for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
+    sound_id_prefix[2 * MAX_NUM_ELEMENTS + i] =
+      global_anim_info[i].token_name;
+  sound_id_prefix[2 * MAX_NUM_ELEMENTS + NUM_GLOBAL_ANIM_TOKENS] = NULL;
 
   for (i = 0; i < NUM_MUSIC_PREFIXES; i++)
     music_id_prefix[i] = music_prefix_info[i].prefix;
@@ -5205,7 +5287,14 @@ void InitGfx()
   init.busy.height = anim_initial.height;
 
   InitMenuDesignSettings_Static();
+
   InitGfxDrawBusyAnimFunction(DrawInitAnim);
+  InitGfxDrawGlobalAnimFunction(DrawGlobalAnim);
+  InitGfxDrawGlobalBorderFunction(DrawMaskedBorderToTarget);
+
+  gfx.fade_border_source_status = global.border_status;
+  gfx.fade_border_target_status = global.border_status;
+  gfx.masked_border_bitmap_ptr = backbuffer;
 
   /* use copy of busy animation to prevent change while reloading artwork */
   init_last = init;
@@ -5342,6 +5431,11 @@ static void InitMusic(char *identifier)
   print_timestamp_done("InitMusic");
 }
 
+static void InitArtworkDone()
+{
+  InitGlobalAnimations();
+}
+
 void InitNetworkServer()
 {
 #if defined(NETWORK_AVALIABLE)
@@ -5582,7 +5676,7 @@ void ReloadCustomArtwork(int force_reload)
 
   print_timestamp_init("ReloadCustomArtwork");
 
-  game_status = GAME_MODE_LOADING;
+  SetGameStatus(GAME_MODE_LOADING);
 
   FadeOut(REDRAW_ALL);
 
@@ -5617,7 +5711,9 @@ void ReloadCustomArtwork(int force_reload)
     print_timestamp_time("InitMusic");
   }
 
-  game_status = last_game_status;      /* restore current game status */
+  InitArtworkDone();
+
+  SetGameStatus(last_game_status);     /* restore current game status */
 
   init_last = init;                    /* switch to new busy animation */
 
@@ -5712,7 +5808,7 @@ void OpenAll()
 {
   print_timestamp_init("OpenAll");
 
-  game_status = GAME_MODE_LOADING;
+  SetGameStatus(GAME_MODE_LOADING);
 
   InitCounter();
 
@@ -5791,6 +5887,8 @@ void OpenAll()
   InitMusic(NULL);             /* needs to know current level directory */
   print_timestamp_time("InitMusic");
 
+  InitArtworkDone();
+
   InitGfxBackground();
 
   em_open_all();
@@ -5812,7 +5910,7 @@ void OpenAll()
     return;
   }
 
-  game_status = GAME_MODE_MAIN;
+  SetGameStatus(GAME_MODE_MAIN);
 
   FadeSetEnterScreen();
   if (!(fading.fade_mode & FADE_TYPE_TRANSFORM))
index 9c6185f7bdda42b5239fd2490336fdf95384a876..ab14b75de2e7e623d67396172e24f8ab7e3e1405 100644 (file)
@@ -43,6 +43,7 @@ void KeyboardAutoRepeatOffUnlessAutoplay();
 
 void InitGfxBuffers();
 void InitGadgets();
+void InitImageTextures();
 
 void DisplayExitMessage(char *, va_list);
 
index 9ff99690e96a1f3438a9cc1b4dca79747beb6a0b..6200c9dc3da22291d19e086f1c5acdf99685e4d4 100644 (file)
@@ -704,6 +704,10 @@ static void DrawGadget(struct GadgetInfo *gi, boolean pressed, boolean direct)
       return;
   }
 
+  // do not use direct gadget drawing anymore; this worked as a speed-up once,
+  // but would slow things down a lot now the screen is always fully redrawn
+  direct = FALSE;
+
   if (direct)
   {
     BlitBitmap(drawto, window,
index 7fc7e2b82bca4edbaad546b5e996ac623b545658..76d9b183b730b1ef85511a101d869038b18aa8c9 100644 (file)
@@ -25,6 +25,7 @@ struct ImageInfo
   int original_height;                 /* original image file height */
 
   boolean contains_small_images;       /* set after adding small images */
+  boolean contains_textures;           /* set after adding GPU textures */
   boolean scaled_up;                   /* set after scaling up */
 
   int conf_tile_size;                  /* tile size as defined in config */
@@ -56,6 +57,7 @@ static void *Load_Image(char *filename)
   img_info->original_height = img_info->bitmaps[IMG_BITMAP_STANDARD]->height;
 
   img_info->contains_small_images = FALSE;
+  img_info->contains_textures = FALSE;
   img_info->scaled_up = FALSE;
 
   img_info->conf_tile_size = 0;                // will be set later
@@ -349,6 +351,39 @@ void CreateImageWithSmallImages(int pos, int zoom_factor, int tile_size)
   setString(&img_info->leveldir, leveldir_current->identifier);
 }
 
+void CreateImageTextures(int pos)
+{
+  ImageInfo *img_info = getImageInfoEntryFromImageID(pos);
+
+  if (img_info == NULL || img_info->contains_textures)
+    return;
+
+  CreateBitmapTextures(img_info->bitmaps);
+
+  img_info->contains_textures = TRUE;
+}
+
+void FreeImageTextures(int pos)
+{
+  ImageInfo *img_info = getImageInfoEntryFromImageID(pos);
+
+  if (img_info == NULL || !img_info->contains_textures)
+    return;
+
+  FreeBitmapTextures(img_info->bitmaps);
+
+  img_info->contains_textures = FALSE;
+}
+
+void FreeAllImageTextures()
+{
+  int num_images = getImageListSize();
+  int i;
+
+  for (i = 0; i < num_images; i++)
+    FreeImageTextures(i);
+}
+
 void ScaleImage(int pos, int zoom_factor)
 {
   ImageInfo *img_info = getImageInfoEntryFromImageID(pos);
index db988c6bf0012891fc3658c7652a957f9f2d877d..76ff3509fa583b24f60229d15f3644cb09387d74 100644 (file)
@@ -67,6 +67,8 @@ void InitImageList(struct ConfigInfo *, int, struct ConfigTypeInfo *,
 
 void ReloadCustomImages();
 void CreateImageWithSmallImages(int, int, int);
+void CreateImageTextures(int);
+void FreeAllImageTextures();
 void ScaleImage(int, int);
 
 void FreeAllImages();
index 7d5268c21a41c7af4d63812c01dd2149d64d1635..3be57faf78ea796d4bd4e638bd56b4bd72f2f829 100644 (file)
@@ -357,25 +357,7 @@ unsigned int Counter()     /* get milliseconds since last call of InitCounter() */
 
 static void sleep_milliseconds(unsigned int milliseconds_delay)
 {
-  boolean do_busy_waiting = (milliseconds_delay < 5 ? TRUE : FALSE);
-
-  if (do_busy_waiting)
-  {
-    /* we want to wait only a few ms -- if we assume that we have a
-       kernel timer resolution of 10 ms, we would wait far too long;
-       therefore it's better to do a short interval of busy waiting
-       to get our sleeping time more accurate */
-
-    unsigned int base_counter = Counter(), actual_counter = Counter();
-
-    while (actual_counter < base_counter + milliseconds_delay &&
-          actual_counter >= base_counter)
-      actual_counter = Counter();
-  }
-  else
-  {
-    SDL_Delay(milliseconds_delay);
-  }
+  SDL_Delay(milliseconds_delay);
 }
 
 void Delay(unsigned int delay) /* Sleep specified number of milliseconds */
@@ -383,32 +365,42 @@ void Delay(unsigned int delay)    /* Sleep specified number of milliseconds */
   sleep_milliseconds(delay);
 }
 
-boolean FrameReached(unsigned int *frame_counter_var,
-                    unsigned int frame_delay)
+boolean DelayReachedExt(unsigned int *counter_var, unsigned int delay,
+                       unsigned int actual_counter)
 {
-  unsigned int actual_frame_counter = FrameCounter;
-
-  if (actual_frame_counter >= *frame_counter_var &&
-      actual_frame_counter < *frame_counter_var + frame_delay)
+  if (actual_counter >= *counter_var &&
+      actual_counter < *counter_var + delay)
     return FALSE;
 
-  *frame_counter_var = actual_frame_counter;
+  *counter_var = actual_counter;
 
   return TRUE;
 }
 
-boolean DelayReached(unsigned int *counter_var,
-                    unsigned int delay)
+boolean FrameReached(unsigned int *frame_counter_var, unsigned int frame_delay)
 {
-  unsigned int actual_counter = Counter();
+  return DelayReachedExt(frame_counter_var, frame_delay, FrameCounter);
+}
 
-  if (actual_counter >= *counter_var &&
-      actual_counter < *counter_var + delay)
-    return FALSE;
+boolean DelayReached(unsigned int *counter_var, unsigned int delay)
+{
+  return DelayReachedExt(counter_var, delay, Counter());
+}
 
-  *counter_var = actual_counter;
+void ResetDelayCounterExt(unsigned int *counter_var,
+                         unsigned int actual_counter)
+{
+  DelayReachedExt(counter_var, 0, actual_counter);
+}
 
-  return TRUE;
+void ResetFrameCounter(unsigned int *frame_counter_var)
+{
+  FrameReached(frame_counter_var, 0);
+}
+
+void ResetDelayCounter(unsigned int *counter_var)
+{
+  DelayReached(counter_var, 0);
 }
 
 int WaitUntilDelayReached(unsigned int *counter_var, unsigned int delay)
@@ -784,46 +776,27 @@ char *getPath3(char *path1, char *path2, char *path3)
   return getStringCat3WithSeparator(path1, path2, path3, STRING_PATH_SEPARATOR);
 }
 
-char *getImg2(char *path1, char *path2)
+static char *getPngOrPcxIfNotExists(char *filename)
 {
-  char *filename = getPath2(path1, path2);
-
-  if (!fileExists(filename) && strSuffix(path2, ".png"))
-  {
-    // backward compatibility: if PNG file not found, check for PCX file
-    char *path2pcx = getStringCopy(path2);
-
-    strcpy(&path2pcx[strlen(path2pcx) - 3], "pcx");
-
-    free(filename);
+  // switch from PNG to PCX file and vice versa, if file does not exist
+  // (backwards compatibility with PCX files used in previous versions)
 
-    filename = getPath2(path1, path2pcx);
-
-    free(path2pcx);
-  }
+  if (!fileExists(filename) && strSuffix(filename, ".png"))
+    strcpy(&filename[strlen(filename) - 3], "pcx");
+  else if (!fileExists(filename) && strSuffix(filename, ".pcx"))
+    strcpy(&filename[strlen(filename) - 3], "png");
 
   return filename;
 }
 
-char *getImg3(char *path1, char *path2, char *path3)
+char *getImg2(char *path1, char *path2)
 {
-  char *filename = getPath3(path1, path2, path3);
-
-  if (!fileExists(filename) && strSuffix(path3, ".png"))
-  {
-    // backward compatibility: if PNG file not found, check for PCX file
-    char *path3pcx = getStringCopy(path3);
-
-    strcpy(&path3pcx[strlen(path3pcx) - 3], "pcx");
-
-    free(filename);
-
-    filename = getPath3(path1, path2, path3pcx);
-
-    free(path3pcx);
-  }
+  return getPngOrPcxIfNotExists(getPath2(path1, path2));
+}
 
-  return filename;
+char *getImg3(char *path1, char *path2, char *path3)
+{
+  return getPngOrPcxIfNotExists(getPath3(path1, path2, path3));
 }
 
 char *getStringCopy(const char *s)
@@ -966,7 +939,6 @@ void GetOptions(int argc, char *argv[],
     rw_base_path = getProgramMainDataPath();
 
   /* initialize global program options */
-  options.display_name = NULL;
   options.server_host = NULL;
   options.server_port = 0;
 
@@ -1037,15 +1009,6 @@ void GetOptions(int argc, char *argv[],
 
       exit(0);
     }
-    else if (strncmp(option, "-display", option_len) == 0)
-    {
-      if (option_arg == NULL)
-       Error(ERR_EXIT_HELP, "option '%s' requires an argument", option_str);
-
-      options.display_name = option_arg;
-      if (option_arg == next_option)
-       options_left++;
-    }
     else if (strncmp(option, "-basepath", option_len) == 0)
     {
       if (option_arg == NULL)
@@ -2604,6 +2567,43 @@ char *get_mapped_token(char *token)
   return NULL;
 }
 
+char *get_special_base_token(struct ArtworkListInfo *artwork_info, char *token)
+{
+  /* !!! make this dynamically configurable (init.c:InitArtworkConfig) !!! */
+  static struct ConfigTypeInfo prefix_list[] =
+  {
+    { "global.anim_1"  },
+    { "global.anim_2"  },
+    { "global.anim_3"  },
+    { "global.anim_4"  },
+    { "global.anim_5"  },
+    { "global.anim_6"  },
+    { "global.anim_7"  },
+    { "global.anim_8"  },
+
+    { NULL             }
+  };
+  struct ConfigTypeInfo *suffix_list = artwork_info->suffix_list;
+  boolean prefix_found = FALSE;
+  int len_suffix = 0;
+  int i;
+
+  /* search for prefix to check if base token has to be created */
+  for (i = 0; prefix_list[i].token != NULL; i++)
+    if (strPrefix(token, prefix_list[i].token))
+      prefix_found = TRUE;
+
+  if (!prefix_found)
+    return NULL;
+
+  /* search for suffix (parameter) to determine base token length */
+  for (i = 0; suffix_list[i].token != NULL; i++)
+    if (strSuffix(token, suffix_list[i].token))
+      len_suffix = strlen(suffix_list[i].token);
+
+  return getStringCopyN(token, strlen(token) - len_suffix);
+}
+
 /* This function checks if a string <s> of the format "string1, string2, ..."
    exactly contains a string <s_contained>. */
 
@@ -2653,6 +2653,17 @@ int get_parameter_value(char *value_raw, char *suffix, int type)
              strEqual(value, "up")    ? MV_UP :
              strEqual(value, "down")  ? MV_DOWN : MV_NONE);
   }
+  else if (strEqual(suffix, ".position"))
+  {
+    result = (strEqual(value, "left")   ? POS_LEFT :
+             strEqual(value, "right")  ? POS_RIGHT :
+             strEqual(value, "top")    ? POS_TOP :
+             strEqual(value, "upper")  ? POS_UPPER :
+             strEqual(value, "middle") ? POS_MIDDLE :
+             strEqual(value, "lower")  ? POS_LOWER :
+             strEqual(value, "bottom") ? POS_BOTTOM :
+             strEqual(value, "any")    ? POS_ANY : POS_UNDEFINED);
+  }
   else if (strEqual(suffix, ".align"))
   {
     result = (strEqual(value, "left")   ? ALIGN_LEFT :
@@ -2681,8 +2692,12 @@ int get_parameter_value(char *value_raw, char *suffix, int type)
              string_has_parameter(value, "horizontal") ? ANIM_HORIZONTAL :
              string_has_parameter(value, "vertical")   ? ANIM_VERTICAL :
              string_has_parameter(value, "centered")   ? ANIM_CENTERED :
+             string_has_parameter(value, "all")        ? ANIM_ALL :
              ANIM_DEFAULT);
 
+    if (string_has_parameter(value, "once"))
+      result |= ANIM_ONCE;
+
     if (string_has_parameter(value, "reverse"))
       result |= ANIM_REVERSE;
 
@@ -2694,7 +2709,8 @@ int get_parameter_value(char *value_raw, char *suffix, int type)
   }
   else if (strEqual(suffix, ".class"))
   {
-    result = get_hash_from_key(value);
+    result = (strEqual(value, ARG_UNDEFINED) ? ARG_UNDEFINED_VALUE :
+             get_hash_from_key(value));
   }
   else if (strEqual(suffix, ".style"))
   {
@@ -2732,48 +2748,6 @@ int get_parameter_value(char *value_raw, char *suffix, int type)
   return result;
 }
 
-struct ScreenModeInfo *get_screen_mode_from_string(char *screen_mode_string)
-{
-  static struct ScreenModeInfo screen_mode;
-  char *screen_mode_string_x = strchr(screen_mode_string, 'x');
-  char *screen_mode_string_copy;
-  char *screen_mode_string_pos_w;
-  char *screen_mode_string_pos_h;
-
-  if (screen_mode_string_x == NULL)    /* invalid screen mode format */
-    return NULL;
-
-  screen_mode_string_copy = getStringCopy(screen_mode_string);
-
-  screen_mode_string_pos_w = screen_mode_string_copy;
-  screen_mode_string_pos_h = strchr(screen_mode_string_copy, 'x');
-  *screen_mode_string_pos_h++ = '\0';
-
-  screen_mode.width  = atoi(screen_mode_string_pos_w);
-  screen_mode.height = atoi(screen_mode_string_pos_h);
-
-  return &screen_mode;
-}
-
-void get_aspect_ratio_from_screen_mode(struct ScreenModeInfo *screen_mode,
-                                      int *x, int *y)
-{
-  float aspect_ratio = (float)screen_mode->width / (float)screen_mode->height;
-  float aspect_ratio_new;
-  int i = 1;
-
-  do
-  {
-    *x = i * aspect_ratio + 0.000001;
-    *y = i;
-
-    aspect_ratio_new = (float)*x / (float)*y;
-
-    i++;
-  }
-  while (aspect_ratio_new != aspect_ratio && *y < screen_mode->height);
-}
-
 static void FreeCustomArtworkList(struct ArtworkListInfo *,
                                  struct ListNodeInfo ***, int *);
 
@@ -3013,6 +2987,7 @@ static void LoadArtworkConfigFromFilename(struct ArtworkListInfo *artwork_info,
   SetupFileHash *setup_file_hash, *valid_file_hash;
   SetupFileHash *extra_file_hash, *empty_file_hash;
   char *known_token_value = KNOWN_TOKEN_VALUE;
+  char *base_token_value = UNDEFINED_FILENAME;
   int i, j, k, l;
 
   if (filename == NULL)
@@ -3057,6 +3032,23 @@ static void LoadArtworkConfigFromFilename(struct ArtworkListInfo *artwork_info,
   }
   END_HASH_ITERATION(valid_file_hash, itr)
 
+  /* add special base tokens (using prefix match and replace) */
+  BEGIN_HASH_ITERATION(valid_file_hash, itr)
+  {
+    char *token = HASH_ITERATION_TOKEN(itr);
+    char *base_token = get_special_base_token(artwork_info, token);
+
+    if (base_token != NULL)
+    {
+      /* add base token only if it does not already exist */
+      if (getHashEntry(valid_file_hash, base_token) == NULL)
+       setHashEntry(valid_file_hash, base_token, base_token_value);
+
+      free(base_token);
+    }
+  }
+  END_HASH_ITERATION(valid_file_hash, itr)
+
   /* read parameters for all known config file tokens */
   for (i = 0; i < num_file_list_entries; i++)
     read_token_parameters(valid_file_hash, suffix_list, &file_list[i]);
index 8c0e4f431974afc9540cbf2e6d009c9b7ec6ec61..1e8f039d3274cc9e6e7472fa6ae1b317c8a63ec2 100644 (file)
@@ -131,8 +131,12 @@ boolean getTokenValueFromString(char *, char **, char **);
 void InitCounter(void);
 unsigned int Counter(void);
 void Delay(unsigned int);
+boolean DelayReachedExt(unsigned int *, unsigned int, unsigned int);
 boolean FrameReached(unsigned int *, unsigned int);
 boolean DelayReached(unsigned int *, unsigned int);
+void ResetDelayCounterExt(unsigned int *, unsigned int);
+void ResetFrameCounter(unsigned int *);
+void ResetDelayCounter(unsigned int *);
 int WaitUntilDelayReached(unsigned int *, unsigned int);
 void SkipUntilDelayReached(unsigned int *, unsigned int, int *, int);
 
@@ -261,9 +265,6 @@ char *get_mapped_token(char *);
 
 int get_parameter_value(char *, char *, int);
 
-struct ScreenModeInfo *get_screen_mode_from_string(char *);
-void get_aspect_ratio_from_screen_mode(struct ScreenModeInfo *, int *x, int *y);
-
 struct FileInfo *getFileListFromConfigList(struct ConfigInfo *,
                                           struct ConfigTypeInfo *,
                                           char **, int);
index 3ab03783ba16a33a1da73c7c76362b368118368b..2507be4c97da205b22edef149ac0e413b7716091 100644 (file)
 #if defined(TARGET_SDL2)
 static SDL_Window *sdl_window = NULL;
 static SDL_Renderer *sdl_renderer = NULL;
-static SDL_Texture *sdl_texture = NULL;
+static SDL_Texture *sdl_texture_stream = NULL;
+static SDL_Texture *sdl_texture_target = NULL;
 static boolean fullscreen_enabled = FALSE;
-
-#define USE_RENDERER   TRUE
 #endif
 
-/* stuff needed to work around SDL/Windows fullscreen drawing bug */
-static int fullscreen_width;
-static int fullscreen_height;
-static int fullscreen_xoffset;
-static int fullscreen_yoffset;
-static int video_xoffset;
-static int video_yoffset;
 static boolean limit_screen_updates = FALSE;
 
 
@@ -50,10 +42,26 @@ void SDLLimitScreenUpdates(boolean enable)
   limit_screen_updates = enable;
 }
 
+static void FinalizeScreen()
+{
+  // 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);
+}
+
 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,18 +86,34 @@ static void UpdateScreen(SDL_Rect *rect)
   }
 #endif
 
+  if (video.screen_rendering_mode == SPECIAL_RENDERING_BITMAP &&
+      gfx.final_screen_bitmap != NULL) // may not be initialized yet
+  {
+    // 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);
+
+    FinalizeScreen();
+
+    screen = gfx.final_screen_bitmap->surface;
+
+    // force full window redraw
+    rect = NULL;
+  }
+
 #if defined(TARGET_SDL2)
-#if USE_RENDERER
-  SDL_Surface *screen = backbuffer->surface;
+  SDL_Texture *sdl_texture = sdl_texture_stream;
+
+  if (video.screen_rendering_mode == SPECIAL_RENDERING_TARGET)
+    sdl_texture = sdl_texture_target;
 
   if (rect)
   {
     int bytes_x = screen->pitch / video.width;
     int bytes_y = screen->pitch;
 
-    if (video.fullscreen_enabled)
-      bytes_x = screen->pitch / fullscreen_width;
-
     SDL_UpdateTexture(sdl_texture, rect,
                      screen->pixels + rect->x * bytes_x + rect->y * bytes_y,
                      screen->pitch);
@@ -98,56 +122,38 @@ static void UpdateScreen(SDL_Rect *rect)
   {
     SDL_UpdateTexture(sdl_texture, NULL, screen->pixels, screen->pitch);
   }
-  SDL_RenderClear(sdl_renderer);
-  SDL_RenderCopy(sdl_renderer, sdl_texture, NULL, NULL);
-  SDL_RenderPresent(sdl_renderer);
-#else
-  if (rect)
-    SDL_UpdateWindowSurfaceRects(sdl_window, rect, 1);
-  else
-    SDL_UpdateWindowSurface(sdl_window);
-#endif
-
-#else  // TARGET_SDL
-  if (rect)
-    SDL_UpdateRects(backbuffer->surface, 1, rect);
-  else
-    SDL_UpdateRect(backbuffer->surface, 0, 0, 0, 0);
-#endif
-}
-
-static void setFullscreenParameters(char *fullscreen_mode_string)
-{
-#if defined(TARGET_SDL2)
-  fullscreen_width = video.width;
-  fullscreen_height = video.height;
-  fullscreen_xoffset = 0;
-  fullscreen_yoffset = 0;  
 
-#else
+  // clear render target buffer
+  SDL_RenderClear(sdl_renderer);
 
-  struct ScreenModeInfo *fullscreen_mode;
-  int i;
+  // set renderer to use target texture for rendering
+  if (video.screen_rendering_mode == SPECIAL_RENDERING_TARGET ||
+      video.screen_rendering_mode == SPECIAL_RENDERING_DOUBLE)
+    SDL_SetRenderTarget(sdl_renderer, sdl_texture_target);
 
-  fullscreen_mode = get_screen_mode_from_string(fullscreen_mode_string);
+  // copy backbuffer texture to render target buffer
+  if (video.screen_rendering_mode != SPECIAL_RENDERING_TARGET)
+    SDL_RenderCopy(sdl_renderer, sdl_texture_stream, NULL, NULL);
 
-  if (fullscreen_mode == NULL)
-    return;
+  if (video.screen_rendering_mode != SPECIAL_RENDERING_BITMAP)
+    FinalizeScreen();
 
-  for (i = 0; video.fullscreen_modes[i].width != -1; i++)
+  // when using target texture, copy it to screen buffer
+  if (video.screen_rendering_mode == SPECIAL_RENDERING_TARGET ||
+      video.screen_rendering_mode == SPECIAL_RENDERING_DOUBLE)
   {
-    if (fullscreen_mode->width  == video.fullscreen_modes[i].width &&
-       fullscreen_mode->height == video.fullscreen_modes[i].height)
-    {
-      fullscreen_width  = fullscreen_mode->width;
-      fullscreen_height = fullscreen_mode->height;
+    SDL_SetRenderTarget(sdl_renderer, NULL);
+    SDL_RenderCopy(sdl_renderer, sdl_texture_target, NULL, NULL);
+  }
 
-      fullscreen_xoffset = (fullscreen_width  - video.width)  / 2;
-      fullscreen_yoffset = (fullscreen_height - video.height) / 2;
+  // show render target buffer on screen
+  SDL_RenderPresent(sdl_renderer);
 
-      break;
-    }
-  }
+#else  // TARGET_SDL
+  if (rect)
+    SDL_UpdateRects(screen, 1, rect);
+  else
+    SDL_UpdateRect(screen, 0, 0, 0, 0);
 #endif
 }
 
@@ -228,15 +234,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());
@@ -286,6 +300,51 @@ SDL_Surface *SDLGetNativeSurface(SDL_Surface *surface)
 
 #endif
 
+#if defined(TARGET_SDL2)
+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());
+
+  return texture;
+}
+#endif
+
+void SDLCreateBitmapTextures(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        = SDLCreateTextureFromSurface(bitmap->surface);
+  bitmap->texture_masked = SDLCreateTextureFromSurface(bitmap->surface_masked);
+#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)
@@ -307,167 +366,28 @@ void SDLInitVideoDisplay(void)
 #endif
 }
 
-void SDLInitVideoBuffer(DrawBuffer **backbuffer, DrawWindow **window,
-                       boolean fullscreen)
+void SDLInitVideoBuffer(boolean fullscreen)
 {
-#if !defined(TARGET_SDL2)
-  static int screen_xy[][2] =
-  {
-    {  640, 480 },
-    {  800, 600 },
-    { 1024, 768 },
-    {   -1,  -1 }
-  };
-#endif
-  SDL_Rect **modes = NULL;
-  boolean hardware_fullscreen_available = TRUE;
-  int i, j;
-
-  /* default: normal game window size */
-  fullscreen_width = video.width;
-  fullscreen_height = video.height;
-  fullscreen_xoffset = 0;
-  fullscreen_yoffset = 0;
-
-#if !defined(TARGET_SDL2)
-  /* determine required standard fullscreen mode for game screen size */
-  for (i = 0; screen_xy[i][0] != -1; i++)
-  {
-    if (screen_xy[i][0] >= video.width && screen_xy[i][1] >= video.height)
-    {
-      fullscreen_width  = screen_xy[i][0];
-      fullscreen_height = screen_xy[i][1];
-
-      break;
-    }
-  }
-
-  fullscreen_xoffset = (fullscreen_width  - video.width)  / 2;
-  fullscreen_yoffset = (fullscreen_height - video.height) / 2;
-#endif
-
-  checked_free(video.fullscreen_modes);
-
-  video.fullscreen_modes = NULL;
-  video.fullscreen_mode_current = NULL;
-
   video.window_scaling_percent = setup.window_scaling_percent;
   video.window_scaling_quality = setup.window_scaling_quality;
+  video.screen_rendering_mode =
+    (strEqual(setup.screen_rendering_mode, STR_SPECIAL_RENDERING_BITMAP) ?
+     SPECIAL_RENDERING_BITMAP :
+     strEqual(setup.screen_rendering_mode, STR_SPECIAL_RENDERING_TARGET) ?
+     SPECIAL_RENDERING_TARGET:
+     strEqual(setup.screen_rendering_mode, STR_SPECIAL_RENDERING_DOUBLE) ?
+     SPECIAL_RENDERING_DOUBLE : SPECIAL_RENDERING_OFF);
 
 #if defined(TARGET_SDL2)
-  int num_displays = SDL_GetNumVideoDisplays();
-
-  if (num_displays > 0)
-  {
-    // currently only display modes of first display supported
-    int num_modes = SDL_GetNumDisplayModes(0);
-
-    if (num_modes > 0)
-    {
-      modes = checked_calloc((num_modes + 1) * sizeof(SDL_Rect *));
-
-      for (i = 0; i < num_modes; i++)
-      {
-       SDL_DisplayMode mode;
-
-       if (SDL_GetDisplayMode(0, i, &mode) < 0)
-         break;
-
-       modes[i] = checked_calloc(sizeof(SDL_Rect));
-
-       modes[i]->w = mode.w;
-       modes[i]->h = mode.h;
-      }
-    }
-  }
-#else
-  /* get available hardware supported fullscreen modes */
-  modes = SDL_ListModes(NULL, SDL_FULLSCREEN | SDL_HWSURFACE);
-#endif
-
-  if (modes == NULL)
-  {
-    /* no hardware screen modes available => no fullscreen mode support */
-    // video.fullscreen_available = FALSE;
-    hardware_fullscreen_available = FALSE;
-  }
-  else if (modes == (SDL_Rect **)-1)
-  {
-    /* fullscreen resolution is not restricted -- all resolutions available */
-    video.fullscreen_modes = checked_calloc(2 * sizeof(struct ScreenModeInfo));
-
-    /* use native video buffer size for fullscreen mode */
-    video.fullscreen_modes[0].width  = video.width;
-    video.fullscreen_modes[0].height = video.height;
-
-    video.fullscreen_modes[1].width  = -1;
-    video.fullscreen_modes[1].height = -1;
-  }
-  else
-  {
-    /* in this case, a certain number of screen modes is available */
-    int num_modes = 0;
-
-    for (i = 0; modes[i] != NULL; i++)
-    {
-      boolean found_mode = FALSE;
-
-      /* screen mode is smaller than video buffer size -- skip it */
-      if (modes[i]->w < video.width || modes[i]->h < video.height)
-       continue;
-
-      if (video.fullscreen_modes != NULL)
-       for (j = 0; video.fullscreen_modes[j].width != -1; j++)
-         if (modes[i]->w == video.fullscreen_modes[j].width &&
-             modes[i]->h == video.fullscreen_modes[j].height)
-           found_mode = TRUE;
-
-      if (found_mode)          /* screen mode already stored -- skip it */
-       continue;
-
-      /* new mode found; add it to list of available fullscreen modes */
-
-      num_modes++;
-
-      video.fullscreen_modes = checked_realloc(video.fullscreen_modes,
-                                              (num_modes + 1) *
-                                              sizeof(struct ScreenModeInfo));
-
-      video.fullscreen_modes[num_modes - 1].width  = modes[i]->w;
-      video.fullscreen_modes[num_modes - 1].height = modes[i]->h;
-
-      video.fullscreen_modes[num_modes].width  = -1;
-      video.fullscreen_modes[num_modes].height = -1;
-    }
-
-    if (num_modes == 0)
-    {
-      /* no appropriate screen modes available => no fullscreen mode support */
-      // video.fullscreen_available = FALSE;
-      hardware_fullscreen_available = FALSE;
-    }
-  }
-
-  video.fullscreen_available = hardware_fullscreen_available;
-
-#if USE_DESKTOP_FULLSCREEN
-  // in SDL 2.0, there is always support for desktop fullscreen mode
-  // (in SDL 1.2, there is only support for "real" fullscreen mode)
+  // SDL 2.0: support for (desktop) fullscreen mode available
   video.fullscreen_available = TRUE;
-#endif
-
-#if defined(TARGET_SDL2)
-  if (modes)
-  {
-    for (i = 0; modes[i] != NULL; i++)
-      checked_free(modes[i]);
-
-    checked_free(modes);
-  }
+#else
+  // SDL 1.2: no support for fullscreen mode in R'n'D anymore
+  video.fullscreen_available = FALSE;
 #endif
 
   /* open SDL video output device (window or fullscreen mode) */
-  if (!SDLSetVideoMode(backbuffer, fullscreen))
+  if (!SDLSetVideoMode(fullscreen))
     Error(ERR_EXIT, "setting video mode failed");
 
   /* !!! SDL2 can only set the window icon if the window already exists !!! */
@@ -495,29 +415,23 @@ void SDLInitVideoBuffer(DrawBuffer **backbuffer, DrawWindow **window,
      should never be drawn to directly, it would do no harm nevertheless. */
 
   /* create additional (symbolic) buffer for double-buffering */
-  ReCreateBitmap(window, video.width, video.height, video.depth);
+  ReCreateBitmap(&window, video.width, video.height, video.depth);
 }
 
-static SDL_Surface *SDLCreateScreen(DrawBuffer **backbuffer,
-                                   boolean fullscreen)
+static boolean SDLCreateScreen(boolean fullscreen)
 {
   SDL_Surface *new_surface = NULL;
 
 #if defined(TARGET_SDL2)
-  int surface_flags_window = SURFACE_FLAGS | SDL_WINDOW_RESIZABLE;
-#if USE_DESKTOP_FULLSCREEN
+  int surface_flags_window     = SURFACE_FLAGS | SDL_WINDOW_RESIZABLE;
   int surface_flags_fullscreen = SURFACE_FLAGS | SDL_WINDOW_FULLSCREEN_DESKTOP;
 #else
-  int surface_flags_fullscreen = SURFACE_FLAGS | SDL_WINDOW_FULLSCREEN;
-#endif
-
-#else
-  int surface_flags_window = SURFACE_FLAGS;
-  int surface_flags_fullscreen = SURFACE_FLAGS | SDL_FULLSCREEN;
+  int surface_flags_window     = SURFACE_FLAGS;
+  int surface_flags_fullscreen = SURFACE_FLAGS;        // (no fullscreen in SDL 1.2)
 #endif
 
-  int width  = (fullscreen ? fullscreen_width  : video.width);
-  int height = (fullscreen ? fullscreen_height : video.height);
+  int width  = video.width;
+  int height = video.height;
   int surface_flags = (fullscreen ? surface_flags_fullscreen :
                       surface_flags_window);
 
@@ -530,25 +444,21 @@ static SDL_Surface *SDLCreateScreen(DrawBuffer **backbuffer,
   // store if initial screen mode is fullscreen mode when changing screen size
   video.fullscreen_initial = fullscreen;
 
-#if USE_RENDERER
   float window_scaling_factor = (float)setup.window_scaling_percent / 100;
-#if !USE_DESKTOP_FULLSCREEN
-  float screen_scaling_factor = (fullscreen ? 1 : window_scaling_factor);
-#endif
 
   video.window_width  = window_scaling_factor * width;
   video.window_height = window_scaling_factor * height;
 
-  if ((*backbuffer)->surface)
+  if (sdl_texture_stream)
   {
-    SDL_FreeSurface((*backbuffer)->surface);
-    (*backbuffer)->surface = NULL;
+    SDL_DestroyTexture(sdl_texture_stream);
+    sdl_texture_stream = NULL;
   }
 
-  if (sdl_texture)
+  if (sdl_texture_target)
   {
-    SDL_DestroyTexture(sdl_texture);
-    sdl_texture = NULL;
+    SDL_DestroyTexture(sdl_texture_target);
+    sdl_texture_target = NULL;
   }
 
   if (!(fullscreen && fullscreen_enabled))
@@ -570,13 +480,8 @@ static SDL_Surface *SDLCreateScreen(DrawBuffer **backbuffer,
     sdl_window = SDL_CreateWindow(program.window_title,
                                  SDL_WINDOWPOS_CENTERED,
                                  SDL_WINDOWPOS_CENTERED,
-#if USE_DESKTOP_FULLSCREEN
                                  video.window_width,
                                  video.window_height,
-#else
-                                 (int)(screen_scaling_factor * width),
-                                 (int)(screen_scaling_factor * height),
-#endif
                                  surface_flags);
 
   if (sdl_window != NULL)
@@ -599,19 +504,24 @@ static SDL_Surface *SDLCreateScreen(DrawBuffer **backbuffer,
       // SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "linear");
       SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, setup.window_scaling_quality);
 
-      sdl_texture = SDL_CreateTexture(sdl_renderer,
-                                     SDL_PIXELFORMAT_ARGB8888,
-                                     SDL_TEXTUREACCESS_STREAMING,
-                                     width, height);
+      sdl_texture_stream = SDL_CreateTexture(sdl_renderer,
+                                            SDL_PIXELFORMAT_ARGB8888,
+                                            SDL_TEXTUREACCESS_STREAMING,
+                                            width, height);
+
+      sdl_texture_target = SDL_CreateTexture(sdl_renderer,
+                                            SDL_PIXELFORMAT_ARGB8888,
+                                            SDL_TEXTUREACCESS_TARGET,
+                                            width, height);
 
-      if (sdl_texture != NULL)
+      if (sdl_texture_stream != NULL &&
+         sdl_texture_target != NULL)
       {
        // use SDL default values for RGB masks and no alpha channel
        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());
+         Error(ERR_WARN, "SDL_CreateRGBSurface() failed: %s", SDL_GetError());
       }
       else
       {
@@ -628,23 +538,35 @@ static SDL_Surface *SDLCreateScreen(DrawBuffer **backbuffer,
     Error(ERR_WARN, "SDL_CreateWindow() failed: %s", SDL_GetError());
   }
 
-#else
+#else  // TARGET_SDL
 
-  if (sdl_window)
-    SDL_DestroyWindow(sdl_window);
+  if (gfx.final_screen_bitmap == NULL)
+    gfx.final_screen_bitmap = CreateBitmapStruct();
 
-  sdl_window = SDL_CreateWindow(program.window_title,
-                               SDL_WINDOWPOS_CENTERED,
-                               SDL_WINDOWPOS_CENTERED,
-                               width, height,
-                               surface_flags);
+  gfx.final_screen_bitmap->width = width;
+  gfx.final_screen_bitmap->height = height;
 
-  if (sdl_window != NULL)
-    new_surface = SDL_GetWindowSurface(sdl_window);
+  gfx.final_screen_bitmap->surface =
+    SDL_SetVideoMode(width, height, video.depth, surface_flags);
+
+  if (gfx.final_screen_bitmap->surface != NULL)
+  {
+    new_surface =
+      SDL_CreateRGBSurface(surface_flags, width, height, video.depth, 0,0,0, 0);
+
+    if (new_surface == NULL)
+      Error(ERR_WARN, "SDL_CreateRGBSurface() failed: %s", SDL_GetError());
+
+#if 0
+    new_surface = gfx.final_screen_bitmap->surface;
+    gfx.final_screen_bitmap = NULL;
 #endif
 
-#else
-  new_surface = SDL_SetVideoMode(width, height, video.depth, surface_flags);
+  }
+  else
+  {
+    Error(ERR_WARN, "SDL_SetVideoMode() failed: %s", SDL_GetError());
+  }
 #endif
 
 #if defined(TARGET_SDL2)
@@ -653,78 +575,63 @@ static SDL_Surface *SDLCreateScreen(DrawBuffer **backbuffer,
     fullscreen_enabled = fullscreen;
 #endif
 
-  return new_surface;
+  if (backbuffer == NULL)
+    backbuffer = CreateBitmapStruct();
+
+  backbuffer->width  = video.width;
+  backbuffer->height = video.height;
+
+  if (backbuffer->surface)
+    SDL_FreeSurface(backbuffer->surface);
+
+  backbuffer->surface = new_surface;
+
+  return (new_surface != NULL);
 }
 
-boolean SDLSetVideoMode(DrawBuffer **backbuffer, boolean fullscreen)
+boolean SDLSetVideoMode(boolean fullscreen)
 {
-  boolean success = TRUE;
-  SDL_Surface *new_surface = NULL;
+  boolean success = FALSE;
 
   SetWindowTitle();
 
-  if (*backbuffer == NULL)
-    *backbuffer = CreateBitmapStruct();
-
-  /* (real bitmap might be larger in fullscreen mode with video offsets) */
-  (*backbuffer)->width  = video.width;
-  (*backbuffer)->height = video.height;
-
   if (fullscreen && !video.fullscreen_enabled && video.fullscreen_available)
   {
-    setFullscreenParameters(setup.fullscreen_mode);
-
-    video_xoffset = fullscreen_xoffset;
-    video_yoffset = fullscreen_yoffset;
-
     /* switch display to fullscreen mode, if available */
-    new_surface = SDLCreateScreen(backbuffer, TRUE);
+    success = SDLCreateScreen(TRUE);
 
-    if (new_surface == NULL)
+    if (!success)
     {
-      /* switching display to fullscreen mode failed */
-      Error(ERR_WARN, "SDL_SetVideoMode() failed: %s", SDL_GetError());
-
-      /* do not try it again */
+      /* switching display to fullscreen mode failed -- do not try it again */
       video.fullscreen_available = FALSE;
-
-      success = FALSE;
     }
     else
     {
-      (*backbuffer)->surface = new_surface;
-
       video.fullscreen_enabled = TRUE;
-      video.fullscreen_mode_current = setup.fullscreen_mode;
-
-      success = TRUE;
     }
   }
 
-  if ((!fullscreen && video.fullscreen_enabled) || new_surface == NULL)
+  if ((!fullscreen && video.fullscreen_enabled) || !success)
   {
-    video_xoffset = 0;
-    video_yoffset = 0;
-
     /* switch display to window mode */
-    new_surface = SDLCreateScreen(backbuffer, FALSE);
+    success = SDLCreateScreen(FALSE);
 
-    if (new_surface == NULL)
+    if (!success)
     {
       /* switching display to window mode failed -- should not happen */
-      Error(ERR_WARN, "SDL_SetVideoMode() failed: %s", SDL_GetError());
-
-      success = FALSE;
     }
     else
     {
-      (*backbuffer)->surface = new_surface;
-
       video.fullscreen_enabled = FALSE;
       video.window_scaling_percent = setup.window_scaling_percent;
       video.window_scaling_quality = setup.window_scaling_quality;
-
-      success = TRUE;
+      video.screen_rendering_mode =
+       (strEqual(setup.screen_rendering_mode, STR_SPECIAL_RENDERING_BITMAP) ?
+        SPECIAL_RENDERING_BITMAP :
+        strEqual(setup.screen_rendering_mode, STR_SPECIAL_RENDERING_TARGET) ?
+        SPECIAL_RENDERING_TARGET:
+        strEqual(setup.screen_rendering_mode, STR_SPECIAL_RENDERING_DOUBLE) ?
+        SPECIAL_RENDERING_DOUBLE : SPECIAL_RENDERING_OFF);
     }
   }
 
@@ -798,38 +705,60 @@ void SDLSetWindowScaling(int window_scaling_percent)
 
 void SDLSetWindowScalingQuality(char *window_scaling_quality)
 {
-  if (sdl_texture == NULL)
+  SDL_Texture *new_texture;
+
+  if (sdl_texture_stream == NULL ||
+      sdl_texture_target == NULL)
     return;
 
   SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, window_scaling_quality);
 
-  SDL_Texture *new_texture = SDL_CreateTexture(sdl_renderer,
-                                              SDL_PIXELFORMAT_ARGB8888,
-                                              SDL_TEXTUREACCESS_STREAMING,
-                                              video.width, video.height);
+  new_texture = SDL_CreateTexture(sdl_renderer,
+                                 SDL_PIXELFORMAT_ARGB8888,
+                                 SDL_TEXTUREACCESS_STREAMING,
+                                 video.width, video.height);
 
   if (new_texture != NULL)
   {
-    SDL_DestroyTexture(sdl_texture);
+    SDL_DestroyTexture(sdl_texture_stream);
+
+    sdl_texture_stream = new_texture;
+  }
 
-    sdl_texture = new_texture;
+  new_texture = SDL_CreateTexture(sdl_renderer,
+                                 SDL_PIXELFORMAT_ARGB8888,
+                                 SDL_TEXTUREACCESS_TARGET,
+                                 video.width, video.height);
 
-    SDLRedrawWindow();
+  if (new_texture != NULL)
+  {
+    SDL_DestroyTexture(sdl_texture_target);
+
+    sdl_texture_target = new_texture;
   }
 
+  SDLRedrawWindow();
+
   video.window_scaling_quality = window_scaling_quality;
 }
 
+void SDLSetScreenRenderingMode(char *screen_rendering_mode)
+{
+  video.screen_rendering_mode =
+    (strEqual(screen_rendering_mode, STR_SPECIAL_RENDERING_BITMAP) ?
+     SPECIAL_RENDERING_BITMAP :
+     strEqual(screen_rendering_mode, STR_SPECIAL_RENDERING_TARGET) ?
+     SPECIAL_RENDERING_TARGET:
+     strEqual(screen_rendering_mode, STR_SPECIAL_RENDERING_DOUBLE) ?
+     SPECIAL_RENDERING_DOUBLE : SPECIAL_RENDERING_OFF);
+}
+
 void SDLSetWindowFullscreen(boolean fullscreen)
 {
   if (sdl_window == NULL)
     return;
 
-#if USE_DESKTOP_FULLSCREEN
   int flags = (fullscreen ? SDL_WINDOW_FULLSCREEN_DESKTOP : 0);
-#else
-  int flags = (fullscreen ? SDL_WINDOW_FULLSCREEN : 0);
-#endif
 
   if (SDL_SetWindowFullscreen(sdl_window, flags) == 0)
     video.fullscreen_enabled = fullscreen_enabled = fullscreen;
@@ -871,8 +800,19 @@ void SDLFreeBitmapPointers(Bitmap *bitmap)
     SDL_FreeSurface(bitmap->surface);
   if (bitmap->surface_masked)
     SDL_FreeSurface(bitmap->surface_masked);
+
   bitmap->surface = NULL;
   bitmap->surface_masked = NULL;
+
+#if defined(TARGET_SDL2)
+  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 SDLCopyArea(Bitmap *src_bitmap, Bitmap *dst_bitmap,
@@ -882,23 +822,11 @@ void SDLCopyArea(Bitmap *src_bitmap, Bitmap *dst_bitmap,
   Bitmap *real_dst_bitmap = (dst_bitmap == window ? backbuffer : dst_bitmap);
   SDL_Rect src_rect, dst_rect;
 
-  if (src_bitmap == backbuffer)
-  {
-    src_x += video_xoffset;
-    src_y += video_yoffset;
-  }
-
   src_rect.x = src_x;
   src_rect.y = src_y;
   src_rect.w = width;
   src_rect.h = height;
 
-  if (dst_bitmap == backbuffer || dst_bitmap == window)
-  {
-    dst_x += video_xoffset;
-    dst_y += video_yoffset;
-  }
-
   dst_rect.x = dst_x;
   dst_rect.y = dst_y;
   dst_rect.w = width;
@@ -910,19 +838,36 @@ void SDLCopyArea(Bitmap *src_bitmap, Bitmap *dst_bitmap,
                     src_bitmap->surface_masked : src_bitmap->surface),
                    &src_rect, real_dst_bitmap->surface, &dst_rect);
 
-#if defined(TARGET_SDL2)
-  if (dst_bitmap == window)
-  {
-    // SDL_UpdateWindowSurface(sdl_window);
-    // SDL_UpdateWindowSurfaceRects(sdl_window, &dst_rect, 1);
-    UpdateScreen(&dst_rect);
-  }
-#else
   if (dst_bitmap == window)
-  {
-    // SDL_UpdateRect(backbuffer->surface, dst_x, dst_y, width, height);
     UpdateScreen(&dst_rect);
-  }
+}
+
+void SDLBlitTexture(Bitmap *bitmap,
+                   int src_x, int src_y, int width, int height,
+                   int dst_x, int dst_y, int mask_mode)
+{
+#if defined(TARGET_SDL2)
+  SDL_Texture *texture;
+  SDL_Rect src_rect;
+  SDL_Rect dst_rect;
+
+  texture =
+    (mask_mode == BLIT_MASKED ? bitmap->texture_masked : bitmap->texture);
+
+  if (texture == NULL)
+    return;
+
+  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_RenderCopy(sdl_renderer, texture, &src_rect, &dst_rect);
 #endif
 }
 
@@ -932,12 +877,6 @@ void SDLFillRectangle(Bitmap *dst_bitmap, int x, int y, int width, int height,
   Bitmap *real_dst_bitmap = (dst_bitmap == window ? backbuffer : dst_bitmap);
   SDL_Rect rect;
 
-  if (dst_bitmap == backbuffer || dst_bitmap == window)
-  {
-    x += video_xoffset;
-    y += video_yoffset;
-  }
-
   rect.x = x;
   rect.y = y;
   rect.w = width;
@@ -945,30 +884,17 @@ void SDLFillRectangle(Bitmap *dst_bitmap, int x, int y, int width, int height,
 
   SDL_FillRect(real_dst_bitmap->surface, &rect, color);
 
-#if defined(TARGET_SDL2)
-  if (dst_bitmap == window)
-  {
-    // SDL_UpdateWindowSurface(sdl_window);
-    // SDL_UpdateWindowSurfaceRects(sdl_window, &rect, 1);
-    UpdateScreen(&rect);
-  }
-#else
   if (dst_bitmap == window)
-  {
-    // SDL_UpdateRect(backbuffer->surface, x, y, width, height);
     UpdateScreen(&rect);
-  }
-#endif
 }
 
 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;
@@ -977,25 +903,18 @@ 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;
   src_rect.w = width;
   src_rect.h = height;
 
-  dst_x += video_xoffset;
-  dst_y += video_yoffset;
-
   dst_rect.x = dst_x;
   dst_rect.y = dst_y;
   dst_rect.w = width;          /* (ignored) */
@@ -1003,78 +922,28 @@ 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)
   {
     SDL_BlitSurface(surface_cross,  &src_rect, surface_source, &src_rect);
     SDL_BlitSurface(surface_screen, &dst_rect, surface_target, &src_rect);
+
+    draw_global_border_function(DRAW_BORDER_TO_FADE_SOURCE);
+    draw_global_border_function(DRAW_BORDER_TO_FADE_TARGET);
   }
   else if (fade_mode & FADE_TYPE_FADE_IN)
   {
     SDL_BlitSurface(surface_black,  &src_rect, surface_source, &src_rect);
     SDL_BlitSurface(surface_screen, &dst_rect, surface_target, &src_rect);
+
+    draw_global_border_function(DRAW_BORDER_TO_FADE_TARGET);
   }
   else         /* FADE_TYPE_FADE_OUT */
   {
     SDL_BlitSurface(surface_screen, &dst_rect, surface_source, &src_rect);
     SDL_BlitSurface(surface_black,  &src_rect, surface_target, &src_rect);
+
+    draw_global_border_function(DRAW_BORDER_TO_FADE_SOURCE);
   }
 
   time_current = SDL_GetTicks();
@@ -1291,7 +1160,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,
@@ -1311,26 +1200,12 @@ void SDLDrawSimpleLine(Bitmap *dst_bitmap, int from_x, int from_y,
   rect.w = (to_x - from_x + 1);
   rect.h = (to_y - from_y + 1);
 
-  if (dst_bitmap == backbuffer || dst_bitmap == window)
-  {
-    rect.x += video_xoffset;
-    rect.y += video_yoffset;
-  }
-
   SDL_FillRect(surface, &rect, color);
 }
 
 void SDLDrawLine(Bitmap *dst_bitmap, int from_x, int from_y,
                 int to_x, int to_y, Uint32 color)
 {
-  if (dst_bitmap == backbuffer || dst_bitmap == window)
-  {
-    from_x += video_xoffset;
-    from_y += video_yoffset;
-    to_x += video_xoffset;
-    to_y += video_yoffset;
-  }
-
   sge_Line(dst_bitmap->surface, from_x, from_y, to_x, to_y, color);
 }
 
@@ -1368,12 +1243,6 @@ Pixel SDLGetPixel(Bitmap *src_bitmap, int x, int y)
 {
   SDL_Surface *surface = src_bitmap->surface;
 
-  if (src_bitmap == backbuffer || src_bitmap == window)
-  {
-    x += video_xoffset;
-    y += video_yoffset;
-  }
-
   switch (surface->format->BytesPerPixel)
   {
     case 1:            /* assuming 8-bpp */
@@ -1865,12 +1734,6 @@ void sge_LineRGB(SDL_Surface *Surface, Sint16 x1, Sint16 y1, Sint16 x2,
 
 void SDLPutPixel(Bitmap *dst_bitmap, int x, int y, Pixel pixel)
 {
-  if (dst_bitmap == backbuffer || dst_bitmap == window)
-  {
-    x += video_xoffset;
-    y += video_yoffset;
-  }
-
   sge_PutPixel(dst_bitmap->surface, x, y, pixel);
 }
 
@@ -2298,8 +2161,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)
   {
@@ -2416,30 +2280,6 @@ void SDLCloseAudio(void)
 void SDLNextEvent(Event *event)
 {
   SDL_WaitEvent(event);
-
-  if (event->type == EVENT_BUTTONPRESS ||
-      event->type == EVENT_BUTTONRELEASE)
-  {
-    if (((ButtonEvent *)event)->x > video_xoffset)
-      ((ButtonEvent *)event)->x -= video_xoffset;
-    else
-      ((ButtonEvent *)event)->x = 0;
-    if (((ButtonEvent *)event)->y > video_yoffset)
-      ((ButtonEvent *)event)->y -= video_yoffset;
-    else
-      ((ButtonEvent *)event)->y = 0;
-  }
-  else if (event->type == EVENT_MOTIONNOTIFY)
-  {
-    if (((MotionEvent *)event)->x > video_xoffset)
-      ((MotionEvent *)event)->x -= video_xoffset;
-    else
-      ((MotionEvent *)event)->x = 0;
-    if (((MotionEvent *)event)->y > video_yoffset)
-      ((MotionEvent *)event)->y -= video_yoffset;
-    else
-      ((MotionEvent *)event)->y = 0;
-  }
 }
 
 void SDLHandleWindowManagerEvent(Event *event)
index 79827b4501dc6247076dc4dd1385378d813ca1be..195a8011c749ed56849f1202088fbf157145ca07 100644 (file)
 #if defined(PLATFORM_ANDROID)
 #define WINDOW_SCALING_STATUS  WINDOW_SCALING_NOT_AVAILABLE
 #define FULLSCREEN_STATUS      FULLSCREEN_AVAILABLE
-#define USE_DESKTOP_FULLSCREEN TRUE
 #elif defined(TARGET_SDL2)
 #define WINDOW_SCALING_STATUS  WINDOW_SCALING_AVAILABLE
 #define FULLSCREEN_STATUS      FULLSCREEN_AVAILABLE
-#define USE_DESKTOP_FULLSCREEN TRUE
 #else  // SDL 1.2
 #define WINDOW_SCALING_STATUS  WINDOW_SCALING_NOT_AVAILABLE
 #define FULLSCREEN_STATUS      FULLSCREEN_AVAILABLE
@@ -102,6 +100,10 @@ struct SDLSurfaceInfo
   int width, height;
   SDL_Surface *surface;
   SDL_Surface *surface_masked;
+#if defined(TARGET_SDL2)
+  SDL_Texture *texture;
+  SDL_Texture *texture_masked;
+#endif
 };
 
 struct MouseCursorInfo
@@ -428,11 +430,14 @@ struct MouseCursorInfo
 
 boolean SDLSetNativeSurface(SDL_Surface **);
 SDL_Surface *SDLGetNativeSurface(SDL_Surface *);
+void SDLCreateBitmapTextures(Bitmap *);
+void SDLFreeBitmapTextures(Bitmap *);
 
 #if defined(TARGET_SDL2)
 SDL_Surface *SDL_DisplayFormat(SDL_Surface *);
 void SDLSetWindowScaling(int);
 void SDLSetWindowScalingQuality(char *);
+void SDLSetScreenRenderingMode(char *);
 void SDLSetWindowFullscreen(boolean);
 void SDLRedrawWindow();
 #endif
@@ -441,11 +446,12 @@ void SDLSetWindowTitle(void);
 
 void SDLLimitScreenUpdates(boolean);
 void SDLInitVideoDisplay(void);
-void SDLInitVideoBuffer(DrawBuffer **, DrawWindow **, boolean);
-boolean SDLSetVideoMode(DrawBuffer **, boolean);
+void SDLInitVideoBuffer(boolean);
+boolean SDLSetVideoMode(boolean);
 void SDLCreateBitmapContent(Bitmap *, int, int, int);
 void SDLFreeBitmapPointers(Bitmap *);
 void SDLCopyArea(Bitmap *, Bitmap *, int, int, int, int, int, int, int);
+void SDLBlitTexture(Bitmap *, int, int, int, int, int, int, int);
 void SDLFillRectangle(Bitmap *, int, int, int, int, Uint32);
 void SDLFadeRectangle(Bitmap *, int, int, int, int, int, int, int,
                      void (*draw_border_function)(void));
index 4af58b671dd45294c2bc1b0a35ab6f54a246bd1b..4831248c86d2b9abc1ef56cf9ad0cd885ebc06c3 100644 (file)
@@ -122,6 +122,7 @@ static int stereo_volume[SOUND_MAX_LEFT2RIGHT + 1];
 
 static struct SoundControl mixer[NUM_MIXER_CHANNELS];
 static int mixer_active_channels = 0;
+static boolean expire_loop_sounds = FALSE;
 
 static void ReloadCustomSounds();
 static void ReloadCustomMusic();
@@ -150,7 +151,8 @@ static void Mixer_ResetChannelExpiration(int channel)
 {
   mixer[channel].playing_starttime = Counter();
 
-  if (IS_LOOP(mixer[channel]) && !IS_MUSIC(mixer[channel]))
+  if (expire_loop_sounds &&
+      IS_LOOP(mixer[channel]) && !IS_MUSIC(mixer[channel]))
     Mix_ExpireChannel(channel, SOUND_LOOP_EXPIRATION_TIME);
 }
 
@@ -159,7 +161,8 @@ static boolean Mixer_ChannelExpired(int channel)
   if (!mixer[channel].active)
     return TRUE;
 
-  if (IS_LOOP(mixer[channel]) && !IS_MUSIC(mixer[channel]) &&
+  if (expire_loop_sounds &&
+      IS_LOOP(mixer[channel]) && !IS_MUSIC(mixer[channel]) &&
       DelayReached(&mixer[channel].playing_starttime,
                   SOUND_LOOP_EXPIRATION_TIME))
     return TRUE;
@@ -478,6 +481,10 @@ static void HandleSoundRequest(SoundControl snd_ctrl)
       if (SAME_SOUND_NR(mixer[i], snd_ctrl) || ALL_SOUNDS(snd_ctrl))
        Mixer_StopChannel(i);
   }
+  else if (SET_EXPIRE_LOOPS(snd_ctrl)) /* set loop expiration on or off */
+  {
+    expire_loop_sounds = snd_ctrl.active;
+  }
   else if (snd_ctrl.active)            /* add new sound to mixer */
   {
     Mixer_InsertSound(snd_ctrl);
@@ -990,6 +997,21 @@ void StopSoundExt(int nr, int state)
   HandleSoundRequest(snd_ctrl);
 }
 
+void ExpireSoundLoops(boolean active)
+{
+  SoundControl snd_ctrl;
+
+  if (!audio.sound_available)
+    return;
+
+  clear_mem(&snd_ctrl, sizeof(SoundControl));  /* to make valgrind happy */
+
+  snd_ctrl.active = active;
+  snd_ctrl.state = SND_CTRL_EXPIRE_LOOPS;
+
+  HandleSoundRequest(snd_ctrl);
+}
+
 static void ReloadCustomSounds()
 {
   LoadArtworkConfig(sound_info);
index 9e2d2420489697359b5542d304491c7fdb07cf35..26e882b3e177c5345b97c8a3670046463dd83c9e 100644 (file)
@@ -56,6 +56,7 @@
 #define SND_CTRL_ALL_SOUNDS            (1 << 4)
 #define SND_CTRL_RELOAD_SOUNDS         (1 << 5)
 #define SND_CTRL_RELOAD_MUSIC          (1 << 6)
+#define SND_CTRL_EXPIRE_LOOPS          (1 << 7)
 
 #define SND_CTRL_PLAY_SOUND            (SND_CTRL_NONE)
 #define SND_CTRL_PLAY_LOOP             (SND_CTRL_LOOP)
@@ -76,6 +77,7 @@
 #define IS_RELOADING(x)                        ((x).state & (SND_CTRL_RELOAD_SOUNDS |\
                                                      SND_CTRL_RELOAD_MUSIC))
 #define ALL_SOUNDS(x)                  ((x).state & SND_CTRL_ALL_SOUNDS)
+#define SET_EXPIRE_LOOPS(x)            ((x).state & SND_CTRL_EXPIRE_LOOPS)
 
 #define MAP_NOCONF_MUSIC(x)            (-((x) + 1))
 #define UNMAP_NOCONF_MUSIC(x)          MAP_NOCONF_MUSIC(x)
@@ -113,6 +115,7 @@ void StopMusic(void);
 void StopSound(int);
 void StopSounds(void);
 void StopSoundExt(int, int);
+void ExpireSoundLoops(boolean);
 
 int getSoundListSize();
 int getMusicListSize();
index b5e4f270c284fbde5d20661d1fb7322fb6b81fcd..595daad7bd3fc148b43b0035fd8bc49b50d51f75 100644 (file)
@@ -207,6 +207,16 @@ void InitGfxWindowInfo(int win_xsize, int win_ysize)
   gfx.background_bitmap_mask = REDRAW_NONE;
 
   ReCreateBitmap(&gfx.background_bitmap, win_xsize, win_ysize, DEFAULT_DEPTH);
+
+#if defined(TARGET_SDL2)
+  ReCreateBitmap(&gfx.final_screen_bitmap, win_xsize, win_ysize, DEFAULT_DEPTH);
+#endif
+
+  ReCreateBitmap(&gfx.fade_bitmap_source, win_xsize, win_ysize, DEFAULT_DEPTH);
+  ReCreateBitmap(&gfx.fade_bitmap_target, win_xsize, win_ysize, DEFAULT_DEPTH);
+  ReCreateBitmap(&gfx.fade_bitmap_black,  win_xsize, win_ysize, DEFAULT_DEPTH);
+
+  ClearRectangle(gfx.fade_bitmap_black, 0, 0, win_xsize, win_ysize);
 }
 
 void InitGfxScrollbufferInfo(int scrollbuffer_width, int scrollbuffer_height)
@@ -231,6 +241,16 @@ void InitGfxDrawBusyAnimFunction(void (*draw_busy_anim_function)(void))
   gfx.draw_busy_anim_function = draw_busy_anim_function;
 }
 
+void InitGfxDrawGlobalAnimFunction(void (*draw_global_anim_function)(int))
+{
+  gfx.draw_global_anim_function = draw_global_anim_function;
+}
+
+void InitGfxDrawGlobalBorderFunction(void (*draw_global_border_function)(int))
+{
+  gfx.draw_global_border_function = draw_global_border_function;
+}
+
 void InitGfxCustomArtworkInfo()
 {
   gfx.override_level_graphics = FALSE;
@@ -358,7 +378,7 @@ void InitVideoBuffer(int width, int height, int depth, boolean fullscreen)
 
   video.window_scaling_available = WINDOW_SCALING_STATUS;
 
-  SDLInitVideoBuffer(&backbuffer, &window, fullscreen);
+  SDLInitVideoBuffer(fullscreen);
 
   video.initialized = TRUE;
 
@@ -399,7 +419,7 @@ void FreeBitmap(Bitmap *bitmap)
 
 Bitmap *CreateBitmapStruct(void)
 {
-  return checked_calloc(sizeof(struct SDLSurfaceInfo));
+  return checked_calloc(sizeof(Bitmap));
 }
 
 Bitmap *CreateBitmap(int width, int height, int depth)
@@ -715,6 +735,56 @@ void BlitBitmapOnBackground(Bitmap *src_bitmap, Bitmap *dst_bitmap,
               dst_x, dst_y);
 }
 
+void BlitTexture(Bitmap *bitmap,
+               int src_x, int src_y, int width, int height,
+               int dst_x, int dst_y)
+{
+  if (bitmap == NULL)
+    return;
+
+  SDLBlitTexture(bitmap, src_x, src_y, width, height, dst_x, dst_y,
+                BLIT_OPAQUE);
+}
+
+void BlitTextureMasked(Bitmap *bitmap,
+                      int src_x, int src_y, int width, int height,
+                      int dst_x, int dst_y)
+{
+  if (bitmap == NULL)
+    return;
+
+  SDLBlitTexture(bitmap, src_x, src_y, width, height, dst_x, dst_y,
+                BLIT_MASKED);
+}
+
+void BlitToScreen(Bitmap *bitmap,
+                 int src_x, int src_y, int width, int height,
+                 int dst_x, int dst_y)
+{
+  if (bitmap == NULL)
+    return;
+
+  if (video.screen_rendering_mode == SPECIAL_RENDERING_BITMAP)
+    BlitBitmap(bitmap, gfx.final_screen_bitmap, src_x, src_y,
+              width, height, dst_x, dst_y);
+  else
+    BlitTexture(bitmap, src_x, src_y, width, height, dst_x, dst_y);
+}
+
+void BlitToScreenMasked(Bitmap *bitmap,
+                       int src_x, int src_y, int width, int height,
+                       int dst_x, int dst_y)
+{
+  if (bitmap == NULL)
+    return;
+
+  if (video.screen_rendering_mode == SPECIAL_RENDERING_BITMAP)
+    BlitBitmapMasked(bitmap, gfx.final_screen_bitmap, src_x, src_y,
+                    width, height, dst_x, dst_y);
+  else
+    BlitTextureMasked(bitmap, src_x, src_y, width, height, dst_x, dst_y);
+}
+
 void DrawSimpleBlackLine(Bitmap *bitmap, int from_x, int from_y,
                         int to_x, int to_y)
 {
@@ -812,7 +882,7 @@ void KeyboardAutoRepeatOff(void)
 
 boolean SetVideoMode(boolean fullscreen)
 {
-  return SDLSetVideoMode(&backbuffer, fullscreen);
+  return SDLSetVideoMode(fullscreen);
 }
 
 boolean ChangeVideoModeIfNeeded(boolean fullscreen)
@@ -1125,6 +1195,16 @@ void CreateBitmapWithSmallBitmaps(Bitmap **bitmaps, int zoom_factor,
   CreateScaledBitmaps(bitmaps, zoom_factor, tile_size, TRUE);
 }
 
+void CreateBitmapTextures(Bitmap **bitmaps)
+{
+  SDLCreateBitmapTextures(bitmaps[IMG_BITMAP_STANDARD]);
+}
+
+void FreeBitmapTextures(Bitmap **bitmaps)
+{
+  SDLFreeBitmapTextures(bitmaps[IMG_BITMAP_STANDARD]);
+}
+
 void ScaleBitmap(Bitmap **bitmaps, int zoom_factor)
 {
   CreateScaledBitmaps(bitmaps, zoom_factor, 0, FALSE);
index fdda818ec8f4b7be172a2b2ccc8a1c930a72ce8b..110e18c2392c3f462650f69e5ad0cf36bb246c29 100644 (file)
 
 #define SCALING_QUALITY_DEFAULT                SCALING_QUALITY_LINEAR
 
+/* values for screen rendering mode */
+#define STR_SPECIAL_RENDERING_OFF      "stream_texture_only"
+#define STR_SPECIAL_RENDERING_BITMAP   "bitmap_and_stream_texture"
+#define STR_SPECIAL_RENDERING_TARGET   "target_texture_only"
+#define STR_SPECIAL_RENDERING_DOUBLE   "stream_and_target_texture"
+
+#if defined(TARGET_SDL2)
+#define STR_SPECIAL_RENDERING_DEFAULT  STR_SPECIAL_RENDERING_DOUBLE
+#else
+#define STR_SPECIAL_RENDERING_DEFAULT  STR_SPECIAL_RENDERING_BITMAP
+#endif
+
+#define SPECIAL_RENDERING_OFF          0
+#define SPECIAL_RENDERING_BITMAP       1
+#define SPECIAL_RENDERING_TARGET       2
+#define SPECIAL_RENDERING_DOUBLE       3
+
+#if defined(TARGET_SDL2)
+#define SPECIAL_RENDERING_DEFAULT      SPECIAL_RENDERING_DOUBLE
+#else
+#define SPECIAL_RENDERING_DEFAULT      SPECIAL_RENDERING_BITMAP
+#endif
+
 /* values for touch control */
 #define TOUCH_CONTROL_VIRTUAL_BUTTONS  "virtual_buttons"
 #define TOUCH_CONTROL_WIPE_GESTURES    "wipe_gestures"
 /* values for special "focus player" bitmasks */
 #define BIT_SET_FOCUS                  6
 
+/* values for drawing stages for global animations */
+#define DRAW_GLOBAL_ANIM_STAGE_1       1
+#define DRAW_GLOBAL_ANIM_STAGE_2       2
+
+/* values for drawing target for global border */
+#define DRAW_BORDER_TO_BACKBUFFER      0
+#define DRAW_BORDER_TO_SCREEN          1
+#define DRAW_BORDER_TO_FADE_SOURCE     2
+#define DRAW_BORDER_TO_FADE_TARGET     3
+
 /* values for move directions and special "button" key bitmasks */
 #define MV_NONE                        0
 #define MV_LEFT                        (1 << MV_BIT_LEFT)
                                 MV_NONE)
 
 /* values for animation mode (frame order and direction) */
+/* (stored in level files -- never change existing values) */
 #define ANIM_NONE              0
 #define ANIM_LOOP              (1 << 0)
 #define ANIM_LINEAR            (1 << 1)
 #define ANIM_OPAQUE_PLAYER     (1 << 9)
 
 /* values for special (non game element) animation modes */
+/* (not stored in level files -- can be changed, if needed) */
 #define ANIM_HORIZONTAL                (1 << 10)
 #define ANIM_VERTICAL          (1 << 11)
 #define ANIM_CENTERED          (1 << 12)
 #define ANIM_STATIC_PANEL      (1 << 13)
+#define ANIM_ALL               (1 << 14)
+#define ANIM_ONCE              (1 << 15)
 
 #define ANIM_DEFAULT           ANIM_LOOP
 
 
 #define FADE_MODE_DEFAULT      FADE_MODE_FADE
 
+/* values for toon positions */
+#define POS_UNDEFINED          -1
+#define POS_LEFT               0
+#define POS_RIGHT              1
+#define POS_TOP                        2
+#define POS_UPPER              3
+#define POS_MIDDLE             4
+#define POS_LOWER              5
+#define POS_BOTTOM             6
+#define POS_ANY                        7
+
 /* values for text alignment */
 #define ALIGN_LEFT             (1 << 0)
 #define ALIGN_RIGHT            (1 << 1)
@@ -684,7 +732,6 @@ struct ProgramInfo
 
 struct OptionInfo
 {
-  char *display_name;
   char *server_host;
   int server_port;
 
@@ -706,11 +753,6 @@ struct OptionInfo
   boolean debug;
 };
 
-struct ScreenModeInfo
-{
-  int width, height;
-};
-
 struct VideoSystemInfo
 {
   int default_depth;
@@ -720,12 +762,11 @@ struct VideoSystemInfo
   boolean fullscreen_available;
   boolean fullscreen_enabled;
   boolean fullscreen_initial;
-  struct ScreenModeInfo *fullscreen_modes;
-  char *fullscreen_mode_current;
 
   boolean window_scaling_available;
   int window_scaling_percent;
   char *window_scaling_quality;
+  int screen_rendering_mode;
 
   boolean initialized;
 };
@@ -792,6 +833,16 @@ struct GfxInfo
   Bitmap *background_bitmap;
   int background_bitmap_mask;
 
+  Bitmap *fade_bitmap_source;
+  Bitmap *fade_bitmap_target;
+  Bitmap *fade_bitmap_black;
+
+  int fade_border_source_status;
+  int fade_border_target_status;
+  Bitmap *masked_border_bitmap_ptr;
+
+  Bitmap *final_screen_bitmap;
+
   boolean clipping_enabled;
   int clip_x, clip_y;
   int clip_width, clip_height;
@@ -810,6 +861,8 @@ struct GfxInfo
   int anim_random_frame;
 
   void (*draw_busy_anim_function)(void);
+  void (*draw_global_anim_function)(int);
+  void (*draw_global_border_function)(int);
 
   int cursor_mode;
 };
@@ -946,6 +999,9 @@ struct SetupInternalInfo
 
   char *default_level_series;
 
+  int default_window_width;
+  int default_window_height;
+
   boolean choose_from_top_leveldir;
 };
 
@@ -970,9 +1026,9 @@ struct SetupInfo
   boolean skip_levels;
   boolean time_limit;
   boolean fullscreen;
-  char *fullscreen_mode;
   int window_scaling_percent;
   char *window_scaling_quality;
+  char *screen_rendering_mode;
   boolean ask_on_escape;
   boolean ask_on_escape_editor;
   boolean quick_switch;
@@ -1306,6 +1362,8 @@ void InitGfxWindowInfo(int, int);
 void InitGfxScrollbufferInfo(int, int);
 void InitGfxClipRegion(boolean, int, int, int, int);
 void InitGfxDrawBusyAnimFunction(void (*draw_busy_anim_function)(void));
+void InitGfxDrawGlobalAnimFunction(void (*draw_global_anim_function)(int));
+void InitGfxDrawGlobalBorderFunction(void (*draw_global_border_function)(int));
 void InitGfxCustomArtworkInfo();
 void InitGfxOtherSettings();
 void SetDrawDeactivationMask(int);
@@ -1335,6 +1393,10 @@ void BlitBitmapMasked(Bitmap *, Bitmap *, int, int, int, int, int, int);
 boolean DrawingOnBackground(int, int);
 boolean DrawingAreaChanged();
 void BlitBitmapOnBackground(Bitmap *, Bitmap *, int, int, int, int, int, int);
+void BlitTexture(Bitmap *, int, int, int, int, int, int);
+void BlitTextureMasked(Bitmap *, int, int, int, int, int, int);
+void BlitToScreen(Bitmap *, int, int, int, int, int, int);
+void BlitToScreenMasked(Bitmap *, int, int, int, int, int, int);
 void DrawSimpleBlackLine(Bitmap *, int, int, int, int);
 void DrawSimpleWhiteLine(Bitmap *, int, int, int, int);
 void DrawLines(Bitmap *, struct XY *, int, Pixel);
@@ -1354,6 +1416,8 @@ void ReloadCustomImage(Bitmap *, char *);
 Bitmap *ZoomBitmap(Bitmap *, int, int);
 void ReCreateGameTileSizeBitmap(Bitmap **);
 void CreateBitmapWithSmallBitmaps(Bitmap **, int, int);
+void CreateBitmapTextures(Bitmap **);
+void FreeBitmapTextures(Bitmap **);
 void ScaleBitmap(Bitmap **, int);
 
 void SetMouseCursor(int);
index 3868bdb68300f2d59a854561be83090325324744..34fa8fbb675f157256375535116f9938538f239e 100644 (file)
 #include "misc.h"
 
 
-/* values for toon animation */
-#define ANIM_START     0
-#define ANIM_CONTINUE  1
-#define ANIM_STOP      2
-
-
 static struct ToonScreenInfo screen_info;
 
 
@@ -385,18 +379,3 @@ void HandleAnimation(int mode)
 
   anim_restart = reset_delay = AnimateToon(toon_nr, anim_restart);
 }
-
-void InitAnimation()
-{
-  HandleAnimation(ANIM_START);
-}
-
-void StopAnimation()
-{
-  HandleAnimation(ANIM_STOP);
-}
-
-void DoAnimation()
-{
-  HandleAnimation(ANIM_CONTINUE);
-}
index 5dc52d021860d38dc2fb20514ab6c506b98c21bf..449687cd26f98a274d7236e61824f588b09973e4 100644 (file)
 #include "system.h"
 
 
+/* values for toon animation */
+#define ANIM_START     0
+#define ANIM_CONTINUE  1
+#define ANIM_STOP      2
+
+
 struct ToonScreenInfo
 {
   Bitmap *save_buffer;
@@ -55,8 +61,7 @@ void InitToonScreen(Bitmap *, void (*update_function)(void),
                    void (*prepare_backbuffer_function)(void),
                    boolean (*redraw_needed_function)(void),
                    struct ToonInfo *, int, int, int, int, int, int);
-void InitAnimation(void);
-void StopAnimation(void);
-void DoAnimation(void);
+
+void HandleAnimation(int);
 
 #endif /* TOONS_H */
index 9659af05c781dd6d8b7bf3b1559d403bda194658..c33369729d47972a43a70f223f99cb7df4d3285e 100644 (file)
@@ -5440,6 +5440,14 @@ struct ElementActionInfo element_action_info[NUM_ACTIONS + 1 + 1] =
   { ".page[30]",               ACTION_PAGE_30,                 FALSE   },
   { ".page[31]",               ACTION_PAGE_31,                 FALSE   },
   { ".page[32]",               ACTION_PAGE_32,                 FALSE   },
+  { ".part_1",                 ACTION_PART_1,                  FALSE   },
+  { ".part_2",                 ACTION_PART_2,                  FALSE   },
+  { ".part_3",                 ACTION_PART_3,                  FALSE   },
+  { ".part_4",                 ACTION_PART_4,                  FALSE   },
+  { ".part_5",                 ACTION_PART_5,                  FALSE   },
+  { ".part_6",                 ACTION_PART_6,                  FALSE   },
+  { ".part_7",                 ACTION_PART_7,                  FALSE   },
+  { ".part_8",                 ACTION_PART_8,                  FALSE   },
   { ".other",                  ACTION_OTHER,                   FALSE   },
 
   /* empty suffix always matches -- check as last entry in InitSoundInfo() */
@@ -5467,7 +5475,17 @@ struct SpecialSuffixInfo special_suffix_info[NUM_SPECIAL_GFX_ARGS + 1 + 1] =
   { ".[DEFAULT]",              GFX_SPECIAL_ARG_DEFAULT,                },
   { ".LOADING",                        GFX_SPECIAL_ARG_LOADING,                },
   { ".TITLE_INITIAL",          GFX_SPECIAL_ARG_TITLE_INITIAL,          },
+  { ".TITLE_INITIAL_1",                GFX_SPECIAL_ARG_TITLE_INITIAL_1,        },
+  { ".TITLE_INITIAL_2",                GFX_SPECIAL_ARG_TITLE_INITIAL_2,        },
+  { ".TITLE_INITIAL_3",                GFX_SPECIAL_ARG_TITLE_INITIAL_3,        },
+  { ".TITLE_INITIAL_4",                GFX_SPECIAL_ARG_TITLE_INITIAL_4,        },
+  { ".TITLE_INITIAL_5",                GFX_SPECIAL_ARG_TITLE_INITIAL_5,        },
   { ".TITLE",                  GFX_SPECIAL_ARG_TITLE,                  },
+  { ".TITLE_1",                        GFX_SPECIAL_ARG_TITLE_1,                },
+  { ".TITLE_2",                        GFX_SPECIAL_ARG_TITLE_2,                },
+  { ".TITLE_3",                        GFX_SPECIAL_ARG_TITLE_3,                },
+  { ".TITLE_4",                        GFX_SPECIAL_ARG_TITLE_4,                },
+  { ".TITLE_5",                        GFX_SPECIAL_ARG_TITLE_5,                },
   { ".MAIN",                   GFX_SPECIAL_ARG_MAIN,                   },
   { ".LEVELS",                 GFX_SPECIAL_ARG_LEVELS                  },
   { ".LEVELNR",                        GFX_SPECIAL_ARG_LEVELNR                 },
@@ -5481,6 +5499,13 @@ struct SpecialSuffixInfo special_suffix_info[NUM_SPECIAL_GFX_ARGS + 1 + 1] =
   { ".PANEL",                  GFX_SPECIAL_ARG_PANEL,                  },
   { ".PREVIEW",                        GFX_SPECIAL_ARG_PREVIEW,                },
   { ".CRUMBLED",               GFX_SPECIAL_ARG_CRUMBLED,               },
+  { ".MAINONLY",               GFX_SPECIAL_ARG_MAINONLY,               },
+  { ".TYPENAME",               GFX_SPECIAL_ARG_TYPENAME,               },
+  { ".SUBMENU",                        GFX_SPECIAL_ARG_SUBMENU,                },
+  { ".MENU",                   GFX_SPECIAL_ARG_MENU,                   },
+  { ".TOONS",                  GFX_SPECIAL_ARG_TOONS,                  },
+  { ".FADING",                 GFX_SPECIAL_ARG_FADING,                 },
+  { ".QUIT",                   GFX_SPECIAL_ARG_QUIT,                   },
 
   /* empty suffix always matches -- check as last entry in InitMusicInfo() */
   { "",                                GFX_SPECIAL_ARG_DEFAULT,                },
@@ -5528,11 +5553,14 @@ struct FontInfo font_info[NUM_FONTS + 1] =
   { "font.input_2.active"      },
   { "font.input_1"             },
   { "font.input_2"             },
+  { "font.option_off_narrow"   },
   { "font.option_off"          },
+  { "font.option_on_narrow"    },
   { "font.option_on"           },
   { "font.value_1"             },
   { "font.value_2"             },
   { "font.value_old"           },
+  { "font.value_narrow"                },
   { "font.level_number.active" },
   { "font.level_number"                },
   { "font.tape_recorder"       },
@@ -5543,6 +5571,31 @@ struct FontInfo font_info[NUM_FONTS + 1] =
   { NULL                       }
 };
 
+struct GlobalAnimInfo global_anim_info[NUM_GLOBAL_ANIM_TOKENS + 1] =
+{
+  /* (real) graphic definitions used to define animation graphics */
+  { "global.anim_1.gfx",       },
+  { "global.anim_2.gfx",       },
+  { "global.anim_3.gfx",       },
+  { "global.anim_4.gfx",       },
+  { "global.anim_5.gfx",       },
+  { "global.anim_6.gfx",       },
+  { "global.anim_7.gfx",       },
+  { "global.anim_8.gfx",       },
+
+  /* (dummy) graphic definitions used to define animation controls */
+  { "global.anim_1",           },
+  { "global.anim_2",           },
+  { "global.anim_3",           },
+  { "global.anim_4",           },
+  { "global.anim_5",           },
+  { "global.anim_6",           },
+  { "global.anim_7",           },
+  { "global.anim_8",           },
+
+  { NULL                       }
+};
+
 
 /* ------------------------------------------------------------------------- */
 /* music token prefix definitions                                            */
@@ -5566,7 +5619,6 @@ static void print_usage()
        "Usage: %s [OPTION]... [HOSTNAME [PORT]]\n"
        "\n"
        "Options:\n"
-       "  -d, --display HOSTNAME[:SCREEN]  specify X server display\n"
        "  -b, --basepath DIRECTORY         alternative base DIRECTORY\n"
        "  -l, --level DIRECTORY            alternative level DIRECTORY\n"
        "  -g, --graphics DIRECTORY         alternative graphics DIRECTORY\n"
@@ -5600,12 +5652,13 @@ static void print_usage()
 
 static void print_version()
 {
-  Print("%s %d.%d.%d.%d\n",
+  Print("%s %d.%d.%d.%d%s\n",
        PROGRAM_TITLE_STRING,
        PROGRAM_VERSION_MAJOR,
        PROGRAM_VERSION_MINOR,
        PROGRAM_VERSION_PATCH,
-       PROGRAM_VERSION_BUILD);
+       PROGRAM_VERSION_BUILD,
+       PROGRAM_VERSION_EXTRA);
 
   if (options.debug)
   {
@@ -5679,6 +5732,14 @@ static void InitProgramConfig(char *command_filename)
   userdata_subdir = USERDATA_DIRECTORY_OTHER;
 #endif
 
+  // set default window size (only relevant on program startup)
+  if (setup.internal.default_window_width  != 0 &&
+      setup.internal.default_window_height != 0)
+  {
+    WIN_XSIZE = setup.internal.default_window_width;
+    WIN_YSIZE = setup.internal.default_window_height;
+  }
+
   InitProgramInfo(command_filename,
                  config_filename,
                  userdata_subdir,
index 8b4948d7530be721eda7d145ee7e7b6c900b2cfb..f61c4edc85d58372aedbd126a0f8584a8b3ed6f0 100644 (file)
@@ -41,8 +41,6 @@
 #define SND_UNDEFINED                  (-1)
 #define MUS_UNDEFINED                  (-1)
 
-#define DEFAULT_FULLSCREEN_MODE                "800x600"
-
 #define WIN_XSIZE_DEFAULT              672
 #define WIN_YSIZE_DEFAULT              560
 
 
 #define IS_SPECIAL_GFX_ARG(a)  ((a) >= 0 && (a) < NUM_SPECIAL_GFX_ARGS)
 
+#define IS_GLOBAL_ANIM_PART(a) ((a) >= 0 && (a) < NUM_GLOBAL_ANIM_PARTS)
+
 #define EL_CASCADE_ACTIVE(e)   (IS_EDITOR_CASCADE_INACTIVE(e) ? (e) + 1 : (e))
 #define EL_CASCADE_INACTIVE(e) (IS_EDITOR_CASCADE_ACTIVE(e)   ? (e) - 1 : (e))
 #define EL_CASCADE_TOGGLE(e)   (IS_EDITOR_CASCADE_INACTIVE(e) ? (e) + 1 :    \
 #define ACTION_PAGE_30                 81
 #define ACTION_PAGE_31                 82
 #define ACTION_PAGE_32                 83
-#define ACTION_OTHER                   84
-
-#define NUM_ACTIONS                    85
+#define ACTION_PART_1                  84
+#define ACTION_PART_2                  85
+#define ACTION_PART_3                  86
+#define ACTION_PART_4                  87
+#define ACTION_PART_5                  88
+#define ACTION_PART_6                  89
+#define ACTION_PART_7                  90
+#define ACTION_PART_8                  91
+#define ACTION_OTHER                   92
+
+#define NUM_ACTIONS                    93
 
 #define ACTION_BORING_LAST             ACTION_BORING_10
 #define ACTION_SLEEPING_LAST           ACTION_SLEEPING_3
 #define GFX_SPECIAL_ARG_DEFAULT                0
 #define GFX_SPECIAL_ARG_LOADING                1
 #define GFX_SPECIAL_ARG_TITLE_INITIAL  2
-#define GFX_SPECIAL_ARG_TITLE          3
-#define GFX_SPECIAL_ARG_MAIN           4
-#define GFX_SPECIAL_ARG_LEVELS         5
-#define GFX_SPECIAL_ARG_LEVELNR                6
-#define GFX_SPECIAL_ARG_SCORES         7
-#define GFX_SPECIAL_ARG_EDITOR         8
-#define GFX_SPECIAL_ARG_INFO           9
-#define GFX_SPECIAL_ARG_SETUP          10
-#define GFX_SPECIAL_ARG_PLAYING                11
-#define GFX_SPECIAL_ARG_DOOR           12
-#define GFX_SPECIAL_ARG_TAPE           13
-#define GFX_SPECIAL_ARG_PANEL          14
-#define GFX_SPECIAL_ARG_PREVIEW                15
-#define GFX_SPECIAL_ARG_CRUMBLED       16
-
-#define NUM_SPECIAL_GFX_ARGS           17
+#define GFX_SPECIAL_ARG_TITLE_INITIAL_1        3
+#define GFX_SPECIAL_ARG_TITLE_INITIAL_2        4
+#define GFX_SPECIAL_ARG_TITLE_INITIAL_3        5
+#define GFX_SPECIAL_ARG_TITLE_INITIAL_4        6
+#define GFX_SPECIAL_ARG_TITLE_INITIAL_5        7
+#define GFX_SPECIAL_ARG_TITLE          8
+#define GFX_SPECIAL_ARG_TITLE_1                9
+#define GFX_SPECIAL_ARG_TITLE_2                10
+#define GFX_SPECIAL_ARG_TITLE_3                11
+#define GFX_SPECIAL_ARG_TITLE_4                12
+#define GFX_SPECIAL_ARG_TITLE_5                13
+#define GFX_SPECIAL_ARG_MAIN           14
+#define GFX_SPECIAL_ARG_LEVELS         15
+#define GFX_SPECIAL_ARG_LEVELNR                16
+#define GFX_SPECIAL_ARG_SCORES         17
+#define GFX_SPECIAL_ARG_EDITOR         18
+#define GFX_SPECIAL_ARG_INFO           19
+#define GFX_SPECIAL_ARG_SETUP          20
+#define GFX_SPECIAL_ARG_PLAYING                21
+#define GFX_SPECIAL_ARG_DOOR           22
+#define GFX_SPECIAL_ARG_TAPE           23
+#define GFX_SPECIAL_ARG_PANEL          24
+#define GFX_SPECIAL_ARG_PREVIEW                25
+#define GFX_SPECIAL_ARG_CRUMBLED       26
+#define GFX_SPECIAL_ARG_MAINONLY       27
+#define GFX_SPECIAL_ARG_TYPENAME       28
+#define GFX_SPECIAL_ARG_SUBMENU                29
+#define GFX_SPECIAL_ARG_MENU           30
+#define GFX_SPECIAL_ARG_TOONS          31
+#define GFX_SPECIAL_ARG_FADING         32
+#define GFX_SPECIAL_ARG_QUIT           33
+
+#define NUM_SPECIAL_GFX_ARGS           34
 
 /* these additional definitions are currently only used for draw offsets */
 #define GFX_SPECIAL_ARG_INFO_MAIN      0
 #define GFX_ARG_DIGGABLE_LIKE          23
 #define GFX_ARG_BORDER_SIZE            24
 #define GFX_ARG_STEP_OFFSET            25
-#define GFX_ARG_STEP_DELAY             26
-#define GFX_ARG_DIRECTION              27
-#define GFX_ARG_POSITION               28
-#define GFX_ARG_DRAW_XOFFSET           29
-#define GFX_ARG_DRAW_YOFFSET           30
-#define GFX_ARG_DRAW_MASKED            31
-#define GFX_ARG_ANIM_DELAY_FIXED       32
-#define GFX_ARG_ANIM_DELAY_RANDOM      33
-#define GFX_ARG_POST_DELAY_FIXED       34
-#define GFX_ARG_POST_DELAY_RANDOM      35
-#define GFX_ARG_NAME                   36
-#define GFX_ARG_SCALE_UP_FACTOR                37
-#define GFX_ARG_TILE_SIZE              38
-#define GFX_ARG_CLONE_FROM             39
-#define GFX_ARG_FADE_MODE              40
-#define GFX_ARG_FADE_DELAY             41
-#define GFX_ARG_POST_DELAY             42
-#define GFX_ARG_AUTO_DELAY             43
-#define GFX_ARG_ALIGN                  44
-#define GFX_ARG_VALIGN                 45
-#define GFX_ARG_SORT_PRIORITY          46
-#define GFX_ARG_CLASS                  47
-#define GFX_ARG_STYLE                  48
-#define GFX_ARG_ACTIVE_XOFFSET         49
-#define GFX_ARG_ACTIVE_YOFFSET         50
-#define GFX_ARG_PRESSED_XOFFSET                51
-#define GFX_ARG_PRESSED_YOFFSET                52
-
-#define NUM_GFX_ARGS                   53
+#define GFX_ARG_STEP_XOFFSET           26
+#define GFX_ARG_STEP_YOFFSET           27
+#define GFX_ARG_STEP_DELAY             28
+#define GFX_ARG_DIRECTION              29
+#define GFX_ARG_POSITION               30
+#define GFX_ARG_DRAW_XOFFSET           31
+#define GFX_ARG_DRAW_YOFFSET           32
+#define GFX_ARG_DRAW_MASKED            33
+#define GFX_ARG_DRAW_ORDER             34
+#define GFX_ARG_INIT_DELAY_FIXED       35
+#define GFX_ARG_INIT_DELAY_RANDOM      36
+#define GFX_ARG_ANIM_DELAY_FIXED       37
+#define GFX_ARG_ANIM_DELAY_RANDOM      38
+#define GFX_ARG_POST_DELAY_FIXED       39
+#define GFX_ARG_POST_DELAY_RANDOM      40
+#define GFX_ARG_NAME                   41
+#define GFX_ARG_SCALE_UP_FACTOR                42
+#define GFX_ARG_TILE_SIZE              43
+#define GFX_ARG_CLONE_FROM             44
+#define GFX_ARG_FADE_MODE              45
+#define GFX_ARG_FADE_DELAY             46
+#define GFX_ARG_POST_DELAY             47
+#define GFX_ARG_AUTO_DELAY             48
+#define GFX_ARG_ALIGN                  49
+#define GFX_ARG_VALIGN                 50
+#define GFX_ARG_SORT_PRIORITY          51
+#define GFX_ARG_CLASS                  52
+#define GFX_ARG_STYLE                  53
+#define GFX_ARG_ACTIVE_XOFFSET         54
+#define GFX_ARG_ACTIVE_YOFFSET         55
+#define GFX_ARG_PRESSED_XOFFSET                56
+#define GFX_ARG_PRESSED_YOFFSET                57
+
+#define NUM_GFX_ARGS                   58
 
 
 /* values for sound configuration suffixes */
 #define FONT_INPUT_2_ACTIVE            24
 #define FONT_INPUT_1                   25
 #define FONT_INPUT_2                   26
-#define FONT_OPTION_OFF                        27
-#define FONT_OPTION_ON                 28
-#define FONT_VALUE_1                   29
-#define FONT_VALUE_2                   30
-#define FONT_VALUE_OLD                 31
-#define FONT_LEVEL_NUMBER_ACTIVE       32
-#define FONT_LEVEL_NUMBER              33
-#define FONT_TAPE_RECORDER             34
-#define FONT_GAME_INFO                 35
-#define FONT_INFO_ELEMENTS             36
-#define FONT_INFO_LEVELSET             37
-
-#define NUM_FONTS                      38
+#define FONT_OPTION_OFF_NARROW         27
+#define FONT_OPTION_OFF                        28
+#define FONT_OPTION_ON_NARROW          29
+#define FONT_OPTION_ON                 30
+#define FONT_VALUE_1                   31
+#define FONT_VALUE_2                   32
+#define FONT_VALUE_OLD                 33
+#define FONT_VALUE_NARROW              34
+#define FONT_LEVEL_NUMBER_ACTIVE       35
+#define FONT_LEVEL_NUMBER              36
+#define FONT_TAPE_RECORDER             37
+#define FONT_GAME_INFO                 38
+#define FONT_INFO_ELEMENTS             39
+#define FONT_INFO_LEVELSET             40
+
+#define NUM_FONTS                      41
 #define NUM_INITIAL_FONTS              4
 
+/* values for toon animation configuration */
+#define MAX_NUM_TOONS                  20
+
+/* values for global animation configuration (must match those from main.c) */
+#define NUM_GLOBAL_ANIMS               8
+#define NUM_GLOBAL_ANIM_PARTS          8
+#define NUM_GLOBAL_ANIM_PARTS_ALL      (NUM_GLOBAL_ANIM_PARTS + 1)
+#define NUM_GLOBAL_ANIM_TOKENS         (2 * NUM_GLOBAL_ANIMS)
+
+#define GLOBAL_ANIM_ID_GRAPHIC_FIRST   0
+#define GLOBAL_ANIM_ID_GRAPHIC_LAST    7
+#define GLOBAL_ANIM_ID_CONTROL_FIRST   (NUM_GLOBAL_ANIMS + 0)
+#define GLOBAL_ANIM_ID_CONTROL_LAST    (NUM_GLOBAL_ANIMS + 7)
+
+#define GLOBAL_ANIM_ID_PART_FIRST      0
+#define GLOBAL_ANIM_ID_PART_LAST       7
+#define GLOBAL_ANIM_ID_PART_BASE       8
+
+/* values for global border graphics */
+#define IMG_GLOBAL_BORDER_FIRST                IMG_GLOBAL_BORDER
+#define IMG_GLOBAL_BORDER_LAST         IMG_GLOBAL_BORDER_PLAYING
+
 /* values for game_status (must match special image configuration suffixes) */
 #define GAME_MODE_DEFAULT              0
 #define GAME_MODE_LOADING              1
 #define GAME_MODE_TITLE_INITIAL                2
-#define GAME_MODE_TITLE                        3
-#define GAME_MODE_MAIN                 4
-#define GAME_MODE_LEVELS               5
-#define GAME_MODE_LEVELNR              6
-#define GAME_MODE_SCORES               7
-#define GAME_MODE_EDITOR               8
-#define GAME_MODE_INFO                 9
-#define GAME_MODE_SETUP                        10
-#define GAME_MODE_PLAYING              11
-#define GAME_MODE_PSEUDO_DOOR          12
-#define GAME_MODE_PSEUDO_TAPE          13
-#define GAME_MODE_PSEUDO_PANEL         14
-#define GAME_MODE_PSEUDO_PREVIEW       15
-#define GAME_MODE_PSEUDO_CRUMBLED      16
-
-/* there are no special config file suffixes for these modes */
-#define GAME_MODE_PSEUDO_TYPENAME      17
-#define GAME_MODE_QUIT                 18
+#define GAME_MODE_TITLE_INITIAL_1      3
+#define GAME_MODE_TITLE_INITIAL_2      4
+#define GAME_MODE_TITLE_INITIAL_3      5
+#define GAME_MODE_TITLE_INITIAL_4      6
+#define GAME_MODE_TITLE_INITIAL_5      7
+#define GAME_MODE_TITLE                        8
+#define GAME_MODE_TITLE_1              9
+#define GAME_MODE_TITLE_2              10
+#define GAME_MODE_TITLE_3              11
+#define GAME_MODE_TITLE_4              12
+#define GAME_MODE_TITLE_5              13
+#define GAME_MODE_MAIN                 14
+#define GAME_MODE_LEVELS               15
+#define GAME_MODE_LEVELNR              16
+#define GAME_MODE_SCORES               17
+#define GAME_MODE_EDITOR               18
+#define GAME_MODE_INFO                 19
+#define GAME_MODE_SETUP                        20
+#define GAME_MODE_PLAYING              21
+#define GAME_MODE_PSEUDO_DOOR          22
+#define GAME_MODE_PSEUDO_TAPE          23
+#define GAME_MODE_PSEUDO_PANEL         24
+#define GAME_MODE_PSEUDO_PREVIEW       25
+#define GAME_MODE_PSEUDO_CRUMBLED      26
+#define GAME_MODE_PSEUDO_MAINONLY      27
+#define GAME_MODE_PSEUDO_TYPENAME      28
+#define GAME_MODE_PSEUDO_SUBMENU       29
+#define GAME_MODE_PSEUDO_MENU          30
+#define GAME_MODE_PSEUDO_TOONS         31
+#define GAME_MODE_PSEUDO_FADING                32
+#define GAME_MODE_QUIT                 33
+
+#define NUM_GAME_MODES                 34
 
 /* special definitions currently only used for custom artwork configuration */
 #define MUSIC_PREFIX_BACKGROUND                0
 #define PROGRAM_VERSION_MINOR          0
 #define PROGRAM_VERSION_PATCH          0
 #define PROGRAM_VERSION_BUILD          0
+#define PROGRAM_VERSION_EXTRA          " RC1"
 
 #define PROGRAM_TITLE_STRING           "Rocks'n'Diamonds"
 #define PROGRAM_AUTHOR_STRING          "Holger Schemel"
 #define PROGRAM_EMAIL_STRING           "info@artsoft.org"
 #define PROGRAM_WEBSITE_STRING         "http://www.artsoft.org/"
-#define PROGRAM_COPYRIGHT_STRING       "Copyright \xa9""1995-2015 by Holger Schemel"
+#define PROGRAM_COPYRIGHT_STRING       "Copyright \xa9""1995-2016 by Holger Schemel"
 #define PROGRAM_COMPANY_STRING         "A Game by Artsoft Entertainment"
 
 #define PROGRAM_ICON_FILENAME          "RocksIcon32x32.png"
@@ -2541,6 +2612,10 @@ struct GlobalInfo
   /* global values for fading screens and masking borders */
   int border_status;
 
+  /* values for global animations */
+  int anim_status;
+  int anim_status_next;
+
   boolean use_envelope_request;
 };
 
@@ -2743,6 +2818,17 @@ struct FontInfo
                                /* internal bitmap ID for special graphics */
 };
 
+struct GlobalAnimInfo
+{
+  char *token_name;            /* global animation token in config files */
+
+  /* global animation graphic and control definitions */
+  int graphic[NUM_GLOBAL_ANIM_PARTS_ALL][NUM_SPECIAL_GFX_ARGS];
+
+  /* global animation sound definitions */
+  int sound[NUM_GLOBAL_ANIM_PARTS_ALL][NUM_SPECIAL_GFX_ARGS];
+};
+
 struct GraphicInfo
 {
   Bitmap **bitmaps;            /* bitmaps in all required sizes */
@@ -2778,18 +2864,27 @@ struct GraphicInfo
 
   int clone_from;              /* graphic for cloning *all* settings */
 
-  int anim_delay_fixed;                /* optional delay values for bored and   */
-  int anim_delay_random;       /* sleeping player animations (animation */
-  int post_delay_fixed;                /* intervall and following pause before  */
-  int post_delay_random;       /* next intervall (bored animation only) */
+  int init_delay_fixed;                /* optional initial delay values for global */
+  int init_delay_random;       /* animations (pause interval before start) */
+  int anim_delay_fixed;                /* optional delay values for bored/sleeping */
+  int anim_delay_random;       /* and global animations (animation length) */
+  int post_delay_fixed;                /* optional delay values after bored/global */
+  int post_delay_random;       /* animations (pause before next animation) */
 
   int step_offset;             /* optional step offset of toon animations */
+  int step_xoffset;            /* optional step offset of toon animations */
+  int step_yoffset;            /* optional step offset of toon animations */
   int step_delay;              /* optional step delay of toon animations */
+  int direction;               /* optional move direction of toon animations */
+  int position;                        /* optional draw position of toon animations */
+  int x;                       /* optional draw position of toon animations */
+  int y;                       /* optional draw position of toon animations */
 
   int draw_xoffset;            /* optional offset for drawing font chars */
   int draw_yoffset;            /* optional offset for drawing font chars */
 
   int draw_masked;             /* optional setting for drawing envelope gfx */
+  int draw_order;              /* optional draw order for global animations */
 
   int fade_mode;               /* optional setting for drawing title screens */
   int fade_delay;              /* optional setting for drawing title screens */
@@ -3016,6 +3111,7 @@ extern struct ElementDirectionInfo element_direction_info[];
 extern struct SpecialSuffixInfo special_suffix_info[];
 extern struct TokenIntPtrInfo  image_config_vars[];
 extern struct FontInfo         font_info[];
+extern struct GlobalAnimInfo   global_anim_info[];
 extern struct MusicPrefixInfo  music_prefix_info[];
 extern struct GraphicInfo      *graphic_info;
 extern struct SoundInfo               *sound_info;
index e62df4ce2d5e596a963f1a03959a63db5c5156e9..2946240128ce35ae379715dbd54f67f863b333e4 100644 (file)
@@ -464,7 +464,8 @@ static void Handle_OP_STOP_PLAYING()
       Request("Network game stopped!", REQ_CONFIRM);
   }
 
-  game_status = GAME_MODE_MAIN;
+  SetGameStatus(GAME_MODE_MAIN);
+
   DrawMainMenu();
 }
 
index c45e9badb79740cadbf519c085d788bd2ad14f4d..c6e3c645c87796d4690ea98663725436cdbfbd8d 100644 (file)
@@ -61,9 +61,9 @@
 #define SETUP_MODE_CHOOSE_GAME_SPEED   16
 #define SETUP_MODE_CHOOSE_SCROLL_DELAY 17
 #define SETUP_MODE_CHOOSE_SNAPSHOT_MODE        18
-#define SETUP_MODE_CHOOSE_SCREEN_MODE  19
-#define SETUP_MODE_CHOOSE_WINDOW_SIZE  20
-#define SETUP_MODE_CHOOSE_SCALING_TYPE 21
+#define SETUP_MODE_CHOOSE_WINDOW_SIZE  19
+#define SETUP_MODE_CHOOSE_SCALING_TYPE 20
+#define SETUP_MODE_CHOOSE_RENDERING    21
 #define SETUP_MODE_CHOOSE_GRAPHICS     22
 #define SETUP_MODE_CHOOSE_SOUNDS       23
 #define SETUP_MODE_CHOOSE_MUSIC                24
@@ -196,15 +196,15 @@ static struct GadgetInfo *screen_gadget[NUM_SCREEN_GADGETS];
 static int info_mode = INFO_MODE_MAIN;
 static int setup_mode = SETUP_MODE_MAIN;
 
-static TreeInfo *screen_modes = NULL;
-static TreeInfo *screen_mode_current = NULL;
-
 static TreeInfo *window_sizes = NULL;
 static TreeInfo *window_size_current = NULL;
 
 static TreeInfo *scaling_types = NULL;
 static TreeInfo *scaling_type_current = NULL;
 
+static TreeInfo *rendering_modes = NULL;
+static TreeInfo *rendering_mode_current = NULL;
+
 static TreeInfo *scroll_delays = NULL;
 static TreeInfo *scroll_delay_current = NULL;
 
@@ -235,6 +235,9 @@ static TreeInfo *drop_distance_current = NULL;
 static TreeInfo *level_number = NULL;
 static TreeInfo *level_number_current = NULL;
 
+static unsigned int sync_frame_delay = 0;
+static unsigned int sync_frame_delay_value = GAME_FRAME_DELAY;
+
 static struct
 {
   int value;
@@ -270,6 +273,20 @@ static struct
   {    NULL,                    NULL           },
 };
 
+static struct
+{
+  char *value;
+  char *text;
+} rendering_modes_list[] =
+{
+  {    STR_SPECIAL_RENDERING_OFF,      "Off (May show artifacts, fast)" },
+  {    STR_SPECIAL_RENDERING_BITMAP,   "Bitmap/Texture mode (slower)"   },
+  {    STR_SPECIAL_RENDERING_TARGET,   "Target Texture mode (slower)"   },
+  {    STR_SPECIAL_RENDERING_DOUBLE,   "Double Texture mode (slower)"   },
+
+  {    NULL,                            NULL                            },
+};
+
 static struct
 {
   int value;
@@ -708,6 +725,13 @@ static int getTitleMessageGameMode(boolean initial)
   return (initial ? GAME_MODE_TITLE_INITIAL : GAME_MODE_TITLE);
 }
 
+static int getTitleAnimMode(struct TitleControlInfo *tci)
+{
+  int base = (tci->initial ? GAME_MODE_TITLE_INITIAL_1 : GAME_MODE_TITLE_1);
+
+  return base + tci->local_nr;
+}
+
 #if 0
 static int getTitleScreenBackground(boolean initial)
 {
@@ -1230,11 +1254,7 @@ static void drawCursorXY(int xpos, int ypos, int graphic)
 
 static void drawChooseTreeCursor(int ypos, boolean active)
 {
-  int last_game_status = game_status;  /* save current game status */
-
   drawCursorExt(0, ypos, active, -1);
-
-  game_status = last_game_status;      /* restore current game status */
 }
 
 void DrawHeadline()
@@ -1292,13 +1312,12 @@ void DrawTitleScreenMessage(int nr, boolean initial)
 {
   char *filename = getLevelSetTitleMessageFilename(nr, initial);
   struct TitleMessageInfo *tmi = getTitleMessageInfo(nr, initial);
-  int last_game_status = game_status;  /* save current game status */
 
   if (filename == NULL)
     return;
 
   /* force TITLE font on title message screen */
-  game_status = getTitleMessageGameMode(initial);
+  SetFontStatus(getTitleMessageGameMode(initial));
 
   /* if chars *and* width set to "-1", automatically determine width */
   if (tmi->chars == -1 && tmi->width == -1)
@@ -1337,7 +1356,7 @@ void DrawTitleScreenMessage(int nr, boolean initial)
               filename, tmi->font, tmi->chars, -1, tmi->lines, 0, -1,
               tmi->autowrap, tmi->centered, tmi->parse_comments);
 
-  game_status = last_game_status;      /* restore current game status */
+  ResetFontStatus();
 }
 
 void DrawTitleScreen()
@@ -1381,6 +1400,8 @@ void DrawMainMenu()
   UnmapAllGadgets();
   FadeSoundsAndMusic();
 
+  ExpireSoundLoops(FALSE);
+
   KeyboardAutoRepeatOn();
   ActivateJoystick();
 
@@ -1391,7 +1412,10 @@ void DrawMainMenu()
   /* needed if last screen was the playing screen, invoked from level editor */
   if (level_editor_test_game)
   {
-    game_status = GAME_MODE_EDITOR;
+    CloseDoor(DOOR_CLOSE_ALL);
+
+    SetGameStatus(GAME_MODE_EDITOR);
+
     DrawLevelEd();
 
     return;
@@ -1416,6 +1440,17 @@ void DrawMainMenu()
   /* needed if last screen (level choice) changed graphics, sounds or music */
   ReloadCustomArtwork(0);
 
+  if (CheckTitleScreen(levelset_has_changed))
+  {
+    game_status_last_screen = GAME_MODE_MAIN;
+
+    SetGameStatus(GAME_MODE_TITLE);
+
+    DrawTitleScreen();
+
+    return;
+  }
+
   /* needed if different viewport properties defined for menues */
   ChangeViewportPropertiesIfNeeded();
 
@@ -1427,21 +1462,8 @@ void DrawMainMenu()
 
   FadeOut(fade_mask);
 
-  /* needed if last screen was the editor screen */
-  UndrawSpecialEditorDoor();
-
   SetDrawtoField(DRAW_BACKBUFFER);
 
-  if (CheckTitleScreen(levelset_has_changed))
-  {
-    game_status_last_screen = GAME_MODE_MAIN;
-    game_status = GAME_MODE_TITLE;
-
-    DrawTitleScreen();
-
-    return;
-  }
-
   /* level_nr may have been set to value over handicap with level editor */
   if (setup.handicap && level_nr > leveldir_current->handicap_level)
     level_nr = leveldir_current->handicap_level;
@@ -1552,6 +1574,8 @@ void HandleTitleScreen(int mx, int my, int dx, int dy, int button)
     title_screen_nr = 0;
     tci = &title_controls[title_screen_nr];
 
+    SetAnimStatus(getTitleAnimMode(tci));
+
     last_sound = SND_UNDEFINED;
     last_music = MUS_UNDEFINED;
 
@@ -1568,19 +1592,18 @@ void HandleTitleScreen(int mx, int my, int dx, int dy, int button)
       if (num_title_screens == 0)
       {
        /* switch game mode from title screen mode back to info screen mode */
-       game_status = GAME_MODE_INFO;
+       SetGameStatus(GAME_MODE_INFO);
 
        DrawInfoScreen_NotAvailable("Title screen information:",
                                    "No title screen for this level set.");
-
        return;
       }
 
       FadeSoundsAndMusic();
-
-      FadeOut(REDRAW_ALL);
     }
 
+    FadeOut(REDRAW_ALL);
+
     /* only required to update logic for redrawing global border */
     ClearField();
 
@@ -1623,7 +1646,8 @@ void HandleTitleScreen(int mx, int my, int dx, int dy, int button)
   {
     if (game_status_last_screen == GAME_MODE_INFO && num_title_screens == 0)
     {
-      game_status = GAME_MODE_INFO;
+      SetGameStatus(GAME_MODE_INFO);
+
       info_mode = INFO_MODE_MAIN;
 
       DrawInfoScreen();
@@ -1632,10 +1656,13 @@ void HandleTitleScreen(int mx, int my, int dx, int dy, int button)
     }
 
     title_screen_nr++;
-    tci = &title_controls[title_screen_nr];
 
     if (title_screen_nr < num_title_screens)
     {
+      tci = &title_controls[title_screen_nr];
+
+      SetAnimStatus(getTitleAnimMode(tci));
+
       sound = getTitleSound(tci);
       music = getTitleMusic(tci);
 
@@ -1685,14 +1712,15 @@ void HandleTitleScreen(int mx, int my, int dx, int dy, int button)
 
     if (game_status_last_screen == GAME_MODE_INFO)
     {
-      game_status = GAME_MODE_INFO;
+      SetGameStatus(GAME_MODE_INFO);
+
       info_mode = INFO_MODE_MAIN;
 
       DrawInfoScreen();
     }
     else       /* default: return to main menu */
     {
-      game_status = GAME_MODE_MAIN;
+      SetGameStatus(GAME_MODE_MAIN);
 
       DrawMainMenu();
     }
@@ -1827,7 +1855,7 @@ void HandleMainMenu(int mx, int my, int dx, int dy, int button)
 
     CloseDoor(DOOR_CLOSE_2);
 
-    game_status = GAME_MODE_LEVELNR;
+    SetGameStatus(GAME_MODE_LEVELNR);
 
     ChangeViewportPropertiesIfNeeded();
 
@@ -1853,7 +1881,7 @@ void HandleMainMenu(int mx, int my, int dx, int dy, int button)
 
       if (pos == MAIN_CONTROL_NAME)
       {
-       game_status = GAME_MODE_PSEUDO_TYPENAME;
+       SetGameStatus(GAME_MODE_PSEUDO_TYPENAME);
 
        HandleTypeName(strlen(setup.player_name), 0);
       }
@@ -1865,7 +1893,7 @@ void HandleMainMenu(int mx, int my, int dx, int dy, int button)
 
          CloseDoor(DOOR_CLOSE_2);
 
-         game_status = GAME_MODE_LEVELS;
+         SetGameStatus(GAME_MODE_LEVELS);
 
          SaveLevelSetup_LastSeries();
          SaveLevelSetup_SeriesInfo();
@@ -1884,7 +1912,7 @@ void HandleMainMenu(int mx, int my, int dx, int dy, int button)
 
        CloseDoor(DOOR_CLOSE_2);
 
-       game_status = GAME_MODE_SCORES;
+       SetGameStatus(GAME_MODE_SCORES);
 
        DrawHallOfFame(-1);
       }
@@ -1898,7 +1926,7 @@ void HandleMainMenu(int mx, int my, int dx, int dy, int button)
 
        CloseDoor(DOOR_CLOSE_2);
 
-       game_status = GAME_MODE_EDITOR;
+       SetGameStatus(GAME_MODE_EDITOR);
 
        FadeSetEnterScreen();
 
@@ -1910,7 +1938,8 @@ void HandleMainMenu(int mx, int my, int dx, int dy, int button)
 
        CloseDoor(DOOR_CLOSE_2);
 
-       game_status = GAME_MODE_INFO;
+       SetGameStatus(GAME_MODE_INFO);
+
        info_mode = INFO_MODE_MAIN;
 
        ChangeViewportPropertiesIfNeeded();
@@ -1929,7 +1958,8 @@ void HandleMainMenu(int mx, int my, int dx, int dy, int button)
 
        CloseDoor(DOOR_CLOSE_2);
 
-       game_status = GAME_MODE_SETUP;
+       SetGameStatus(GAME_MODE_SETUP);
+
        setup_mode = SETUP_MODE_MAIN;
 
        ChangeViewportPropertiesIfNeeded();
@@ -1942,7 +1972,7 @@ void HandleMainMenu(int mx, int my, int dx, int dy, int button)
        SaveLevelSetup_SeriesInfo();
 
         if (Request("Do you really want to quit?", REQ_ASK | REQ_STAY_CLOSED))
-         game_status = GAME_MODE_QUIT;
+         SetGameStatus(GAME_MODE_QUIT);
       }
     }
   }
@@ -2010,7 +2040,7 @@ static void execInfoLevelSet()
 
 static void execExitInfo()
 {
-  game_status = GAME_MODE_MAIN;
+  SetGameStatus(GAME_MODE_MAIN);
 
   DrawMainMenu();
 }
@@ -2083,7 +2113,6 @@ static void DrawCursorAndText_Setup(int screen_pos, int menu_info_pos_raw,
   DrawCursorAndText_Menu_Ext(setup_info, screen_pos, menu_info_pos_raw, active);
 }
 
-static char *screen_mode_text;
 static char *window_size_text;
 static char *scaling_type_text;
 
@@ -2110,7 +2139,6 @@ static void drawMenuInfoList(int first_entry, int num_page_entries,
        (value_ptr == &setup.sound_loops  && !audio.loops_available) ||
        (value_ptr == &setup.sound_music  && !audio.music_available) ||
        (value_ptr == &setup.fullscreen   && !video.fullscreen_available) ||
-       (value_ptr == &screen_mode_text   && !video.fullscreen_available) ||
        (value_ptr == &window_size_text   && !video.window_scaling_available) ||
        (value_ptr == &scaling_type_text  && !video.window_scaling_available))
       si->type |= TYPE_GHOSTED;
@@ -2142,12 +2170,11 @@ static void DrawInfoScreen_Main()
     fade_mask = REDRAW_ALL;
 
   UnmapAllGadgets();
+  FadeSoundsAndMusic();
 
   FreeScreenGadgets();
   CreateScreenGadgets();
 
-  CloseDoor(DOOR_CLOSE_2);
-
   /* (needed after displaying title screens which disable auto repeat) */
   KeyboardAutoRepeatOn();
 
@@ -2157,10 +2184,10 @@ static void DrawInfoScreen_Main()
 
   ChangeViewportPropertiesIfNeeded();
 
-  OpenDoor(GetDoorState() | DOOR_NO_DELAY | DOOR_FORCE_REDRAW);
-
   ClearField();
 
+  OpenDoor(GetDoorState() | DOOR_NO_DELAY | DOOR_FORCE_REDRAW);
+
   DrawTextSCentered(mSY - SY + 16, FONT_TITLE_1, "Info Screen");
 
   info_info = info_info_main;
@@ -2182,11 +2209,6 @@ static void DrawInfoScreen_Main()
   PlayMenuSound();
   PlayMenuMusic();
 
-#if 1
-  // needed after returning from title screens with different window size
-  OpenDoor(GetDoorState() | DOOR_NO_DELAY | DOOR_FORCE_REDRAW);
-#endif
-
   DrawMaskedBorder(fade_mask);
 
   FadeIn(fade_mask);
@@ -2666,7 +2688,8 @@ void DrawInfoScreen_HelpText(int element, int action, int direction, int ypos)
 void DrawInfoScreen_TitleScreen()
 {
   game_status_last_screen = GAME_MODE_INFO;
-  game_status = GAME_MODE_TITLE;
+
+  SetGameStatus(GAME_MODE_TITLE);
 
   DrawTitleScreen();
 }
@@ -3599,7 +3622,7 @@ void HandleTypeName(int newxpos, Key key)
 
     is_active = FALSE;
 
-    game_status = GAME_MODE_MAIN;
+    SetGameStatus(GAME_MODE_MAIN);
   }
   else if (key == KSYM_Escape)
   {
@@ -3607,7 +3630,7 @@ void HandleTypeName(int newxpos, Key key)
 
     is_active = FALSE;
 
-    game_status = GAME_MODE_MAIN;
+    SetGameStatus(GAME_MODE_MAIN);
   }
 
   if (is_active)
@@ -3645,7 +3668,7 @@ static void DrawChooseTree(TreeInfo **ti_ptr)
 
   if (strEqual((*ti_ptr)->subdir, STRING_TOP_DIRECTORY))
   {
-    game_status = GAME_MODE_MAIN;
+    SetGameStatus(GAME_MODE_MAIN);
 
     DrawMainMenu();
 
@@ -3657,14 +3680,12 @@ static void DrawChooseTree(TreeInfo **ti_ptr)
   FreeScreenGadgets();
   CreateScreenGadgets();
 
-  CloseDoor(DOOR_CLOSE_2);
-
   FadeOut(fade_mask);
 
-  OpenDoor(GetDoorState() | DOOR_NO_DELAY | DOOR_FORCE_REDRAW);
-
   ClearField();
 
+  OpenDoor(GetDoorState() | DOOR_NO_DELAY | DOOR_FORCE_REDRAW);
+
   HandleChooseTree(0, 0, 0, 0, MB_MENU_INITIALIZE, ti_ptr);
   MapScreenTreeGadgets(*ti_ptr);
 
@@ -3684,7 +3705,6 @@ static void drawChooseTreeList(int first_entry, int num_page_entries,
   int yoffset_setup = 16;
   int yoffset = (ti->type == TREE_TYPE_LEVEL_DIR ||
                 ti->type == TREE_TYPE_LEVEL_NR ? yoffset_sets : yoffset_setup);
-  int last_game_status = game_status;  /* save current game status */
 
   title_string = ti->infotext;
 
@@ -3724,8 +3744,6 @@ static void drawChooseTreeList(int first_entry, int num_page_entries,
       initCursor(i, IMG_MENU_BUTTON);
   }
 
-  game_status = last_game_status;      /* restore current game status */
-
   redraw_mask |= REDRAW_FIELD;
 }
 
@@ -3773,7 +3791,6 @@ static void HandleChooseTree(int mx, int my, int dx, int dy, int button,
   int step = (button == 1 ? 1 : button == 2 ? 5 : 10);
   int num_entries = numTreeInfoInGroup(ti);
   int num_page_entries;
-  int last_game_status = game_status;  /* save current game status */
   boolean position_set_by_scrollbar = (dx == 999);
 
   if (num_entries <= NUM_MENU_ENTRIES_ON_SCREEN)
@@ -3781,8 +3798,6 @@ static void HandleChooseTree(int mx, int my, int dx, int dy, int button,
   else
     num_page_entries = NUM_MENU_ENTRIES_ON_SCREEN;
 
-  game_status = last_game_status;      /* restore current game status */
-
   if (button == MB_MENU_INITIALIZE)
   {
     int num_entries = numTreeInfoInGroup(ti);
@@ -3832,9 +3847,9 @@ static void HandleChooseTree(int mx, int my, int dx, int dy, int button,
          setup_mode == SETUP_MODE_CHOOSE_SCROLL_DELAY ||
          setup_mode == SETUP_MODE_CHOOSE_SNAPSHOT_MODE)
        execSetupGame();
-      else if (setup_mode == SETUP_MODE_CHOOSE_SCREEN_MODE ||
-              setup_mode == SETUP_MODE_CHOOSE_WINDOW_SIZE ||
-              setup_mode == SETUP_MODE_CHOOSE_SCALING_TYPE)
+      else if (setup_mode == SETUP_MODE_CHOOSE_WINDOW_SIZE ||
+              setup_mode == SETUP_MODE_CHOOSE_SCALING_TYPE ||
+              setup_mode == SETUP_MODE_CHOOSE_RENDERING)
        execSetupGraphics();
       else if (setup_mode == SETUP_MODE_CHOOSE_VOLUME_SIMPLE ||
               setup_mode == SETUP_MODE_CHOOSE_VOLUME_LOOPS ||
@@ -3856,7 +3871,7 @@ static void HandleChooseTree(int mx, int my, int dx, int dy, int button,
        HandleMainMenu_SelectLevel(0, 0, new_level_nr);
       }
 
-      game_status = GAME_MODE_MAIN;
+      SetGameStatus(GAME_MODE_MAIN);
 
       DrawMainMenu();
     }
@@ -3866,12 +3881,8 @@ static void HandleChooseTree(int mx, int my, int dx, int dy, int button,
 
   if (mx || my)                /* mouse input */
   {
-    int last_game_status = game_status;        /* save current game status */
-
     x = (mx - mSX) / 32;
     y = (my - mSY) / 32 - MENU_SCREEN_START_YPOS;
-
-    game_status = last_game_status;    /* restore current game status */
   }
   else if (dx || dy)   /* keyboard or scrollbar/scrollbutton input */
   {
@@ -4030,9 +4041,9 @@ static void HandleChooseTree(int mx, int my, int dx, int dy, int button,
              setup_mode == SETUP_MODE_CHOOSE_SCROLL_DELAY ||
              setup_mode == SETUP_MODE_CHOOSE_SNAPSHOT_MODE)
            execSetupGame();
-         else if (setup_mode == SETUP_MODE_CHOOSE_SCREEN_MODE ||
-                  setup_mode == SETUP_MODE_CHOOSE_WINDOW_SIZE ||
-                  setup_mode == SETUP_MODE_CHOOSE_SCALING_TYPE)
+         else if (setup_mode == SETUP_MODE_CHOOSE_WINDOW_SIZE ||
+                  setup_mode == SETUP_MODE_CHOOSE_SCALING_TYPE ||
+                  setup_mode == SETUP_MODE_CHOOSE_RENDERING)
            execSetupGraphics();
          else if (setup_mode == SETUP_MODE_CHOOSE_VOLUME_SIMPLE ||
                   setup_mode == SETUP_MODE_CHOOSE_VOLUME_LOOPS ||
@@ -4054,7 +4065,7 @@ static void HandleChooseTree(int mx, int my, int dx, int dy, int button,
            HandleMainMenu_SelectLevel(0, 0, new_level_nr);
          }
 
-         game_status = GAME_MODE_MAIN;
+         SetGameStatus(GAME_MODE_MAIN);
 
          DrawMainMenu();
        }
@@ -4065,6 +4076,8 @@ static void HandleChooseTree(int mx, int my, int dx, int dy, int button,
 
 void DrawChooseLevelSet()
 {
+  FadeSoundsAndMusic();
+
   SetMainBackgroundImage(IMG_BACKGROUND_LEVELS);
 
   DrawChooseTree(&leveldir_current);
@@ -4082,6 +4095,8 @@ void DrawChooseLevelNr()
 {
   int i;
 
+  FadeSoundsAndMusic();
+
   if (level_number != NULL)
   {
     freeTreeInfo(level_number);
@@ -4143,9 +4158,6 @@ void DrawHallOfFame(int highlight_position)
 {
   int fade_mask = REDRAW_FIELD;
 
-  /* required before door position may be changed in next step */
-  CloseDoor(DOOR_CLOSE_ALL);
-
   /* needed if different viewport properties defined for scores */
   ChangeViewportPropertiesIfNeeded();
 
@@ -4270,7 +4282,7 @@ void HandleHallOfFame(int mx, int my, int dx, int dy, int button)
 
     FadeSound(SND_BACKGROUND_SCORES);
 
-    game_status = GAME_MODE_MAIN;
+    SetGameStatus(GAME_MODE_MAIN);
 
     DrawMainMenu();
   }
@@ -4280,7 +4292,7 @@ void HandleHallOfFame(int mx, int my, int dx, int dy, int button)
 
     FadeSound(SND_BACKGROUND_SCORES);
 
-    game_status = GAME_MODE_MAIN;
+    SetGameStatus(GAME_MODE_MAIN);
 
     DrawMainMenu();
   }
@@ -4298,9 +4310,9 @@ static struct TokenInfo *setup_info;
 static int num_setup_info;     /* number of setup entries shown on screen */
 static int max_setup_info;     /* total number of setup entries in list */
 
-static char *screen_mode_text;
 static char *window_size_text;
 static char *scaling_type_text;
+static char *rendering_mode_text;
 static char *scroll_delay_text;
 static char *snapshot_mode_text;
 static char *game_speed_text;
@@ -4393,31 +4405,31 @@ static void execSetupGame_setScrollDelays()
       setString(&ti->identifier, identifier);
       setString(&ti->name, name);
       setString(&ti->name_sorting, name);
-      setString(&ti->infotext, "Scaling Type");
+      setString(&ti->infotext, "Scroll Delay");
 
       pushTreeInfo(&scroll_delays, ti);
     }
 
-    /* sort scaling type values to start with lowest scaling type value */
+    /* sort scroll delay values to start with lowest scroll delay value */
     sortTreeInfo(&scroll_delays);
 
-    /* set current scaling type value to configured scaling type value */
+    /* set current scroll delay value to configured scroll delay value */
     scroll_delay_current =
       getTreeInfoFromIdentifier(scroll_delays,i_to_a(setup.scroll_delay_value));
 
-    /* if that fails, set current scaling type to reliable default value */
+    /* if that fails, set current scroll delay to reliable default value */
     if (scroll_delay_current == NULL)
       scroll_delay_current =
        getTreeInfoFromIdentifier(scroll_delays, i_to_a(STD_SCROLL_DELAY));
 
-    /* if that also fails, set current scaling type to first available value */
+    /* if that also fails, set current scroll delay to first available value */
     if (scroll_delay_current == NULL)
       scroll_delay_current = scroll_delays;
   }
 
   setup.scroll_delay_value = atoi(scroll_delay_current->identifier);
 
-  /* needed for displaying scaling type text instead of identifier */
+  /* needed for displaying scroll delay text instead of identifier */
   scroll_delay_text = scroll_delay_current->name;
 }
 
@@ -4645,65 +4657,55 @@ static void execSetupGraphics_setScalingTypes()
   scaling_type_text = scaling_type_current->name;
 }
 
-static void execSetupGraphics_setScreenModes()
+static void execSetupGraphics_setRenderingModes()
 {
-  // if (screen_modes == NULL && video.fullscreen_available)
-  if (screen_modes == NULL && video.fullscreen_modes != NULL)
+  if (rendering_modes == NULL)
   {
     int i;
 
-    for (i = 0; video.fullscreen_modes[i].width != -1; i++)
+    for (i = 0; rendering_modes_list[i].value != NULL; i++)
     {
       TreeInfo *ti = newTreeInfo_setDefaults(TREE_TYPE_UNDEFINED);
       char identifier[32], name[32];
-      int x = video.fullscreen_modes[i].width;
-      int y = video.fullscreen_modes[i].height;
-      int xx, yy;
+      char *value = rendering_modes_list[i].value;
+      char *text = rendering_modes_list[i].text;
 
-      get_aspect_ratio_from_screen_mode(&video.fullscreen_modes[i], &xx, &yy);
-
-      ti->node_top = &screen_modes;
-      ti->sort_priority = x * 10000 + y;
+      ti->node_top = &rendering_modes;
+      ti->sort_priority = i;
 
-      sprintf(identifier, "%dx%d", x, y);
-      sprintf(name, "%d x %d [%d:%d]", x, y, xx, yy);
+      sprintf(identifier, "%s", value);
+      sprintf(name, "%s", text);
 
       setString(&ti->identifier, identifier);
       setString(&ti->name, name);
       setString(&ti->name_sorting, name);
-      setString(&ti->infotext, "Fullscreen Mode");
+      setString(&ti->infotext, "Special Rendering");
 
-      pushTreeInfo(&screen_modes, ti);
+      pushTreeInfo(&rendering_modes, ti);
     }
 
-    /* sort fullscreen modes to start with lowest available screen resolution */
-    sortTreeInfo(&screen_modes);
+    /* sort rendering mode values to start with lowest rendering mode value */
+    sortTreeInfo(&rendering_modes);
 
-    /* set current screen mode for fullscreen mode to configured setup value */
-    screen_mode_current = getTreeInfoFromIdentifier(screen_modes,
-                                                   setup.fullscreen_mode);
+    /* set current rendering mode value to configured rendering mode value */
+    rendering_mode_current =
+      getTreeInfoFromIdentifier(rendering_modes, setup.screen_rendering_mode);
 
-    /* if that fails, set current screen mode to reliable default value */
-    if (screen_mode_current == NULL)
-      screen_mode_current = getTreeInfoFromIdentifier(screen_modes,
-                                                     DEFAULT_FULLSCREEN_MODE);
+    /* if that fails, set current rendering mode to reliable default value */
+    if (rendering_mode_current == NULL)
+      rendering_mode_current =
+       getTreeInfoFromIdentifier(rendering_modes,
+                                 STR_SPECIAL_RENDERING_DEFAULT);
 
-    /* if that also fails, set current screen mode to first available mode */
-    if (screen_mode_current == NULL)
-      screen_mode_current = screen_modes;
-
-    if (screen_mode_current == NULL)
-      video.fullscreen_available = FALSE;
+    /* if that also fails, set current rendering mode to first available one */
+    if (rendering_mode_current == NULL)
+      rendering_mode_current = rendering_modes;
   }
 
-  // if (video.fullscreen_available)
-  if (screen_mode_current != NULL)
-  {
-    setup.fullscreen_mode = screen_mode_current->identifier;
+  setup.screen_rendering_mode = rendering_mode_current->identifier;
 
-    /* needed for displaying screen mode name instead of identifier */
-    screen_mode_text = screen_mode_current->name;
-  }
+  /* needed for displaying rendering mode text instead of identifier */
+  rendering_mode_text = rendering_mode_current->name;
 }
 
 static void execSetupGraphics()
@@ -4720,7 +4722,7 @@ static void execSetupGraphics()
   }
 
   execSetupGraphics_setScalingTypes();
-  execSetupGraphics_setScreenModes();
+  execSetupGraphics_setRenderingModes();
 
   setup_mode = SETUP_MODE_GRAPHICS;
 
@@ -4733,11 +4735,13 @@ static void execSetupGraphics()
   // window scaling quality may have changed at this point
   if (!strEqual(setup.window_scaling_quality, video.window_scaling_quality))
     SDLSetWindowScalingQuality(setup.window_scaling_quality);
+
+  // screen rendering mode may have changed at this point
+  SDLSetScreenRenderingMode(setup.screen_rendering_mode);
 #endif
 }
 
-#if !defined(PLATFORM_ANDROID)
-#if defined(TARGET_SDL2)
+#if defined(TARGET_SDL2) && !defined(PLATFORM_ANDROID)
 static void execSetupChooseWindowSize()
 {
   setup_mode = SETUP_MODE_CHOOSE_WINDOW_SIZE;
@@ -4751,18 +4755,14 @@ static void execSetupChooseScalingType()
 
   DrawSetupScreen();
 }
-#else
-static void execSetupChooseScreenMode()
-{
-  if (!video.fullscreen_available)
-    return;
 
-  setup_mode = SETUP_MODE_CHOOSE_SCREEN_MODE;
+static void execSetupChooseRenderingMode()
+{
+  setup_mode = SETUP_MODE_CHOOSE_RENDERING;
 
   DrawSetupScreen();
 }
 #endif
-#endif
 
 static void execSetupChooseVolumeSimple()
 {
@@ -5270,7 +5270,7 @@ static void execSetupShortcuts5()
 
 static void execExitSetup()
 {
-  game_status = GAME_MODE_MAIN;
+  SetGameStatus(GAME_MODE_MAIN);
 
   DrawMainMenu();
 }
@@ -5360,17 +5360,14 @@ static struct TokenInfo setup_info_editor[] =
 
 static struct TokenInfo setup_info_graphics[] =
 {
-#if !defined(PLATFORM_ANDROID)
+#if defined(TARGET_SDL2) && !defined(PLATFORM_ANDROID)
   { TYPE_SWITCH,       &setup.fullscreen,      "Fullscreen:"           },
-#if defined(TARGET_SDL2)
   { TYPE_ENTER_LIST,   execSetupChooseWindowSize, "Window Scaling:"    },
   { TYPE_STRING,       &window_size_text,      ""                      },
   { TYPE_ENTER_LIST,   execSetupChooseScalingType, "Anti-Aliasing:"    },
   { TYPE_STRING,       &scaling_type_text,     ""                      },
-#else
-  { TYPE_ENTER_LIST,   execSetupChooseScreenMode, "Fullscreen Mode:"   },
-  { TYPE_STRING,       &screen_mode_text,      ""                      },
-#endif
+  { TYPE_ENTER_LIST,   execSetupChooseRenderingMode, "Special Rendering:" },
+  { TYPE_STRING,       &rendering_mode_text,   ""                      },
 #endif
 #if 0
   { TYPE_ENTER_LIST,   execSetupChooseScrollDelay, "Scroll Delay:"     },
@@ -5380,7 +5377,7 @@ static struct TokenInfo setup_info_graphics[] =
   { TYPE_SWITCH,       &setup.quick_switch,    "Quick Player Focus Switch:" },
   { TYPE_SWITCH,       &setup.quick_doors,     "Quick Menu Doors:"     },
   { TYPE_SWITCH,       &setup.show_titlescreen,"Show Title Screens:"   },
-  { TYPE_SWITCH,       &setup.toons,           "Show Toons:"           },
+  { TYPE_SWITCH,       &setup.toons,           "Show Menu Animations:" },
   { TYPE_ECS_AGA,      &setup.prefer_aga_graphics,"EMC graphics preference:" },
   { TYPE_SWITCH, &setup.sp_show_border_elements,"Supaplex Border Elements:" },
   { TYPE_SWITCH,       &setup.small_game_graphics, "Small Game Graphics:" },
@@ -5599,8 +5596,7 @@ static Key getSetupKey()
     DoAnimation();
     BackToFront();
 
-    /* don't eat all CPU time */
-    Delay(10);
+    WaitUntilDelayReached(&sync_frame_delay, sync_frame_delay_value);
   }
 
   return key;
@@ -5623,13 +5619,22 @@ static int getSetupValueFont(int type, void *value)
     return FONT_VALUE_1;
 }
 
+static int getSetupValueFontNarrow(int type, int font_nr)
+{
+  return (font_nr == FONT_VALUE_1    ? FONT_VALUE_NARROW :
+         font_nr == FONT_OPTION_ON  ? FONT_OPTION_ON_NARROW :
+         font_nr == FONT_OPTION_OFF ? FONT_OPTION_OFF_NARROW :
+         font_nr);
+}
+
 static void drawSetupValue(int screen_pos, int setup_info_pos_raw)
 {
   int si_pos = (setup_info_pos_raw < 0 ? screen_pos : setup_info_pos_raw);
   struct TokenInfo *si = &setup_info[si_pos];
   boolean font_draw_xoffset_modified = FALSE;
+  boolean scrollbar_needed = (num_setup_info < max_setup_info);
   int font_draw_xoffset_old = -1;
-  int xoffset = (num_setup_info < max_setup_info ? -1 : 0);
+  int xoffset = (scrollbar_needed ? -1 : 0);
   int menu_screen_value_xpos = MENU_SCREEN_VALUE_XPOS + xoffset;
   int menu_screen_max_xpos = MENU_SCREEN_MAX_XPOS + xoffset;
   int xpos = menu_screen_value_xpos;
@@ -5671,6 +5676,26 @@ static void drawSetupValue(int screen_pos, int setup_info_pos_raw)
   font_nr = getSetupValueFont(type, value);
   font_width = getFontWidth(font_nr);
 
+  // special check if right-side setup values moved left due to scrollbar
+  if (scrollbar_needed && xpos > MENU_SCREEN_START_XPOS)
+  {
+    int max_menu_text_length = 26;     // maximum text length for classic menu
+    int font_xoffset = getFontBitmapInfo(font_nr)->draw_xoffset;
+    int text_startx = mSX + MENU_SCREEN_START_XPOS * 32;
+    int text_font_nr = getMenuTextFont(FONT_MENU_2);
+    int text_font_xoffset = getFontBitmapInfo(text_font_nr)->draw_xoffset;
+    int text_width = max_menu_text_length * getFontWidth(text_font_nr);
+
+    if (startx + font_xoffset < text_startx + text_width + text_font_xoffset)
+    {
+      xpos += 1;
+      startx = mSX + xpos * 32;
+
+      font_nr = getSetupValueFontNarrow(type, font_nr);
+      font_width = getFontWidth(font_nr);
+    }
+  }
+
   /* downward compatibility correction for Juergen Bonhagen's menu settings */
   if (setup_mode != SETUP_MODE_INPUT)
   {
@@ -5767,21 +5792,20 @@ static void DrawSetupScreen_Generic()
     fade_mask = REDRAW_ALL;
 
   UnmapAllGadgets();
+  FadeSoundsAndMusic();
 
   FreeScreenGadgets();
   CreateScreenGadgets();
 
-  CloseDoor(DOOR_CLOSE_2);
-
   if (redraw_mask & REDRAW_ALL)
     redraw_all = TRUE;
 
   FadeOut(fade_mask);
 
-  OpenDoor(GetDoorState() | DOOR_NO_DELAY | DOOR_FORCE_REDRAW);
-
   ClearField();
 
+  OpenDoor(GetDoorState() | DOOR_NO_DELAY | DOOR_FORCE_REDRAW);
+
   if (setup_mode == SETUP_MODE_MAIN)
   {
     setup_info = setup_info_main;
@@ -6287,8 +6311,7 @@ void CustomizeKeyboard(int player_nr)
     DoAnimation();
     BackToFront();
 
-    /* don't eat all CPU time */
-    Delay(10);
+    WaitUntilDelayReached(&sync_frame_delay, sync_frame_delay_value);
   }
 
   /* write new key bindings back to player setup */
@@ -6443,8 +6466,7 @@ static boolean CalibrateJoystickMain(int player_nr)
     DoAnimation();
     BackToFront();
 
-    /* don't eat all CPU time */
-    Delay(10);
+    WaitUntilDelayReached(&sync_frame_delay, sync_frame_delay_value);
   }
 
   /* calibrated center position (joystick should now be centered) */
@@ -6466,7 +6488,7 @@ static boolean CalibrateJoystickMain(int player_nr)
       NextEvent(&event);
       HandleOtherEvents(&event);
 
-      Delay(10);
+      WaitUntilDelayReached(&sync_frame_delay, sync_frame_delay_value);
     }
   }
 
@@ -6510,12 +6532,12 @@ void DrawSetupScreen()
     DrawChooseTree(&scroll_delay_current);
   else if (setup_mode == SETUP_MODE_CHOOSE_SNAPSHOT_MODE)
     DrawChooseTree(&snapshot_mode_current);
-  else if (setup_mode == SETUP_MODE_CHOOSE_SCREEN_MODE)
-    DrawChooseTree(&screen_mode_current);
   else if (setup_mode == SETUP_MODE_CHOOSE_WINDOW_SIZE)
     DrawChooseTree(&window_size_current);
   else if (setup_mode == SETUP_MODE_CHOOSE_SCALING_TYPE)
     DrawChooseTree(&scaling_type_current);
+  else if (setup_mode == SETUP_MODE_CHOOSE_RENDERING)
+    DrawChooseTree(&rendering_mode_current);
   else if (setup_mode == SETUP_MODE_CHOOSE_GRAPHICS)
     DrawChooseTree(&artwork.gfx_current);
   else if (setup_mode == SETUP_MODE_CHOOSE_SOUNDS)
@@ -6563,12 +6585,12 @@ void HandleSetupScreen(int mx, int my, int dx, int dy, int button)
     HandleChooseTree(mx, my, dx, dy, button, &scroll_delay_current);
   else if (setup_mode == SETUP_MODE_CHOOSE_SNAPSHOT_MODE)
     HandleChooseTree(mx, my, dx, dy, button, &snapshot_mode_current);
-  else if (setup_mode == SETUP_MODE_CHOOSE_SCREEN_MODE)
-    HandleChooseTree(mx, my, dx, dy, button, &screen_mode_current);
   else if (setup_mode == SETUP_MODE_CHOOSE_WINDOW_SIZE)
     HandleChooseTree(mx, my, dx, dy, button, &window_size_current);
   else if (setup_mode == SETUP_MODE_CHOOSE_SCALING_TYPE)
     HandleChooseTree(mx, my, dx, dy, button, &scaling_type_current);
+  else if (setup_mode == SETUP_MODE_CHOOSE_RENDERING)
+    HandleChooseTree(mx, my, dx, dy, button, &rendering_mode_current);
   else if (setup_mode == SETUP_MODE_CHOOSE_GRAPHICS)
     HandleChooseTree(mx, my, dx, dy, button, &artwork.gfx_current);
   else if (setup_mode == SETUP_MODE_CHOOSE_SOUNDS)
@@ -6917,14 +6939,10 @@ static void CreateScreenScrollbars()
 
 void CreateScreenGadgets()
 {
-  int last_game_status = game_status;  /* save current game status */
-
   CreateScreenMenubuttons();
 
   CreateScreenScrollbuttons();
   CreateScreenScrollbars();
-
-  game_status = last_game_status;      /* restore current game status */
 }
 
 void FreeScreenGadgets()
index 4d8222e023cf196310b65e0a25d3fba33b84814c..8610e5103476b976aa2731326f38226e22fb99a8 100644 (file)
@@ -24,7 +24,8 @@
 
 
 /* select level set with EMC X11 graphics before activating EM GFX debugging */
-#define DEBUG_EM_GFX   0
+#define DEBUG_EM_GFX           FALSE
+#define DEBUG_FRAME_TIME       FALSE
 
 /* tool button identifiers */
 #define TOOL_CTRL_ID_YES       0
@@ -173,6 +174,9 @@ static int el_act2crm(int, int);
 static struct GadgetInfo *tool_gadget[NUM_TOOL_BUTTONS];
 static int request_gadget_id = -1;
 
+static unsigned int sync_frame_delay = 0;
+static unsigned int sync_frame_delay_value = GAME_FRAME_DELAY;
+
 static char *print_if_not_empty(int element)
 {
   static char *s = NULL;
@@ -284,68 +288,126 @@ void RedrawPlayfield()
             gfx.sx, gfx.sy);
 }
 
-void DrawMaskedBorder_Rect(int x, int y, int width, int height)
+static void DrawMaskedBorderExt_Rect(int x, int y, int width, int height,
+                                    int draw_target)
 {
-  Bitmap *bitmap = getGlobalBorderBitmapFromGameStatus();
+  Bitmap *src_bitmap = getGlobalBorderBitmapFromStatus(global.border_status);
+  Bitmap *dst_bitmap = gfx.masked_border_bitmap_ptr;
+
+  if (x == -1 && y == -1)
+    return;
 
-  BlitBitmapMasked(bitmap, backbuffer, x, y, width, height, x, y);
+  if (draw_target == DRAW_BORDER_TO_SCREEN)
+    BlitToScreenMasked(src_bitmap, x, y, width, height, x, y);
+  else
+    BlitBitmapMasked(src_bitmap, dst_bitmap, x, y, width, height, x, y);
 }
 
-void DrawMaskedBorder_FIELD()
+static void DrawMaskedBorderExt_FIELD(int draw_target)
 {
-  if (global.border_status >= GAME_MODE_TITLE &&
+  if (global.border_status >= GAME_MODE_MAIN &&
       global.border_status <= GAME_MODE_PLAYING &&
       border.draw_masked[global.border_status])
-    DrawMaskedBorder_Rect(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
+    DrawMaskedBorderExt_Rect(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
+                            draw_target);
 }
 
-void DrawMaskedBorder_DOOR_1()
+static void DrawMaskedBorderExt_DOOR_1(int draw_target)
 {
+  // when drawing to backbuffer, never draw border over open doors
+  if (draw_target == DRAW_BORDER_TO_BACKBUFFER &&
+      (GetDoorState() & DOOR_OPEN_1))
+    return;
+
   if (border.draw_masked[GFX_SPECIAL_ARG_DOOR] &&
       (global.border_status != GAME_MODE_EDITOR ||
        border.draw_masked[GFX_SPECIAL_ARG_EDITOR]))
-    DrawMaskedBorder_Rect(DX, DY, DXSIZE, DYSIZE);
+    DrawMaskedBorderExt_Rect(DX, DY, DXSIZE, DYSIZE, draw_target);
 }
 
-void DrawMaskedBorder_DOOR_2()
+static void DrawMaskedBorderExt_DOOR_2(int draw_target)
 {
+  // when drawing to backbuffer, never draw border over open doors
+  if (draw_target == DRAW_BORDER_TO_BACKBUFFER &&
+      (GetDoorState() & DOOR_OPEN_2))
+    return;
+
   if (border.draw_masked[GFX_SPECIAL_ARG_DOOR] &&
       global.border_status != GAME_MODE_EDITOR)
-    DrawMaskedBorder_Rect(VX, VY, VXSIZE, VYSIZE);
+    DrawMaskedBorderExt_Rect(VX, VY, VXSIZE, VYSIZE, draw_target);
 }
 
-void DrawMaskedBorder_DOOR_3()
+static void DrawMaskedBorderExt_DOOR_3(int draw_target)
 {
   /* currently not available */
 }
 
-void DrawMaskedBorder_ALL()
+static void DrawMaskedBorderExt_ALL(int draw_target)
 {
-  DrawMaskedBorder_FIELD();
-  DrawMaskedBorder_DOOR_1();
-  DrawMaskedBorder_DOOR_2();
-  DrawMaskedBorder_DOOR_3();
+  DrawMaskedBorderExt_FIELD(draw_target);
+  DrawMaskedBorderExt_DOOR_1(draw_target);
+  DrawMaskedBorderExt_DOOR_2(draw_target);
+  DrawMaskedBorderExt_DOOR_3(draw_target);
 }
 
-void DrawMaskedBorder(int redraw_mask)
+static void DrawMaskedBorderExt(int redraw_mask, int draw_target)
 {
   /* never draw masked screen borders on borderless screens */
-  if (game_status == GAME_MODE_LOADING ||
-      game_status == GAME_MODE_TITLE)
+  if (global.border_status == GAME_MODE_LOADING ||
+      global.border_status == GAME_MODE_TITLE)
     return;
 
   if (redraw_mask & REDRAW_ALL)
-    DrawMaskedBorder_ALL();
+    DrawMaskedBorderExt_ALL(draw_target);
   else
   {
     if (redraw_mask & REDRAW_FIELD)
-      DrawMaskedBorder_FIELD();
+      DrawMaskedBorderExt_FIELD(draw_target);
     if (redraw_mask & REDRAW_DOOR_1)
-      DrawMaskedBorder_DOOR_1();
+      DrawMaskedBorderExt_DOOR_1(draw_target);
     if (redraw_mask & REDRAW_DOOR_2)
-      DrawMaskedBorder_DOOR_2();
+      DrawMaskedBorderExt_DOOR_2(draw_target);
     if (redraw_mask & REDRAW_DOOR_3)
-      DrawMaskedBorder_DOOR_3();
+      DrawMaskedBorderExt_DOOR_3(draw_target);
+  }
+}
+
+void DrawMaskedBorder_FIELD()
+{
+  DrawMaskedBorderExt_FIELD(DRAW_BORDER_TO_BACKBUFFER);
+}
+
+void DrawMaskedBorder(int redraw_mask)
+{
+  DrawMaskedBorderExt(redraw_mask, DRAW_BORDER_TO_BACKBUFFER);
+}
+
+void DrawMaskedBorderToTarget(int draw_target)
+{
+  if (draw_target == DRAW_BORDER_TO_BACKBUFFER ||
+      draw_target == DRAW_BORDER_TO_SCREEN)
+  {
+    DrawMaskedBorderExt(REDRAW_ALL, draw_target);
+  }
+  else
+  {
+    int last_border_status = global.border_status;
+
+    if (draw_target == DRAW_BORDER_TO_FADE_SOURCE)
+    {
+      global.border_status = gfx.fade_border_source_status;
+      gfx.masked_border_bitmap_ptr = gfx.fade_bitmap_source;
+    }
+    else if (draw_target == DRAW_BORDER_TO_FADE_TARGET)
+    {
+      global.border_status = gfx.fade_border_target_status;
+      gfx.masked_border_bitmap_ptr = gfx.fade_bitmap_target;
+    }
+
+    DrawMaskedBorderExt(REDRAW_ALL, draw_target);
+
+    global.border_status = last_border_status;
+    gfx.masked_border_bitmap_ptr = backbuffer;
   }
 }
 
@@ -431,13 +493,61 @@ void DrawFramesPerSecond()
              font_nr, BLIT_OPAQUE);
 }
 
+#if DEBUG_FRAME_TIME
+static void PrintFrameTimeDebugging()
+{
+  static unsigned int last_counter = 0;
+  unsigned int counter = Counter();
+  int diff_1 = counter - last_counter;
+  int diff_2 = diff_1 - GAME_FRAME_DELAY;
+  int diff_2_max = 20;
+  int diff_2_cut = MIN(ABS(diff_2), diff_2_max);
+  char diff_bar[2 * diff_2_max + 5];
+  int pos = 0;
+  int i;
+
+  diff_bar[pos++] = (diff_2 < -diff_2_max ? '<' : ' ');
+
+  for (i = 0; i < diff_2_max; i++)
+    diff_bar[pos++] = (diff_2 >= 0 ? ' ' :
+                      i >= diff_2_max - diff_2_cut ? '-' : ' ');
+
+  diff_bar[pos++] = '|';
+
+  for (i = 0; i < diff_2_max; i++)
+    diff_bar[pos++] = (diff_2 <= 0 ? ' ' : i < diff_2_cut ? '+' : ' ');
+
+  diff_bar[pos++] = (diff_2 > diff_2_max ? '>' : ' ');
+
+  diff_bar[pos++] = '\0';
+
+  Error(ERR_INFO, "%06d [%02d] [%c%02d] %s",
+       counter,
+       diff_1,
+       (diff_2 < 0 ? '-' : diff_2 > 0 ? '+' : ' '), ABS(diff_2),
+       diff_bar);
+
+  last_counter = counter;
+}
+#endif
+
 void BackToFront()
 {
+  static int last_redraw_mask = REDRAW_NONE;
+
+  // force screen redraw in every frame to continue drawing global animations
+  // (but always use the last redraw mask to prevent unwanted side effects)
   if (redraw_mask == REDRAW_NONE)
-    return;
+    redraw_mask = last_redraw_mask;
+
+  last_redraw_mask = redraw_mask;
 
+#if 1
+  // masked border now drawn immediately when blitting backbuffer to window
+#else
   // draw masked border to all viewports, if defined
   DrawMaskedBorder(redraw_mask);
+#endif
 
   // draw frames per second (only if debug mode is enabled)
   if (redraw_mask & REDRAW_FPS)
@@ -474,6 +584,10 @@ void BackToFront()
   }
 
   redraw_mask = REDRAW_NONE;
+
+#if DEBUG_FRAME_TIME
+  PrintFrameTimeDebugging();
+#endif
 }
 
 static void FadeCrossSaveBackbuffer()
@@ -593,8 +707,43 @@ static void FadeExt(int fade_mask, int fade_mode, int fade_type)
   redraw_mask &= ~fade_mask;
 }
 
+static void SetScreenStates_BeforeFadingIn()
+{
+}
+
+static void SetScreenStates_AfterFadingIn()
+{
+  // store new source screen (to use correct masked border for fading)
+  gfx.fade_border_source_status = global.border_status;
+
+  global.anim_status = global.anim_status_next;
+
+  // force update of global animation status in case of rapid screen changes
+  redraw_mask = REDRAW_ALL;
+  BackToFront();
+}
+
+static void SetScreenStates_BeforeFadingOut()
+{
+  // store new target screen (to use correct masked border for fading)
+  gfx.fade_border_target_status = game_status;
+
+  global.anim_status = GAME_MODE_PSEUDO_FADING;
+}
+
+static void SetScreenStates_AfterFadingOut()
+{
+  global.border_status = game_status;
+}
+
 void FadeIn(int fade_mask)
 {
+  SetScreenStates_BeforeFadingIn();
+
+#if 1
+  DrawMaskedBorder(REDRAW_ALL);
+#endif
+
   if (fading.fade_mode & FADE_TYPE_TRANSFORM)
     FadeExt(fade_mask, fading.fade_mode, FADE_TYPE_FADE_IN);
   else
@@ -604,16 +753,24 @@ void FadeIn(int fade_mask)
   FADE_SY = REAL_SY;
   FADE_SXSIZE = FULL_SXSIZE;
   FADE_SYSIZE = FULL_SYSIZE;
+
+  SetScreenStates_AfterFadingIn();
 }
 
 void FadeOut(int fade_mask)
 {
+  SetScreenStates_BeforeFadingOut();
+
+#if 0
+  DrawMaskedBorder(REDRAW_ALL);
+#endif
+
   if (fading.fade_mode & FADE_TYPE_TRANSFORM)
     FadeExt(fade_mask, fading.fade_mode, FADE_TYPE_FADE_OUT);
   else
     FadeExt(fade_mask, FADE_MODE_FADE_OUT, FADE_TYPE_FADE_OUT);
 
-  global.border_status = game_status;
+  SetScreenStates_AfterFadingOut();
 }
 
 static void FadeSetLeaveNext(struct TitleFadingInfo fading_leave, boolean set)
@@ -707,14 +864,14 @@ Bitmap *getGlobalBorderBitmap(int graphic)
   return getBitmapFromGraphicOrDefault(graphic, IMG_GLOBAL_BORDER);
 }
 
-Bitmap *getGlobalBorderBitmapFromGameStatus()
+Bitmap *getGlobalBorderBitmapFromStatus(int status)
 {
   int graphic =
-    (game_status == GAME_MODE_MAIN ||
-     game_status == GAME_MODE_PSEUDO_TYPENAME  ? IMG_GLOBAL_BORDER_MAIN :
-     game_status == GAME_MODE_SCORES           ? IMG_GLOBAL_BORDER_SCORES :
-     game_status == GAME_MODE_EDITOR           ? IMG_GLOBAL_BORDER_EDITOR :
-     game_status == GAME_MODE_PLAYING          ? IMG_GLOBAL_BORDER_PLAYING :
+    (status == GAME_MODE_MAIN ||
+     status == GAME_MODE_PSEUDO_TYPENAME       ? IMG_GLOBAL_BORDER_MAIN :
+     status == GAME_MODE_SCORES                        ? IMG_GLOBAL_BORDER_SCORES :
+     status == GAME_MODE_EDITOR                        ? IMG_GLOBAL_BORDER_EDITOR :
+     status == GAME_MODE_PLAYING               ? IMG_GLOBAL_BORDER_PLAYING :
      IMG_GLOBAL_BORDER);
 
   return getGlobalBorderBitmap(graphic);
@@ -815,7 +972,7 @@ boolean CheckIfGlobalBorderHasChanged()
     return FALSE;
 
   // determine and store new global border bitmap for current game status
-  global_border_bitmap = getGlobalBorderBitmapFromGameStatus();
+  global_border_bitmap = getGlobalBorderBitmapFromStatus(game_status);
 
   return (global_border_bitmap_last != global_border_bitmap);
 }
@@ -862,7 +1019,7 @@ void RedrawGlobalBorderFromBitmap(Bitmap *bitmap)
 
 void RedrawGlobalBorder()
 {
-  Bitmap *bitmap = getGlobalBorderBitmapFromGameStatus();
+  Bitmap *bitmap = getGlobalBorderBitmapFromStatus(game_status);
 
   RedrawGlobalBorderFromBitmap(bitmap);
 
@@ -2271,7 +2428,6 @@ static void setRequestPosition(int *x, int *y, boolean add_border_size)
 
 void DrawEnvelopeRequest(char *text)
 {
-  int last_game_status = game_status;  /* save current game status */
   char *text_final = text;
   char *text_door_style = NULL;
   int graphic = IMG_BACKGROUND_REQUEST;
@@ -2339,13 +2495,13 @@ void DrawEnvelopeRequest(char *text)
                                  tile_size, tile_size);
 
   /* force DOOR font inside door area */
-  game_status = GAME_MODE_PSEUDO_DOOR;
+  SetFontStatus(GAME_MODE_PSEUDO_DOOR);
 
   DrawTextBuffer(sx + sx_offset, sy + sy_offset, text_final, font_nr,
                 line_length, -1, max_lines, line_spacing, mask_mode,
                 request.autowrap, request.centered, FALSE);
 
-  game_status = last_game_status;      /* restore current game status */
+  ResetFontStatus();
 
   for (i = 0; i < NUM_TOOL_BUTTONS; i++)
     RedrawGadget(tool_gadget[i]);
@@ -2704,7 +2860,6 @@ static void DrawPreviewLevelExt(boolean restart)
   boolean show_level_border = (BorderElement != EL_EMPTY);
   int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
   int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
-  int last_game_status = game_status;          /* save current game status */
 
   if (restart)
   {
@@ -2750,8 +2905,6 @@ static void DrawPreviewLevelExt(boolean restart)
        DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
     }
 
-    game_status = last_game_status;    /* restore current game status */
-
     return;
   }
 
@@ -2851,8 +3004,6 @@ static void DrawPreviewLevelExt(boolean restart)
 
     DrawPreviewLevelLabelExt(label_state);
   }
-
-  game_status = last_game_status;      /* restore current game status */
 }
 
 void DrawPreviewLevelInitial()
@@ -3396,8 +3547,7 @@ void WaitForEventToContinue()
 
     DoAnimation();
 
-    /* don't eat all CPU time */
-    Delay(10);
+    WaitUntilDelayReached(&sync_frame_delay, sync_frame_delay_value);
   }
 }
 
@@ -3568,12 +3718,11 @@ static int RequestHandleEvents(unsigned int req_state)
     else
     {
       DoAnimation();
-
-      if (!PendingEvent())     /* delay only if no pending events */
-       Delay(10);
     }
 
     BackToFront();
+
+    WaitUntilDelayReached(&sync_frame_delay, sync_frame_delay_value);
   }
 
   return result;
@@ -3582,7 +3731,6 @@ static int RequestHandleEvents(unsigned int req_state)
 static boolean RequestDoor(char *text, unsigned int req_state)
 {
   unsigned int old_door_state;
-  int last_game_status = game_status;  /* save current game status */
   int max_request_line_len = MAX_REQUEST_LINE_FONT1_LEN;
   int font_nr = FONT_TEXT_2;
   char *text_ptr;
@@ -3639,7 +3787,7 @@ static boolean RequestDoor(char *text, unsigned int req_state)
   DrawBackground(DX, DY, DXSIZE, DYSIZE);
 
   /* force DOOR font inside door area */
-  game_status = GAME_MODE_PSEUDO_DOOR;
+  SetFontStatus(GAME_MODE_PSEUDO_DOOR);
 
   /* write text for request */
   for (text_ptr = text, ty = 0; ty < MAX_REQUEST_LINES; ty++)
@@ -3679,7 +3827,7 @@ static boolean RequestDoor(char *text, unsigned int req_state)
     // text_ptr += tl + (tc == ' ' || tc == '?' || tc == '!' ? 1 : 0);
   }
 
-  game_status = last_game_status;      /* restore current game status */
+  ResetFontStatus();
 
   if (req_state & REQ_ASK)
   {
@@ -4123,7 +4271,7 @@ unsigned int MoveDoor(unsigned int door_state)
     { DX, DY, DXSIZE, DYSIZE },
     { VX, VY, VXSIZE, VYSIZE }
   };
-  static int door1 = DOOR_OPEN_1;
+  static int door1 = DOOR_CLOSE_1;
   static int door2 = DOOR_CLOSE_2;
   unsigned int door_delay = 0;
   unsigned int door_delay_value;
@@ -4437,6 +4585,10 @@ unsigned int MoveDoor(unsigned int door_state)
   if (door_state & DOOR_ACTION_2)
     door2 = door_state & DOOR_ACTION_2;
 
+  // draw masked border over door area
+  DrawMaskedBorder(REDRAW_DOOR_1);
+  DrawMaskedBorder(REDRAW_DOOR_2);
+
   return (door1 | door2);
 }
 
@@ -8052,9 +8204,6 @@ void ToggleFullscreenOrChangeWindowScalingIfNeeded()
 {
   boolean change_fullscreen = (setup.fullscreen !=
                               video.fullscreen_enabled);
-  boolean change_fullscreen_mode = (video.fullscreen_enabled &&
-                                   !strEqual(setup.fullscreen_mode,
-                                             video.fullscreen_mode_current));
   boolean change_window_scaling_percent = (!video.fullscreen_enabled &&
                                           setup.window_scaling_percent !=
                                           video.window_scaling_percent);
@@ -8084,7 +8233,6 @@ void ToggleFullscreenOrChangeWindowScalingIfNeeded()
 #endif
 
   if (change_fullscreen ||
-      change_fullscreen_mode ||
       change_window_scaling_percent)
   {
     Bitmap *tmp_backbuffer = CreateBitmap(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
@@ -8092,12 +8240,6 @@ void ToggleFullscreenOrChangeWindowScalingIfNeeded()
     /* save backbuffer content which gets lost when toggling fullscreen mode */
     BlitBitmap(backbuffer, tmp_backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
 
-    if (change_fullscreen_mode)
-    {
-      /* keep fullscreen, but change fullscreen mode (screen resolution) */
-      video.fullscreen_enabled = FALSE;                /* force new fullscreen mode */
-    }
-
     if (change_window_scaling_percent)
     {
       /* keep window mode, but change window scaling */
@@ -8133,6 +8275,50 @@ void JoinRectangles(int *x, int *y, int *width, int *height,
   *height = MAX(*height, height2);
 }
 
+void SetAnimStatus(int anim_status_new)
+{
+  if (anim_status_new == GAME_MODE_MAIN)
+    anim_status_new = GAME_MODE_PSEUDO_MAINONLY;
+
+  global.anim_status_next = anim_status_new;
+
+  // directly set screen modes that are entered without fading
+  if ((global.anim_status      == GAME_MODE_PSEUDO_MAINONLY &&
+       global.anim_status_next == GAME_MODE_PSEUDO_TYPENAME) ||
+      (global.anim_status      == GAME_MODE_PSEUDO_TYPENAME &&
+       global.anim_status_next == GAME_MODE_PSEUDO_MAINONLY))
+    global.anim_status = global.anim_status_next;
+}
+
+void SetGameStatus(int game_status_new)
+{
+  game_status = game_status_new;
+
+  SetAnimStatus(game_status_new);
+}
+
+void SetFontStatus(int game_status_new)
+{
+  static int last_game_status = -1;
+
+  if (game_status_new != -1)
+  {
+    // set game status for font use after storing last game status
+    last_game_status = game_status;
+    game_status = game_status_new;
+  }
+  else
+  {
+    // reset game status after font use from last stored game status
+    game_status = last_game_status;
+  }
+}
+
+void ResetFontStatus()
+{
+  SetFontStatus(-1);
+}
+
 void ChangeViewportPropertiesIfNeeded()
 {
   int gfx_game_mode = game_status;
@@ -8188,6 +8374,7 @@ void ChangeViewportPropertiesIfNeeded()
 
     init_video_buffer = TRUE;
     init_gfx_buffers = TRUE;
+    init_gadgets_and_toons = TRUE;
 
     // printf("::: video: init_video_buffer, init_gfx_buffers\n");
   }
@@ -8329,6 +8516,7 @@ void ChangeViewportPropertiesIfNeeded()
     // printf("::: init_video_buffer\n");
 
     InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen);
+    InitImageTextures();
   }
 
   if (init_gadgets_and_toons)
@@ -8337,6 +8525,7 @@ void ChangeViewportPropertiesIfNeeded()
 
     InitGadgets();
     InitToons();
+    InitGlobalAnimations();
   }
 
   if (init_em_graphics)
index 1fc4b5dbb982e7ed2fa40c193009bdd3967ae96d..53a1af6569fcf590ab63bdadd45b248be9c978f6 100644 (file)
@@ -76,6 +76,7 @@ void DrawMaskedBorder_DOOR_2();
 void DrawMaskedBorder_DOOR_3();
 void DrawMaskedBorder_ALL();
 void DrawMaskedBorder(int);
+void DrawMaskedBorderToTarget(int);
 
 void SetDrawtoField(int);
 void RedrawPlayfield();
@@ -95,7 +96,7 @@ void FadeSetDisabled();
 void FadeSkipNextFadeIn();
 void FadeSkipNextFadeOut();
 
-Bitmap *getGlobalBorderBitmapFromGameStatus();
+Bitmap *getGlobalBorderBitmapFromStatus(int);
 
 void ClearField();
 void SetWindowBackgroundImageIfDefined(int);
@@ -248,6 +249,11 @@ void PlayMenuMusic();
 void PlaySoundActivating();
 void PlaySoundSelecting();
 
+void SetAnimStatus(int);
+void SetGameStatus(int);
+void SetFontStatus(int);
+void ResetFontStatus();
+
 void ToggleFullscreenOrChangeWindowScalingIfNeeded();
 void ChangeViewportPropertiesIfNeeded();