Merge branch 'master' into global-anims
authorHolger Schemel <info@artsoft.org>
Tue, 1 Mar 2016 23:56:08 +0000 (00:56 +0100)
committerHolger Schemel <info@artsoft.org>
Tue, 1 Mar 2016 23:56:08 +0000 (00:56 +0100)
21 files changed:
src/cartoons.c
src/cartoons.h
src/conf_gfx.c
src/events.c
src/init.c
src/init.h
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/system.c
src/libgame/system.h
src/libgame/toons.c
src/libgame/toons.h
src/main.c
src/main.h
src/screens.c
src/tools.c
src/tools.h

index a0115cf..0048d4b 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_MENU            0
+#define ANIM_CLASS_BIT_TOONS           1
+
+#define NUM_ANIM_CLASSES               2
+
+#define ANIM_CLASS_NONE                        0
+#define ANIM_CLASS_MENU                        (1 << ANIM_CLASS_BIT_MENU)
+#define ANIM_CLASS_TOONS               (1 << ANIM_CLASS_BIT_TOONS)
+
+
+struct GlobalAnimPartControlInfo
+{
+  int nr;
+  int anim_nr;
+  int mode_nr;
+
+  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_game_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;
+};
+
+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_MAIN,            ANIM_CLASS_TOONS | ANIM_CLASS_MENU      },
+  { GAME_MODE_LEVELS,          ANIM_CLASS_TOONS | ANIM_CLASS_MENU      },
+  { GAME_MODE_LEVELNR,         ANIM_CLASS_TOONS | ANIM_CLASS_MENU      },
+  { GAME_MODE_INFO,            ANIM_CLASS_TOONS | ANIM_CLASS_MENU      },
+  { GAME_MODE_SETUP,           ANIM_CLASS_TOONS | ANIM_CLASS_MENU      },
+  { GAME_MODE_SCORES,          ANIM_CLASS_TOONS                        },
+
+  { -1,                                -1                                      }
+};
+
+struct AnimClassGameMode
+{
+  int class_bit;
+  int game_mode;
+} anim_class_game_modes_list[] =
+{
+  { 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 game_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 void PrepareBackbuffer()
 {
   if (game_status != GAME_MODE_PLAYING)
@@ -71,3 +209,737 @@ 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 graphic = IMG_TOON_1 + i;
+    int control = graphic;
+
+    part->nr = part_nr;
+    part->anim_nr = anim_nr;
+    part->mode_nr = mode_nr;
+    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_game_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 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];
+
+       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
+
+       part->nr = part_nr;
+       part->anim_nr = anim_nr;
+       part->mode_nr = mode_nr;
+       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_game_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();
+
+  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;
+
+  game_status_last = GAME_MODE_LOADING;
+  anim_classes_last = ANIM_CLASS_NONE;
+}
+
+void InitGlobalAnimations()
+{
+  InitGlobalAnimControls();
+}
+
+void DrawGlobalAnimExt(int drawing_stage)
+{
+  int anim_classes = game_mode_anim_classes[game_status];
+  int mode_nr;
+  int i;
+
+  // start or stop global animations by change of game mode
+  // (special handling of animations for "current screen" and "all screens")
+  if (game_status != game_status_last)
+  {
+    // stop animations for last screen
+    HandleGlobalAnim(ANIM_STOP, game_status_last);
+
+    // start animations for current screen
+    HandleGlobalAnim(ANIM_START, game_status);
+
+    // start animations for all screens after loading new artwork set
+    if (game_status_last == GAME_MODE_LOADING)
+      HandleGlobalAnim(ANIM_START, GAME_MODE_DEFAULT);
+
+    game_status_last = game_status;
+  }
+
+  // start or stop global animations by change of animation class
+  // (generic handling of animations for "class of screens")
+  if (anim_classes != anim_classes_last)
+  {
+    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      = anim_classes      & anim_class_check;
+
+      if (anim_class_last && !anim_class)
+       HandleGlobalAnim(ANIM_STOP, anim_class_game_mode);
+      else if (!anim_class_last && anim_class)
+       HandleGlobalAnim(ANIM_START, anim_class_game_mode);
+    }
+
+    anim_classes_last = anim_classes;
+  }
+
+  if (!setup.toons || game_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));
+
+       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_game_status == game_status)
+    return FALSE;
+
+  part->last_game_status = game_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;
+}
+
+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)
+  {
+    part->init_delay_counter--;
+
+    return ANIM_STATE_WAITING;
+  }
+
+  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))
+    return ANIM_STATE_RESTART;
+
+  if (part->anim_delay_counter > 0)
+  {
+    part->anim_delay_counter--;
+
+    if (part->anim_delay_counter == 0)
+    {
+      part->post_delay_counter =
+       (c->post_delay_fixed + GetSimpleRandom(c->post_delay_random));
+
+      if (part->post_delay_counter > 0)
+       return ANIM_STATE_RUNNING;
+
+      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;
+  boolean skip = FALSE;
+
+#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_STATE_RESTART;
+      anim->part_counter = 0;
+      anim->active_part_nr = 0;
+      skip = TRUE;
+
+      break;
+
+    case ANIM_CONTINUE:
+      if (anim->state == ANIM_STATE_INACTIVE)
+       skip = TRUE;
+
+      break;
+
+    case ANIM_STOP:
+      anim->state = ANIM_STATE_INACTIVE;
+      skip = TRUE;
+
+      break;
+
+    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;
+         skip = TRUE;
+
+         break;
+
+        case ANIM_CONTINUE:
+         if (part->state == ANIM_STATE_INACTIVE)
+           skip = TRUE;
+
+         break;
+
+        case ANIM_STOP:
+         part->state = ANIM_STATE_INACTIVE;
+         skip = TRUE;
+
+         break;
+
+        default:
+         break;
+      }
+
+      if (skip)
+       continue;
+
+      part->state = HandleGlobalAnim_Part(part, part->state);
+    }
+
+    return;
+  }
+
+  if (skip)
+    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++;
+}
+
+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 b3c2019..2b7680d 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 4766b3f..04db35a 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"                     },
index e82d366..952f899 100644 (file)
@@ -19,6 +19,7 @@
 #include "editor.h"
 #include "files.h"
 #include "tape.h"
+#include "cartoons.h"
 #include "network.h"
 
 
@@ -153,6 +154,9 @@ boolean NextValidEvent(Event *event)
 
 void EventLoop(void)
 {
+  static unsigned int sync_frame_delay = 0;
+  unsigned int sync_frame_delay_value = GAME_FRAME_DELAY;
+
   while (1)
   {
     if (PendingEvent())                /* got event */
@@ -246,18 +250,14 @@ void EventLoop(void)
        has its own synchronization and is CPU friendly, too */
 
     if (game_status == GAME_MODE_PLAYING)
-    {
       HandleGameActions();
-    }
-    else
-    {
-      if (!PendingEvent())     /* delay only if no pending events */
-       Delay(10);
-    }
 
     /* 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;
   }
index ca82088..e7cbd04 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,65 @@ 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 InitElementGraphicInfo()
 {
   struct PropertyMapping *property_mapping = getImageListPropertyMapping();
@@ -1042,6 +1130,8 @@ 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;
@@ -1247,7 +1337,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 +1351,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 +1368,9 @@ 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 */
+  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 +2039,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");
@@ -1951,6 +2059,7 @@ static void ReinitializeGraphics()
   InitGadgets();
   print_timestamp_time("InitGadgets");
   InitToons();
+  InitGlobalAnimations();
   print_timestamp_time("InitToons");
   InitDoors();
   print_timestamp_time("InitDoors");
@@ -4901,7 +5010,9 @@ 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 *image_id_prefix[MAX_NUM_ELEMENTS +
+                              NUM_FONTS +
+                              NUM_GLOBAL_ANIM_TOKENS + 1];
   static char *sound_id_prefix[2 * MAX_NUM_ELEMENTS + 1];
   static char *music_id_prefix[NUM_MUSIC_PREFIXES + 1];
   static char *action_id_suffix[NUM_ACTIONS + 1];
@@ -4962,7 +5073,10 @@ 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;
@@ -5205,7 +5319,10 @@ void InitGfx()
   init.busy.height = anim_initial.height;
 
   InitMenuDesignSettings_Static();
+
   InitGfxDrawBusyAnimFunction(DrawInitAnim);
+  InitGfxDrawGlobalAnimFunction(DrawGlobalAnim);
+  InitGfxDrawGlobalBorderFunction(DrawMaskedBorderToScreen);
 
   /* use copy of busy animation to prevent change while reloading artwork */
   init_last = init;
index 9c6185f..ab14b75 100644 (file)
@@ -43,6 +43,7 @@ void KeyboardAutoRepeatOffUnlessAutoplay();
 
 void InitGfxBuffers();
 void InitGadgets();
+void InitImageTextures();
 
 void DisplayExitMessage(char *, va_list);
 
index 7fc7e2b..76d9b18 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 db988c6..76ff350 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 7d5268c..c34cddd 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);
+  // switch from PNG to PCX file and vice versa, if file does not exist
+  // (backwards compatibility with PCX files used in previous versions)
 
-  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);
-
-    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)
@@ -2604,6 +2577,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 +2663,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,6 +2702,7 @@ 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, "reverse"))
@@ -2694,7 +2716,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"))
   {
@@ -3013,6 +3036,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 +3081,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 8c0e4f4..36e1dfc 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);
 
index 3ab0378..9b4e0cf 100644 (file)
@@ -54,6 +54,7 @@ static void UpdateScreen(SDL_Rect *rect)
 {
   static unsigned int update_screen_delay = 0;
   unsigned int update_screen_delay_value = 20;         /* (milliseconds) */
+  SDL_Surface *screen = backbuffer->surface;
 
   if (limit_screen_updates &&
       !DelayReached(&update_screen_delay, update_screen_delay_value))
@@ -78,10 +79,37 @@ static void UpdateScreen(SDL_Rect *rect)
   }
 #endif
 
+#if USE_FINAL_SCREEN_BITMAP
+  if (gfx.final_screen_bitmap != NULL) // may not be initialized yet
+  {
+    // !!! TEST !!!
+    // draw global animations using bitmaps instead of using textures
+    // to prevent texture scaling artefacts (this is potentially slower)
+
+    BlitBitmap(backbuffer, gfx.final_screen_bitmap, 0, 0,
+              gfx.win_xsize, gfx.win_ysize, 0, 0);
+
+    // copy global animations to render target buffer, if defined (below border)
+    if (gfx.draw_global_anim_function != NULL)
+      gfx.draw_global_anim_function(DRAW_GLOBAL_ANIM_STAGE_1);
+
+    // copy global masked border to render target buffer, if defined
+    if (gfx.draw_global_border_function != NULL)
+      gfx.draw_global_border_function(REDRAW_ALL);
+
+    // copy global animations to render target buffer, if defined (above border)
+    if (gfx.draw_global_anim_function != NULL)
+      gfx.draw_global_anim_function(DRAW_GLOBAL_ANIM_STAGE_2);
+
+    screen = gfx.final_screen_bitmap->surface;
+
+    // force full window redraw
+    rect = NULL;
+  }
+#endif
+
 #if defined(TARGET_SDL2)
 #if USE_RENDERER
-  SDL_Surface *screen = backbuffer->surface;
-
   if (rect)
   {
     int bytes_x = screen->pitch / video.width;
@@ -98,10 +126,32 @@ static void UpdateScreen(SDL_Rect *rect)
   {
     SDL_UpdateTexture(sdl_texture, NULL, screen->pixels, screen->pitch);
   }
+
+  // clear render target buffer
   SDL_RenderClear(sdl_renderer);
+
+  // copy backbuffer to render target buffer
   SDL_RenderCopy(sdl_renderer, sdl_texture, NULL, NULL);
+
+#if !USE_FINAL_SCREEN_BITMAP
+  // copy global animations to render target buffer, if defined (below border)
+  if (gfx.draw_global_anim_function != NULL)
+    gfx.draw_global_anim_function(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(REDRAW_ALL);
+
+  // copy global animations to render target buffer, if defined (above border)
+  if (gfx.draw_global_anim_function != NULL)
+    gfx.draw_global_anim_function(DRAW_GLOBAL_ANIM_STAGE_2);
+#endif
+
+  // show render target buffer on screen
   SDL_RenderPresent(sdl_renderer);
+
 #else
+
   if (rect)
     SDL_UpdateWindowSurfaceRects(sdl_window, rect, 1);
   else
@@ -110,9 +160,9 @@ static void UpdateScreen(SDL_Rect *rect)
 
 #else  // TARGET_SDL
   if (rect)
-    SDL_UpdateRects(backbuffer->surface, 1, rect);
+    SDL_UpdateRects(screen, 1, rect);
   else
-    SDL_UpdateRect(backbuffer->surface, 0, 0, 0, 0);
+    SDL_UpdateRect(screen, 0, 0, 0, 0);
 #endif
 }
 
@@ -286,6 +336,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)
@@ -871,8 +966,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,
@@ -926,6 +1032,37 @@ void SDLCopyArea(Bitmap *src_bitmap, Bitmap *dst_bitmap,
 #endif
 }
 
+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)
+#if USE_RENDERER
+  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
+#endif
+}
+
 void SDLFillRectangle(Bitmap *dst_bitmap, int x, int y, int width, int height,
                      Uint32 color)
 {
@@ -977,6 +1114,13 @@ 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;
 
+  // store function for drawing global masked border
+  void (*draw_global_border_function)(int) = gfx.draw_global_border_function;
+
+  // deactivate drawing of global border while fading, if needed
+  if (draw_border_function == NULL)
+    gfx.draw_global_border_function = NULL;
+
   /* check if screen size has changed */
   if (surface_source != NULL && (video.width  != surface_source->w ||
                                 video.height != surface_source->h))
@@ -1291,7 +1435,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,
index 79827b4..121b15b 100644 (file)
@@ -58,6 +58,8 @@
 #define FULLSCREEN_STATUS      FULLSCREEN_AVAILABLE
 #endif
 
+#define USE_FINAL_SCREEN_BITMAP        FALSE
+
 #define CURSOR_MAX_WIDTH       32
 #define CURSOR_MAX_HEIGHT      32
 
@@ -102,6 +104,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,6 +434,8 @@ 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 *);
@@ -446,6 +454,7 @@ boolean SDLSetVideoMode(DrawBuffer **, 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 b5e4f27..38ec0b5 100644 (file)
@@ -207,6 +207,9 @@ 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 USE_FINAL_SCREEN_BITMAP
+  ReCreateBitmap(&gfx.final_screen_bitmap, win_xsize, win_ysize, DEFAULT_DEPTH);
+#endif
 }
 
 void InitGfxScrollbufferInfo(int scrollbuffer_width, int scrollbuffer_height)
@@ -231,6 +234,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;
@@ -399,7 +412,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 +728,58 @@ 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 USE_FINAL_SCREEN_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);
+#endif
+}
+
+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 USE_FINAL_SCREEN_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);
+#endif
+}
+
 void DrawSimpleBlackLine(Bitmap *bitmap, int from_x, int from_y,
                         int to_x, int to_y)
 {
@@ -1125,6 +1190,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 fdda818..1fe8d9f 100644 (file)
 /* 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 move directions and special "button" key bitmasks */
 #define MV_NONE                        0
 #define MV_LEFT                        (1 << MV_BIT_LEFT)
 #define ANIM_VERTICAL          (1 << 11)
 #define ANIM_CENTERED          (1 << 12)
 #define ANIM_STATIC_PANEL      (1 << 13)
+#define ANIM_ALL               (1 << 14)
 
 #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)
@@ -792,6 +808,10 @@ struct GfxInfo
   Bitmap *background_bitmap;
   int background_bitmap_mask;
 
+#if USE_FINAL_SCREEN_BITMAP
+  Bitmap *final_screen_bitmap;
+#endif
+
   boolean clipping_enabled;
   int clip_x, clip_y;
   int clip_width, clip_height;
@@ -810,6 +830,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;
 };
@@ -1306,6 +1328,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 +1359,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 +1382,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 3868bdb..34fa8fb 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 5dc52d0..449687c 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 9659af0..7593e01 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() */
@@ -5481,6 +5489,10 @@ 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,               },
+  { ".TYPENAME",               GFX_SPECIAL_ARG_TYPENAME,               },
+  { ".MENU",                   GFX_SPECIAL_ARG_MENU,                   },
+  { ".TOONS",                  GFX_SPECIAL_ARG_TOONS,                  },
+  { ".QUIT",                   GFX_SPECIAL_ARG_QUIT,                   },
 
   /* empty suffix always matches -- check as last entry in InitMusicInfo() */
   { "",                                GFX_SPECIAL_ARG_DEFAULT,                },
@@ -5543,6 +5555,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                                            */
index 8b4948d..05c28b8 100644 (file)
 
 #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_PANEL          14
 #define GFX_SPECIAL_ARG_PREVIEW                15
 #define GFX_SPECIAL_ARG_CRUMBLED       16
+#define GFX_SPECIAL_ARG_TYPENAME       17
+#define GFX_SPECIAL_ARG_MENU           18
+#define GFX_SPECIAL_ARG_TOONS          19
+#define GFX_SPECIAL_ARG_QUIT           20
 
-#define NUM_SPECIAL_GFX_ARGS           17
+#define NUM_SPECIAL_GFX_ARGS           21
 
 /* 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 NUM_FONTS                      38
 #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_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_PSEUDO_MENU          18
+#define GAME_MODE_PSEUDO_TOONS         19
+#define GAME_MODE_QUIT                 20
+
+#define NUM_GAME_MODES                 21
 
 /* special definitions currently only used for custom artwork configuration */
 #define MUSIC_PREFIX_BACKGROUND                0
@@ -2743,6 +2786,14 @@ 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];
+};
+
 struct GraphicInfo
 {
   Bitmap **bitmaps;            /* bitmaps in all required sizes */
@@ -2778,18 +2829,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 +3076,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 c45e9ba..97feee6 100644 (file)
@@ -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;
@@ -5380,7 +5383,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 +5602,7 @@ static Key getSetupKey()
     DoAnimation();
     BackToFront();
 
-    /* don't eat all CPU time */
-    Delay(10);
+    WaitUntilDelayReached(&sync_frame_delay, sync_frame_delay_value);
   }
 
   return key;
@@ -6287,8 +6289,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 +6444,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 +6466,7 @@ static boolean CalibrateJoystickMain(int player_nr)
       NextEvent(&event);
       HandleOtherEvents(&event);
 
-      Delay(10);
+      WaitUntilDelayReached(&sync_frame_delay, sync_frame_delay_value);
     }
   }
 
index 4d8222e..17a5cf5 100644 (file)
@@ -173,6 +173,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,50 +287,63 @@ 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,
+                                    boolean blit_to_screen)
 {
   Bitmap *bitmap = getGlobalBorderBitmapFromGameStatus();
 
-  BlitBitmapMasked(bitmap, backbuffer, x, y, width, height, x, y);
+  if (blit_to_screen)
+    BlitToScreenMasked(bitmap, x, y, width, height, x, y);
+  else
+    BlitBitmapMasked(bitmap, backbuffer, x, y, width, height, x, y);
 }
 
-void DrawMaskedBorder_FIELD()
+static void DrawMaskedBorderExt_FIELD(boolean blit_to_screen)
 {
   if (global.border_status >= GAME_MODE_TITLE &&
       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,
+                            blit_to_screen);
 }
 
-void DrawMaskedBorder_DOOR_1()
+static void DrawMaskedBorderExt_DOOR_1(boolean blit_to_screen)
 {
+  // only draw border over closed doors when drawing to backbuffer
+  if (!blit_to_screen && (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, blit_to_screen);
 }
 
-void DrawMaskedBorder_DOOR_2()
+static void DrawMaskedBorderExt_DOOR_2(boolean blit_to_screen)
 {
+  // only draw border over closed doors when drawing to backbuffer
+  if (!blit_to_screen && (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, blit_to_screen);
 }
 
-void DrawMaskedBorder_DOOR_3()
+static void DrawMaskedBorderExt_DOOR_3(boolean blit_to_screen)
 {
   /* currently not available */
 }
 
-void DrawMaskedBorder_ALL()
+static void DrawMaskedBorderExt_ALL(boolean blit_to_screen)
 {
-  DrawMaskedBorder_FIELD();
-  DrawMaskedBorder_DOOR_1();
-  DrawMaskedBorder_DOOR_2();
-  DrawMaskedBorder_DOOR_3();
+  DrawMaskedBorderExt_FIELD(blit_to_screen);
+  DrawMaskedBorderExt_DOOR_1(blit_to_screen);
+  DrawMaskedBorderExt_DOOR_2(blit_to_screen);
+  DrawMaskedBorderExt_DOOR_3(blit_to_screen);
 }
 
-void DrawMaskedBorder(int redraw_mask)
+static void DrawMaskedBorderExt(int redraw_mask, boolean blit_to_screen)
 {
   /* never draw masked screen borders on borderless screens */
   if (game_status == GAME_MODE_LOADING ||
@@ -335,20 +351,35 @@ void DrawMaskedBorder(int redraw_mask)
     return;
 
   if (redraw_mask & REDRAW_ALL)
-    DrawMaskedBorder_ALL();
+    DrawMaskedBorderExt_ALL(blit_to_screen);
   else
   {
     if (redraw_mask & REDRAW_FIELD)
-      DrawMaskedBorder_FIELD();
+      DrawMaskedBorderExt_FIELD(blit_to_screen);
     if (redraw_mask & REDRAW_DOOR_1)
-      DrawMaskedBorder_DOOR_1();
+      DrawMaskedBorderExt_DOOR_1(blit_to_screen);
     if (redraw_mask & REDRAW_DOOR_2)
-      DrawMaskedBorder_DOOR_2();
+      DrawMaskedBorderExt_DOOR_2(blit_to_screen);
     if (redraw_mask & REDRAW_DOOR_3)
-      DrawMaskedBorder_DOOR_3();
+      DrawMaskedBorderExt_DOOR_3(blit_to_screen);
   }
 }
 
+void DrawMaskedBorder_FIELD()
+{
+  DrawMaskedBorderExt_FIELD(FALSE);
+}
+
+void DrawMaskedBorder(int redraw_mask)
+{
+  DrawMaskedBorderExt(redraw_mask, FALSE);
+}
+
+void DrawMaskedBorderToScreen(int redraw_mask)
+{
+  DrawMaskedBorderExt(redraw_mask, TRUE);
+}
+
 void BlitScreenToBitmap_RND(Bitmap *target_bitmap)
 {
   int fx = FX, fy = FY;
@@ -436,8 +467,12 @@ void BackToFront()
   if (redraw_mask == REDRAW_NONE)
     return;
 
+#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)
@@ -595,6 +630,10 @@ static void FadeExt(int fade_mask, int fade_mode, int fade_type)
 
 void FadeIn(int fade_mask)
 {
+#if 1
+  DrawMaskedBorder(REDRAW_ALL);
+#endif
+
   if (fading.fade_mode & FADE_TYPE_TRANSFORM)
     FadeExt(fade_mask, fading.fade_mode, FADE_TYPE_FADE_IN);
   else
@@ -608,6 +647,10 @@ void FadeIn(int fade_mask)
 
 void FadeOut(int fade_mask)
 {
+#if 0
+  DrawMaskedBorder(REDRAW_ALL);
+#endif
+
   if (fading.fade_mode & FADE_TYPE_TRANSFORM)
     FadeExt(fade_mask, fading.fade_mode, FADE_TYPE_FADE_OUT);
   else
@@ -3396,8 +3439,7 @@ void WaitForEventToContinue()
 
     DoAnimation();
 
-    /* don't eat all CPU time */
-    Delay(10);
+    WaitUntilDelayReached(&sync_frame_delay, sync_frame_delay_value);
   }
 }
 
@@ -3568,12 +3610,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;
@@ -4437,6 +4478,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);
 }
 
@@ -8188,6 +8233,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 +8375,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 +8384,7 @@ void ChangeViewportPropertiesIfNeeded()
 
     InitGadgets();
     InitToons();
+    InitGlobalAnimations();
   }
 
   if (init_em_graphics)
index 1fc4b5d..439517c 100644 (file)
@@ -76,6 +76,7 @@ void DrawMaskedBorder_DOOR_2();
 void DrawMaskedBorder_DOOR_3();
 void DrawMaskedBorder_ALL();
 void DrawMaskedBorder(int);
+void DrawMaskedBorderToScreen(int);
 
 void SetDrawtoField(int);
 void RedrawPlayfield();