From 06aa68266738a424563adc9a0bde9b9d15fc5ca7 Mon Sep 17 00:00:00 2001 From: Bill Kendrick Date: Tue, 28 Feb 2023 01:20:47 -0800 Subject: [PATCH] Actually commiting new Magic tool source ...and CHANGES.txt update --- docs/CHANGES.txt | 16 +++- magic/src/fade_darken.c | 162 ++++++++++++++++++++++++++++------------ 2 files changed, 130 insertions(+), 48 deletions(-) diff --git a/docs/CHANGES.txt b/docs/CHANGES.txt index afb917385..c9831a3d0 100644 --- a/docs/CHANGES.txt +++ b/docs/CHANGES.txt @@ -7,7 +7,7 @@ Various contributors (see below, and AUTHORS.txt) https://tuxpaint.org/ -2023.February.26 (0.9.29) +2023.February.28 (0.9.29) * Improvements to "Stamp" tool: ----------------------------- * Stamps may now be rotated. @@ -58,6 +58,20 @@ https://tuxpaint.org/ Attribution 4.0 International (CC BY 4.0) by https://freesound.org/people/juskiddink/) + * [WIP] "Saturate" & "Desaturate" - Increase or decrease color saturation. + Bill Kendrick + - need icons + - need sound effects + + * [WIP] "Keep Color" & "Remove Color" - Completely desaturate + parts of the picture, based on the chosen color. + "Keep" keeps the saturation intact if the colors match; + while "Remove" desaturates parts of the image that match the + chosen color. + Bill Kendrick + - need icons + - need sound effects + * [WIP] "Rivulet"; apply rivulets of water to the canvas - needs better icon - needs sound effect diff --git a/magic/src/fade_darken.c b/magic/src/fade_darken.c index d3c1ca437..75bccb5e6 100644 --- a/magic/src/fade_darken.c +++ b/magic/src/fade_darken.c @@ -23,7 +23,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA (See COPYING.txt) - Last updated: February 12, 2023 + Last updated: February 28, 2023 */ #include @@ -36,10 +36,75 @@ enum { TOOL_FADE, TOOL_DARKEN, + TOOL_DESATURATE, + TOOL_SATURATE, + TOOL_REMOVE, + TOOL_KEEP, NUM_TOOLS }; +char * tool_names[NUM_TOOLS] = { + gettext_noop("Lighten"), + gettext_noop("Darken"), + gettext_noop("Desaturate"), + gettext_noop("Saturate"), + gettext_noop("Remove Color"), + gettext_noop("Keep Color"), +}; + +char * tool_descriptions[NUM_TOOLS][2] = { + { + gettext_noop("Click and drag the mouse to lighten parts of your picture."), + gettext_noop("Click to lighten your entire picture.") + }, + { + gettext_noop("Click and drag the mouse to darken parts of your picture."), + gettext_noop("Click to darken your entire picture.") + }, + { + gettext_noop("Click and drag the mouse to desaturate parts of your picture."), + gettext_noop("Click to desaturate your entire picture.") + }, + { + gettext_noop("Click and drag the mouse to saturate parts of your picture."), + gettext_noop("Click to saturate your entire picture.") + }, + { + gettext_noop("Click and drag the mouse to entirely desaturate parts of your picture that match the chosen color."), + gettext_noop("Click to entirely desaturate your the parts of your picture that match the chosen color."), + }, + { + gettext_noop("Click and drag the mouse to entirely desaturate parts of your picture that don't match the chosen color."), + gettext_noop("Click to entirely desaturate your the parts of your picture that don't match the chosen color."), + }, +}; + +char * sfx_filenames[NUM_TOOLS] = { + "fade.wav", + "darken.wav", + "fade.wav", // FIXME + "darken.wav", // FIXME + "darken.wav", // FIXME + "darken.wav", // FIXME +}; + +char * icon_filenames[NUM_TOOLS] = { + "fade.png", + "darken.png", + "fade.png", // FIXME + "darken.png", // FIXME + "darken.png", // FIXME + "darken.png", // FIXME +}; + static Mix_Chunk *snd_effects[NUM_TOOLS]; +float chosen_h, chosen_s; + +#define KEEP_REMOVE_HUE_THRESH 15.0 +#define KEEP_REMOVE_VALUE_THRESH 0.4 + +#define SAT_DESAT_RATIO_NUM 3 +#define SAT_DESAT_RATIO_DENOM 4 /* Local function prototypes: */ @@ -74,17 +139,17 @@ void fade_darken_switchout(magic_api * api, int which, int mode, SDL_Surface * canvas); int fade_darken_modes(magic_api * api, int which); + int fade_darken_init(magic_api * api) { + int i; char fname[1024]; - snprintf(fname, sizeof(fname), "%ssounds/magic/fade.wav", - api->data_directory); - snd_effects[TOOL_FADE] = Mix_LoadWAV(fname); - - snprintf(fname, sizeof(fname), "%ssounds/magic/darken.wav", - api->data_directory); - snd_effects[TOOL_DARKEN] = Mix_LoadWAV(fname); + for (i = 0; i < NUM_TOOLS; i++) { + snprintf(fname, sizeof(fname), "%ssounds/magic/%s", + api->data_directory, sfx_filenames[i]); + snd_effects[i] = Mix_LoadWAV(fname); + } return (1); } @@ -105,16 +170,8 @@ SDL_Surface *fade_darken_get_icon(magic_api * api, int which) { char fname[1024]; - if (which == TOOL_FADE) - { - snprintf(fname, sizeof(fname), "%simages/magic/fade.png", - api->data_directory); - } - else if (which == TOOL_DARKEN) - { - snprintf(fname, sizeof(fname), "%simages/magic/darken.png", - api->data_directory); - } + snprintf(fname, sizeof(fname), "%simages/magic/%s", + api->data_directory, icon_filenames[which]); return (IMG_Load(fname)); } @@ -122,12 +179,7 @@ SDL_Surface *fade_darken_get_icon(magic_api * api, int which) // Return our name, localized: char *fade_darken_get_name(magic_api * api ATTRIBUTE_UNUSED, int which) { - if (which == TOOL_FADE) - return (strdup(gettext_noop("Lighten"))); - else if (which == TOOL_DARKEN) - return (strdup(gettext_noop("Darken"))); - - return (NULL); + return strdup(gettext(tool_names[which])); } // Return our group (all the same): @@ -141,26 +193,7 @@ int fade_darken_get_group(magic_api * api ATTRIBUTE_UNUSED, char *fade_darken_get_description(magic_api * api ATTRIBUTE_UNUSED, int which, int mode) { - if (which == TOOL_FADE) - { - if (mode == MODE_PAINT) - return (strdup - (gettext_noop - ("Click and drag the mouse to lighten parts of your picture."))); - else if (mode == MODE_FULLSCREEN) - return (strdup(gettext_noop("Click to lighten your entire picture."))); - } - else if (which == TOOL_DARKEN) - { - if (mode == MODE_PAINT) - return (strdup - (gettext_noop - ("Click and drag the mouse to darken parts of your picture."))); - else if (mode == MODE_FULLSCREEN) - return (strdup(gettext_noop("Click to darken your entire picture."))); - } - - return (NULL); + return strdup(gettext(tool_descriptions[which][mode - 1])); } static void do_fade_darken(void *ptr, int which, SDL_Surface * canvas, @@ -183,10 +216,40 @@ static void do_fade_darken(void *ptr, int which, SDL_Surface * canvas, g = max(g - 48, 0); b = max(b - 48, 0); } + else + { + float h, s, v; + + api->rgbtohsv(r, g, b, &h, &s, &v); + + if (which == TOOL_DESATURATE) { + s = (s * SAT_DESAT_RATIO_NUM) / SAT_DESAT_RATIO_DENOM; + } else if (which == TOOL_SATURATE) { + if (s > 0.1) { /* don't saturate things w/o undefined color! */ + s = (s * SAT_DESAT_RATIO_DENOM) / SAT_DESAT_RATIO_NUM; + if (s > 1.0) { + s = 1.0; + } + } + } else if (which == TOOL_REMOVE) { + if (fabs(h - chosen_h) <= KEEP_REMOVE_HUE_THRESH && + fabs(s - chosen_s) <= KEEP_REMOVE_VALUE_THRESH) { + s = 0.0; + } + } else if (which == TOOL_KEEP) { + if (fabs(h - chosen_h) > KEEP_REMOVE_HUE_THRESH || + fabs(s - chosen_s) > KEEP_REMOVE_VALUE_THRESH) { + s = 0.0; + } + } + + api->hsvtorgb(h, s, v, &r, &g, &b); + } api->putpixel(canvas, x, y, SDL_MapRGB(canvas->format, r, g, b)); } + // Callback that does the fade_darken color effect on a circle centered around x,y static void do_fade_darken_paint(void *ptr, int which, SDL_Surface * canvas, SDL_Surface * last, int x, int y) @@ -288,16 +351,21 @@ void fade_darken_shutdown(magic_api * api ATTRIBUTE_UNUSED) Mix_FreeChunk(snd_effects[1]); } -// We don't use colors -void fade_darken_set_color(magic_api * api ATTRIBUTE_UNUSED, int which 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) +void fade_darken_set_color(magic_api * api, int which ATTRIBUTE_UNUSED, SDL_Surface * canvas ATTRIBUTE_UNUSED, + SDL_Surface * last ATTRIBUTE_UNUSED, Uint8 r, Uint8 g, Uint8 b, SDL_Rect * update_rect ATTRIBUTE_UNUSED) { + float tmp; + + api->rgbtohsv(r, g, b, &chosen_h, &chosen_s, &tmp); } // We don't use colors int fade_darken_requires_colors(magic_api * api ATTRIBUTE_UNUSED, int which ATTRIBUTE_UNUSED) { + if (which == TOOL_REMOVE || which == TOOL_KEEP) + return 1; + return 0; }