From 948158c1fdf54dd16c547f530a921b28c3d9a5a8 Mon Sep 17 00:00:00 2001 From: Bill Kendrick Date: Mon, 6 Feb 2023 02:22:21 -0800 Subject: [PATCH] WIP "Bloom" magic effect. Mend crash in "perspective.c" --- docs/CHANGES.txt | 15 +- magic/icons/bloom.png | Bin 0 -> 7904 bytes magic/src/bloom.c | 367 ++++++++++++++++++++++++++++++++++++++++ magic/src/perspective.c | 43 +++-- 4 files changed, 412 insertions(+), 13 deletions(-) create mode 100644 magic/icons/bloom.png create mode 100644 magic/src/bloom.c diff --git a/docs/CHANGES.txt b/docs/CHANGES.txt index 847966397..083f0697b 100644 --- a/docs/CHANGES.txt +++ b/docs/CHANGES.txt @@ -7,7 +7,7 @@ Various contributors (see below, and AUTHORS.txt) https://tuxpaint.org/ -2022.January.30 (0.9.29) +2023.February.6 (0.9.29) * Improvements to "Stamp" tool: ----------------------------- * Stamps may now be rotated. @@ -32,8 +32,7 @@ https://tuxpaint.org/ (Inspired by "Night Sky Scene [Pen Parallax]" Scratch Project by -HexaScape- ) - [WIP] - Fur sound effect needed - [WIP] - Fur sound icon needed + [WIP] - Fur icon needed ("Circles" and "Rays" sound effects based on Richard Wagner's "Ride of the Valkyries", recording licensed as Creative Commons @@ -43,6 +42,12 @@ https://tuxpaint.org/ ("Fur" sound effected licensed as Creative Commons 0 (CC0 1.0) by https://freesound.org/people/Kawgrim/) + * "Bloom" - Apply a glowing light bloom effect to the image. + Bill Kendrick + + [WIP] - Bloom icon needed + [WIP] - Bloom sound effect needed + * [WIP] "Rivulet"; apply rivulets of water to the canvas - needs better icon - needs sound effect @@ -167,6 +172,10 @@ https://tuxpaint.org/ (h/t Miyagi Andel for reporting & Shin-ichi TOYAMA for pinpointing the issue) + * Mend crash bug in "perspective.c" Magic tools. + (Perspective, Panels, Timezoom, Zoom, Rush) + Bill Kendrick + * Disallow using Ctrl-Z shortcut while drawing or rotating shapes or shapes, to avoid unexpected results. Closes https://sourceforge.net/p/tuxpaint/bugs/239/ diff --git a/magic/icons/bloom.png b/magic/icons/bloom.png new file mode 100644 index 0000000000000000000000000000000000000000..9768bca0deb28fd7587c5dd109ff787d0090ed17 GIT binary patch literal 7904 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 +#include +#include +#include + +#include "tp_magic_api.h" +#include "SDL_image.h" +#include "SDL_mixer.h" + +/* Radius of the painting tool */ +#define BLOOM_PAINT_RADIUS 24 + +/* Overall weight to apply the sampled pixels */ +#define BLOOM_WEIGHT_CONST 0.025 + +/* Length of spike shape */ +#define BLOOM_SPIKE_LENGTH 5 + +/* From https://www.shadertoy.com/view/lsXGWn */ +//float sample_weights[9] = { +// 0.05, 0.09, 0.12, 0.15, 0.16, 0.15, 0.12, 0.09, 0.05 +//}; + +/* Take N digits consecutive digits (1-n), calculate SIN() of + * (PI/(N+1))*n, take the SQRT(), and scale by a constant + * so they all SUM() to approx. 1.0000 */ +#define NUM_SAMPLE_WEIGHTS 13 +float sample_weights[NUM_SAMPLE_WEIGHTS] = { + 0.0449, 0.0627, 0.0752, 0.0842, 0.0904, 0.0940, 0.0952, 0.0940, 0.0904, 0.0842, 0.0752, 0.0627, 0.0449 +}; + +Mix_Chunk * snd_effects = NULL; +Uint8 * bloom_mask = NULL; +int bloom_scale; + +Uint32 bloom_api_version(void); +int bloom_init(magic_api * api); +int bloom_get_tool_count(magic_api * api); +SDL_Surface *bloom_get_icon(magic_api * api, int which); +char *bloom_get_name(magic_api * api, int which); +int bloom_get_group(magic_api * api, int which); +char *bloom_get_description(magic_api * api, int which, int mode); +int bloom_requires_colors(magic_api * api, int which); +int bloom_modes(magic_api * api, int which); +void bloom_shutdown(magic_api * api); +void bloom_click(magic_api * api, int which, int mode, + SDL_Surface * canvas, SDL_Surface * snapshot, int x, + int y, SDL_Rect * update_rect); +void bloom_set_color(magic_api * api, int which, SDL_Surface * canvas, + SDL_Surface * last, Uint8 r, Uint8 g, Uint8 b, SDL_Rect * update_rect); +void bloom_drag(magic_api * api, int which, SDL_Surface * canvas, + SDL_Surface * snapshot, int ox, int oy, int x, int y, + SDL_Rect * update_rect); +void bloom_line_callback_drag(void *ptr, int which, SDL_Surface * canvas, + SDL_Surface * snapshot, int x, int y); +void bloom_release(magic_api * api, int which, SDL_Surface * canvas, + SDL_Surface * snapshot, int x, int y, + SDL_Rect * update_rect); +void bloom_switchin(magic_api * api, int which, int mode, + SDL_Surface * canvas); +void bloom_switchout(magic_api * api, int which, int mode, + SDL_Surface * canvas); +float luminance(float r, float g, float b); +float change_luminance(float c_in, float l_in, float l_out); + + +Uint32 bloom_api_version(void) +{ + return (TP_MAGIC_API_VERSION); +} + +int bloom_init(magic_api * api) +{ + char fname[1024]; + + snprintf(fname, sizeof(fname), "%ssounds/magic/bloom.ogg", + api->data_directory); + snd_effects = NULL; /* FIXME Mix_LoadWAV(fname); */ + + bloom_scale = sqrt(2 * (BLOOM_PAINT_RADIUS * BLOOM_PAINT_RADIUS)); + + return (1); +} + +int bloom_get_tool_count(magic_api * api ATTRIBUTE_UNUSED) +{ + return (1); +} + +SDL_Surface *bloom_get_icon(magic_api * api, int which ATTRIBUTE_UNUSED) +{ + char fname[1024]; + + snprintf(fname, sizeof(fname), "%simages/magic/bloom.png", + api->data_directory); + + return (IMG_Load(fname)); +} + +char *bloom_get_name(magic_api * api ATTRIBUTE_UNUSED, + int which ATTRIBUTE_UNUSED) +{ + return strdup(gettext("Bloom")); +} + +int bloom_get_group(magic_api * api ATTRIBUTE_UNUSED, + int which ATTRIBUTE_UNUSED ATTRIBUTE_UNUSED) +{ + return MAGIC_TYPE_COLOR_FILTERS; +} + +char *bloom_get_description(magic_api * api ATTRIBUTE_UNUSED, + int which ATTRIBUTE_UNUSED, int mode ATTRIBUTE_UNUSED) +{ + return strdup(gettext("Bloom!")); /* FIXME */ +} + +int bloom_requires_colors(magic_api * api ATTRIBUTE_UNUSED, + int which ATTRIBUTE_UNUSED) +{ + return 0; /* TODO: Maybe some day? */ +} + +int bloom_modes(magic_api * api ATTRIBUTE_UNUSED, + int which ATTRIBUTE_UNUSED ATTRIBUTE_UNUSED) +{ + return (MODE_PAINT | MODE_FULLSCREEN); +} + +void bloom_shutdown(magic_api * api ATTRIBUTE_UNUSED) +{ + if (snd_effects != NULL) { + Mix_FreeChunk(snd_effects); + snd_effects = NULL; + } + + if (bloom_mask != NULL) { + free(bloom_mask); + bloom_mask = NULL; + } +} + +void +bloom_click(magic_api * api, int which, int mode, + SDL_Surface * canvas, SDL_Surface * snapshot, int x, int y, + SDL_Rect * update_rect) +{ + if (bloom_mask == NULL) + return; + + if (snd_effects != NULL) + api->stopsound(); + + if (mode == MODE_PAINT) { + memset(bloom_mask, 0, (canvas->w * canvas->h)); + bloom_drag(api, which, canvas, snapshot, x, y, x, y, update_rect); + } else { + if (snd_effects != NULL) { + api->playsound(snd_effects, (x * 255) / canvas->w, 255); + } + + memset(bloom_mask, 128, (canvas->w * canvas->h)); + bloom_release(api, which, canvas, snapshot, x, y, + update_rect); + + update_rect->x = 0; + update_rect->y = 0; + update_rect->w = canvas->w; + update_rect->h = canvas->h; + } +} + + +void +bloom_drag(magic_api * api ATTRIBUTE_UNUSED, int which ATTRIBUTE_UNUSED, SDL_Surface * canvas, + SDL_Surface * snapshot, int ox, int oy, int x, int y, SDL_Rect * update_rect) +{ + if (bloom_mask == NULL) + return; + + api->line((void *) api, which, canvas, snapshot, ox, oy, x, y, 1 /* FIXME: Consider fewer iterations? */, + bloom_line_callback_drag); + + /* FIXME: Would be good to only update the area around the line (ox,oy)->(x,y) (+/- the maxium radius of the effect) */ + update_rect->x = 0; + update_rect->y = 0; + update_rect->w = canvas->w; + update_rect->h = canvas->h; +} + + +void bloom_release(magic_api * api, int which ATTRIBUTE_UNUSED, + SDL_Surface * canvas ATTRIBUTE_UNUSED, + SDL_Surface * snapshot ATTRIBUTE_UNUSED, + int x ATTRIBUTE_UNUSED, int y ATTRIBUTE_UNUSED, + SDL_Rect * update_rect ATTRIBUTE_UNUSED) { + int sample, offset, offset_flip, xx, yy; + Uint8 r, g, b; + float rf, gf, bf, mask_weight, lum; + float sums[3]; + Uint32 color; + + if (bloom_mask == NULL) + return; + + if (snd_effects != NULL) + api->stopsound(); + + SDL_BlitSurface(snapshot, NULL, canvas, NULL); + + for (y = 0; y < canvas->h; y++) { + for (x = 0; x < canvas->w; x++) { + if (bloom_mask[y * canvas->w + x] > 0) { + sums[0] = 0.0; + sums[1] = 0.0; + sums[2] = 0.0; + + /* (Pull from snapshot) */ + for (sample = 0; sample < NUM_SAMPLE_WEIGHTS; sample++) { + /* Horizontal samples */ + color = api->getpixel(snapshot, x - ((NUM_SAMPLE_WEIGHTS - 1) / 2) + sample, y); + SDL_GetRGB(color, snapshot->format, &r, &g, &b); + sums[0] += r * sample_weights[sample]; + sums[1] += g * sample_weights[sample]; + sums[2] += b * sample_weights[sample]; + + /* Vertical samples */ + color = api->getpixel(snapshot, x, y - ((NUM_SAMPLE_WEIGHTS - 1) / 2) + sample); + SDL_GetRGB(color, snapshot->format, &r, &g, &b); + sums[0] += r * sample_weights[sample]; + sums[1] += g * sample_weights[sample]; + sums[2] += b * sample_weights[sample]; + } + + /* (Blend an "X" shape, additively, onto target canvas) */ + for (offset = -BLOOM_SPIKE_LENGTH; offset <= BLOOM_SPIKE_LENGTH; offset++) { + for (offset_flip = -1; offset <= 1; offset += 2) { + xx = x + offset; + yy = y + (offset * offset_flip); + + if (xx >= 0 && xx < canvas->w && yy >= 0 && yy < canvas->h) { + color = api->getpixel(snapshot, xx, yy); + SDL_GetRGB(color, snapshot->format, &r, &g, &b); + + mask_weight = (float) (bloom_mask[(yy) * canvas->w + xx] / 255.0); + mask_weight *= BLOOM_WEIGHT_CONST; + mask_weight *= ((BLOOM_SPIKE_LENGTH + 1) - (abs(offset)) / BLOOM_SPIKE_LENGTH); + + rf = (((float) r) + (sums[0] * mask_weight)) / 255.0; + gf = (((float) g) + (sums[1] * mask_weight)) / 255.0; + bf = (((float) b) + (sums[2] * mask_weight)) / 255.0; + + /* Reinhard Tonemap (Luminence) */ + lum = luminance(rf, gf, bf); + + if (lum > 0.0) { + float numerator = lum * (1.0f + lum); + float l_new = numerator / (1.0f + lum); + rf = change_luminance(rf, lum, l_new); + gf = change_luminance(gf, lum, l_new); + bf = change_luminance(bf, lum, l_new); + } + + /* Clamp */ + if (rf > 1.0) + rf = 1.0; + if (gf > 1.0) + gf = 1.0; + if (bf > 1.0) + bf = 1.0; + + rf *= 255.0; + gf *= 255.0; + bf *= 255.0; + + api->putpixel(canvas, xx, yy, SDL_MapRGB(canvas->format, (Uint8) rf, (Uint8) gf, (Uint8) bf)); + } + } + } + } + } + } + + update_rect->x = 0; + update_rect->y = 0; + update_rect->w = canvas->w; + update_rect->h = canvas->h; +} + + +void bloom_set_color(magic_api * api ATTRIBUTE_UNUSED, int which ATTRIBUTE_UNUSED ATTRIBUTE_UNUSED, + SDL_Surface * canvas ATTRIBUTE_UNUSED, + SDL_Surface * last ATTRIBUTE_UNUSED, + Uint8 r ATTRIBUTE_UNUSED, Uint8 g ATTRIBUTE_UNUSED, Uint8 b ATTRIBUTE_UNUSED, + SDL_Rect * update_rect ATTRIBUTE_UNUSED) +{ + /* TODO: Maybe some day? */ +} + + +void bloom_line_callback_drag(void *ptr, int which ATTRIBUTE_UNUSED, + SDL_Surface * canvas, + SDL_Surface * snapshot ATTRIBUTE_UNUSED, + int x, int y) +{ + int xrad, yrad, xx, yy, chg, n; + magic_api *api = (magic_api *) ptr; + + if (snd_effects != NULL) + api->playsound(snd_effects, (x * 255) / canvas->w, 255); + + for (yrad = -BLOOM_PAINT_RADIUS; yrad < BLOOM_PAINT_RADIUS; yrad++) { + yy = y + yrad; + if (yy >= 0 && yy < canvas->h) { + for (xrad = -BLOOM_PAINT_RADIUS; xrad < BLOOM_PAINT_RADIUS; xrad++) { + xx = x + xrad; + if (xx >= 0 && xx < canvas->w) { + if (api->in_circle(xrad, yrad, BLOOM_PAINT_RADIUS)) { + /* Add to the bloom mask */ + n = (int) bloom_mask[yy * canvas->w + xx]; + chg = sqrt(bloom_scale - sqrt((xrad * xrad) + (yrad * yrad))); + n += chg; + if (n > 255) { + n = 255; + } + bloom_mask[yy * canvas->w + xx] = (Uint8) n; + + /* Draw on the canvas temporarily */ + api->putpixel(canvas, xx, yy, SDL_MapRGB(canvas->format, n, n, n)); + } + } + } + } + } +} + + +void bloom_switchin(magic_api * api ATTRIBUTE_UNUSED, + int which ATTRIBUTE_UNUSED ATTRIBUTE_UNUSED, int mode ATTRIBUTE_UNUSED, + SDL_Surface * canvas ATTRIBUTE_UNUSED) +{ + if (bloom_mask == NULL) + bloom_mask = (Uint8 *) malloc(sizeof(Uint8) * canvas-> w * canvas->h); +} + +void bloom_switchout(magic_api * api ATTRIBUTE_UNUSED, + int which ATTRIBUTE_UNUSED ATTRIBUTE_UNUSED, + int mode ATTRIBUTE_UNUSED, + SDL_Surface * canvas ATTRIBUTE_UNUSED) +{ +} + +float luminance(float r, float g, float b) { + return (r * 0.2126) + (g * 0.7152) + (b * 0.0722); +} + +float change_luminance(float c_in, float l_in, float l_out) { + return c_in * (l_out / l_in); +} diff --git a/magic/src/perspective.c b/magic/src/perspective.c index f2a535ef6..0c9f6ca94 100644 --- a/magic/src/perspective.c +++ b/magic/src/perspective.c @@ -32,7 +32,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA (See COPYING.txt) - Last updated: January 25, 2023 + Last updated: February 6, 2023 */ #include @@ -146,7 +146,7 @@ enum /* A copy of canvas at switchin, will be used to draw from it as snapshot changes at each click */ -static SDL_Surface *canvas_back; +static SDL_Surface *canvas_back = NULL; static Mix_Chunk *perspective_snd_effect[perspective_NUM_TOOLS + 1]; @@ -252,6 +252,9 @@ void perspective_drag(magic_api * api, int which, SDL_Surface * canvas, int oy ATTRIBUTE_UNUSED, int x, int y, SDL_Rect * update_rect) { + if (canvas_back == NULL) + return; + latest_x = x; latest_y = y; @@ -479,6 +482,9 @@ void perspective_release(magic_api * api, int which, SDL_Surface * canvas, SDL_Surface * last, int x, int y, SDL_Rect * update_rect) { + if (canvas_back == NULL) + return; + if (which == TOOL_PANELS) return; @@ -662,6 +668,10 @@ void perspective_release(magic_api * api, int which, canvas->format->Gmask, canvas->format->Bmask, 0); +printf("SDL_BlitSurface(canvas_back (%d), update_rect (%d), aux_surf (%d), NULL\n", +canvas_back, update_rect, aux_surf); +fflush(stdout); + SDL_BlitSurface(canvas_back, update_rect, aux_surf, NULL); scaled_surf = api->scale(aux_surf, canvas->w, canvas->h, 0); SDL_BlitSurface(scaled_surf, NULL, canvas, NULL); @@ -687,6 +697,9 @@ void perspective_preview(magic_api * api, int which, int ox_distance, oy_distance; int center_ofset_x, center_ofset_y; + if (canvas_back == NULL) + return; + update_rect->x = update_rect->y = 0; update_rect->w = canvas->w; @@ -826,13 +839,20 @@ void perspective_switchin(magic_api * api ATTRIBUTE_UNUSED, amask = ~(canvas->format->Rmask | canvas->format->Gmask | canvas->format->Bmask); - canvas_back = SDL_CreateRGBSurface(SDL_SWSURFACE, - canvas->w, - canvas->h, - canvas->format->BitsPerPixel, - canvas->format->Rmask, - canvas->format->Gmask, - canvas->format->Bmask, amask); + if (canvas_back == NULL) { + canvas_back = SDL_CreateRGBSurface(SDL_SWSURFACE, + canvas->w, + canvas->h, + canvas->format->BitsPerPixel, + canvas->format->Rmask, + canvas->format->Gmask, + canvas->format->Bmask, amask); + } + + if (canvas_back == NULL) { + fprintf(stderr, "perspective cannot create background canvas!\n"); + return; + } SDL_BlitSurface(canvas, NULL, canvas_back, NULL); } @@ -842,7 +862,10 @@ void perspective_switchout(magic_api * api ATTRIBUTE_UNUSED, int mode ATTRIBUTE_UNUSED, SDL_Surface * canvas ATTRIBUTE_UNUSED) { - SDL_FreeSurface(canvas_back); + if (canvas_back != NULL) { + SDL_FreeSurface(canvas_back); + canvas_back = NULL; + } } int perspective_modes(magic_api * api ATTRIBUTE_UNUSED, int which)