From d3db3fa83e02cd96036e2cf7268660daabc0d261 Mon Sep 17 00:00:00 2001 From: kichikuou Date: Sun, 1 Sep 2024 10:53:58 +0900 Subject: [PATCH] sdl_effect: Implement EFFECT_PAN_IN_* and EFFECT_SKIP_LINE_* This also fixes incorrect behavior of `CD 1` and `CD 2`. --- src/ecopy.c | 131 ++++++---------------------------------------- src/effect.h | 8 +++ src/sdl_core.h | 1 + src/sdl_draw.c | 21 ++++++-- src/sdl_effect.c | 128 ++++++++++++++++++++++++++++++++++++++++++++ src/sdl_image.c | 2 + src/sdl_private.h | 1 + 7 files changed, 173 insertions(+), 119 deletions(-) diff --git a/src/ecopy.c b/src/ecopy.c index 9c02fbc..7daeb69 100644 --- a/src/ecopy.c +++ b/src/ecopy.c @@ -54,84 +54,6 @@ static void eCopyUpdateArea(int sx, int sy, int w, int h, int dx, int dy) { sdl_updateArea(&src, &dst); } -static int eCopyArea1(int dx, int dy, int w, int h, int opt) { - int y, key = 0, cnt; - int waitcnt = opt == 0 ? 20 : opt; - - cnt = sdl_getTicks(); - for (y = 0; y < h - 24; y += 24) { - cnt += waitcnt; - eCopyUpdateArea(dx, dy + h - y, w, y, dx, dy); - EC_WAIT; - } - - eCopyUpdateArea(dx, dy, w, h, dx, dy); - return key; -} - -static int eCopyArea2(int dx, int dy, int w, int h, int opt) { - int y, key = 0, cnt; - int waitcnt = opt == 0 ? 20 : opt; - - cnt = sdl_getTicks(); - for (y = 0; y < h - 24; y += 24) { - cnt += waitcnt; - eCopyUpdateArea(dx, dy , w, y, dx, dy + h - y); - EC_WAIT; - } - - eCopyUpdateArea(dx, dy, w, h, dx, dy); - return key; -} - -static int eCopyArea3(int dx, int dy, int w, int h, int opt) { - int y1, y2, key = 0, cnt; - int waitcnt = opt == 0 ? 3 : opt; - - if (h % 2) { - h--; - eCopyUpdateArea(dx , dy + h, w, 1, dx, dy + h); - } - y1 = dy; - y2 = dy + h - 1; - cnt = sdl_getTicks(); - while (h > 0) { - cnt += waitcnt; - eCopyUpdateArea(dx, y1, w, 1, dx, y1); - eCopyUpdateArea(dx, y2, w, 1, dx, y2); - y1 += 2; - y2 -= 2; - h -= 2; - EC_WAIT; - } - eCopyUpdateArea(dx, dy, w, h, dx, dy); - return key; -} - -static int eCopyArea4(int dx, int dy, int w, int h, int opt) { - int x1,x2, key = 0, cnt; - int waitcnt = opt == 0 ? 3 : opt; - - if (w % 2) { - w--; - eCopyUpdateArea(dx + w , dy, 1, h, dx + w, dy); - } - x1 = dx; - x2 = dx + w - 1; - cnt = sdl_getTicks(); - while (w > 0) { - cnt += waitcnt; - eCopyUpdateArea(x1, dy, 1, h, x1, dy); - eCopyUpdateArea(x2, dy, 1, h, x2, dy); - x1 += 2; - x2 -= 2; - w -= 2; - EC_WAIT; - } - eCopyUpdateArea(dx, dy, w, h, dx, dy); - return key; -} - static int eCopyArea5(int sx, int sy, int w, int h, int dx, int dy, int opt) { int i, x, y, key = 0, cnt; int waitcnt = opt == 0 ? 20 : opt; @@ -299,6 +221,13 @@ static int eCopyArea2001(int sx, int sy, int w, int h, int dx, int dy, int opt) static int duration(enum nact_effect effect, int opt, SDL_Rect *rect) { switch (effect) { + case NACT_EFFECT_PAN_IN_DOWN: + case NACT_EFFECT_PAN_IN_UP: + return (opt ? opt : 20) * (rect->h / 24); + case NACT_EFFECT_SKIP_LINE_UP_DOWN: + return (opt ? opt : 3) * (rect->h / 2); + case NACT_EFFECT_SKIP_LINE_LR_RL: + return (opt ? opt : 3) * (rect->w / 2); case NACT_EFFECT_ZOOM_IN: return opt ? opt * 64 : 500; case NACT_EFFECT_BLIND_DOWN: @@ -423,10 +352,6 @@ void ags_eCopyArea(int sx, int sy, int w, int h, int dx, int dy, int sw, int opt ecp_cancel = cancel; switch(sw) { - case 1: - case 2: - case 3: - case 4: case 6: case 16: case 17: @@ -441,18 +366,6 @@ void ags_eCopyArea(int sx, int sy, int w, int h, int dx, int dy, int sw, int opt } switch(sw) { - case 1: - ret = eCopyArea1(dx, dy, w, h, opt); - break; - case 2: - ret = eCopyArea2(dx, dy, w, h, opt); - break; - case 3: - ret = eCopyArea3(dx, dy, w, h, opt); - break; - case 4: - ret = eCopyArea4(dx, dy, w, h, opt); - break; case 5: ret = eCopyArea5(sx, sy, w, h, dx, dy, opt); break; @@ -505,6 +418,16 @@ void ags_eSpriteCopyArea(int sx, int sy, int w, int h, int dx, int dy, int sw, i nact->waitcancel_key = 0; + if (1 <= sw && sw <= 4) { + SDL_Rect rect = { dx - nact->ags.view_area.x, dy - nact->ags.view_area.y, w, h }; + struct sdl_effect *eff = sdl_sprite_effect_init(&rect, dx, dy, sx, sy, spCol, from_nact_effect(sw)); + ags_runEffect(duration(sw, opt, &rect), cancel, (ags_EffectStepFunc)sdl_effect_step, eff); + sdl_effect_finish(eff); + // Actual copy. + ags_copyAreaSP(sx, sy, w, h, dx, dy, spCol); + ags_updateArea(dx, dy, w, h); + return; + } if (sw == 5) { SDL_Rect rect = { dx - nact->ags.view_area.x, dy - nact->ags.view_area.y, w, h }; struct sdl_effect *eff = sdl_effect_raster_blend_init(&rect, sx, sy); @@ -518,28 +441,8 @@ void ags_eSpriteCopyArea(int sx, int sy, int w, int h, int dx, int dy, int sw, i ecp_cancel = cancel; - if (1 <= sw && sw <= 4) { - ags_copyAreaSP(sx, sy, w, h, dx, dy, spCol); - MyRectangle r = {dx, dy, w, h}, update; - SDL_IntersectRect(&nact->ags.view_area, &r, &update); - w = update.w; - h = update.h; - } - int ret = 0; switch(sw) { - case 1: - ret = eCopyArea1(dx, dy, w, h, opt); - break; - case 2: - ret = eCopyArea2(dx, dy, w, h, opt); - break; - case 3: - ret = eCopyArea3(dx, dy, w, h, opt); - break; - case 4: - ret = eCopyArea4(dx, dy, w, h, opt); - break; case NACT_EFFECT_PALETTE_SHIFT: if (nact->ags.world_depth != 8) return; ags_copyPaletteShift(sx, sy, w, h, dx, dy, spCol); diff --git a/src/effect.h b/src/effect.h index 7d9af48..ee0dc20 100644 --- a/src/effect.h +++ b/src/effect.h @@ -22,6 +22,10 @@ // Effect types of the CE/CD command. enum nact_effect { + NACT_EFFECT_PAN_IN_DOWN = 1, + NACT_EFFECT_PAN_IN_UP = 2, + NACT_EFFECT_SKIP_LINE_UP_DOWN = 3, + NACT_EFFECT_SKIP_LINE_LR_RL = 4, NACT_EFFECT_WIPE_IN = 7, NACT_EFFECT_WIPE_OUT = 8, NACT_EFFECT_ZOOM_IN = 10, @@ -124,6 +128,10 @@ enum sdl_effect_type { EFFECT_DITHERING_FADEIN, EFFECT_DITHERING_WHITEOUT, EFFECT_DITHERING_WHITEIN, + EFFECT_PAN_IN_DOWN, + EFFECT_PAN_IN_UP, + EFFECT_SKIP_LINE_UP_DOWN, + EFFECT_SKIP_LINE_LR_RL, EFFECT_WIPE_IN, EFFECT_WIPE_OUT, EFFECT_WIPE_LR, diff --git a/src/sdl_core.h b/src/sdl_core.h index 75f0c5e..69bdd09 100644 --- a/src/sdl_core.h +++ b/src/sdl_core.h @@ -87,6 +87,7 @@ extern SDL_Surface *com2surface(agsurface_t *s); /* Effects */ struct sdl_effect; struct sdl_effect *sdl_effect_init(SDL_Rect *rect, agsurface_t *old, int ox, int oy, agsurface_t *new, int nx, int ny, enum sdl_effect_type effect); +struct sdl_effect *sdl_sprite_effect_init(SDL_Rect *rect, int dx, int dy, int sx, int sy, int col, enum sdl_effect_type type); struct sdl_effect *sdl_effect_magnify_init(agsurface_t *surface, SDL_Rect *view_rect, SDL_Rect *target_rect); struct sdl_effect *sdl_effect_raster_blend_init(SDL_Rect *rect, int sx, int sy); void sdl_effect_step(struct sdl_effect *eff, float progress); diff --git a/src/sdl_draw.c b/src/sdl_draw.c index 4c69233..c22bba9 100644 --- a/src/sdl_draw.c +++ b/src/sdl_draw.c @@ -202,10 +202,7 @@ void sdl_copyArea(int sx, int sy, int w, int h, int dx, int dy) { } } -/* - * dib に指定のパレット sp を抜いてコピー - */ -void sdl_copyAreaSP(int sx, int sy, int w, int h, int dx, int dy, uint8_t sp) { +static void sdl_dib_sprite_copy(SDL_Surface *dst, int sx, int sy, int w, int h, int dx, int dy, uint8_t sp) { sdl_pal_check(); Uint32 col = palette_color(sp); @@ -214,10 +211,24 @@ void sdl_copyAreaSP(int sx, int sy, int w, int h, int dx, int dy, uint8_t sp) { SDL_Rect r_src = {sx, sy, w, h}; SDL_Rect r_dst = {dx, dy, w, h}; - SDL_BlitSurface(sdl_dib, &r_src, sdl_dib, &r_dst); + SDL_BlitSurface(sdl_dib, &r_src, dst, &r_dst); SDL_SetColorKey(sdl_dib, SDL_FALSE, 0); } +/* + * dib に指定のパレット sp を抜いてコピー + */ +void sdl_copyAreaSP(int sx, int sy, int w, int h, int dx, int dy, uint8_t sp) { + sdl_dib_sprite_copy(sdl_dib, sx, sy, w, h, dx, dy, sp); +} + +SDL_Surface *sdl_dib_to_surface_colorkey(int x, int y, int w, int h, int sp) { + SDL_Surface *s = SDL_CreateRGBSurfaceWithFormat(0, w, h, 32, SDL_PIXELFORMAT_ARGB8888); + SDL_FillRect(s, NULL, 0); + sdl_dib_sprite_copy(s, x, y, w, h, 0, 0, sp); + return s; +} + void sdl_drawImage8_fromData(cgdata *cg, int dx, int dy, int sprite_color) { int w = cg->width; int h = cg->height; diff --git a/src/sdl_effect.c b/src/sdl_effect.c index bb3ef39..84b7533 100644 --- a/src/sdl_effect.c +++ b/src/sdl_effect.c @@ -32,6 +32,10 @@ enum sdl_effect_type from_nact_effect(enum nact_effect effect) { switch (effect) { + case NACT_EFFECT_PAN_IN_DOWN: return EFFECT_PAN_IN_DOWN; + case NACT_EFFECT_PAN_IN_UP: return EFFECT_PAN_IN_UP; + case NACT_EFFECT_SKIP_LINE_UP_DOWN: return EFFECT_SKIP_LINE_UP_DOWN; + case NACT_EFFECT_SKIP_LINE_LR_RL: return EFFECT_SKIP_LINE_LR_RL; case NACT_EFFECT_WIPE_IN: return EFFECT_WIPE_IN; case NACT_EFFECT_WIPE_OUT: return EFFECT_WIPE_OUT; case NACT_EFFECT_ZOOM_IN: return EFFECT_ZOOM_IN; @@ -563,6 +567,107 @@ static void dithering_fade_free(struct sdl_effect *eff) { free(eff); } +// EFFECT_PAN_IN_* + +static void pan_in_step(struct sdl_effect *eff, float progress); +static void pan_in_free(struct sdl_effect *eff); + +static struct sdl_effect *pan_in_new(SDL_Rect *rect, SDL_Surface *old, SDL_Surface *new, enum sdl_effect_type type) { + struct sdl_effect *eff = calloc(1, sizeof(struct sdl_effect)); + if (!eff) + NOMEMERR(); + effect_init(eff, rect, old, new, type); + eff->step = pan_in_step; + eff->finish = pan_in_free; + return eff; +} + +static void pan_in_step(struct sdl_effect *eff, float progress) { + SDL_RenderCopy(sdl_renderer, eff->tx_old, NULL, &eff->dst_rect); + + int h = eff->dst_rect.h * progress; + SDL_Rect sr = { 0, 0, eff->dst_rect.w, h }; + SDL_Rect dr = eff->dst_rect; + dr.h = h; + if (eff->type == EFFECT_PAN_IN_DOWN) { + sr.y = eff->dst_rect.h - h; + } else { + dr.y += eff->dst_rect.h - h; + } + SDL_RenderCopy(sdl_renderer, eff->tx_new, &sr, &dr); + + SDL_RenderPresent(sdl_renderer); +} + +static void pan_in_free(struct sdl_effect *eff) { + effect_finish(eff, true); + free(eff); +} + +// EFFECT_SKIP_LINE_* + +static void skip_line_step(struct sdl_effect *eff, float progress); +static void skip_line_free(struct sdl_effect *eff); + +static struct sdl_effect *skip_line_new(SDL_Rect *rect, SDL_Surface *old, SDL_Surface *new, enum sdl_effect_type type) { + struct sdl_effect *eff = calloc(1, sizeof(struct sdl_effect)); + if (!eff) + NOMEMERR(); + effect_init(eff, rect, old, new, type); + eff->step = skip_line_step; + eff->finish = skip_line_free; + return eff; +} + +static void skip_line_step(struct sdl_effect *eff, float progress) { + SDL_RenderCopy(sdl_renderer, eff->tx_old, NULL, &eff->dst_rect); + + if (eff->type == EFFECT_SKIP_LINE_UP_DOWN) { + int h = eff->dst_rect.h * progress; + SDL_Rect sr = { 0, 0, eff->dst_rect.w, 1 }; + SDL_Rect dr = eff->dst_rect; + dr.h = 1; + + int bottom = (eff->dst_rect.h - 1) | 1; + for (int y = 0; y < h; y += 2) { + sr.y = y; + dr.y = eff->dst_rect.y + y; + SDL_RenderCopy(sdl_renderer, eff->tx_new, &sr, &dr); + + if (y == 0 && eff->dst_rect.h & 1) + continue; + sr.y = bottom - y; + dr.y = eff->dst_rect.y + bottom - y; + SDL_RenderCopy(sdl_renderer, eff->tx_new, &sr, &dr); + } + } else { + int w = eff->dst_rect.w * progress; + SDL_Rect sr = { 0, 0, 1, eff->dst_rect.h }; + SDL_Rect dr = eff->dst_rect; + dr.w = 1; + + int right = (eff->dst_rect.w - 1) | 1; + for (int x = 0; x < w; x += 2) { + sr.x = x; + dr.x = eff->dst_rect.x + x; + SDL_RenderCopy(sdl_renderer, eff->tx_new, &sr, &dr); + + if (x == 0 && eff->dst_rect.w & 1) + continue; + sr.x = right - x; + dr.x = eff->dst_rect.x + right - x; + SDL_RenderCopy(sdl_renderer, eff->tx_new, &sr, &dr); + } + } + + SDL_RenderPresent(sdl_renderer); +} + +static void skip_line_free(struct sdl_effect *eff) { + effect_finish(eff, true); + free(eff); +} + // EFFECT_WIPE_* static void wipe_step(struct sdl_effect *eff, float progress); @@ -1607,6 +1712,12 @@ struct sdl_effect *sdl_effect_init(SDL_Rect *rect, agsurface_t *old, int ox, int case EFFECT_DITHERING_WHITEOUT: case EFFECT_DITHERING_WHITEIN: return dithering_fade_new(rect, sf_old, sf_new, type); + case EFFECT_PAN_IN_DOWN: + case EFFECT_PAN_IN_UP: + return pan_in_new(rect, sf_old, sf_new, type); + case EFFECT_SKIP_LINE_UP_DOWN: + case EFFECT_SKIP_LINE_LR_RL: + return skip_line_new(rect, sf_old, sf_new, type); case EFFECT_WIPE_IN: case EFFECT_WIPE_OUT: case EFFECT_WIPE_LR: @@ -1663,6 +1774,23 @@ struct sdl_effect *sdl_effect_init(SDL_Rect *rect, agsurface_t *old, int ox, int } } +struct sdl_effect *sdl_sprite_effect_init(SDL_Rect *rect, int dx, int dy, int sx, int sy, int col, enum sdl_effect_type type) { + SDL_Surface *sf_old = create_surface(sdl_dibinfo, dx, dy, rect->w, rect->h); + SDL_Surface *sprite = sdl_dib_to_surface_colorkey(sx, sy, rect->w, rect->h, col); + + switch (type) { + case EFFECT_PAN_IN_DOWN: + case EFFECT_PAN_IN_UP: + return pan_in_new(rect, sf_old, sprite, type); + case EFFECT_SKIP_LINE_UP_DOWN: + case EFFECT_SKIP_LINE_LR_RL: + return skip_line_new(rect, sf_old, sprite, type); + default: + SYSERROR("Unknown sprite effect %d", type); + return NULL; + } +} + struct sdl_effect *sdl_effect_magnify_init(agsurface_t *surface, SDL_Rect *view_rect, SDL_Rect *target_rect) { SDL_Surface *sf = create_surface(surface, view_rect->x, view_rect->y, view_rect->w, view_rect->h); return magnify_new(sf, view_rect, target_rect); diff --git a/src/sdl_image.c b/src/sdl_image.c index 8ef37da..d4e69ea 100644 --- a/src/sdl_image.c +++ b/src/sdl_image.c @@ -245,6 +245,7 @@ void sdl_copyAreaSP16_alphaBlend(int sx, int sy, int w, int h, int dx, int dy, i SDL_SetSurfaceBlendMode(sdl_dib, SDL_BLENDMODE_BLEND); SDL_SetSurfaceAlphaMod(sdl_dib, lv); SDL_BlitSurface(sdl_dib, &r_src, sdl_dib, &r_dst); + SDL_SetSurfaceAlphaMod(sdl_dib, 255); SDL_SetSurfaceBlendMode(sdl_dib, SDL_BLENDMODE_NONE); } @@ -255,6 +256,7 @@ void sdl_copyAreaSP16_alphaLevel(int sx, int sy, int w, int h, int dx, int dy, i SDL_SetSurfaceAlphaMod(sdl_dib, lv); SDL_FillRect(sdl_dib, &r_dst, 0); SDL_BlitSurface(sdl_dib, &r_src, sdl_dib, &r_dst); + SDL_SetSurfaceAlphaMod(sdl_dib, 255); SDL_SetSurfaceBlendMode(sdl_dib, SDL_BLENDMODE_NONE); } diff --git a/src/sdl_private.h b/src/sdl_private.h index 5827622..f465bbf 100644 --- a/src/sdl_private.h +++ b/src/sdl_private.h @@ -57,6 +57,7 @@ void sdl_cursor_init(void); int sdl_nearest_color(int r, int g, int b); boolean sdl_joy_open(int index); SDL_Surface *sdl_dib_to_surface_with_alpha(int x, int y, int w, int h); +SDL_Surface *sdl_dib_to_surface_colorkey(int x, int y, int w, int h, int col); extern struct sdl_private_data *sdl_videodev;