From 6a43019f850bbbed02e46625f2cfa86f556ab234 Mon Sep 17 00:00:00 2001 From: Bill Kendrick Date: Mon, 16 Jan 2023 16:17:57 -0800 Subject: [PATCH] WIP: Rivulet magic tool --- docs/CHANGES.txt | 4 +- magic/icons/rivulet-angles.png | Bin 0 -> 1700 bytes magic/icons/rivulet-brush-add.png | Bin 0 -> 6692 bytes magic/icons/rivulet-brush-sub.png | Bin 0 -> 992 bytes magic/icons/rivulet.png | Bin 0 -> 6692 bytes magic/src/rivulet.c | 311 ++++++++++++++++++++++++++++++ 6 files changed, 314 insertions(+), 1 deletion(-) create mode 100644 magic/icons/rivulet-angles.png create mode 100644 magic/icons/rivulet-brush-add.png create mode 100644 magic/icons/rivulet-brush-sub.png create mode 100644 magic/icons/rivulet.png create mode 100644 magic/src/rivulet.c diff --git a/docs/CHANGES.txt b/docs/CHANGES.txt index b7ced01bb..cf565da80 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.11 (0.9.29) +2022.January.16 (0.9.29) * Improvements to "Stamp" tool: ----------------------------- * Stamps may now be rotated. @@ -21,6 +21,8 @@ https://tuxpaint.org/ (Sound effect licensed as Creative Commons 0 by https://freesound.org/people/MrFossy/) + * [WIP] "Rivulet"; apply rivulets of water to the canvas + * Improvements to Magic Tools: ---------------------------- * Better performance from "Rush" (by using SDL_gfx rotozoom) diff --git a/magic/icons/rivulet-angles.png b/magic/icons/rivulet-angles.png new file mode 100644 index 0000000000000000000000000000000000000000..4199ed07ca7b47de76cf9af06619054892c8ff4a GIT binary patch literal 1700 zcmV;V23z@wP)EX>4Tx04R}tkv&MmP!xqvQ>7{u1q+HeWT-A$5EXIMDionYs1;guFnQ@8G-*gu zTpR`0f`dPcRRFVUWr1gg%w%GoI7BSwnpkOKmNzxxDdMoI>69;| zJXSexan_1uR=+2IVKAewEOVXK5Mo%w5+sOFP(}eo*oe@slVTx3=g}7aLDw&lOCeVQ zj2sInL4)l2!T;d*Y_06%gqIYI0_`u3^Dztrc7a;OalVfor*;DPpMfjA;V)HznNQLy z4J~{G^lSqc*9}eC11@)ffhR*YWmodk60%v~{fxdT4fNdtU2ERl>gPCp0FpGT_ziGy z2#n+?d%eZGJDTVAZ%=)GKUcbPoNSbDkpKVy32;bRa{vG?BLDy{BLR4&KXw2B00(qQ zO+^Ri0T350A>YOT@c;k-8FWQhbVF}#ZDnqB07G(RVRU6=Aa`kWXdp*PO;A^X4i^9b z1dT~VK~zY`Wma2~Bt;UFCSYC509+swT-k&3yZRp zza;nIZ@>ReQluo3`oC3G|MRX|RiFQ>5;^~02z)*(4itklA=n|4IAN{@AlQpQ5C9}d zk_0J{0LRnq?`*XaW1wN0DkQK)Isu|>Be{@qA(MMQP#b&J<3zTd>j~o6nGg~L!KXkT zaR30WRA8e?ti8MJiOUHakOhTp2qbKhrfHI7f=LteDFQ%OS_YnaR^SR?#SY2Pov4bj z8!B!aVJuvU0tte^6Zw&n$9BI+h+1w_>`*1T0VpI8Z2v>%44F$Ou@3F_8oP$b}Opm2lS>q^R1imNx!C*CeYT3RoS>q?ELvC_xfnU0jsXj(jl| zgs!S;tc*TBr)#3aL=cdU!~hBtKtNxlq?%Op;1NkZb+?sQDoGsorI81T>NqioJ=(lgj3Cjwjo91D>XxoRYwK*U+K(r`dksj613 zwQ8->1fZ%SAPHhk{XndC6AU-?q}U`Q$K|-Z0z%TcmhTa{*1BD5tx~PJDD-R|o5@^m z&mM$8d!$8)w9G13Vg#!44?jq{-ELp*_xqPGx7(7cYH3Sr+!mi~!*Vy~0Ptm&04NfY z)O8+bp9cB$&w^s?N)1*>XG01FvRl#*6E(zvs(fTAut?DzLRf%zrFtb zis0ve{ruCnpKiC?ZVG&;o8xs50z2oxPSLCYL=aAoo0G%|Y=0adfBgGDzx?{kU*EqU z$6-6RhXHN82Uc?zem25lCvC-DES0 z-ss)!c6XnB9>;NTx0+@QW}AVN)ottpZ2WDY&$DgYXS?m*Gj#gA20zI3^#)-IZknO(X$e{5 z@zecH9Jkx{d7gc`+wL9c+#afAtE#+vY!+y^0W&s*Kya|yJ&7N}+qSzMpYBWqj@!7V z!PT>7)+_}HvYZZ43>^|d49Z@Q5^StwlkTzd>6S6A1SCL7O2mRjM{$Az%)kf}1Iz9J z?(Kczbo{iEZ2`XY7!nj|k&)y;N+1B8-X} literal 0 HcmV?d00001 diff --git a/magic/icons/rivulet-brush-add.png b/magic/icons/rivulet-brush-add.png new file mode 100644 index 0000000000000000000000000000000000000000..3b756dc7de52787068c62de30603e6fef66f2e1a GIT binary patch literal 6692 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 Za_SL3v+VOp7TC8SHdgkQrJMd0`EQEetkM7g literal 0 HcmV?d00001 diff --git a/magic/icons/rivulet-brush-sub.png b/magic/icons/rivulet-brush-sub.png new file mode 100644 index 0000000000000000000000000000000000000000..d56ffa21e47ae570f7731a6cf73d549db5890354 GIT binary patch literal 992 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 Za_SL3v+VOp7TC8SHdgkQrJMd0`EQEetkM7g literal 0 HcmV?d00001 diff --git a/magic/src/rivulet.c b/magic/src/rivulet.c new file mode 100644 index 000000000..2eacdf9a0 --- /dev/null +++ b/magic/src/rivulet.c @@ -0,0 +1,311 @@ +/* rivulet.c + + Applys a lense effect like rivulets of water dripping + down a pane of glass. Applies an additive brush at + the mouse pointer, and a subtractive brush slightly + above (to simulate the water breaking up due to + evaporation), only allowing the draw path to go downwards, + and the left/right delta to change slightly (will not + follow the mouse precisely). Upon release, the lense + effect will be applied. + + Last modified: 2023.01.16 +*/ + +#include +#include +#include +#include + +#include "tp_magic_api.h" +#include "SDL_image.h" +#include "SDL_mixer.h" + +Mix_Chunk *snd_effect = NULL; +SDL_Surface * rivulet_img_brush_add, + * rivulet_img_brush_sub, + * rivulet_img_angles; +int riv_x, riv_y; +Uint8 * riv_radii = NULL, + * riv_angles = NULL; + +Uint32 rivulet_api_version(void); +int rivulet_init(magic_api * api); +int rivulet_get_tool_count(magic_api * api); +SDL_Surface *rivulet_get_icon(magic_api * api, int which); +char *rivulet_get_name(magic_api * api, int which); +int rivulet_get_group(magic_api * api, int which); +char *rivulet_get_description(magic_api * api, int which, int mode); +int rivulet_requires_colors(magic_api * api, int which); +int rivulet_modes(magic_api * api, int which); +void rivulet_shutdown(magic_api * api); +void rivulet_click(magic_api * api, int which, int mode, + SDL_Surface * canvas, SDL_Surface * snapshot, int x, + int y, SDL_Rect * update_rect); +void rivulet_set_color(magic_api * api, Uint8 r, Uint8 g, Uint8 b); +void rivulet_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 rivulet_line_callback_drag(void *ptr, int which, SDL_Surface * canvas, + SDL_Surface * snapshot, int x, int y); +void rivulet_release(magic_api * api, int which, SDL_Surface * canvas, + SDL_Surface * snapshot, int x, int y, + SDL_Rect * update_rect); +void rivulet_switchin(magic_api * api, int which, int mode, + SDL_Surface * canvas); +void rivulet_switchout(magic_api * api, int which, int mode, + SDL_Surface * canvas); +void zero_riv_arrays(SDL_Surface * canvas); + + +Uint32 rivulet_api_version(void) +{ + return (TP_MAGIC_API_VERSION); +} + +int rivulet_init(magic_api * api) +{ + char fname[1024]; + + /* FIXME */ +// snprintf(fname, sizeof(fname), "%ssounds/magic/rivulet.ogg", +// api->data_directory); +// snd_effect = Mix_LoadWAV(fname); + + /* Load our images */ + snprintf(fname, sizeof(fname), "%simages/magic/rivulet-brush-add.png", + api->data_directory); + rivulet_img_brush_add = IMG_Load(fname); + if (rivulet_img_brush_add == NULL) + { + fprintf(stderr, "Can't open %s\n", fname); + return 0; + } + + snprintf(fname, sizeof(fname), "%simages/magic/rivulet-brush-sub.png", + api->data_directory); + rivulet_img_brush_sub = IMG_Load(fname); + if (rivulet_img_brush_sub == NULL) + { + fprintf(stderr, "Can't open %s\n", fname); + return 0; + } + + snprintf(fname, sizeof(fname), "%simages/magic/rivulet-brush-sub.png", + api->data_directory); + rivulet_img_angles = IMG_Load(fname); + if (rivulet_img_angles == NULL) + { + fprintf(stderr, "Can't open %s\n", fname); + return 0; + } + + return (1); +} + +int rivulet_get_tool_count(magic_api * api ATTRIBUTE_UNUSED) +{ + return (1); +} + + +SDL_Surface *rivulet_get_icon(magic_api * api, int which ATTRIBUTE_UNUSED) +{ + char fname[1024]; + + snprintf(fname, sizeof(fname), "%simages/magic/rivulet.png", + api->data_directory); + + return (IMG_Load(fname)); +} + +char *rivulet_get_name(magic_api * api ATTRIBUTE_UNUSED, + int which ATTRIBUTE_UNUSED) +{ + return strdup(gettext("Rivulet")); +} + +int rivulet_get_group(magic_api * api ATTRIBUTE_UNUSED, + int which ATTRIBUTE_UNUSED) +{ + return MAGIC_TYPE_DISTORTS; +} + +char *rivulet_get_description(magic_api * api ATTRIBUTE_UNUSED, + int which ATTRIBUTE_UNUSED, + int mode ATTRIBUTE_UNUSED) +{ + return(gettext("Click and drag to add water rivulets to your drawing")); +} + +int rivulet_requires_colors(magic_api * api ATTRIBUTE_UNUSED, + int which ATTRIBUTE_UNUSED) +{ + return 0; +} + +int rivulet_modes(magic_api * api ATTRIBUTE_UNUSED, + int which ATTRIBUTE_UNUSED) +{ + return MODE_PAINT; +} + +void rivulet_shutdown(magic_api * api ATTRIBUTE_UNUSED) +{ + if (snd_effect != NULL) + Mix_FreeChunk(snd_effect); + + if (rivulet_img_brush_add != NULL) + SDL_FreeSurface(rivulet_img_brush_add); + + if (rivulet_img_brush_sub != NULL) + SDL_FreeSurface(rivulet_img_brush_add); + + if (rivulet_img_angles != NULL) + SDL_FreeSurface(rivulet_img_angles); + + if (riv_radii != NULL) + free(riv_radii); + + if (riv_angles != NULL) + free(riv_angles); +} + + +void +rivulet_click(magic_api * api, int which, int mode ATTRIBUTE_UNUSED, + SDL_Surface * canvas, SDL_Surface * snapshot, int x, int y, + SDL_Rect * update_rect) +{ + riv_x = x; + riv_y = y; + + if (riv_radii == NULL) + return; + + if (snd_effect != NULL) + { + api->stopsound(); + api->playsound(snd_effect, (x * 255) / canvas->w, 255); + } + + rivulet_drag(api, which, canvas, snapshot, x, y, x, y, update_rect); +} + + +void +rivulet_drag(magic_api * api ATTRIBUTE_UNUSED, int which, SDL_Surface * canvas, + SDL_Surface * snapshot, int ox ATTRIBUTE_UNUSED, + int oy ATTRIBUTE_UNUSED, int x, int y, SDL_Rect * update_rect) +{ + int old_riv_x, old_riv_y; + + if (riv_radii == NULL) + return; + + /* Don't go backwards */ + if (y < riv_y) + return; + + /* Don't stray too far left/right */ + if (x < riv_x - 2) + x = riv_x - 2; + if (x > riv_x + 2) + x = riv_x + 2; + + old_riv_x = riv_x; + old_riv_y = riv_y; + + riv_x = x; + riv_y = y; + + api->line((void *) api, which, canvas, snapshot, old_riv_x, old_riv_y, riv_x, riv_y, 1, + rivulet_line_callback_drag); + + /* FIXME */ + update_rect->x = 0; + update_rect->y = 0; + update_rect->w = canvas->w; + update_rect->h = canvas->h; +} + + +void +rivulet_release(magic_api * api ATTRIBUTE_UNUSED, 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) +{ + if (riv_radii == NULL) + return; + + /* FIXME */ +} + + +void rivulet_set_color(magic_api * api ATTRIBUTE_UNUSED, + Uint8 r ATTRIBUTE_UNUSED, Uint8 g ATTRIBUTE_UNUSED, Uint8 b ATTRIBUTE_UNUSED) +{ +} + + +void rivulet_line_callback_drag(void *ptr ATTRIBUTE_UNUSED, int which ATTRIBUTE_UNUSED, + SDL_Surface * canvas, + SDL_Surface * snapshot ATTRIBUTE_UNUSED, + int x, int y) +{ + SDL_Rect dest; + + dest.x = x - 3; + dest.y = y - 3; + dest.w = 7; + dest.h = 7; + + SDL_FillRect(canvas, &dest, SDL_MapRGB(canvas->format, 255, 255, 255)); + + dest.x = x - 2; + dest.y = y - 3; + dest.w = 5; + dest.h = 8; + + SDL_FillRect(canvas, &dest, SDL_MapRGB(canvas->format, 0, 0, 0)); +} + +void rivulet_switchin(magic_api * api ATTRIBUTE_UNUSED, + int which ATTRIBUTE_UNUSED, int mode ATTRIBUTE_UNUSED, + SDL_Surface * canvas) +{ + if (riv_radii == NULL) + { + riv_radii = (Uint8 *) malloc(sizeof(Uint8) * canvas->w * canvas->h); + if (riv_radii == NULL) + { + fprintf(stderr, "rivulet: Cannot malloc() riv_radii!\n"); + return; + } + + riv_angles = (Uint8 *) malloc(sizeof(Uint8) * canvas->w * canvas->h); + if (riv_angles == NULL) + { + free(riv_radii); + riv_radii = NULL; + fprintf(stderr, "rivulet: Cannot malloc() riv_angles!\n"); + return; + } + } + + zero_riv_arrays(canvas); +} + +void rivulet_switchout(magic_api * api ATTRIBUTE_UNUSED, + int which ATTRIBUTE_UNUSED, + int mode ATTRIBUTE_UNUSED, + SDL_Surface * canvas ATTRIBUTE_UNUSED) +{ +} + +void zero_riv_arrays(SDL_Surface * canvas) +{ + memset(riv_radii, 0, (canvas->w * canvas->h)); + memset(riv_angles, 0, (canvas->w * canvas->h)); +}