diff --git a/src/ags.c b/src/ags.c index e022e81..b61aea0 100644 --- a/src/ags.c +++ b/src/ags.c @@ -545,36 +545,74 @@ void ags_runEffect(int duration_ms, boolean cancelable, ags_EffectStepFunc step, step(arg, 1.0); } -void ags_fadeIn(int rate, boolean flag) { - if (!need_update) - rate = 0; - fade_outed = FALSE; +static void fade(int duration, boolean cancelable, enum sdl_effect_type type) { nact->waitcancel_key = 0; - ags_runEffect(rate * 16 * 1000 / 60, flag, sdl_fadeIn, NULL); + + SDL_Rect rect = {0, 0, nact->sys_view_area.w, nact->sys_view_area.h}; + struct sdl_effect *eff = sdl_effect_init( + &rect, NULL, 0, 0, + sdl_getDIB(), nact->sys_view_area.x, nact->sys_view_area.y, + type); + ags_runEffect(duration, cancelable, (ags_EffectStepFunc)sdl_effect_step, eff); + sdl_effect_finish(eff); +} + +void ags_fadeIn(int rate, boolean flag) { + int duration = rate * 16 * 1000 / 60; + if (!need_update) + duration = 0; + fade_outed = FALSE; + + if (nact->sys_world_depth == 8) + sdl_setPalette(nact->sys_pal, 0, 256); + + fade(duration, flag, nact->sys_world_depth == 8 ? EFFECT_FADEIN : EFFECT_DITHERING_FADEIN); + + sdl_updateAll(); } void ags_fadeOut(int rate, boolean flag) { + int duration = rate * 16 * 1000 / 60; if (!need_update || fade_outed) - rate = 0; + duration = 0; fade_outed = TRUE; - nact->waitcancel_key = 0; - ags_runEffect(rate * 16 * 1000 / 60, flag, sdl_fadeOut, NULL); + + fade(duration, flag, nact->sys_world_depth == 8 ? EFFECT_FADEOUT : EFFECT_DITHERING_FADEOUT); + + if (nact->sys_world_depth == 8) { + Palette256 pal; + memset(&pal, 0, sizeof(pal)); + sdl_setPalette(&pal, 0, 256); + } } void ags_whiteIn(int rate, boolean flag) { + int duration = rate * 16 * 1000 / 60; if (!need_update) - rate = 0; + duration = 0; fade_outed = FALSE; - nact->waitcancel_key = 0; - ags_runEffect(rate * 16 * 1000 / 60, flag, sdl_whiteIn, NULL); + + if (nact->sys_world_depth == 8) + sdl_setPalette(nact->sys_pal, 0, 256); + + fade(duration, flag, nact->sys_world_depth == 8 ? EFFECT_WHITEIN : EFFECT_DITHERING_WHITEIN); + + sdl_updateAll(); } void ags_whiteOut(int rate, boolean flag) { + int duration = rate * 16 * 1000 / 60; if (!need_update || fade_outed) - rate = 0; + duration = 0; fade_outed = TRUE; - nact->waitcancel_key = 0; - ags_runEffect(rate * 16 * 1000 / 60, flag, sdl_whiteOut, NULL); + + fade(duration, flag, nact->sys_world_depth == 8 ? EFFECT_WHITEIN : EFFECT_DITHERING_WHITEOUT); + + if (nact->sys_world_depth == 8) { + Palette256 pal; + memset(&pal, 255, sizeof(pal)); + sdl_setPalette(&pal, 0, 256); + } } void ags_setFont(int type, int size) { diff --git a/src/effect.h b/src/effect.h index f5c5f56..eda72fe 100644 --- a/src/effect.h +++ b/src/effect.h @@ -107,6 +107,10 @@ enum sdl_effect_type { EFFECT_WHITEOUT, EFFECT_WHITEOUT_FROM_NEW, EFFECT_WHITEIN, + EFFECT_DITHERING_FADEOUT, + EFFECT_DITHERING_FADEIN, + EFFECT_DITHERING_WHITEOUT, + EFFECT_DITHERING_WHITEIN, EFFECT_BLIND_DOWN, EFFECT_BLIND_UP, EFFECT_BLIND_LR, diff --git a/src/sdl_core.h b/src/sdl_core.h index 3efa283..bdc43da 100644 --- a/src/sdl_core.h +++ b/src/sdl_core.h @@ -50,6 +50,7 @@ extern void sdl_setIntegerScaling(boolean enable); /* 画面更新 */ extern void sdl_updateArea(MyRectangle *src, MyPoint *dst); +extern void sdl_updateAll(void); extern void sdl_updateScreen(void); /* パレット関係 */ @@ -83,14 +84,9 @@ 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); -void sdl_effect_step(struct sdl_effect *fader, double progress); -void sdl_effect_finish(struct sdl_effect *fader); -extern void sdl_fadeIn(void *arg, double progress); -extern void sdl_fadeOut(void *arg, double progress); -extern void sdl_whiteIn(void *arg, double progress); -extern void sdl_whiteOut(void *arg, double progress); +void sdl_effect_step(struct sdl_effect *eff, double progress); +void sdl_effect_finish(struct sdl_effect *eff); /* key/pointer 関係 */ extern void sdl_setJoyDeviceIndex(int index); diff --git a/src/sdl_draw.c b/src/sdl_draw.c index 1060878..00f87c6 100644 --- a/src/sdl_draw.c +++ b/src/sdl_draw.c @@ -42,24 +42,6 @@ #include "nact.h" #include "debugger.h" -static const int fadeX[16] = {0,2,2,0,1,3,3,1,1,3,3,1,0,2,2,0}; -static const int fadeY[16] = {0,2,0,2,1,3,1,3,0,2,0,2,1,3,1,3}; - -static int fadestep[256] = -{0,1,3,4,6,7,9,10,12,14,15,17,18,20,21,23,25,26,28,29,31,32,34,36,37,39,40, - 42,43,45,46,48,49,51,53,54,56,57,59,60,62,63,65,66,68,69,71,72,74,75,77,78, - 80,81,83,84,86,87,89,90,92,93,95,96,97,99,100,102,103,105,106,108,109,110, - 112,113,115,116,117,119,120,122,123,124,126,127,128,130,131,132,134,135,136, - 138,139,140,142,143,144,146,147,148,149,151,152,153,155,156,157,158,159,161, - 162,163,164,166,167,168,169,170,171,173,174,175,176,177,178,179,181,182,183, - 184,185,186,187,188,189,190,191,192,193,194,195,196,197,198,199,200,201,202, - 203,204,205,206,207,208,209,210,211,211,212,213,214,215,216,217,217,218,219, - 220,221,221,222,223,224,225,225,226,227,227,228,229,230,230,231,232,232,233, - 234,234,235,235,236,237,237,238,238,239,239,240,241,241,242,242,243,243,244, - 244,244,245,245,246,246,247,247,247,248,248,249,249,249,250,250,250,251,251, - 251,251,252,252,252,252,253,253,253,253,254,254,254,254,254,254,255,255,255, - 255,255,255,255,255,255,255,255,255,255,255}; - static void sdl_pal_check(void) { if (nact->sys_pal_changed) { nact->sys_pal_changed = FALSE; @@ -121,7 +103,7 @@ void sdl_updateArea(MyRectangle *src, MyPoint *dst) { } /* 全画面更新 */ -static void sdl_updateAll() { +void sdl_updateAll(void) { SDL_Rect rect = {0, 0, view_w, view_h}; SDL_BlitSurface(sdl_dib, &sdl_view, sdl_display, &rect); @@ -341,130 +323,6 @@ SDL_Rect sdl_drawString(int x, int y, const char *str_utf8, BYTE col) { return font_draw_glyph(x, y, str_utf8, col); } -static void setBligtness(SDL_Surface *s, int val) { - int i; - Palette256 *pal = nact->sys_pal; - Uint8 *r = pal->red, *g = pal->green, *b = pal->blue; - SDL_Color *cl = sdl_col; - - for (i = 0; i < 256; i++) { - cl->r = (val * (*(r++))) / 255; - cl->g = (val * (*(g++))) / 255; - cl->b = (val * (*(b++))) / 255; - cl++; - } - SDL_SetPaletteColors(s->format->palette, sdl_col, 0, 256); -} - -static void setWhiteness(SDL_Surface *s, int val) { - int i; - Palette256 *pal = nact->sys_pal; - Uint8 *r = pal->red, *g = pal->green, *b = pal->blue; - SDL_Color *cl = sdl_col; - - for (i = 0; i < 256; i++) { - cl->r = (((255- *r) * val) / 256) + *r; r++; - cl->g = (((255- *g) * val) / 256) + *g; g++; - cl->b = (((255- *b) * val) / 256) + *b; b++; - cl++; - } - SDL_SetPaletteColors(s->format->palette, sdl_col, 0, 256); -} - -static void fader_in(int n) { - static SDL_Surface *src; - - if (n == 0) { - src = SDL_CreateRGBSurfaceWithFormat(0, sdl_display->w, sdl_display->h, 32, SDL_PIXELFORMAT_RGB888); - SDL_Rect r_src = {view_x, view_y, view_w, view_h}; - SDL_Rect r_dst = {0, 0, view_w, view_h}; - SDL_BlitSurface(sdl_dib, &r_src, src, &r_dst); - } - - if (n == 255) { - SDL_FreeSurface(src); - sdl_updateAll(); - return; - } - - int lv = n / 16; - for (int y = 0; y < src->h; y += 4) { - DWORD *yls = PIXEL_AT(src, 0, y + fadeY[lv]); - DWORD *yld = PIXEL_AT(sdl_display, 0, y + fadeY[lv]); - for (int x = 0; x < src->w; x += 4) { - *(yld + fadeX[lv]) = *(yls + fadeX[lv]); - yls += 4; yld += 4; - } - } - - sdl_dirty = TRUE; -} - -static void fader_out(int n, Uint32 c) { - if (n == 255) { - SDL_FillRect(sdl_display, NULL, c); - return; - } - - int lv = (255 - n) / 16; - for (int y = 0; y < sdl_display->h; y += 4) { - DWORD *yld = PIXEL_AT(sdl_display, 0, y + fadeY[lv]); - for (int x = 0; x < sdl_display->w; x += 4) { - *(yld + fadeX[lv]) = c; - yld += 4; - } - } - - sdl_dirty = TRUE; -} - -static __inline void sdl_fade_blit(void) { - SDL_Rect r_dst = {0, 0, view_w, view_h}; - - SDL_BlitSurface(sdl_dib, &sdl_view, sdl_display, &r_dst); - sdl_dirty = TRUE; -} - -void sdl_fadeIn(void *arg, double progress) { - int step = progress * 255; - if (sdl_dib->format->BitsPerPixel == 8) { - setBligtness(sdl_dib, fadestep[step]); - sdl_fade_blit(); - } else { - fader_in(step); - } -} - -void sdl_fadeOut(void *arg, double progress) { - int step = progress * 255; - if (sdl_dib->format->BitsPerPixel == 8) { - setBligtness(sdl_dib, fadestep[255 - step]); - sdl_fade_blit(); - } else { - fader_out(step, SDL_MapRGB(sdl_display->format, 0, 0, 0)); - } -} - -void sdl_whiteIn(void *arg, double progress) { - int step = progress * 255; - if (sdl_dib->format->BitsPerPixel == 8) { - setWhiteness(sdl_dib, fadestep[255 - step]); /* ??? */ - sdl_fade_blit(); - } else { - fader_in(step); - } -} - -void sdl_whiteOut(void *arg, double progress) { - int step = progress * 255; - if (sdl_dib->format->BitsPerPixel == 8) { - setWhiteness(sdl_dib, fadestep[step]); /* ??? */ - sdl_fade_blit(); - } else { - fader_out(step, SDL_MapRGB(sdl_display->format, 255, 255, 255)); - } -} - /* * 指定範囲にパレット col を rate の割合で重ねる CK1 */ diff --git a/src/sdl_effect.c b/src/sdl_effect.c index e38721b..e1a95e6 100644 --- a/src/sdl_effect.c +++ b/src/sdl_effect.c @@ -461,6 +461,95 @@ static void brightness_free(struct sdl_effect *eff) { free(eff); } +// EFFECT_DITHERING_{FADE,WHITE}{OUT,IN} + +static void dithering_fade_step(struct sdl_effect *eff, double progress); +static void dithering_fade_free(struct sdl_effect *eff); + +static SDL_Texture *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); + + Uint32 *pixels = calloc(w * h, sizeof(Uint32)); + if (!pixels) + NOMEMERR(); + for (int y = 0; y < h; y += 4) { + Uint32 *row = pixels + y * w; + for (int x = 0; x < w; x += 4) + 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); + free(pixels); + SDL_SetTextureBlendMode(tx, SDL_BLENDMODE_BLEND); + return tx; +} + +static struct sdl_effect *dithering_fade_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(); + switch (type) { + case EFFECT_DITHERING_FADEOUT: + SDL_FreeSurface(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); + 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); + 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); + effect_init(eff, rect, new, NULL, type); + eff->tx_new = create_dither_pattern_texture(rect->w, rect->h, 255); + break; + default: + assert(!"Cannot happen"); + } + eff->step = dithering_fade_step; + eff->finish = dithering_fade_free; + return eff; +} + +static void dithering_fade_step(struct sdl_effect *eff, double 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); + + if (eff->type == EFFECT_DITHERING_FADEIN || eff->type == EFFECT_DITHERING_WHITEIN) + progress = 1 - progress; + int level = round(progress * 16); + + assert(eff->is_fullscreen); + SDL_Rect dr = eff->dst_rect; + 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); + } + + 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)); + effect_finish(eff, false); + free(eff); +} + // EFFECT_BLIND_* static void blind_step(struct sdl_effect *eff, double progress); @@ -1348,6 +1437,11 @@ struct sdl_effect *sdl_effect_init(SDL_Rect *rect, agsurface_t *old, int ox, int case EFFECT_WHITEOUT_FROM_NEW: case EFFECT_WHITEIN: return brightness_new(rect, sf_old, sf_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); case EFFECT_BLIND_DOWN: case EFFECT_BLIND_UP: case EFFECT_BLIND_LR: