#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)
+
+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;
+};
+
+
+/* forward declaration for internal use */
+static void DoAnimationExt(void);
+
+static struct GlobalAnimControlInfo global_anim_ctrl[NUM_SPECIAL_GFX_ARGS];
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 boolean do_animations = FALSE;
+
+
+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)
REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
GAME_FRAME_DELAY);
}
+
+static void InitToonControls()
+{
+ struct GlobalAnimControlInfo *ctrl = &global_anim_ctrl[GAME_MODE_DEFAULT];
+ 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 = GAME_MODE_DEFAULT;
+ 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 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_SPECIAL_GFX_ARGS; 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();
+}
+
+void DrawGlobalAnimExt(int drawing_stage)
+{
+ int mode_nr;
+
+ if (game_status == GAME_MODE_LOADING)
+ do_animations = FALSE;
+
+ if (!do_animations || !setup.toons)
+ return;
+
+ if (drawing_stage == DRAW_GLOBAL_ANIM_STAGE_1)
+ DoAnimationExt();
+
+ for (mode_nr = 0; mode_nr < NUM_SPECIAL_GFX_ARGS; mode_nr++)
+ {
+ struct GlobalAnimControlInfo *ctrl = &global_anim_ctrl[mode_nr];
+ int anim_nr;
+
+ if (mode_nr != GFX_SPECIAL_ARG_DEFAULT &&
+ mode_nr != game_status)
+ continue;
+
+ 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)
+{
+ if (!do_animations || !setup.toons)
+ return;
+
+ 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);
+}
+
+void HandleGlobalAnim(int action)
+{
+#if 0
+ printf("::: HandleGlobalAnim [mode == %d]\n", game_status);
+#endif
+
+ HandleGlobalAnim_Mode(&global_anim_ctrl[GAME_MODE_DEFAULT], action);
+ HandleGlobalAnim_Mode(&global_anim_ctrl[game_status], action);
+}
+
+void InitAnimation()
+{
+ // HandleAnimation(ANIM_START);
+
+#if 0
+ printf("::: InitAnimation\n");
+#endif
+
+ // InitCounter();
+
+ InitGlobalAnimControls();
+
+ HandleGlobalAnim(ANIM_START);
+
+ do_animations = TRUE;
+}
+
+void StopAnimation()
+{
+ // HandleAnimation(ANIM_STOP);
+
+#if 0
+ printf("::: StopAnimation\n");
+#endif
+
+ HandleGlobalAnim(ANIM_STOP);
+
+ do_animations = FALSE;
+}
+
+static void DoAnimationExt()
+{
+#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
+
+ HandleGlobalAnim(ANIM_CONTINUE);
+
+#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
+}
#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 DrawGlobalAnim(int);
+
+void InitAnimation(void);
+void StopAnimation(void);
+void DoAnimation(void);
+
#endif
{ ".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 },
{ "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" },
#include "editor.h"
#include "files.h"
#include "tape.h"
+#include "cartoons.h"
#include "network.h"
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 */
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;
}
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)
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();
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;
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)
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];
/* 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];
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");
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];
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;
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;
void InitGfxBuffers();
void InitGadgets();
+void InitImageTextures();
void DisplayExitMessage(char *, va_list);
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 */
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
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);
void ReloadCustomImages();
void CreateImageWithSmallImages(int, int, int);
+void CreateImageTextures(int);
+void FreeAllImageTextures();
void ScaleImage(int, int);
void FreeAllImages();
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 */
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)
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)
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>. */
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 :
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"))
}
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"))
{
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)
}
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]);
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);
{
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))
}
#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;
{
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
#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
}
#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)
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,
#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)
{
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))
}
}
- 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,
#define FULLSCREEN_STATUS FULLSCREEN_AVAILABLE
#endif
+#define USE_FINAL_SCREEN_BITMAP FALSE
+
#define CURSOR_MAX_WIDTH 32
#define CURSOR_MAX_HEIGHT 32
int width, height;
SDL_Surface *surface;
SDL_Surface *surface_masked;
+#if defined(TARGET_SDL2)
+ SDL_Texture *texture;
+ SDL_Texture *texture_masked;
+#endif
};
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 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));
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)
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;
Bitmap *CreateBitmapStruct(void)
{
- return checked_calloc(sizeof(struct SDLSurfaceInfo));
+ return checked_calloc(sizeof(Bitmap));
}
Bitmap *CreateBitmap(int width, int height, int depth)
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)
{
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);
/* 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)
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;
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;
};
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);
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);
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);
#include "misc.h"
-/* values for toon animation */
-#define ANIM_START 0
-#define ANIM_CONTINUE 1
-#define ANIM_STOP 2
-
-
static struct ToonScreenInfo screen_info;
anim_restart = reset_delay = AnimateToon(toon_nr, anim_restart);
}
-
-void InitAnimation()
-{
- HandleAnimation(ANIM_START);
-}
-
-void StopAnimation()
-{
- HandleAnimation(ANIM_STOP);
-}
-
-void DoAnimation()
-{
- HandleAnimation(ANIM_CONTINUE);
-}
#include "system.h"
+/* values for toon animation */
+#define ANIM_START 0
+#define ANIM_CONTINUE 1
+#define ANIM_STOP 2
+
+
struct ToonScreenInfo
{
Bitmap *save_buffer;
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 */
{ ".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() */
{ 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 */
#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_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
/* 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 */
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 */
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;
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;
{ 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:" },
DoAnimation();
BackToFront();
- /* don't eat all CPU time */
- Delay(10);
+ WaitUntilDelayReached(&sync_frame_delay, sync_frame_delay_value);
}
return key;
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 */
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) */
NextEvent(&event);
HandleOtherEvents(&event);
- Delay(10);
+ WaitUntilDelayReached(&sync_frame_delay, sync_frame_delay_value);
}
}
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;
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 ||
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;
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)
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
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
DoAnimation();
- /* don't eat all CPU time */
- Delay(10);
+ WaitUntilDelayReached(&sync_frame_delay, sync_frame_delay_value);
}
}
else
{
DoAnimation();
-
- if (!PendingEvent()) /* delay only if no pending events */
- Delay(10);
}
BackToFront();
+
+ WaitUntilDelayReached(&sync_frame_delay, sync_frame_delay_value);
}
return result;
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);
}
// printf("::: init_video_buffer\n");
InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen);
+ InitImageTextures();
}
if (init_gadgets_and_toons)
void DrawMaskedBorder_DOOR_3();
void DrawMaskedBorder_ALL();
void DrawMaskedBorder(int);
+void DrawMaskedBorderToScreen(int);
void SetDrawtoField(int);
void RedrawPlayfield();