diff --git a/src/ecopy.c b/src/ecopy.c index 6490f37..929b833 100644 --- a/src/ecopy.c +++ b/src/ecopy.c @@ -329,7 +329,7 @@ void ags_eCopyArea(int sx, int sy, int w, int h, int dx, int dy, int sw, int opt enum sdl_effect_type sdl_effect = from_nact_effect(sw); if (sdl_effect != EFFECT_INVALID) { SDL_Rect rect = { dx - nact->ags.view_area.x, dy - nact->ags.view_area.y, w, h }; - // Note that we specify NULL (which means sdl_display) for the old + // Note that we specify NULL (which means sdl_texture) for the old // surface rather than sdl_getDIB(). This is to use the current display // contents, not reflecting uncommitted palette changes. struct sdl_effect *eff = sdl_effect_init(&rect, NULL, rect.x, rect.y, sdl_getDIB(), sx, sy, sdl_effect); diff --git a/src/sdl_core.h b/src/sdl_core.h index 5c605dc..49f50bc 100644 --- a/src/sdl_core.h +++ b/src/sdl_core.h @@ -82,7 +82,7 @@ extern void sdl_putRegion(void *src, int x, int y); extern void sdl_restoreRegion(void *src, int x, int y); extern void* sdl_saveRegion(int x, int y, int w, int h); extern void sdl_delRegion(void *src); -extern SDL_Surface *com2surface(agsurface_t *s); +extern SDL_Surface *com2surface(agsurface_t *s, int x, int y, int w, int h); /* Effects */ struct sdl_effect; diff --git a/src/sdl_draw.c b/src/sdl_draw.c index 423a118..49d30d9 100644 --- a/src/sdl_draw.c +++ b/src/sdl_draw.c @@ -59,7 +59,6 @@ static Uint32 palette_color(uint8_t c) { void sdl_updateScreen(void) { if (!sdl_dirty) return; - SDL_UpdateTexture(sdl_texture, NULL, sdl_display->pixels, sdl_display->pitch); SDL_RenderClear(sdl_renderer); SDL_RenderCopy(sdl_renderer, sdl_texture, NULL, NULL); SDL_RenderPresent(sdl_renderer); @@ -104,21 +103,31 @@ void sdl_wait_vsync() { } /* off-screen の指定領域を Main Window へ転送 */ -void sdl_updateArea(MyRectangle *src, MyPoint *dst) { - SDL_Rect rect_d = {dst->x, dst->y, src->w, src->h}; - - SDL_BlitSurface(sdl_dib, src, sdl_display, &rect_d); - +void sdl_updateArea(MyRectangle *rect, MyPoint *dst) { + SDL_Rect rs = {0, 0, sdl_dib->w, sdl_dib->h}; + if (!SDL_IntersectRect(rect, &rs, &rs)) + return; + int dx = dst->x + (rs.x - rect->x); + int dy = dst->y + (rs.y - rect->y); + SDL_Rect rd = {dx, dy, rs.w, rs.h}; + if (!SDL_IntersectRect(&rd, &(SDL_Rect){0, 0, view_w, view_h}, &rd)) + return; + rs.x += rd.x - dx; + rs.y += rd.y - dy; + rs.w = rd.w; + rs.h = rd.h; + + SDL_Surface *sf; + SDL_LockTextureToSurface(sdl_texture, &rd, &sf); + SDL_BlitSurface(sdl_dib, &rs, sf, NULL); + SDL_UnlockTexture(sdl_texture); + sdl_dirty = true; } /* 全画面更新 */ void sdl_updateAll(MyRectangle *view_rect) { - SDL_Rect rect = {0, 0, view_w, view_h}; - - SDL_BlitSurface(sdl_dib, view_rect, sdl_display, &rect); - - sdl_dirty = true; + sdl_updateArea(view_rect, &(MyPoint){0, 0}); } /* Color の複数個指定 */ @@ -297,9 +306,9 @@ SDL_Rect sdl_floodFill(int x, int y, int c) { } } -SDL_Surface *com2surface(agsurface_t *s) { - return SDL_CreateRGBSurfaceFrom( - s->pixel, s->width, s->height, s->depth, s->bytes_per_line, 0, 0, 0, 0); +SDL_Surface *com2surface(agsurface_t *s, int x, int y, int w, int h) { + uint8_t *pixels = s->pixel + y * s->bytes_per_line + x * s->bytes_per_pixel; + return SDL_CreateRGBSurfaceFrom(pixels, w, h, s->depth, s->bytes_per_line, 0, 0, 0, 0); } int sdl_nearest_color(int r, int g, int b) { diff --git a/src/sdl_effect.c b/src/sdl_effect.c index 8a4cee7..9b49f5c 100644 --- a/src/sdl_effect.c +++ b/src/sdl_effect.c @@ -126,28 +126,78 @@ enum sdl_effect_type from_sact_effect(enum sact_effect effect) { } } +typedef struct { + SDL_Texture *tx; + SDL_Rect rect; +} EffectTexture; + +static SDL_Surface *create_surface_view(SDL_Surface *sf, int x, int y, int w, int h) { + uint8_t *pixels = sf->pixels; + pixels += y * sf->pitch + x * sf->format->BytesPerPixel; + SDL_Surface *view = SDL_CreateRGBSurfaceWithFormatFrom( + pixels, w, h, sf->format->BitsPerPixel, sf->pitch, sf->format->format); + return view; +} + +static EffectTexture *create_effect_texture(agsurface_t *as, int x, int y, int w, int h) { + EffectTexture *t = calloc(1, sizeof(EffectTexture)); + if (!as) { + t->tx = sdl_texture; + t->rect = (SDL_Rect){ x, y, w, h }; + } else { + SDL_Surface *sf = (as == sdl_dibinfo) + ? create_surface_view(sdl_dib, x, y, w, h) + : com2surface(as, x, y, w, h); + t->tx = SDL_CreateTextureFromSurface(sdl_renderer, sf); + SDL_FreeSurface(sf); + t->rect = (SDL_Rect){ 0, 0, w, h }; + } + return t; +} + +static EffectTexture *create_effect_texture_from_surface(SDL_Surface *sf) { + EffectTexture *t = calloc(1, sizeof(EffectTexture)); + t->tx = SDL_CreateTextureFromSurface(sdl_renderer, sf); + t->rect = (SDL_Rect){ 0, 0, sf->w, sf->h }; + return t; +} + +static void destroy_effect_texture(EffectTexture *t) { + if (!t) + return; + if (t->tx && t->tx != sdl_texture) + SDL_DestroyTexture(t->tx); + free(t); +} + +static int render_effect_texture(EffectTexture *t, const SDL_Rect* srcrect, const SDL_Rect* dstrect) { + SDL_Rect real_srcrect; + if (!srcrect) { + real_srcrect = t->rect; + } else { + real_srcrect = *srcrect; + real_srcrect.x += t->rect.x; + real_srcrect.y += t->rect.y; + } + return SDL_RenderCopy(sdl_renderer, t->tx, &real_srcrect, dstrect); +} + struct sdl_effect { void (*step)(struct sdl_effect *this, float progress); void (*finish)(struct sdl_effect *this); enum sdl_effect_type type; SDL_Rect dst_rect; bool is_fullscreen; - SDL_Texture *tx_old, *tx_new; + EffectTexture *tx_old, *tx_new; }; -static void effect_init(struct sdl_effect *eff, SDL_Rect *rect, SDL_Surface *old, SDL_Surface *new, enum sdl_effect_type type) { +static void effect_init(struct sdl_effect *eff, SDL_Rect *rect, EffectTexture *old, EffectTexture *new, enum sdl_effect_type type) { eff->type = type; eff->dst_rect = *rect; eff->is_fullscreen = rect->x == 0 && rect->y == 0 - && rect->w == sdl_display->w && rect->h == sdl_display->h; - if (old) { - eff->tx_old = SDL_CreateTextureFromSurface(sdl_renderer, old); - SDL_FreeSurface(old); - } - if (new) { - eff->tx_new = SDL_CreateTextureFromSurface(sdl_renderer, new); - SDL_FreeSurface(new); - } + && rect->w == view_w && rect->h == view_h; + eff->tx_old = old; + eff->tx_new = new; if (!eff->is_fullscreen) sdl_updateScreen(); // Flush pending display changes. @@ -158,13 +208,11 @@ static void effect_finish(struct sdl_effect *eff, bool present) { SDL_RenderClear(sdl_renderer); if (!eff->is_fullscreen) SDL_RenderCopy(sdl_renderer, sdl_texture, NULL, NULL); - SDL_RenderCopy(sdl_renderer, eff->tx_new, NULL, &eff->dst_rect); + render_effect_texture(eff->tx_new, NULL, &eff->dst_rect); SDL_RenderPresent(sdl_renderer); } - if (eff->tx_old) - SDL_DestroyTexture(eff->tx_old); - if (eff->tx_new) - SDL_DestroyTexture(eff->tx_new); + destroy_effect_texture(eff->tx_old); + destroy_effect_texture(eff->tx_new); } static inline void flip_rect_h(SDL_Rect *r, int w) { @@ -194,7 +242,7 @@ static inline void move_rect(SDL_Rect *r, int off_x, int off_y) { static void crossfade_step(struct sdl_effect *eff, float progress); static void crossfade_free(struct sdl_effect *eff); -static struct sdl_effect *crossfade_new(SDL_Rect *rect, SDL_Surface *old, SDL_Surface *new) { +static struct sdl_effect *crossfade_new(SDL_Rect *rect, EffectTexture *old, EffectTexture *new) { struct sdl_effect *eff = calloc(1, sizeof(struct sdl_effect)); if (!eff) NOMEMERR(); @@ -205,11 +253,12 @@ static struct sdl_effect *crossfade_new(SDL_Rect *rect, SDL_Surface *old, SDL_Su } static void crossfade_step(struct sdl_effect *eff, float progress) { - SDL_RenderCopy(sdl_renderer, eff->tx_old, NULL, &eff->dst_rect); - SDL_SetTextureBlendMode(eff->tx_new, SDL_BLENDMODE_BLEND); - SDL_SetTextureAlphaMod(eff->tx_new, progress * 255); - SDL_RenderCopy(sdl_renderer, eff->tx_new, NULL, &eff->dst_rect); - SDL_SetTextureBlendMode(eff->tx_new, SDL_BLENDMODE_NONE); + render_effect_texture(eff->tx_old, NULL, &eff->dst_rect); + SDL_SetTextureBlendMode(eff->tx_new->tx, SDL_BLENDMODE_BLEND); + SDL_SetTextureAlphaMod(eff->tx_new->tx, progress * 255); + render_effect_texture(eff->tx_new, NULL, &eff->dst_rect); + SDL_SetTextureAlphaMod(eff->tx_new->tx, 255); + SDL_SetTextureBlendMode(eff->tx_new->tx, SDL_BLENDMODE_NONE); SDL_RenderPresent(sdl_renderer); } @@ -218,7 +267,7 @@ 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) { +static struct sdl_effect *fallback_effect_new(SDL_Rect *rect, EffectTexture *old, EffectTexture *new, enum sdl_effect_type type) { WARNING("Effect %d is not supported in this system. Falling back to crossfade.", type); return crossfade_new(rect, old, new); } @@ -228,7 +277,7 @@ static struct sdl_effect *fallback_effect_new(SDL_Rect *rect, SDL_Surface *old, static void crossfade_animation_step(struct sdl_effect *eff, float progress); static void crossfade_animation_free(struct sdl_effect *eff); -static struct sdl_effect *crossfade_animation_new(SDL_Rect *rect, SDL_Surface *old, SDL_Surface *new, enum sdl_effect_type type) { +static struct sdl_effect *crossfade_animation_new(SDL_Rect *rect, EffectTexture *old, EffectTexture *new, enum sdl_effect_type type) { struct sdl_effect *eff = calloc(1, sizeof(struct sdl_effect)); if (!eff) NOMEMERR(); @@ -238,7 +287,7 @@ static struct sdl_effect *crossfade_animation_new(SDL_Rect *rect, SDL_Surface *o return eff; } -static void crossfade_animation_step_sub(SDL_Rect *rect, SDL_Texture *tx, int tx_x, int tx_y, float progress, int band_width, bool lr, bool flip) { +static void crossfade_animation_step_sub(SDL_Rect *rect, EffectTexture *tx, int tx_x, int tx_y, float progress, int band_width, bool lr, bool flip) { int maxstep = (lr ? rect->w : rect->h) + band_width; int band_top = maxstep * progress - band_width; if (band_top > 0) { @@ -253,10 +302,10 @@ static void crossfade_animation_step_sub(SDL_Rect *rect, SDL_Texture *tx, int tx SDL_Rect dr = sr; move_rect(&sr, tx_x, tx_y); move_rect(&dr, rect->x, rect->y); - SDL_RenderCopy(sdl_renderer, tx, &sr, &dr); + render_effect_texture(tx, &sr, &dr); } - SDL_SetTextureBlendMode(tx, SDL_BLENDMODE_BLEND); + SDL_SetTextureBlendMode(tx->tx, SDL_BLENDMODE_BLEND); for (int i = 0; i < band_width; i++) { SDL_Rect sr; if (lr) { @@ -277,14 +326,15 @@ static void crossfade_animation_step_sub(SDL_Rect *rect, SDL_Texture *tx, int tx SDL_Rect dr = sr; move_rect(&sr, tx_x, tx_y); move_rect(&dr, rect->x, rect->y); - SDL_SetTextureAlphaMod(tx, 255 - (i + 1) * (256 / band_width)); - SDL_RenderCopy(sdl_renderer, tx, &sr, &dr); + SDL_SetTextureAlphaMod(tx->tx, 255 - (i + 1) * (256 / band_width)); + render_effect_texture(tx, &sr, &dr); } - SDL_SetTextureBlendMode(tx, SDL_BLENDMODE_NONE); + SDL_SetTextureAlphaMod(tx->tx, 255); + SDL_SetTextureBlendMode(tx->tx, SDL_BLENDMODE_NONE); } static void crossfade_animation_step(struct sdl_effect *eff, float progress) { - SDL_RenderCopy(sdl_renderer, eff->tx_old, NULL, &eff->dst_rect); + render_effect_texture(eff->tx_old, NULL, &eff->dst_rect); switch (eff->type) { case EFFECT_CROSSFADE_DOWN: @@ -343,7 +393,7 @@ struct mosaic_effect { static void mosaic_step(struct sdl_effect *eff, float 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) { +static struct sdl_effect *mosaic_new(SDL_Rect *rect, EffectTexture *old, EffectTexture *new, enum sdl_effect_type type) { if (!SDL_RenderTargetSupported(sdl_renderer)) return fallback_effect_new(rect, old, new, type); @@ -359,7 +409,7 @@ static struct sdl_effect *mosaic_new(SDL_Rect *rect, SDL_Surface *old, SDL_Surfa return &eff->eff; } -static void mosaic(SDL_Texture *src, SDL_Texture *tmp, SDL_Texture *dst, int w, int h, float scale) { +static void mosaic(EffectTexture *src, SDL_Texture *tmp, SDL_Texture *dst, int w, int h, float scale) { int cx = w / 2; int cy = h / 2; SDL_FRect fr = { @@ -369,7 +419,7 @@ static void mosaic(SDL_Texture *src, SDL_Texture *tmp, SDL_Texture *dst, int w, .h = h / scale, }; SDL_SetRenderTarget(sdl_renderer, tmp); - SDL_RenderCopyF(sdl_renderer, src, NULL, &fr); + SDL_RenderCopyF(sdl_renderer, src->tx, &src->rect, &fr); SDL_Rect dstr = { .x = w * (1 - scale) / 2, @@ -427,7 +477,7 @@ static void mosaic_free(struct sdl_effect *eff) { static void brightness_step(struct sdl_effect *eff, float progress); static void brightness_free(struct sdl_effect *eff); -static struct sdl_effect *brightness_new(SDL_Rect *rect, SDL_Surface *old, SDL_Surface *new, enum sdl_effect_type type) { +static struct sdl_effect *brightness_new(SDL_Rect *rect, EffectTexture *old, EffectTexture *new, enum sdl_effect_type type) { struct sdl_effect *eff = calloc(1, sizeof(struct sdl_effect)); if (!eff) NOMEMERR(); @@ -438,7 +488,7 @@ static struct sdl_effect *brightness_new(SDL_Rect *rect, SDL_Surface *old, SDL_S } static void brightness_step(struct sdl_effect *eff, float progress) { - SDL_Texture *texture; + EffectTexture *texture; int color; int alpha; switch (eff->type) { @@ -475,7 +525,7 @@ static void brightness_step(struct sdl_effect *eff, float progress) { default: assert(!"Cannot happen"); } - SDL_RenderCopy(sdl_renderer, texture, NULL, &eff->dst_rect); + render_effect_texture(texture, NULL, &eff->dst_rect); SDL_SetRenderDrawBlendMode(sdl_renderer, SDL_BLENDMODE_BLEND); SDL_SetRenderDrawColor(sdl_renderer, color, color, color, alpha); SDL_RenderFillRect(sdl_renderer, &eff->dst_rect); @@ -494,7 +544,7 @@ static void brightness_free(struct sdl_effect *eff) { static void dithering_fade_step(struct sdl_effect *eff, float progress); static void dithering_fade_free(struct sdl_effect *eff); -static SDL_Texture *create_dither_pattern_texture(int w, int h, int val) { +static EffectTexture *create_dither_pattern_texture(int w, int h, int val) { SDL_PixelFormat *fmt = SDL_AllocFormat(SDL_PIXELFORMAT_ARGB8888); Uint32 col = SDL_MapRGBA(fmt, val, val, val, SDL_ALPHA_OPAQUE); SDL_FreeFormat(fmt); @@ -508,35 +558,37 @@ static SDL_Texture *create_dither_pattern_texture(int w, int h, int val) { row[x] = col; } - SDL_Texture *tx = SDL_CreateTexture(sdl_renderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STATIC, w, h); - SDL_UpdateTexture(tx, NULL, pixels, w * 4); + EffectTexture *t = calloc(1, sizeof(EffectTexture)); + t->tx = SDL_CreateTexture(sdl_renderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STATIC, w, h); + SDL_UpdateTexture(t->tx, NULL, pixels, w * 4); free(pixels); - SDL_SetTextureBlendMode(tx, SDL_BLENDMODE_BLEND); - return tx; + SDL_SetTextureBlendMode(t->tx, SDL_BLENDMODE_BLEND); + t->rect = (SDL_Rect){ 0, 0, w, h }; + return t; } -static struct sdl_effect *dithering_fade_new(SDL_Rect *rect, SDL_Surface *old, SDL_Surface *new, enum sdl_effect_type type) { +static struct sdl_effect *dithering_fade_new(SDL_Rect *rect, EffectTexture *old, EffectTexture *new, enum sdl_effect_type type) { struct sdl_effect *eff = calloc(1, sizeof(struct sdl_effect)); if (!eff) NOMEMERR(); switch (type) { case EFFECT_DITHERING_FADEOUT: - SDL_FreeSurface(new); + destroy_effect_texture(new); effect_init(eff, rect, old, NULL, type); eff->tx_new = create_dither_pattern_texture(rect->w, rect->h, 0); break; case EFFECT_DITHERING_FADEIN: - SDL_FreeSurface(old); + destroy_effect_texture(old); effect_init(eff, rect, new, NULL, type); eff->tx_new = create_dither_pattern_texture(rect->w, rect->h, 0); break; case EFFECT_DITHERING_WHITEOUT: - SDL_FreeSurface(new); + destroy_effect_texture(new); effect_init(eff, rect, old, NULL, type); eff->tx_new = create_dither_pattern_texture(rect->w, rect->h, 255); break; case EFFECT_DITHERING_WHITEIN: - SDL_FreeSurface(old); + destroy_effect_texture(old); effect_init(eff, rect, new, NULL, type); eff->tx_new = create_dither_pattern_texture(rect->w, rect->h, 255); break; @@ -552,7 +604,7 @@ static void dithering_fade_step(struct sdl_effect *eff, float progress) { static const int dither_x[16] = {0,2,2,0,1,3,3,1,1,3,3,1,0,2,2,0}; static const int dither_y[16] = {0,2,0,2,1,3,1,3,0,2,0,2,1,3,1,3}; - SDL_RenderCopy(sdl_renderer, eff->tx_old, NULL, &eff->dst_rect); + render_effect_texture(eff->tx_old, NULL, &eff->dst_rect); if (eff->type == EFFECT_DITHERING_FADEIN || eff->type == EFFECT_DITHERING_WHITEIN) progress = 1.f - progress; @@ -563,17 +615,20 @@ static void dithering_fade_step(struct sdl_effect *eff, float progress) { for (int i = 0; i < level; i++) { dr.x = eff->dst_rect.x + dither_x[i]; dr.y = eff->dst_rect.y + dither_y[i]; - SDL_RenderCopy(sdl_renderer, eff->tx_new, NULL, &dr); + render_effect_texture(eff->tx_new, NULL, &dr); } SDL_RenderPresent(sdl_renderer); } static void dithering_fade_free(struct sdl_effect *eff) { - if (eff->type == EFFECT_DITHERING_FADEOUT) - SDL_FillRect(sdl_display, &eff->dst_rect, SDL_MapRGB(sdl_display->format, 0, 0, 0)); - else if (eff->type == EFFECT_DITHERING_WHITEOUT) - SDL_FillRect(sdl_display, &eff->dst_rect, SDL_MapRGB(sdl_display->format, 255, 255, 255)); + if (eff->type == EFFECT_DITHERING_FADEOUT) { + SDL_SetRenderDrawColor(sdl_renderer, 0, 0, 0, 255); + SDL_RenderFillRect(sdl_renderer, &eff->dst_rect); + } else if (eff->type == EFFECT_DITHERING_WHITEOUT) { + SDL_SetRenderDrawColor(sdl_renderer, 255, 255, 255, 255); + SDL_RenderFillRect(sdl_renderer, &eff->dst_rect); + } effect_finish(eff, false); free(eff); } @@ -583,7 +638,7 @@ static void dithering_fade_free(struct sdl_effect *eff) { 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) { +static struct sdl_effect *pan_in_new(SDL_Rect *rect, EffectTexture *old, EffectTexture *new, enum sdl_effect_type type) { struct sdl_effect *eff = calloc(1, sizeof(struct sdl_effect)); if (!eff) NOMEMERR(); @@ -594,7 +649,7 @@ static struct sdl_effect *pan_in_new(SDL_Rect *rect, SDL_Surface *old, SDL_Surfa } static void pan_in_step(struct sdl_effect *eff, float progress) { - SDL_RenderCopy(sdl_renderer, eff->tx_old, NULL, &eff->dst_rect); + render_effect_texture(eff->tx_old, NULL, &eff->dst_rect); int h = eff->dst_rect.h * progress; SDL_Rect sr = { 0, 0, eff->dst_rect.w, h }; @@ -605,7 +660,7 @@ static void pan_in_step(struct sdl_effect *eff, float progress) { } else { dr.y += eff->dst_rect.h - h; } - SDL_RenderCopy(sdl_renderer, eff->tx_new, &sr, &dr); + render_effect_texture(eff->tx_new, &sr, &dr); SDL_RenderPresent(sdl_renderer); } @@ -620,7 +675,7 @@ static void pan_in_free(struct sdl_effect *eff) { 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) { +static struct sdl_effect *skip_line_new(SDL_Rect *rect, EffectTexture *old, EffectTexture *new, enum sdl_effect_type type) { struct sdl_effect *eff = calloc(1, sizeof(struct sdl_effect)); if (!eff) NOMEMERR(); @@ -631,7 +686,7 @@ static struct sdl_effect *skip_line_new(SDL_Rect *rect, SDL_Surface *old, SDL_Su } static void skip_line_step(struct sdl_effect *eff, float progress) { - SDL_RenderCopy(sdl_renderer, eff->tx_old, NULL, &eff->dst_rect); + render_effect_texture(eff->tx_old, NULL, &eff->dst_rect); if (eff->type == EFFECT_SKIP_LINE_UP_DOWN) { int h = eff->dst_rect.h * progress; @@ -643,13 +698,13 @@ static void skip_line_step(struct sdl_effect *eff, float progress) { 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); + render_effect_texture(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); + render_effect_texture(eff->tx_new, &sr, &dr); } } else { int w = eff->dst_rect.w * progress; @@ -661,13 +716,13 @@ static void skip_line_step(struct sdl_effect *eff, float progress) { 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); + render_effect_texture(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); + render_effect_texture(eff->tx_new, &sr, &dr); } } @@ -684,7 +739,7 @@ static void skip_line_free(struct sdl_effect *eff) { static void wipe_step(struct sdl_effect *eff, float progress); static void wipe_free(struct sdl_effect *eff); -static struct sdl_effect *wipe_new(SDL_Rect *rect, SDL_Surface *old, SDL_Surface *new, enum sdl_effect_type type) { +static struct sdl_effect *wipe_new(SDL_Rect *rect, EffectTexture *old, EffectTexture *new, enum sdl_effect_type type) { struct sdl_effect *eff = calloc(1, sizeof(struct sdl_effect)); if (!eff) NOMEMERR(); @@ -695,8 +750,8 @@ static struct sdl_effect *wipe_new(SDL_Rect *rect, SDL_Surface *old, SDL_Surface } static void wipe_step(struct sdl_effect *eff, float progress) { - SDL_Texture *bg = eff->tx_old; - SDL_Texture *fg = eff->tx_new; + EffectTexture *bg = eff->tx_old; + EffectTexture *fg = eff->tx_new; if (eff->type == EFFECT_WIPE_RL || eff->type == EFFECT_WIPE_UP || eff->type == EFFECT_WIPE_IN || @@ -707,7 +762,7 @@ static void wipe_step(struct sdl_effect *eff, float progress) { progress = 1.f - progress; } - SDL_RenderCopy(sdl_renderer, bg, NULL, &eff->dst_rect); + render_effect_texture(bg, NULL, &eff->dst_rect); SDL_Rect sr = { 0, 0, eff->dst_rect.w, eff->dst_rect.h }; SDL_Rect dr = eff->dst_rect; @@ -743,7 +798,7 @@ static void wipe_step(struct sdl_effect *eff, float progress) { default: assert(!"Cannot happen"); } - SDL_RenderCopy(sdl_renderer, fg, &sr, &dr); + render_effect_texture(fg, &sr, &dr); SDL_RenderPresent(sdl_renderer); } @@ -758,7 +813,7 @@ static void wipe_free(struct sdl_effect *eff) { static void circle_wipe_step(struct sdl_effect *eff, float progress); static void circle_wipe_free(struct sdl_effect *eff); -static struct sdl_effect *circle_wipe_new(SDL_Rect *rect, SDL_Surface *old, SDL_Surface *new, enum sdl_effect_type type) { +static struct sdl_effect *circle_wipe_new(SDL_Rect *rect, EffectTexture *old, EffectTexture *new, enum sdl_effect_type type) { struct sdl_effect *eff = calloc(1, sizeof(struct sdl_effect)); if (!eff) NOMEMERR(); @@ -769,14 +824,14 @@ static struct sdl_effect *circle_wipe_new(SDL_Rect *rect, SDL_Surface *old, SDL_ } static void circle_wipe_step(struct sdl_effect *eff, float progress) { - SDL_Texture *bg = eff->tx_old; - SDL_Texture *fg = eff->tx_new; + EffectTexture *bg = eff->tx_old; + EffectTexture *fg = eff->tx_new; if (eff->type == EFFECT_CIRCLE_WIPE_IN) { bg = eff->tx_new; fg = eff->tx_old; progress = 1 - progress; } - SDL_RenderCopy(sdl_renderer, bg, NULL, &eff->dst_rect); + render_effect_texture(bg, NULL, &eff->dst_rect); int hw = eff->dst_rect.w / 2; int hh = eff->dst_rect.h / 2; @@ -789,7 +844,7 @@ static void circle_wipe_step(struct sdl_effect *eff, float progress) { if (y*y + x*x <= r*r) { SDL_Rect sr = {hw + x, hh + y, -2*x, 1}; SDL_Rect dr = {eff->dst_rect.x + hw + x, eff->dst_rect.y + hh + y, -2*x, 1}; - SDL_RenderCopy(sdl_renderer, fg, &sr, &dr); + render_effect_texture(fg, &sr, &dr); break; } } @@ -808,7 +863,7 @@ static void circle_wipe_free(struct sdl_effect *eff) { static void blind_step(struct sdl_effect *eff, float progress); static void blind_free(struct sdl_effect *eff); -static struct sdl_effect *blind_new(SDL_Rect *rect, SDL_Surface *old, SDL_Surface *new, enum sdl_effect_type type) { +static struct sdl_effect *blind_new(SDL_Rect *rect, EffectTexture *old, EffectTexture *new, enum sdl_effect_type type) { struct sdl_effect *eff = calloc(1, sizeof(struct sdl_effect)); if (!eff) NOMEMERR(); @@ -818,7 +873,7 @@ static struct sdl_effect *blind_new(SDL_Rect *rect, SDL_Surface *old, SDL_Surfac return eff; } -static void blind_vstep(float progress, SDL_Rect *rect, SDL_Texture *tx_new, int offset_y, bool flip) { +static void blind_vstep(float progress, SDL_Rect *rect, EffectTexture *tx_new, int offset_y, bool flip) { const int N = 16; int nr_bands = rect->h / N + N - 1; @@ -834,7 +889,7 @@ static void blind_vstep(float progress, SDL_Rect *rect, SDL_Texture *tx_new, int SDL_Rect dr = sr; move_rect(&dr, rect->x, rect->y); sr.y += offset_y; - SDL_RenderCopy(sdl_renderer, tx_new, &sr, &dr); + render_effect_texture(tx_new, &sr, &dr); } for (int i = 1; i < N; i++) { int y = (step - i) * N; @@ -846,14 +901,14 @@ static void blind_vstep(float progress, SDL_Rect *rect, SDL_Texture *tx_new, int SDL_Rect dr = sr; move_rect(&dr, rect->x, rect->y); sr.y += offset_y; - SDL_RenderCopy(sdl_renderer, tx_new, &sr, &dr); + render_effect_texture(tx_new, &sr, &dr); } } static void blind_step(struct sdl_effect *eff, float progress) { const int N = 16; - SDL_RenderCopy(sdl_renderer, eff->tx_old, NULL, &eff->dst_rect); + render_effect_texture(eff->tx_old, NULL, &eff->dst_rect); if (eff->type == EFFECT_BLIND_DOWN || eff->type == EFFECT_BLIND_UP || eff->type == EFFECT_BLIND_DOWN_LR) { blind_vstep(progress, &eff->dst_rect, eff->tx_new, 0, eff->type == EFFECT_BLIND_UP); @@ -882,7 +937,7 @@ static void blind_step(struct sdl_effect *eff, float progress) { flip_rect_h(&sr, eff->dst_rect.w); SDL_Rect dr = sr; move_rect(&dr, eff->dst_rect.x, eff->dst_rect.y); - SDL_RenderCopy(sdl_renderer, eff->tx_new, &sr, &dr); + render_effect_texture(eff->tx_new, &sr, &dr); } for (int i = 1; i < N; i++) { int x = (step - i) * N; @@ -893,7 +948,7 @@ static void blind_step(struct sdl_effect *eff, float progress) { flip_rect_h(&sr, eff->dst_rect.w); SDL_Rect dr = sr; move_rect(&dr, eff->dst_rect.x, eff->dst_rect.y); - SDL_RenderCopy(sdl_renderer, eff->tx_new, &sr, &dr); + render_effect_texture(eff->tx_new, &sr, &dr); } } @@ -910,7 +965,7 @@ static void blind_free(struct sdl_effect *eff) { static void blend_animation_step(struct sdl_effect *eff, float progress); static void blend_animation_free(struct sdl_effect *eff); -static struct sdl_effect *blend_animation_new(SDL_Rect *rect, SDL_Surface *old, SDL_Surface *new, enum sdl_effect_type type) { +static struct sdl_effect *blend_animation_new(SDL_Rect *rect, EffectTexture *old, EffectTexture *new, enum sdl_effect_type type) { struct sdl_effect *eff = calloc(1, sizeof(struct sdl_effect)); if (!eff) NOMEMERR(); @@ -923,7 +978,7 @@ static struct sdl_effect *blend_animation_new(SDL_Rect *rect, SDL_Surface *old, static void blend_animation_step(struct sdl_effect *eff, float progress) { const bool lr = eff->type == EFFECT_BLEND_LR_RL; - SDL_Texture *bg, *fg; + EffectTexture *bg, *fg; if (progress < 0.5f) { bg = eff->tx_old; fg = eff->tx_new; @@ -933,10 +988,10 @@ static void blend_animation_step(struct sdl_effect *eff, float progress) { progress = 1.f - progress; } - SDL_RenderCopy(sdl_renderer, bg, NULL, &eff->dst_rect); + render_effect_texture(bg, NULL, &eff->dst_rect); int k = (lr ? eff->dst_rect.w : eff->dst_rect.h) * progress; - SDL_SetTextureBlendMode(fg, SDL_BLENDMODE_BLEND); - SDL_SetTextureAlphaMod(fg, 127); + SDL_SetTextureBlendMode(fg->tx, SDL_BLENDMODE_BLEND); + SDL_SetTextureAlphaMod(fg->tx, 127); SDL_Rect sr = {0, 0, eff->dst_rect.w, eff->dst_rect.h}; SDL_Rect dr = eff->dst_rect; @@ -944,7 +999,7 @@ static void blend_animation_step(struct sdl_effect *eff, float progress) { sr.w = dr.w = k; else sr.h = dr.h = k; - SDL_RenderCopy(sdl_renderer, fg, &sr, &dr); + render_effect_texture(fg, &sr, &dr); if (lr) { sr.x = eff->dst_rect.w - k; @@ -953,9 +1008,10 @@ static void blend_animation_step(struct sdl_effect *eff, float progress) { sr.y = eff->dst_rect.h - k; dr.y += sr.y; } - SDL_RenderCopy(sdl_renderer, fg, &sr, &dr); + render_effect_texture(fg, &sr, &dr); - SDL_SetTextureBlendMode(fg, SDL_BLENDMODE_NONE); + SDL_SetTextureAlphaMod(fg->tx, 255); + SDL_SetTextureBlendMode(fg->tx, SDL_BLENDMODE_NONE); SDL_RenderPresent(sdl_renderer); } @@ -977,7 +1033,7 @@ struct zoom_blend_blur_effect { static void zoom_blend_blur_step(struct sdl_effect *eff, float progress); static void zoom_blend_blur_free(struct sdl_effect *eff); -static struct sdl_effect *zoom_blend_blur_new(SDL_Rect *rect, SDL_Surface *old, SDL_Surface *new) { +static struct sdl_effect *zoom_blend_blur_new(SDL_Rect *rect, EffectTexture *old, EffectTexture *new) { if (!SDL_RenderTargetSupported(sdl_renderer)) return fallback_effect_new(rect, old, new, EFFECT_ZOOM_BLEND_BLUR); @@ -1007,19 +1063,21 @@ static void zoom_blend_blur_step(struct sdl_effect *eff, float progress) { .h = h }; SDL_SetRenderTarget(sdl_renderer, this->tx[this->index]); - SDL_RenderCopy(sdl_renderer, eff->tx_new, &r, NULL); + render_effect_texture(eff->tx_new, &r, NULL); SDL_SetRenderTarget(sdl_renderer, NULL); this->index = (this->index + 1) % ZOOM_BLEND_BLUR_STEPS; SDL_RenderFillRect(sdl_renderer, &eff->dst_rect); + EffectTexture texture_rect = { NULL, { 0, 0, eff->dst_rect.w, eff->dst_rect.h } }; for (int i = 0; i < ZOOM_BLEND_BLUR_STEPS; i++) { - SDL_Texture *tx = this->tx[i] ? this->tx[i] : eff->tx_new; - SDL_SetTextureBlendMode(tx, SDL_BLENDMODE_ADD); - SDL_SetTextureAlphaMod(tx, 255 / ZOOM_BLEND_BLUR_STEPS); - SDL_RenderCopy(sdl_renderer, tx, NULL, &eff->dst_rect); - SDL_SetTextureBlendMode(tx, SDL_BLENDMODE_NONE); - SDL_SetTextureAlphaMod(tx, 255); + texture_rect.tx = this->tx[i]; + EffectTexture *t = this->tx[i] ? &texture_rect : eff->tx_new; + SDL_SetTextureBlendMode(t->tx, SDL_BLENDMODE_ADD); + SDL_SetTextureAlphaMod(t->tx, 255 / ZOOM_BLEND_BLUR_STEPS); + render_effect_texture(t, NULL, &eff->dst_rect); + SDL_SetTextureBlendMode(t->tx, SDL_BLENDMODE_NONE); + SDL_SetTextureAlphaMod(t->tx, 255); } SDL_RenderPresent(sdl_renderer); } @@ -1040,14 +1098,14 @@ static void zoom_blend_blur_free(struct sdl_effect *eff) { struct linear_blur_effect { struct sdl_effect eff; - SDL_Texture *blurred_old[LINEAR_BLUR_STEPS]; - SDL_Texture *blurred_new[LINEAR_BLUR_STEPS]; + EffectTexture *blurred_old[LINEAR_BLUR_STEPS]; + EffectTexture *blurred_new[LINEAR_BLUR_STEPS]; }; static void linear_blur_step(struct sdl_effect *eff, float 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) { +static struct sdl_effect *linear_blur_new(SDL_Rect *rect, EffectTexture *old, EffectTexture *new, enum sdl_effect_type type) { if (!SDL_RenderTargetSupported(sdl_renderer)) return fallback_effect_new(rect, old, new, type); @@ -1060,28 +1118,30 @@ static struct sdl_effect *linear_blur_new(SDL_Rect *rect, SDL_Surface *old, SDL_ return &lbe->eff; } -static SDL_Texture *blur(struct linear_blur_effect *this, SDL_Texture *src, int stride) { +static EffectTexture *blur(struct linear_blur_effect *this, EffectTexture *src, int stride) { bool vertical = this->eff.type == EFFECT_LINEAR_BLUR_VERT; int w = this->eff.dst_rect.w; int h = this->eff.dst_rect.h; - SDL_Texture *dst = SDL_CreateTexture(sdl_renderer, SDL_PIXELFORMAT_RGB888, SDL_TEXTUREACCESS_TARGET, w, h); + EffectTexture *dst = calloc(1, sizeof(EffectTexture)); + dst->tx = SDL_CreateTexture(sdl_renderer, SDL_PIXELFORMAT_RGB888, SDL_TEXTUREACCESS_TARGET, w, h); + dst->rect = (SDL_Rect){0, 0, w, h}; - SDL_SetRenderTarget(sdl_renderer, dst); + SDL_SetRenderTarget(sdl_renderer, dst->tx); SDL_RenderClear(sdl_renderer); - SDL_SetTextureBlendMode(src, SDL_BLENDMODE_ADD); - SDL_SetTextureAlphaMod(src, 127); + SDL_SetTextureBlendMode(src->tx, SDL_BLENDMODE_ADD); + SDL_SetTextureAlphaMod(src->tx, 127); SDL_Rect dr = {0, 0, w, h}; *(vertical ? &dr. y : &dr.x) = -stride / 2; - SDL_RenderCopy(sdl_renderer, src, NULL, &dr); + render_effect_texture(src, NULL, &dr); *(vertical ? &dr. y : &dr.x) = max(1, stride / 2); - SDL_RenderCopy(sdl_renderer, src, NULL, &dr); + render_effect_texture(src, NULL, &dr); // Copy the edge pixels to emulate texture clamping. SDL_Rect sr = {0, 0, vertical ? w : 1, vertical ? 1 : h}; *(vertical ? &dr.h : &dr.w) = max(1, stride / 2); *(vertical ? &dr.y : &dr.x) = 0; - SDL_RenderCopy(sdl_renderer, src, &sr, &dr); + render_effect_texture(src, &sr, &dr); if (stride > 1) { if (vertical) { sr.y = h - 1; @@ -1090,11 +1150,11 @@ static SDL_Texture *blur(struct linear_blur_effect *this, SDL_Texture *src, int sr.x = w - 1; dr.x = w - stride / 2; } - SDL_RenderCopy(sdl_renderer, src, &sr, &dr); + render_effect_texture(src, &sr, &dr); } - SDL_SetTextureAlphaMod(src, 255); - SDL_SetTextureBlendMode(src, SDL_BLENDMODE_NONE); + SDL_SetTextureAlphaMod(src->tx, 255); + SDL_SetTextureBlendMode(src->tx, SDL_BLENDMODE_NONE); SDL_SetRenderTarget(sdl_renderer, NULL); return dst; @@ -1105,7 +1165,7 @@ static void linear_blur_step(struct sdl_effect *eff, float progress) { int step = progress * LINEAR_BLUR_STEPS * 2; if (step == LINEAR_BLUR_STEPS * 2) { - SDL_RenderCopy(sdl_renderer, eff->tx_new, NULL, NULL); + render_effect_texture(eff->tx_new, NULL, NULL); SDL_RenderPresent(sdl_renderer); return; } @@ -1118,12 +1178,12 @@ static void linear_blur_step(struct sdl_effect *eff, float progress) { } int i = step < LINEAR_BLUR_STEPS ? step : LINEAR_BLUR_STEPS * 2 - 1 - step; - SDL_Texture *old = this->blurred_old[i]; - SDL_Texture *new = this->blurred_new[i]; - SDL_RenderCopy(sdl_renderer, old, NULL, &eff->dst_rect); - SDL_SetTextureBlendMode(new, SDL_BLENDMODE_BLEND); - SDL_SetTextureAlphaMod(new, 255 * progress); - SDL_RenderCopy(sdl_renderer, new, NULL, &eff->dst_rect); + EffectTexture *old = this->blurred_old[i]; + EffectTexture *new = this->blurred_new[i]; + render_effect_texture(old, NULL, &eff->dst_rect); + SDL_SetTextureBlendMode(new->tx, SDL_BLENDMODE_BLEND); + SDL_SetTextureAlphaMod(new->tx, 255 * progress); + render_effect_texture(new, NULL, &eff->dst_rect); SDL_RenderPresent(sdl_renderer); } @@ -1131,9 +1191,9 @@ static void linear_blur_free(struct sdl_effect *eff) { struct linear_blur_effect *this = (struct linear_blur_effect *)eff; for (int i = 0; i < LINEAR_BLUR_STEPS; i++) { if (this->blurred_old[i]) - SDL_DestroyTexture(this->blurred_old[i]); + destroy_effect_texture(this->blurred_old[i]); if (this->blurred_new[i]) - SDL_DestroyTexture(this->blurred_new[i]); + destroy_effect_texture(this->blurred_new[i]); } effect_finish(&this->eff, true); free(this); @@ -1149,7 +1209,7 @@ struct polygon_mask_effect { static void polygon_mask_step(struct sdl_effect *eff, float progress); static void polygon_mask_free(struct sdl_effect *eff); -static struct sdl_effect *polygon_mask_new(SDL_Rect *rect, SDL_Surface *old, SDL_Surface *new, enum sdl_effect_type type) { +static struct sdl_effect *polygon_mask_new(SDL_Rect *rect, EffectTexture *old, EffectTexture *new, enum sdl_effect_type type) { #if HAS_SDL_RenderGeometry if (SDL_RenderTargetSupported(sdl_renderer)) { struct polygon_mask_effect *pmf = calloc(1, sizeof(struct polygon_mask_effect)); @@ -1357,7 +1417,7 @@ static void polygon_mask_step(struct sdl_effect *eff, float progress) { int w = eff->dst_rect.w; int h = eff->dst_rect.h; SDL_SetRenderTarget(sdl_renderer, this->tx_tmp); - SDL_RenderCopy(sdl_renderer, eff->tx_old, NULL, NULL); + render_effect_texture(eff->tx_old, NULL, NULL); switch (eff->type) { case EFFECT_PENTAGRAM_IN_OUT: draw_pentagram(w / 2, h / 2, max(w, h) * progress, M_PIf * progress); @@ -1384,7 +1444,7 @@ static void polygon_mask_step(struct sdl_effect *eff, float progress) { assert(!"Cannot happen"); } SDL_SetRenderTarget(sdl_renderer, NULL); - SDL_RenderCopy(sdl_renderer, eff->tx_new, NULL, &eff->dst_rect); + render_effect_texture(eff->tx_new, NULL, &eff->dst_rect); SDL_SetTextureBlendMode(this->tx_tmp, SDL_BLENDMODE_BLEND); SDL_RenderCopy(sdl_renderer, this->tx_tmp, NULL, &eff->dst_rect); SDL_RenderPresent(sdl_renderer); @@ -1404,7 +1464,7 @@ static void polygon_mask_free(struct sdl_effect *eff) { static void rotate_step(struct sdl_effect *eff, float progress); static void rotate_free(struct sdl_effect *eff); -static struct sdl_effect *rotate_new(SDL_Rect *rect, SDL_Surface *old, SDL_Surface *new, enum sdl_effect_type type) { +static struct sdl_effect *rotate_new(SDL_Rect *rect, EffectTexture *old, EffectTexture *new, enum sdl_effect_type type) { struct sdl_effect *eff = calloc(1, sizeof(struct sdl_effect)); if (!eff) NOMEMERR(); @@ -1415,7 +1475,7 @@ static struct sdl_effect *rotate_new(SDL_Rect *rect, SDL_Surface *old, SDL_Surfa } static void rotate_step(struct sdl_effect *eff, float progress) { - SDL_Texture *bg_texture, *fg_texture; + EffectTexture *bg_texture, *fg_texture; float angle = progress * 360; float scale = progress; switch (eff->type) { @@ -1452,8 +1512,8 @@ static void rotate_step(struct sdl_effect *eff, float progress) { r.y += (1.f - scale) * r.h / 2; r.w *= scale; r.h *= scale; - SDL_RenderCopy(sdl_renderer, bg_texture, NULL, &eff->dst_rect); - SDL_RenderCopyEx(sdl_renderer, fg_texture, NULL, &r, angle, NULL, SDL_FLIP_NONE); + render_effect_texture(bg_texture, NULL, &eff->dst_rect); + SDL_RenderCopyEx(sdl_renderer, fg_texture->tx, &fg_texture->rect, &r, angle, NULL, SDL_FLIP_NONE); SDL_RenderPresent(sdl_renderer); } @@ -1467,7 +1527,7 @@ static void rotate_free(struct sdl_effect *eff) { static void polygon_rotate_step(struct sdl_effect *eff, float progress); static void polygon_rotate_free(struct sdl_effect *eff); -static struct sdl_effect *polygon_rotate_new(SDL_Rect *rect, SDL_Surface *old, SDL_Surface *new, enum sdl_effect_type type) { +static struct sdl_effect *polygon_rotate_new(SDL_Rect *rect, EffectTexture *old, EffectTexture *new, enum sdl_effect_type type) { struct sdl_effect *eff = calloc(1, sizeof(struct sdl_effect)); if (!eff) NOMEMERR(); @@ -1479,7 +1539,7 @@ static struct sdl_effect *polygon_rotate_new(SDL_Rect *rect, SDL_Surface *old, S static void polygon_rotate_step(struct sdl_effect *eff, float progress) { bool vertical = eff->type == EFFECT_POLYGON_ROTATE_Y || eff->type == EFFECT_POLYGON_ROTATE_Y_CW; - SDL_Texture *texture = progress < 0.5f ? eff->tx_old : eff->tx_new; + EffectTexture *texture = progress < 0.5f ? eff->tx_old : eff->tx_new; float angle = progress < 0.5f ? progress * M_PIf : (progress - 1.f) * M_PIf; if (eff->type == EFFECT_POLYGON_ROTATE_Y_CW || eff->type == EFFECT_POLYGON_ROTATE_X_CW) angle *= -1; @@ -1511,7 +1571,7 @@ static void polygon_rotate_step(struct sdl_effect *eff, float progress) { transpose_rect(&sr); transpose_rect(&dr); } - SDL_RenderCopy(sdl_renderer, texture, &sr, &dr); + render_effect_texture(texture, &sr, &dr); } SDL_RenderPresent(sdl_renderer); @@ -1532,7 +1592,7 @@ struct zigzag_crossfade_effect { static void zigzag_crossfade_step(struct sdl_effect *eff, float 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) { +static struct sdl_effect *zigzag_crossfade_new(SDL_Rect *rect, EffectTexture *old, EffectTexture *new) { if (!SDL_RenderTargetSupported(sdl_renderer)) return fallback_effect_new(rect, old, new, EFFECT_ZIGZAG_CROSSFADE); @@ -1547,7 +1607,7 @@ static struct sdl_effect *zigzag_crossfade_new(SDL_Rect *rect, SDL_Surface *old, return &eff->eff; } -static void wave_warp_h(SDL_Texture *src, SDL_Texture *dst, int w, int h, float amplitude, float length, float phase) { +static void wave_warp_h(EffectTexture *src, SDL_Texture *dst, int w, int h, float amplitude, float length, float phase) { SDL_SetRenderTarget(sdl_renderer, dst); SDL_RenderClear(sdl_renderer); SDL_Rect sr = {0, 0, w, 1}; @@ -1555,7 +1615,7 @@ static void wave_warp_h(SDL_Texture *src, SDL_Texture *dst, int w, int h, float for (int y = 0; y < h; y++) { sr.y = dr.y = y; dr.x = sinf(phase + y * (2 * M_PIf / 360 * length)) * amplitude; - SDL_RenderCopy(sdl_renderer, src, &sr, &dr); + render_effect_texture(src, &sr, &dr); } SDL_SetRenderTarget(sdl_renderer, NULL); } @@ -1612,11 +1672,11 @@ struct magnify_effect { static void magnify_step(struct sdl_effect *eff, float progress); static void magnify_free(struct sdl_effect *eff); -static struct sdl_effect *magnify_new(SDL_Surface *sf, SDL_Rect *old_rect, SDL_Rect *new_rect) { +static struct sdl_effect *magnify_new(EffectTexture *tx, SDL_Rect *old_rect, SDL_Rect *new_rect) { struct magnify_effect *eff = calloc(1, sizeof(struct magnify_effect)); if (!eff) NOMEMERR(); - effect_init(&eff->eff, old_rect, sf, NULL, EFFECT_MAGNIFY); + effect_init(&eff->eff, old_rect, tx, NULL, EFFECT_MAGNIFY); eff->new_rect = *new_rect; eff->eff.step = magnify_step; eff->eff.finish = magnify_free; @@ -1633,7 +1693,7 @@ static void magnify_step(struct sdl_effect *eff, float progress) { .w = or->w + (nr->w - or->w) * progress, .h = or->h + (nr->h - or->h) * progress, }; - SDL_RenderCopy(sdl_renderer, eff->tx_old, &r, NULL); + render_effect_texture(eff->tx_old, &r, NULL); SDL_RenderPresent(sdl_renderer); } @@ -1649,10 +1709,12 @@ static void raster_blend_free(struct sdl_effect *eff); static struct sdl_effect *raster_blend_new(SDL_Rect *rect, int sx, int sy) { SDL_Surface *sprite = sdl_dib_to_surface_with_alpha(sx, sy, rect->w, rect->h); + EffectTexture *texture = create_effect_texture_from_surface(sprite); + SDL_FreeSurface(sprite); struct sdl_effect *eff = calloc(1, sizeof(struct sdl_effect)); if (!eff) NOMEMERR(); - effect_init(eff, rect, NULL, sprite, EFFECT_RASTER_BLEND); + effect_init(eff, rect, NULL, texture, EFFECT_RASTER_BLEND); eff->step = raster_blend_step; eff->finish = raster_blend_free; return eff; @@ -1665,7 +1727,7 @@ static void raster_blend_step(struct sdl_effect *eff, float progress) { for (int y = 0; y < eff->dst_rect.h; y++) { float t = 1.f - 4.f * progress + 3.f * y / eff->dst_rect.h; d_rect.x = eff->dst_rect.x + (t < 0 ? 0 : sinf(2 * M_PIf * t) * 50); - SDL_RenderCopy(sdl_renderer, eff->tx_new, &s_rect, &d_rect); + render_effect_texture(eff->tx_new, &s_rect, &d_rect); s_rect.y++; d_rect.y++; } @@ -1679,56 +1741,41 @@ static void raster_blend_free(struct sdl_effect *eff) { // ----------------- -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); - SDL_Rect rect = { x, y, w, h }; - if (!as) { - SDL_BlitSurface(sdl_display, &rect, sf, NULL); - } else if (as == sdl_dibinfo) { - SDL_BlitSurface(sdl_dib, &rect, sf, NULL); - } else { - SDL_Surface *s = com2surface(as); - SDL_BlitSurface(s, &rect, sf, NULL); - SDL_FreeSurface(s); - } - return sf; -} - 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 type) { - SDL_Surface *sf_old = create_surface(old, ox, oy, rect->w, rect->h); - SDL_Surface *sf_new = create_surface(new, nx, ny, rect->w, rect->h); + EffectTexture *tx_old = create_effect_texture(old, ox, oy, rect->w, rect->h); + EffectTexture *tx_new = create_effect_texture(new, nx, ny, rect->w, rect->h); switch (type) { case EFFECT_CROSSFADE: - return crossfade_new(rect, sf_old, sf_new); + return crossfade_new(rect, tx_old, tx_new); case EFFECT_CROSSFADE_DOWN: case EFFECT_CROSSFADE_UP: case EFFECT_CROSSFADE_LR: case EFFECT_CROSSFADE_RL: case EFFECT_CROSSFADE_LR_RL: case EFFECT_CROSSFADE_UP_DOWN: - return crossfade_animation_new(rect, sf_old, sf_new, type); + return crossfade_animation_new(rect, tx_old, tx_new, type); case EFFECT_MOSAIC: case EFFECT_CROSSFADE_MOSAIC: - return mosaic_new(rect, sf_old, sf_new, type); + return mosaic_new(rect, tx_old, tx_new, type); case EFFECT_FADEOUT: case EFFECT_FADEOUT_FROM_NEW: case EFFECT_FADEIN: case EFFECT_WHITEOUT: case EFFECT_WHITEOUT_FROM_NEW: case EFFECT_WHITEIN: - return brightness_new(rect, sf_old, sf_new, type); + return brightness_new(rect, tx_old, tx_new, type); case EFFECT_DITHERING_FADEOUT: case EFFECT_DITHERING_FADEIN: case EFFECT_DITHERING_WHITEOUT: case EFFECT_DITHERING_WHITEIN: - return dithering_fade_new(rect, sf_old, sf_new, type); + return dithering_fade_new(rect, tx_old, tx_new, type); case EFFECT_PAN_IN_DOWN: case EFFECT_PAN_IN_UP: - return pan_in_new(rect, sf_old, sf_new, type); + return pan_in_new(rect, tx_old, tx_new, type); case EFFECT_SKIP_LINE_UP_DOWN: case EFFECT_SKIP_LINE_LR_RL: - return skip_line_new(rect, sf_old, sf_new, type); + return skip_line_new(rect, tx_old, tx_new, type); case EFFECT_WIPE_IN: case EFFECT_WIPE_OUT: case EFFECT_WIPE_LR: @@ -1739,25 +1786,25 @@ struct sdl_effect *sdl_effect_init(SDL_Rect *rect, agsurface_t *old, int ox, int case EFFECT_WIPE_IN_V: case EFFECT_WIPE_OUT_H: case EFFECT_WIPE_IN_H: - return wipe_new(rect, sf_old, sf_new, type); + return wipe_new(rect, tx_old, tx_new, type); case EFFECT_CIRCLE_WIPE_OUT: case EFFECT_CIRCLE_WIPE_IN: - return circle_wipe_new(rect, sf_old, sf_new, type); + return circle_wipe_new(rect, tx_old, tx_new, type); case EFFECT_BLIND_DOWN: case EFFECT_BLIND_UP: case EFFECT_BLIND_LR: case EFFECT_BLIND_RL: case EFFECT_BLIND_UP_DOWN: case EFFECT_BLIND_DOWN_LR: - return blind_new(rect, sf_old, sf_new, type); + return blind_new(rect, tx_old, tx_new, type); case EFFECT_BLEND_UP_DOWN: case EFFECT_BLEND_LR_RL: - return blend_animation_new(rect, sf_old, sf_new, type); + return blend_animation_new(rect, tx_old, tx_new, type); case EFFECT_ZOOM_BLEND_BLUR: - return zoom_blend_blur_new(rect, sf_old, sf_new); + return zoom_blend_blur_new(rect, tx_old, tx_new); case EFFECT_LINEAR_BLUR: case EFFECT_LINEAR_BLUR_VERT: - return linear_blur_new(rect, sf_old, sf_new, type); + return linear_blur_new(rect, tx_old, tx_new, type); case EFFECT_PENTAGRAM_IN_OUT: case EFFECT_PENTAGRAM_OUT_IN: case EFFECT_HEXAGRAM_IN_OUT: @@ -1765,37 +1812,39 @@ struct sdl_effect *sdl_effect_init(SDL_Rect *rect, agsurface_t *old, int ox, int case EFFECT_WINDMILL: case EFFECT_WINDMILL_180: case EFFECT_WINDMILL_360: - return polygon_mask_new(rect, sf_old, sf_new, type); + return polygon_mask_new(rect, tx_old, tx_new, type); case EFFECT_ZOOM_IN: case EFFECT_ROTATE_OUT: case EFFECT_ROTATE_IN: case EFFECT_ROTATE_OUT_CW: case EFFECT_ROTATE_IN_CW: - return rotate_new(rect, sf_old, sf_new, type); + return rotate_new(rect, tx_old, tx_new, type); case EFFECT_POLYGON_ROTATE_Y: case EFFECT_POLYGON_ROTATE_Y_CW: case EFFECT_POLYGON_ROTATE_X: case EFFECT_POLYGON_ROTATE_X_CW: - return polygon_rotate_new(rect, sf_old, sf_new, type); + return polygon_rotate_new(rect, tx_old, tx_new, type); case EFFECT_ZIGZAG_CROSSFADE: - return zigzag_crossfade_new(rect, sf_old, sf_new); + return zigzag_crossfade_new(rect, tx_old, tx_new); default: WARNING("Unknown effect %d", type); - return crossfade_new(rect, sf_old, sf_new); + return crossfade_new(rect, tx_old, tx_new); } } 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); + EffectTexture *tx_old = create_effect_texture(sdl_dibinfo, dx, dy, rect->w, rect->h); SDL_Surface *sprite = sdl_dib_to_surface_colorkey(sx, sy, rect->w, rect->h, col); + EffectTexture *tx_new = create_effect_texture_from_surface(sprite); + SDL_FreeSurface(sprite); switch (type) { case EFFECT_PAN_IN_DOWN: case EFFECT_PAN_IN_UP: - return pan_in_new(rect, sf_old, sprite, type); + return pan_in_new(rect, tx_old, tx_new, type); case EFFECT_SKIP_LINE_UP_DOWN: case EFFECT_SKIP_LINE_LR_RL: - return skip_line_new(rect, sf_old, sprite, type); + return skip_line_new(rect, tx_old, tx_new, type); case EFFECT_RASTER_BLEND: return raster_blend_new(rect, sx, sy); default: @@ -1805,8 +1854,8 @@ struct sdl_effect *sdl_sprite_effect_init(SDL_Rect *rect, int dx, int dy, int sx } 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); + EffectTexture *tx = create_effect_texture(surface, view_rect->x, view_rect->y, view_rect->w, view_rect->h); + return magnify_new(tx, view_rect, target_rect); } void sdl_effect_step(struct sdl_effect *eff, float progress) { diff --git a/src/sdl_private.h b/src/sdl_private.h index 5b1784c..0305096 100644 --- a/src/sdl_private.h +++ b/src/sdl_private.h @@ -33,7 +33,6 @@ extern SDL_Window *sdl_window; extern SDL_Renderer *sdl_renderer; extern SDL_Texture *sdl_texture; -extern SDL_Surface *sdl_display; // toplevel surface extern SDL_Surface *sdl_dib; // offscreen surface extern SDL_Color sdl_col[256]; // color palette extern agsurface_t *sdl_dibinfo; diff --git a/src/sdl_video.c b/src/sdl_video.c index 339ab6c..9313634 100644 --- a/src/sdl_video.c +++ b/src/sdl_video.c @@ -39,7 +39,6 @@ SDL_Window *sdl_window; SDL_Renderer *sdl_renderer; SDL_Texture *sdl_texture; -SDL_Surface *sdl_display; // toplevel surface SDL_Surface *sdl_dib; // offscreen surface SDL_Color sdl_col[256]; // color palette agsurface_t *sdl_dibinfo; @@ -105,12 +104,13 @@ int sdl_Initialize(const char *render_driver) { } void sdl_Remove(void) { - if (sdl_display) { + if (sdl_dib) SDL_FreeSurface(sdl_dib); + if (sdl_renderer) SDL_DestroyRenderer(sdl_renderer); + if (js) SDL_JoystickClose(js); - SDL_Quit(); - } + SDL_Quit(); } /* name is UTF-8 */ @@ -258,13 +258,10 @@ void sdl_setWindowSize(int w, int h) { SDL_SetWindowSize(sdl_window, w, h); #endif SDL_RenderSetLogicalSize(sdl_renderer, w, h); - if (sdl_display) - SDL_FreeSurface(sdl_display); if (sdl_texture) SDL_DestroyTexture(sdl_texture); - sdl_display = SDL_CreateRGBSurfaceWithFormat(0, w, h, 32, SDL_PIXELFORMAT_RGB888); - sdl_texture = SDL_CreateTexture(sdl_renderer, sdl_display->format->format, - SDL_TEXTUREACCESS_STATIC, w, h); + sdl_texture = SDL_CreateTexture( + sdl_renderer, SDL_PIXELFORMAT_RGB888, SDL_TEXTUREACCESS_STREAMING, w, h); #ifdef __EMSCRIPTEN__ EM_ASM( xsystem35.shell.windowSizeChanged(); ); @@ -292,7 +289,7 @@ void sdl_setIntegerScaling(bool enable) { #ifdef __EMSCRIPTEN__ bool EMSCRIPTEN_KEEPALIVE save_screenshot(const char* path) { - return SDL_SaveBMP(sdl_display, path) == 0; + return SDL_SaveBMP(sdl_dib, path) == 0; } #endif diff --git a/src/win/menubar.c b/src/win/menubar.c index 02c7c73..e759b82 100644 --- a/src/win/menubar.c +++ b/src/win/menubar.c @@ -55,7 +55,7 @@ static void saveScreenshot(void) { }; if (!GetSaveFileName(&ofn)) return; - if (SDL_SaveBMP(sdl_display, pathbuf) != 0) { + if (SDL_SaveBMP(sdl_dib, pathbuf) != 0) { sdl_showMessageBox(MESSAGEBOX_ERROR, "xsystem35", SDL_GetError()); SDL_ClearError(); }