From 10b414fb4e34a1095ce78265af87701867c3ef3b Mon Sep 17 00:00:00 2001 From: kichikuou Date: Tue, 4 Jan 2022 21:53:03 +0900 Subject: [PATCH] sdl_effect: Implement mosaic and crossfade-mosaic --- modules/SACT/sprite_eupdate.c | 4 +- modules/SACT/sprite_eupdate_mosaic.c | 35 --------- src/ecopy.c | 52 +------------ src/effect.h | 5 ++ src/image.c | 25 ------ src/image.h | 1 - src/sdl_core.h | 1 - src/sdl_draw.c | 9 --- src/sdl_effect.c | 109 +++++++++++++++++++++++++-- 9 files changed, 113 insertions(+), 128 deletions(-) delete mode 100644 modules/SACT/sprite_eupdate_mosaic.c diff --git a/modules/SACT/sprite_eupdate.c b/modules/SACT/sprite_eupdate.c index 15f06b9..3bcbbcc 100644 --- a/modules/SACT/sprite_eupdate.c +++ b/modules/SACT/sprite_eupdate.c @@ -40,7 +40,6 @@ #include "sdl_core.h" -static void ec6_cb(surface_t *, surface_t *); static void sdl_effect_cb(surface_t *, surface_t *); static void ec_dummy_cb(surface_t *, surface_t *); @@ -56,7 +55,6 @@ typedef struct ecopyparam ecopyparam_t; static ecopyparam_t ecp; #include "sprite_eupdate_perspect.c" -#include "sprite_eupdate_mosaic.c" #include "sprite_eupdate_uneune.c" #include "sprite_eupdate_zmbbul.c" @@ -68,7 +66,7 @@ static entrypoint *cb[39] = { sdl_effect_cb, sdl_effect_cb, sdl_effect_cb, - ec6_cb, + sdl_effect_cb, sdl_effect_cb, sdl_effect_cb, sdl_effect_cb, diff --git a/modules/SACT/sprite_eupdate_mosaic.c b/modules/SACT/sprite_eupdate_mosaic.c deleted file mode 100644 index 3158381..0000000 --- a/modules/SACT/sprite_eupdate_mosaic.c +++ /dev/null @@ -1,35 +0,0 @@ - - - -// クロスフェードモザイク -static void ec6_cb(surface_t *src, surface_t *dst) { - int curstep, maxstep = 32; - surface_t *st, *dt; - static int slices[32]={4,8,12,16,20,28,36,40,44,48,56,64,72,80,88,96, - 88,80,72,64,56,48,44,40,36,28,24,20,16,12,8,4}; - - - curstep = maxstep * (ecp.curtime - ecp.sttime)/ (ecp.edtime - ecp.sttime); - if (ecp.oldstep == curstep) { - usleep(0); - return; - } - st = sf_dup(src); - dt = sf_dup(dst); - - SDL_Surface *stt = com2surface(st); - SDL_Surface *dtt = com2surface(dt); - image_Mosaic(stt, 0, 0, stt->w, stt->h, 0, 0, slices[curstep]); - image_Mosaic(dtt, 0, 0, dtt->w, dtt->h, 0, 0, slices[curstep]); - SDL_FreeSurface(stt); - SDL_FreeSurface(dtt); - - gre_Blend(sf0, 0, 0, st, 0, 0, dt, 0, 0, st->width, st->height, curstep*8); - ags_updateFull(); - - sf_free(st); - sf_free(dt); - - ecp.oldstep = curstep; -} - diff --git a/src/ecopy.c b/src/ecopy.c index 4039988..e5f6557 100644 --- a/src/ecopy.c +++ b/src/ecopy.c @@ -458,23 +458,6 @@ static int eCopyArea23(int sx, int sy, int w, int h, int dx, int dy, int opt) { return key; } -static int eCopyArea24(int sx, int sy, int w, int h, int dx, int dy, int opt) { - int i, key = 0, cnt; - int waitcnt = opt == 0 ? 100 : opt; - static int slices[8]={80,70,60,48,32,16,8,4}; - - cnt = sdl_getTicks(); - for (i = 0; i < 8; i++ ) { - cnt += waitcnt; - sdl_Mosaic(sx, sy, w, h, dx, dy, slices[i]); - ags_updateArea(dx, dy, w, h); - EC_WAIT; - } - ags_copyArea(sx, sy, w, h, dx, dy); - ags_updateArea(dx, dy, w, h); - return key; -} - #define SCA25_6_SLICE 10 static int eCopyArea25(int sx, int sy, int w, int h, int dx, int dy, int opt) { int r, rr, x, xx, y, yy, key = 0, cnt; @@ -569,27 +552,6 @@ static int eCopyArea26(int sx, int sy, int w, int h, int dx, int dy, int opt) { return key; } -static void eCopyArea32(int step) { - static void *save; - static int slices[32]={4,8,12,16,20,28,36,40,44,48,56,64,72,80,88,96, - 88,80,72,64,56,48,44,40,36,28,24,20,16,12,8,4}; - - if (step == 0) { - save = ags_saveRegion(ecp.dx, ecp.dy, ecp.w, ecp.h); - return; - } - if (step == 64) { - ags_copyArea(ecp.sx, ecp.sy, ecp.w, ecp.h, ecp.dx, ecp.dy); - ags_updateArea(ecp.dx, ecp.dy, ecp.w, ecp.h); - ags_delRegion(save); - return; - } - ags_putRegion(save, ecp.dx, ecp.dy); - ags_copyArea_alphaBlend(ecp.sx, ecp.sy, ecp.w, ecp.h, ecp.dx, ecp.dy, step*4); - sdl_Mosaic(ecp.sx, ecp.sy, ecp.w, ecp.h, ecp.dx, ecp.dy, slices[step >> 1]); - ags_updateArea(ecp.dx, ecp.dy, ecp.w, ecp.h); -} - static int eCopyArea39(int sx, int sy, int w, int h, int dx, int dy, int opt) { int i,dy1,dy2,sy1,sy2, key = 0, cnt; int waitcnt = opt == 0 ? 3 : opt; @@ -864,6 +826,8 @@ static int duration(enum nact_effect effect, int opt, SDL_Rect *rect) { case NACT_EFFECT_BLIND_LR: case NACT_EFFECT_BLIND_RL: return (opt ? opt : 40) * (rect->w / 16 + 16); + case NACT_EFFECT_MOSAIC: + return (opt ? opt : 100) * 8; case NACT_EFFECT_FADEIN: case NACT_EFFECT_WHITEIN: case NACT_EFFECT_FADEOUT: @@ -871,6 +835,8 @@ static int duration(enum nact_effect effect, int opt, SDL_Rect *rect) { return opt ? opt * 32 : 1700; case NACT_EFFECT_CROSSFADE: return opt ? opt * 256 : 2700; + case NACT_EFFECT_CROSSFADE_MOSAIC: + return opt ? opt * 256 : 1400; case NACT_EFFECT_CROSSFADE_DOWN: case NACT_EFFECT_CROSSFADE_UP: return opt ? opt * (rect->h + 256) : 1150; @@ -1045,22 +1011,12 @@ void ags_eCopyArea(int sx, int sy, int w, int h, int dx, int dy, int sw, int opt case 23: ret = eCopyArea23(sx, sy, w, h, dx, dy, opt); break; - case 24: - ret = eCopyArea24(sx, sy, w, h, dx, dy, opt); - break; case 25: ret = eCopyArea25(sx, sy, w, h, dx, dy, opt); break; case 26: ret = eCopyArea26(sx, sy, w, h, dx, dy, opt); break; - case 32: - i.step_max = 64; - i.effect_time = opt == 0 ? 1400 : opt * 256; - i.cancel = cancel; - i.callback = eCopyArea32; - ags_fader(&i); - return; case 39: ret = eCopyArea39(sx, sy, w, h, dx, dy, opt); break; diff --git a/src/effect.h b/src/effect.h index 88e3a76..729669e 100644 --- a/src/effect.h +++ b/src/effect.h @@ -23,11 +23,13 @@ // Effect types of the CE command. enum nact_effect { NACT_EFFECT_BLIND_DOWN = 11, + NACT_EFFECT_MOSAIC = 24, NACT_EFFECT_FADEIN = 27, NACT_EFFECT_WHITEIN = 28, NACT_EFFECT_FADEOUT = 29, NACT_EFFECT_WHITEOUT = 30, NACT_EFFECT_CROSSFADE = 31, + NACT_EFFECT_CROSSFADE_MOSAIC = 32, NACT_EFFECT_BLIND_UP = 33, NACT_EFFECT_BLIND_UP_DOWN = 34, NACT_EFFECT_CROSSFADE_DOWN = 35, @@ -53,6 +55,7 @@ enum sact_effect { SACT_EFFECT_FADEIN = 3, SACT_EFFECT_WHITEOUT = 4, SACT_EFFECT_WHITEIN = 5, + SACT_EFFECT_CROSSFADE_MOSAIC = 6, SACT_EFFECT_BLIND_DOWN = 7, SACT_EFFECT_BLIND_LR = 8, SACT_EFFECT_BLIND_DOWN_LR = 9, @@ -90,6 +93,8 @@ enum sdl_effect_type { EFFECT_CROSSFADE_UP, EFFECT_CROSSFADE_LR, EFFECT_CROSSFADE_RL, + EFFECT_CROSSFADE_MOSAIC, + EFFECT_MOSAIC, EFFECT_LINEAR_BLUR, EFFECT_LINEAR_BLUR_VERT, EFFECT_PENTAGRAM_IN_OUT, diff --git a/src/image.c b/src/image.c index 3682ffb..9b5c930 100644 --- a/src/image.c +++ b/src/image.c @@ -325,31 +325,6 @@ void image_copy_to_alpha(agsurface_t *dib, int sx, int sy, int w, int h, int dx, copy_to_alpha(dib, sdata, ddata, w, h, flag); } -/* モザイク */ - -void image_Mosaic(SDL_Surface *dib, int sx, int sy, int w, int h, int dx, int dy, int slice) { - SDL_Rect r = {.h = slice}; - for (int y = 0; y < h; y += slice) { - if (y + slice > h) - r.h = h - y; - r.w = slice; - for (int x = 0; x < w; x += slice) { - void *src = PIXEL_AT(dib, sx + x, sy + y); - Uint32 color; - switch (dib->format->BytesPerPixel) { - case 1: color = *(BYTE *)src; break; - case 2: color = *(WORD *)src; break; - default: color = *(DWORD *)src; break; - } - r.x = dx + x; - r.y = dy + y; - if (r.x + slice > w) - r.w = w - x; - SDL_FillRect(dib, &r, color); - } - } -} - /* 16bitCGの ALPHALEVELを指定 */ BYTE *changeImage16AlphaLevel(cgdata *cg) { WORD *new_pic = malloc(sizeof(WORD) * cg->width * cg->height), *new_pic_; diff --git a/src/image.h b/src/image.h index a795899..7e7ff28 100644 --- a/src/image.h +++ b/src/image.h @@ -31,7 +31,6 @@ extern void image_setdepth(int); extern void image_copy_from_alpha(agsurface_t *dib, int sx, int sy, int w, int h, int dx, int dy, ALPHA_DIB_COPY_TYPE flag); extern void image_copy_to_alpha(agsurface_t *dib, int sx, int sy, int w, int h, int dx, int dy, ALPHA_DIB_COPY_TYPE flag); -extern void image_Mosaic(SDL_Surface *dib, int sx, int sy, int w, int h, int dx, int dy, int slice); extern BYTE *changeImage16AlphaLevel(cgdata *cg); diff --git a/src/sdl_core.h b/src/sdl_core.h index 04b9d0f..e0512aa 100644 --- a/src/sdl_core.h +++ b/src/sdl_core.h @@ -65,7 +65,6 @@ extern SDL_Rect sdl_drawString(int x, int y, const char *str_utf8, BYTE col); extern void sdl_copyArea(int sx,int sy, int w, int h, int dx, int dy); extern void sdl_copyAreaSP(int sx, int sy, int w, int h, int dx, int dy, BYTE sp); extern void sdl_drawImage8_fromData(cgdata *cg, int x, int y, int w, int h); -extern void sdl_Mosaic(int sx, int sy, int w, int h, int dx, int dy, int slice); extern void sdl_wrapColor(int sx, int sy, int w, int h, BYTE cl, int rate); extern void sdl_scaledCopyArea(int sx, int sy, int sw, int sh, int dx, int dy, int dw, int dh, int mirror); extern void sdl_zoom(int x, int y, int w, int h); diff --git a/src/sdl_draw.c b/src/sdl_draw.c index 7c1d85e..0cb7d3b 100644 --- a/src/sdl_draw.c +++ b/src/sdl_draw.c @@ -341,15 +341,6 @@ SDL_Rect sdl_drawString(int x, int y, const char *str_utf8, BYTE col) { return font_draw_glyph(x, y, str_utf8, col); } -void sdl_Mosaic(int sx, int sy, int w, int h, int dx, int dy, int slice) { - - SDL_LockSurface(sdl_dib); - - image_Mosaic(sdl_dib, sx, sy, w, h, dx, dy, slice); - - SDL_UnlockSurface(sdl_dib); -} - static void setBligtness(SDL_Surface *s, int val) { int i; Palette256 *pal = nact->sys_pal; diff --git a/src/sdl_effect.c b/src/sdl_effect.c index 15c681e..59d0eff 100644 --- a/src/sdl_effect.c +++ b/src/sdl_effect.c @@ -32,11 +32,13 @@ enum sdl_effect_type from_nact_effect(enum nact_effect effect) { switch (effect) { case NACT_EFFECT_BLIND_DOWN: return EFFECT_BLIND_DOWN; + case NACT_EFFECT_MOSAIC: return EFFECT_MOSAIC; case NACT_EFFECT_FADEIN: return EFFECT_FADEIN; case NACT_EFFECT_WHITEIN: return EFFECT_WHITEIN; case NACT_EFFECT_FADEOUT: return EFFECT_FADEOUT_FROM_NEW; case NACT_EFFECT_WHITEOUT: return EFFECT_WHITEOUT_FROM_NEW; case NACT_EFFECT_CROSSFADE: return EFFECT_CROSSFADE; + case NACT_EFFECT_CROSSFADE_MOSAIC: return EFFECT_CROSSFADE_MOSAIC; case NACT_EFFECT_BLIND_UP: return EFFECT_BLIND_UP; case NACT_EFFECT_BLIND_UP_DOWN: return EFFECT_BLIND_UP_DOWN; case NACT_EFFECT_CROSSFADE_DOWN: return EFFECT_CROSSFADE_DOWN; @@ -64,6 +66,7 @@ enum sdl_effect_type from_sact_effect(enum sact_effect effect) { case SACT_EFFECT_FADEIN: return EFFECT_FADEIN; case SACT_EFFECT_WHITEOUT: return EFFECT_WHITEOUT; case SACT_EFFECT_WHITEIN: return EFFECT_WHITEIN; + case SACT_EFFECT_CROSSFADE_MOSAIC: return EFFECT_CROSSFADE_MOSAIC; case SACT_EFFECT_BLIND_DOWN: return EFFECT_BLIND_DOWN; case SACT_EFFECT_BLIND_LR: return EFFECT_BLIND_LR; case SACT_EFFECT_BLIND_DOWN_LR: return EFFECT_BLIND_DOWN_LR; @@ -138,6 +141,11 @@ static void crossfade_free(struct sdl_effect *eff) { free(eff); } +static struct sdl_effect *fallback_effect_new(SDL_Rect *rect, SDL_Surface *old, SDL_Surface *new, enum sdl_effect_type type) { + WARNING("Effect %d is not supported in this system. Falling back to crossfade.\n", type); + return crossfade_new(rect, old, new); +} + // EFFECT_CROSSFADE_{UP,DOWN} static void crossfade_down_step(struct sdl_effect *eff, double progress); @@ -291,6 +299,95 @@ static void crossfade_animation_free(struct sdl_effect *eff) { free(eff); } +// EFFECT_MOSAIC, EFFECT_CROSSFADE_MOSAIC + +struct mosaic_effect { + struct sdl_effect eff; + SDL_Texture *tmp_old, *tmp_new, *tx_mosaic; +}; + +static void mosaic_step(struct sdl_effect *eff, double progress); +static void mosaic_free(struct sdl_effect *eff); + +static struct sdl_effect *mosaic_new(SDL_Rect *rect, SDL_Surface *old, SDL_Surface *new, enum sdl_effect_type type) { + if (!SDL_RenderTargetSupported(sdl_renderer)) + return fallback_effect_new(rect, old, new, type); + + struct mosaic_effect *eff = calloc(1, sizeof(struct mosaic_effect)); + if (!eff) + NOMEMERR(); + effect_init(&eff->eff, rect, old, new, type); + eff->tmp_old = SDL_CreateTexture(sdl_renderer, SDL_PIXELFORMAT_RGB888, SDL_TEXTUREACCESS_TARGET, rect->w, rect->h); + eff->tmp_new = SDL_CreateTexture(sdl_renderer, SDL_PIXELFORMAT_RGB888, SDL_TEXTUREACCESS_TARGET, rect->w, rect->h); + eff->tx_mosaic = SDL_CreateTexture(sdl_renderer, SDL_PIXELFORMAT_RGB888, SDL_TEXTUREACCESS_TARGET, rect->w, rect->h); + eff->eff.step = mosaic_step; + eff->eff.finish = mosaic_free; + return &eff->eff; +} + +static void mosaic(SDL_Texture *src, SDL_Texture *tmp, SDL_Texture *dst, int w, int h, double scale) { + int cx = w / 2; + int cy = h / 2; + SDL_FRect fr = { + .x = cx - cx / scale, + .y = cy - cy / scale, + .w = w / scale, + .h = h / scale, + }; + SDL_SetRenderTarget(sdl_renderer, tmp); + SDL_RenderCopyF(sdl_renderer, src, NULL, &fr); + + SDL_Rect dstr = { + .x = w * (1 - scale) / 2, + .y = h * (1 - scale) / 2, + .w = w * scale, + .h = h * scale, + }; + SDL_SetRenderTarget(sdl_renderer, dst); + +#if SDL_VERSION_ATLEAST(2, 0, 12) + SDL_SetTextureScaleMode(tmp, SDL_ScaleModeNearest); +#else + // Should be okay because nearest is the default scaling mode. +#endif + SDL_RenderCopy(sdl_renderer, tmp, NULL, &dstr); + SDL_SetRenderTarget(sdl_renderer, NULL); +} + +static void mosaic_step(struct sdl_effect *eff, double progress) { + struct mosaic_effect *this = (struct mosaic_effect *)eff; + + if (eff->type == EFFECT_MOSAIC) { + const int max_scale = 80; + int scale = (1.0 - progress) * (max_scale - 1) + 1; + mosaic(eff->tx_new, this->tmp_new, this->tx_mosaic, eff->dst_rect.w, eff->dst_rect.h, scale); + SDL_RenderCopy(sdl_renderer, this->tx_mosaic, NULL, &eff->dst_rect); + } else if (eff->type == EFFECT_CROSSFADE_MOSAIC) { + const int max_scale = 96; + double scale = (progress < 0.5 ? progress : 1.0 - progress) * 2 * (max_scale - 1) + 1; + mosaic(eff->tx_old, this->tmp_old, this->tx_mosaic, eff->dst_rect.w, eff->dst_rect.h, scale); + SDL_RenderCopy(sdl_renderer, this->tx_mosaic, NULL, &eff->dst_rect); + mosaic(eff->tx_new, this->tmp_new, this->tx_mosaic, eff->dst_rect.w, eff->dst_rect.h, scale); + SDL_SetTextureBlendMode(this->tx_mosaic, SDL_BLENDMODE_BLEND); + SDL_SetTextureAlphaMod(this->tx_mosaic, progress * 255); + SDL_RenderCopy(sdl_renderer, this->tx_mosaic, NULL, &eff->dst_rect); + SDL_SetTextureBlendMode(this->tx_mosaic, SDL_BLENDMODE_NONE); + } else { + assert(!"Cannot happen"); + } + + SDL_RenderPresent(sdl_renderer); +} + +static void mosaic_free(struct sdl_effect *eff) { + struct mosaic_effect *this = (struct mosaic_effect *)eff; + SDL_DestroyTexture(this->tmp_old); + SDL_DestroyTexture(this->tmp_new); + SDL_DestroyTexture(this->tx_mosaic); + effect_finish(&this->eff, true); + free(this); +} + // EFFECT_{FADE,WHITE}{OUT,IN} static void brightness_step(struct sdl_effect *eff, double progress); @@ -491,10 +588,8 @@ static void linear_blur_step(struct sdl_effect *eff, double progress); static void linear_blur_free(struct sdl_effect *eff); static struct sdl_effect *linear_blur_new(SDL_Rect *rect, SDL_Surface *old, SDL_Surface *new, enum sdl_effect_type type) { - if (!SDL_RenderTargetSupported(sdl_renderer)) { - WARNING("Effect %d is not supported in this system. Falling back to crossfade.\n", type); - return crossfade_new(rect, old, new); - } + if (!SDL_RenderTargetSupported(sdl_renderer)) + return fallback_effect_new(rect, old, new, type); struct linear_blur_effect *lbe = calloc(1, sizeof(struct linear_blur_effect)); if (!lbe) @@ -609,8 +704,7 @@ static struct sdl_effect *polygon_mask_new(SDL_Rect *rect, SDL_Surface *old, SDL } #endif // HAS_SDL_RenderGeometry - WARNING("Effect %d is not supported in this system. Falling back to crossfade.\n", type); - return crossfade_new(rect, old, new); + return fallback_effect_new(rect, old, new, type); } #if HAS_SDL_RenderGeometry @@ -932,6 +1026,9 @@ struct sdl_effect *sdl_effect_init(SDL_Rect *rect, agsurface_t *old, int ox, int case EFFECT_CROSSFADE_LR: case EFFECT_CROSSFADE_RL: return crossfade_animation_new(rect, sf_old, sf_new, type); + case EFFECT_MOSAIC: + case EFFECT_CROSSFADE_MOSAIC: + return mosaic_new(rect, sf_old, sf_new, type); case EFFECT_FADEOUT: case EFFECT_FADEOUT_FROM_NEW: case EFFECT_FADEIN: