sdl_effect: Implement EFFECT_ZIGZAG_CROSSFADE

This effect is hard to implement correctly without writing a custom
shader. We approximate this by combining vertical and horizontal wave
effects.
This commit is contained in:
kichikuou
2022-01-23 16:46:36 +09:00
parent 47d23d4ee7
commit eea1f9c93a
4 changed files with 88 additions and 69 deletions
+1 -2
View File
@@ -55,7 +55,6 @@ typedef struct ecopyparam ecopyparam_t;
static ecopyparam_t ecp;
#include "sprite_eupdate_perspect.c"
#include "sprite_eupdate_uneune.c"
#include "sprite_eupdate_zmbbul.c"
typedef void entrypoint (surface_t *, surface_t *);
@@ -91,7 +90,7 @@ static entrypoint *cb[39] = {
ec28_cb,
ec29_cb,
ec_dummy_cb,
ec31_cb,
sdl_effect_cb,
ec_dummy_cb,
ec_dummy_cb,
ec_dummy_cb,
-67
View File
@@ -1,67 +0,0 @@
static void uneune(surface_t *in, surface_t *out, int st) {
int r = 4 * st;
double th = 4 * st * M_PI;
int x, y, m, n;
switch(in->depth) {
case 16: {
WORD *src, *dst;
for (y = 0; y < in->height; y++) {
for (x = 0; x < in->width; x++) {
m = x + r * sin(y * th / in->height);
n = y + r * cos(x * th / in->width);
src = (WORD *)GETOFFSET_PIXEL(in, m, n);
dst = (WORD *)GETOFFSET_PIXEL(out, x, y);
if ((m > 0) && (m < in->width) && (n > 0) && (n < in->height)) {
*dst = *src;
} else {
*dst = 0;
}
}
}
}
case 24:
case 32: {
DWORD *src, *dst;
for (y = 0; y < in->height; y++) {
for (x = 0; x < in->width; x++) {
m = x + r * sin(y * th / in->height);
n = y + r * cos(x * th / in->width);
src = (DWORD *)GETOFFSET_PIXEL(in, m, n);
dst = (DWORD *)GETOFFSET_PIXEL(out, x, y);
if ((m > 0) && (m < in->width) && (n > 0) && (n < in->height)) {
*dst = *src;
} else {
*dst = 0;
}
}
}
}}
}
// うねうねクロスフェード
static void ec31_cb(surface_t *sfsrc, surface_t *sfdst) {
int curstep, maxstep;
surface_t *st, *dt;
maxstep = 32;
curstep = maxstep * (ecp.curtime - ecp.sttime)/ (ecp.edtime - ecp.sttime);
st = sf_dup2(sfsrc, FALSE, FALSE);
dt = sf_dup2(sfdst, FALSE, FALSE);
if (curstep < 16) {
uneune(sfsrc, st, curstep);
uneune(sfdst, dt, curstep);
gre_Blend(sf0, 0, 0, st, 0, 0, dt, 0, 0, st->width, st->height, curstep * 8);
} else {
uneune(sfsrc, st, 32-curstep);
uneune(sfdst, dt, 32-curstep);
gre_Blend(sf0, 0, 0, st, 0, 0, dt, 0, 0, st->width, st->height, curstep * 8);
}
sf_free(st);
sf_free(dt);
ags_updateFull();
}
+2
View File
@@ -72,6 +72,7 @@ enum sact_effect {
SACT_EFFECT_ROTATE_IN = 21,
SACT_EFFECT_ROTATE_OUT_CW = 22,
SACT_EFFECT_ROTATE_IN_CW = 23,
SACT_EFFECT_ZIGZAG_CROSSFADE = 31,
};
// Internal effect numbers.
@@ -110,6 +111,7 @@ enum sdl_effect_type {
EFFECT_ROTATE_IN,
EFFECT_ROTATE_OUT_CW,
EFFECT_ROTATE_IN_CW,
EFFECT_ZIGZAG_CROSSFADE,
};
enum sdl_effect_type from_nact_effect(enum nact_effect effect);
+85
View File
@@ -83,6 +83,7 @@ enum sdl_effect_type from_sact_effect(enum sact_effect effect) {
case SACT_EFFECT_ROTATE_IN: return EFFECT_ROTATE_IN;
case SACT_EFFECT_ROTATE_OUT_CW: return EFFECT_ROTATE_OUT_CW;
case SACT_EFFECT_ROTATE_IN_CW: return EFFECT_ROTATE_IN_CW;
case SACT_EFFECT_ZIGZAG_CROSSFADE: return EFFECT_ZIGZAG_CROSSFADE;
default: return EFFECT_INVALID;
}
}
@@ -1004,6 +1005,88 @@ static void rotate_free(struct sdl_effect *eff) {
free(eff);
}
// EFFECT_ZIGZAG_CROSSFADE
struct zigzag_crossfade_effect {
struct sdl_effect eff;
SDL_Texture *tmp1, *tmp2;
};
static void zigzag_crossfade_step(struct sdl_effect *eff, double progress);
static void zigzag_crossfade_free(struct sdl_effect *eff);
static struct sdl_effect *zigzag_crossfade_new(SDL_Rect *rect, SDL_Surface *old, SDL_Surface *new) {
if (!SDL_RenderTargetSupported(sdl_renderer))
return fallback_effect_new(rect, old, new, EFFECT_ZIGZAG_CROSSFADE);
struct zigzag_crossfade_effect *eff = calloc(1, sizeof(struct zigzag_crossfade_effect));
if (!eff)
NOMEMERR();
effect_init(&eff->eff, rect, old, new, EFFECT_ZIGZAG_CROSSFADE);
eff->tmp1 = SDL_CreateTexture(sdl_renderer, SDL_PIXELFORMAT_RGB888, SDL_TEXTUREACCESS_TARGET, rect->w, rect->h);
eff->tmp2 = SDL_CreateTexture(sdl_renderer, SDL_PIXELFORMAT_RGB888, SDL_TEXTUREACCESS_TARGET, rect->w, rect->h);
eff->eff.step = zigzag_crossfade_step;
eff->eff.finish = zigzag_crossfade_free;
return &eff->eff;
}
static void wave_warp_h(SDL_Texture *src, SDL_Texture *dst, int w, int h, double amplitude, double length, double phase) {
SDL_SetRenderTarget(sdl_renderer, dst);
SDL_SetRenderDrawColor(sdl_renderer, 0, 0, 0, 255);
SDL_RenderClear(sdl_renderer);
SDL_Rect sr = {0, 0, w, 1};
SDL_Rect dr = {0, 0, w, 1};
for (int y = 0; y < h; y++) {
sr.y = dr.y = y;
dr.x = sin(phase + y * (2 * M_PI / 360 * length)) * amplitude;
SDL_RenderCopy(sdl_renderer, src, &sr, &dr);
}
SDL_SetRenderTarget(sdl_renderer, NULL);
}
static void wave_warp_v(SDL_Texture *src, SDL_Texture *dst, int w, int h, double amplitude, double length, double phase) {
SDL_SetRenderTarget(sdl_renderer, dst);
SDL_SetRenderDrawColor(sdl_renderer, 0, 0, 0, 255);
SDL_RenderClear(sdl_renderer);
SDL_Rect sr = {0, 0, 1, h};
SDL_Rect dr = {0, 0, 1, h};
for (int x = 0; x < w; x++) {
sr.x = dr.x = x;
dr.y = sin(phase + x * (2 * M_PI / 360 * length)) * amplitude;
SDL_RenderCopy(sdl_renderer, src, &sr, &dr);
}
SDL_SetRenderTarget(sdl_renderer, NULL);
}
static void zigzag_crossfade_step(struct sdl_effect *eff, double progress) {
struct zigzag_crossfade_effect *this = (struct zigzag_crossfade_effect *)eff;
double amp = (progress < 0.5 ? progress : 1.0 - progress) * 80;
double len = (progress < 0.5 ? progress : 1.0 - progress) * 20;
double phase = progress * 10;
wave_warp_h(eff->tx_old, this->tmp1, eff->dst_rect.w, eff->dst_rect.h, amp, len, phase);
wave_warp_v(this->tmp1, this->tmp2, eff->dst_rect.w, eff->dst_rect.h, amp, len, phase);
SDL_RenderCopy(sdl_renderer, this->tmp2, NULL, &eff->dst_rect);
wave_warp_h(eff->tx_new, this->tmp1, eff->dst_rect.w, eff->dst_rect.h, amp, len, phase);
wave_warp_v(this->tmp1, this->tmp2, eff->dst_rect.w, eff->dst_rect.h, amp, len, phase);
SDL_SetTextureBlendMode(this->tmp2, SDL_BLENDMODE_BLEND);
SDL_SetTextureAlphaMod(this->tmp2, progress * 255);
SDL_RenderCopy(sdl_renderer, this->tmp2, NULL, &eff->dst_rect);
SDL_SetTextureBlendMode(this->tmp2, SDL_BLENDMODE_NONE);
SDL_RenderPresent(sdl_renderer);
}
static void zigzag_crossfade_free(struct sdl_effect *eff) {
struct zigzag_crossfade_effect *this = (struct zigzag_crossfade_effect *)eff;
SDL_DestroyTexture(this->tmp1);
SDL_DestroyTexture(this->tmp2);
effect_finish(&this->eff, true);
free(this);
}
static SDL_Surface *create_surface(agsurface_t *as, int x, int y, int w, int h) {
SDL_Surface *sf = SDL_CreateRGBSurfaceWithFormat(0, w, h, 32, SDL_PIXELFORMAT_RGB888);
@@ -1066,6 +1149,8 @@ struct sdl_effect *sdl_effect_init(SDL_Rect *rect, agsurface_t *old, int ox, int
case EFFECT_ROTATE_IN_CW:
case EFFECT_ZOOM_IN:
return rotate_new(rect, sf_old, sf_new, type);
case EFFECT_ZIGZAG_CROSSFADE:
return zigzag_crossfade_new(rect, sf_old, sf_new);
default:
WARNING("Unknown effect %d\n", type);
return crossfade_new(rect, sf_old, sf_new);