X-Git-Url: https://git.artsoft.org/?p=rocksndiamonds.git;a=blobdiff_plain;f=src%2Flibgame%2Ftoons.c;h=34fa8fbb675f157256375535116f9938538f239e;hp=5c95800cc72c5f53fa0d126221dbaf9e890ac3ae;hb=29519e4b412b6fd0b2a18145f010f53ca09fa456;hpb=a4eaa7fcd8ca604faeee50f049c441415aa4968c diff --git a/src/libgame/toons.c b/src/libgame/toons.c index 5c95800c..34fa8fbb 100644 --- a/src/libgame/toons.c +++ b/src/libgame/toons.c @@ -1,38 +1,105 @@ -/*********************************************************** -* Artsoft Retro-Game Library * -*----------------------------------------------------------* -* (c) 1995-2002 Artsoft Entertainment * -* Holger Schemel * -* Detmolder Strasse 189 * -* 33604 Bielefeld * -* Germany * -* e-mail: info@artsoft.org * -*----------------------------------------------------------* -* toons.c * -***********************************************************/ +// ============================================================================ +// Artsoft Retro-Game Library +// ---------------------------------------------------------------------------- +// (c) 1995-2014 by Artsoft Entertainment +// Holger Schemel +// info@artsoft.org +// http://www.artsoft.org/ +// ---------------------------------------------------------------------------- +// toons.c +// ============================================================================ #include "toons.h" #include "misc.h" -/* values for toon animation */ -#define ANIM_START 0 -#define ANIM_CONTINUE 1 -#define ANIM_STOP 2 +static struct ToonScreenInfo screen_info; -static struct ToonScreenInfo screen_info; +/* ========================================================================= */ +/* generic animation frame calculation */ +/* ========================================================================= */ + +int getAnimationFrame(int num_frames, int delay, int mode, int start_frame, + int sync_frame) +{ + int frame = 0; + + sync_frame += start_frame * delay; + + if (mode & ANIM_LOOP) /* looping animation */ + { + frame = (sync_frame % (delay * num_frames)) / delay; + } + else if (mode & ANIM_LINEAR) /* linear (non-looping) animation */ + { + frame = sync_frame / delay; + + if (frame > num_frames - 1) + frame = num_frames - 1; + } + else if (mode & ANIM_PINGPONG) /* oscillate (border frames once) */ + { + int max_anim_frames = (num_frames > 1 ? 2 * num_frames - 2 : 1); + + frame = (sync_frame % (delay * max_anim_frames)) / delay; + frame = (frame < num_frames ? frame : max_anim_frames - frame); + } + else if (mode & ANIM_PINGPONG2) /* oscillate (border frames twice) */ + { + int max_anim_frames = 2 * num_frames; + + frame = (sync_frame % (delay * max_anim_frames)) / delay; + frame = (frame < num_frames ? frame : max_anim_frames - frame - 1); + } + else if (mode & ANIM_RANDOM) /* play frames in random order */ + { + /* note: expect different frames for the same delay cycle! */ + + if (gfx.anim_random_frame < 0) + frame = GetSimpleRandom(num_frames); + else + frame = gfx.anim_random_frame % num_frames; + } + else if (mode & (ANIM_CE_VALUE | ANIM_CE_SCORE | ANIM_CE_DELAY)) + { + frame = sync_frame % num_frames; + } + + if (mode & ANIM_REVERSE) /* use reverse animation direction */ + frame = num_frames - frame - 1; + + return frame; +} + + +/* ========================================================================= */ +/* toon animation functions */ +/* ========================================================================= */ + +static int get_toon_direction(char *direction_string_raw) +{ + char *direction_string = getStringToLower(direction_string_raw); + int direction = (strEqual(direction_string, "left") ? MV_LEFT : + strEqual(direction_string, "right") ? MV_RIGHT : + strEqual(direction_string, "up") ? MV_UP : + strEqual(direction_string, "down") ? MV_DOWN : + MV_NONE); + + free(direction_string); + + return direction; +} -void InitToonScreen(Bitmap **toon_bitmap_array, - Bitmap *save_buffer, +void InitToonScreen(Bitmap *save_buffer, void (*update_function)(void), void (*prepare_backbuffer_function)(void), boolean (*redraw_needed_function)(void), struct ToonInfo *toons, int num_toons, int startx, int starty, - int width, int height) + int width, int height, + int frame_delay_value) { - screen_info.toon_bitmap_array = toon_bitmap_array; screen_info.save_buffer = save_buffer; screen_info.update_function = update_function; screen_info.prepare_backbuffer_function = prepare_backbuffer_function; @@ -43,124 +110,146 @@ void InitToonScreen(Bitmap **toon_bitmap_array, screen_info.starty = starty; screen_info.width = width; screen_info.height = height; + screen_info.frame_delay_value = frame_delay_value; } -void DrawAnim(Bitmap *toon_bitmap, GC toon_clip_gc, - int src_x, int src_y, int width, int height, +void DrawAnim(Bitmap *toon_bitmap, int src_x, int src_y, int width, int height, int dest_x, int dest_y, int pad_x, int pad_y) { - int buf_x = DOOR_GFX_PAGEX3, buf_y = DOOR_GFX_PAGEY1; + int pad_dest_x = dest_x - pad_x; + int pad_dest_y = dest_y - pad_y; + int pad_width = width + 2 * pad_x; + int pad_height = height + 2 * pad_y; + int buffer_x = 0; + int buffer_y = 0; + + /* correct values to avoid off-screen blitting (start position) */ + if (pad_dest_x < screen_info.startx) + { + pad_width -= (screen_info.startx - pad_dest_x); + pad_dest_x = screen_info.startx; + } + if (pad_dest_y < screen_info.starty) + { + pad_height -= (screen_info.starty - pad_dest_y); + pad_dest_y = screen_info.starty; + } + + /* correct values to avoid off-screen blitting (blit size) */ + if (pad_width > screen_info.width) + pad_width = screen_info.width; + if (pad_height > screen_info.height) + pad_height = screen_info.height; -#if 1 /* special method to avoid flickering interference with BackToFront() */ - BlitBitmap(backbuffer, screen_info.save_buffer, dest_x-pad_x, dest_y-pad_y, - width+2*pad_x, height+2*pad_y, buf_x, buf_y); - SetClipOrigin(toon_bitmap, toon_clip_gc, dest_x-src_x, dest_y-src_y); - BlitBitmapMasked(toon_bitmap, backbuffer, - src_x, src_y, width, height, dest_x, dest_y); - BlitBitmap(backbuffer, window, dest_x-pad_x, dest_y-pad_y, - width+2*pad_x, height+2*pad_y, dest_x-pad_x, dest_y-pad_y); + BlitBitmap(backbuffer, screen_info.save_buffer, pad_dest_x, pad_dest_y, + pad_width, pad_height, buffer_x, buffer_y); + BlitBitmapMasked(toon_bitmap, backbuffer, src_x, src_y, width, height, + dest_x, dest_y); + BlitBitmap(backbuffer, window, pad_dest_x, pad_dest_y, pad_width, pad_height, + pad_dest_x, pad_dest_y); screen_info.update_function(); - BlitBitmap(screen_info.save_buffer, backbuffer, buf_x, buf_y, - width+2*pad_x, height+2*pad_y, dest_x-pad_x, dest_y-pad_y); -#else - /* normal method, causing flickering interference with BackToFront() */ - BlitBitmap(backbuffer, screen_info.save_buffer, dest_x-pad_x, dest_y-pad_y, - width+2*pad_x, height+2*pad_y, buf_x, buf_y); - SetClipOrigin(toon_bitmap,toon_clip_gc, buf_x-src_x+pad_x,buf_y-src_y+pad_y); - BlitBitmapMasked(toon_bitmap, screen_info.save_buffer, - src_x, src_y, width, height, buf_x+pad_x, buf_y+pad_y); - BlitBitmap(screen_info.save_buffer, window, buf_x, buf_y, - width+2*pad_x, height+2*pad_y, dest_x-pad_x, dest_y-pad_y); -#endif - - FlushDisplay(); + BlitBitmap(screen_info.save_buffer, backbuffer, buffer_x, buffer_y, + pad_width, pad_height, pad_dest_x, pad_dest_y); + + /* prevent immediate redraw of restored toon area in backbuffer */ + redraw_mask = REDRAW_NONE; } boolean AnimateToon(int toon_nr, boolean restart) { + static unsigned int animation_frame_counter = 0; static int pos_x = 0, pos_y = 0; static int delta_x = 0, delta_y = 0; - static int frame = 0, frame_step = 1; + static int frame = 0; static boolean horiz_move, vert_move; - static unsigned long anim_delay = 0; - static unsigned long anim_delay_value = 0; + static unsigned int anim_delay = 0; + static unsigned int anim_delay_value = 0; static int width,height; static int pad_x,pad_y; static int cut_x,cut_y; static int src_x, src_y; static int dest_x, dest_y; - struct ToonInfo *anim = &screen_info.toons[toon_nr]; - int bitmap_nr = screen_info.toons[toon_nr].bitmap_nr; - Bitmap *anim_bitmap = screen_info.toon_bitmap_array[bitmap_nr]; - GC anim_clip_gc = anim_bitmap->stored_clip_gc; + Bitmap *anim_bitmap = screen_info.toons[toon_nr].bitmap; + int direction = get_toon_direction(anim->direction); if (restart) { - horiz_move = (anim->direction & (ANIMDIR_LEFT | ANIMDIR_RIGHT)); - vert_move = (anim->direction & (ANIMDIR_UP | ANIMDIR_DOWN)); - anim_delay_value = 1000/anim->frames_per_second; - frame = 0; + horiz_move = (direction & (MV_LEFT | MV_RIGHT)); + vert_move = (direction & (MV_UP | MV_DOWN)); + anim_delay_value = anim->step_delay * screen_info.frame_delay_value; + + frame = getAnimationFrame(anim->anim_frames, anim->anim_delay, + anim->anim_mode, anim->anim_start_frame, + animation_frame_counter++); if (horiz_move) { - if (anim->position == ANIMPOS_UP) + int pos_bottom = screen_info.height - anim->height; + + if (strEqual(anim->position, "top")) pos_y = 0; - else if (anim->position == ANIMPOS_DOWN) - pos_y = screen_info.height - anim->height; - else if (anim->position == ANIMPOS_UPPER) - pos_y = SimpleRND((screen_info.height - anim->height) / 2); + else if (strEqual(anim->position, "bottom")) + pos_y = pos_bottom; + else if (strEqual(anim->position, "upper")) + pos_y = GetSimpleRandom(pos_bottom / 2); + else if (strEqual(anim->position, "lower")) + pos_y = pos_bottom / 2 + GetSimpleRandom(pos_bottom / 2); else - pos_y = SimpleRND(screen_info.height - anim->height); + pos_y = GetSimpleRandom(pos_bottom); - if (anim->direction == ANIMDIR_RIGHT) + if (direction == MV_RIGHT) { - delta_x = anim->stepsize; + delta_x = anim->step_offset; pos_x = -anim->width + delta_x; } else { - delta_x = -anim->stepsize; + delta_x = -anim->step_offset; pos_x = screen_info.width + delta_x; } + delta_y = 0; } else { - if (anim->position == ANIMPOS_LEFT) + int pos_right = screen_info.width - anim->width; + + if (strEqual(anim->position, "left")) pos_x = 0; - else if (anim->position == ANIMPOS_RIGHT) - pos_x = screen_info.width - anim->width; + else if (strEqual(anim->position, "right")) + pos_x = pos_right; else - pos_x = SimpleRND(screen_info.width - anim->width); + pos_x = GetSimpleRandom(pos_right); - if (anim->direction == ANIMDIR_DOWN) + if (direction == MV_DOWN) { - delta_y = anim->stepsize; + delta_y = anim->step_offset; pos_y = -anim->height + delta_y; } else { - delta_y = -anim->stepsize; - pos_y = screen_info.width + delta_y; + delta_y = -anim->step_offset; + pos_y = screen_info.height + delta_y; } + delta_x = 0; } } - if (pos_x <= -anim->width - anim->stepsize || - pos_x >= screen_info.width + anim->stepsize || - pos_y <= -anim->height - anim->stepsize || - pos_y >= screen_info.height + anim->stepsize) + if (pos_x <= -anim->width - anim->step_offset || + pos_x >= screen_info.width + anim->step_offset || + pos_y <= -anim->height - anim->step_offset || + pos_y >= screen_info.height + anim->step_offset) return TRUE; if (!DelayReached(&anim_delay, anim_delay_value)) { if (screen_info.redraw_needed_function() && !restart) - DrawAnim(anim_bitmap, anim_clip_gc, + DrawAnim(anim_bitmap, src_x + cut_x, src_y + cut_y, width, height, screen_info.startx + dest_x, @@ -179,8 +268,8 @@ boolean AnimateToon(int toon_nr, boolean restart) else if (pos_y > screen_info.height) pos_y = screen_info.height; - pad_x = (horiz_move ? anim->stepsize : 0); - pad_y = (vert_move ? anim->stepsize : 0); + pad_x = (horiz_move ? anim->step_offset : 0); + pad_y = (vert_move ? anim->step_offset : 0); src_x = anim->src_x + frame * anim->width; src_y = anim->src_y; dest_x = pos_x; @@ -189,7 +278,7 @@ boolean AnimateToon(int toon_nr, boolean restart) width = anim->width; height = anim->height; - if (pos_x<0) + if (pos_x < 0) { dest_x = 0; width += pos_x; @@ -198,7 +287,7 @@ boolean AnimateToon(int toon_nr, boolean restart) else if (pos_x > screen_info.width - anim->width) width -= (pos_x - (screen_info.width - anim->width)); - if (pos_y<0) + if (pos_y < 0) { dest_y = 0; height += pos_y; @@ -207,7 +296,7 @@ boolean AnimateToon(int toon_nr, boolean restart) else if (pos_y > screen_info.height - anim->height) height -= (pos_y - (screen_info.height - anim->height)); - DrawAnim(anim_bitmap, anim_clip_gc, + DrawAnim(anim_bitmap, src_x + cut_x, src_y + cut_y, width, height, screen_info.startx + dest_x, @@ -216,54 +305,56 @@ boolean AnimateToon(int toon_nr, boolean restart) pos_x += delta_x; pos_y += delta_y; - frame += frame_step; - if (frame<0 || frame>=anim->frames) - { - if (anim->mode == ANIM_PINGPONG) - { - frame_step *= -1; - frame = (frame<0 ? 1 : anim->frames-2); - } - else - frame = (frame<0 ? anim->frames-1 : 0); - } + frame = getAnimationFrame(anim->anim_frames, anim->anim_delay, + anim->anim_mode, anim->anim_start_frame, + animation_frame_counter++); return FALSE; } void HandleAnimation(int mode) { - static unsigned long animstart_delay = -1; - static unsigned long animstart_delay_value = 0; + static unsigned int animstart_delay = -1; + static unsigned int animstart_delay_value = 0; + static boolean anim_running = FALSE; static boolean anim_restart = TRUE; static boolean reset_delay = TRUE; static int toon_nr = 0; - int draw_mode; - if (!setup.toons) + if (!setup.toons || screen_info.num_toons == 0) return; + /* this may happen after reloading graphics and redefining "num_toons" */ + if (toon_nr >= screen_info.num_toons) + anim_restart = TRUE; + switch(mode) { case ANIM_START: screen_info.prepare_backbuffer_function(); + + anim_running = TRUE; anim_restart = TRUE; reset_delay = TRUE; return; case ANIM_CONTINUE: + if (!anim_running) + return; + break; case ANIM_STOP: - redraw_mask |= (REDRAW_FIELD | REDRAW_FROM_BACKBUFFER); + if (anim_running) + { + redraw_mask |= REDRAW_FIELD; + + screen_info.update_function(); - /* Redraw background even when in direct drawing mode */ - draw_mode = setup.direct_draw; - setup.direct_draw = FALSE; - screen_info.update_function(); - setup.direct_draw = draw_mode; + anim_running = FALSE; + } return; @@ -274,7 +365,7 @@ void HandleAnimation(int mode) if (reset_delay) { animstart_delay = Counter(); - animstart_delay_value = SimpleRND(3000); + animstart_delay_value = GetSimpleRandom(3000); reset_delay = FALSE; } @@ -283,23 +374,8 @@ void HandleAnimation(int mode) if (!DelayReached(&animstart_delay, animstart_delay_value)) return; - toon_nr = SimpleRND(screen_info.num_toons); + toon_nr = GetSimpleRandom(screen_info.num_toons); } - anim_restart = reset_delay = AnimateToon(toon_nr,anim_restart); -} - -void InitAnimation() -{ - HandleAnimation(ANIM_START); -} - -void StopAnimation() -{ - HandleAnimation(ANIM_STOP); -} - -void DoAnimation() -{ - HandleAnimation(ANIM_CONTINUE); + anim_restart = reset_delay = AnimateToon(toon_nr, anim_restart); }