diff --git a/docs/CHANGES.txt b/docs/CHANGES.txt index 5b9d9935b..5f75f4b48 100644 --- a/docs/CHANGES.txt +++ b/docs/CHANGES.txt @@ -7,6 +7,16 @@ Various contributors (see below, and AUTHORS.txt) https://tuxpaint.org/ 2024.February.28 (0.9.33) + * New Magic Tools: + ---------------- + * WIP Specular Reflection: Draws a slightly blurred, wavy, and + faded reflection of the opposite half of the drawing. + Bill Kendrick + + WIP Needs docs + + WIP Add to new features lists + + WIP Needs icon + + WIP Needs sound effect + * Other Improvements: ------------------- * Make screen refresh more snappy on macOS. diff --git a/magic/src/specular.c b/magic/src/specular.c new file mode 100644 index 000000000..345a52fda --- /dev/null +++ b/magic/src/specular.c @@ -0,0 +1,229 @@ +/* specular.c + + A specular reflection Magic tool for Tux Paint + by Bill Kendrick + + Last updated: February 28, 2024 +*/ + + +/* Inclusion of header files */ +/* ---------------------------------------------------------------------- */ + +#include +#include +#include + +#include "tp_magic_api.h" +#include "SDL_image.h" +#include "SDL_mixer.h" + +/* Our global variables: */ +/* ---------------------------------------------------------------------- */ + +/* Sound effects: */ +Mix_Chunk *snd_effect; + +/* The size the user has selected in Tux Paint: */ +Uint8 specular_size = 32; + + +void specular_drag(magic_api * api, int which, SDL_Surface * canvas, + SDL_Surface * snapshot, int old_x, int old_y, int x, int y, + SDL_Rect * update_rect); + +void specular_line_callback(void *pointer, int which, SDL_Surface * canvas, + SDL_Surface * snapshot, int x, int y); + + +Uint32 specular_api_version(void) +{ + return (TP_MAGIC_API_VERSION); +} + +int specular_init(magic_api * api, Uint8 disabled_features, Uint8 complexity_level) +{ + int i; + char filename[1024]; + + snprintf(filename, sizeof(filename), "%ssounds/magic/%s", api->data_directory, + "reflection.ogg"); // FIXME + snd_effect = Mix_LoadWAV(filename); + + return (1); +} + + +int specular_get_tool_count(magic_api * api) +{ + return (1); +} + +SDL_Surface *specular_get_icon(magic_api * api, int which) +{ + char filename[1024]; + + snprintf(filename, sizeof(filename), "%simages/magic/%s", + api->data_directory, "reflection.png"); // FIXME + + return (IMG_Load(filename)); +} + + +char *specular_get_name(magic_api * api, int which) +{ + return strdup(gettext("Specular Reflection")); +} + + +int specular_get_group(magic_api * api, int which) +{ + return MAGIC_TYPE_PAINTING; +} + + +int specular_get_order(int which) +{ + return 1710; +} + + +char *specular_get_description(magic_api * api, int which, int mode) +{ + return strdup(gettext("Click and drag on the bottom half of your picture to draw a specular reflection — like a puddle, pond, or lake — that mirrors the top half of your picture.")); +} + + +int specular_requires_colors(magic_api * api, int which) +{ + return 0; +} + + +int specular_modes(magic_api * api, int which) +{ + return MODE_PAINT; +} + + +Uint8 specular_accepted_sizes(magic_api * api, int which, int mode) +{ + return 4; +} + + +Uint8 specular_default_size(magic_api * api, int which, int mode) +{ + return 2; +} + + +void specular_shutdown(magic_api * api) +{ + if (snd_effect != NULL) { + Mix_FreeChunk(snd_effect); + } +} + + +void +specular_click(magic_api * api, int which, int mode, + SDL_Surface * canvas, SDL_Surface * snapshot, int x, int y, + SDL_Rect * update_rect) +{ + specular_drag(api, which, canvas, snapshot, x, y, x, y, update_rect); +} + + +void +specular_drag(magic_api * api, int which, + SDL_Surface * canvas, SDL_Surface * snapshot, + int old_x, int old_y, int x, int y, + SDL_Rect * update_rect) +{ + SDL_LockSurface(snapshot); + SDL_LockSurface(canvas); + + api->line((void *) api, which, canvas, snapshot, + old_x, old_y, x, y, 1, + specular_line_callback); + + SDL_UnlockSurface(canvas); + SDL_UnlockSurface(snapshot); + + if (old_x > x) + { + int temp = old_x; + + old_x = x; + x = temp; + } + if (old_y > y) + { + int temp = old_y; + + old_y = y; + y = temp; + } + + update_rect->x = old_x - specular_size; + update_rect->y = old_y - specular_size; + update_rect->w = (x + specular_size) - update_rect->x + 1; + update_rect->h = (y + specular_size) - update_rect->y + 1; + + api->playsound(snd_effect, (x * 255) / canvas->w, 255); +} + +void +specular_release(magic_api * api, int which, + SDL_Surface * canvas, SDL_Surface * snapshot, int x, int y, + SDL_Rect * update_rect) +{ +} + +void specular_set_color(magic_api * api, int which, SDL_Surface * canvas, SDL_Surface * snapshot, Uint8 r, Uint8 g, Uint8 b, SDL_Rect * update_rect) +{ +} + +void specular_set_size(magic_api * api, int which, int mode, SDL_Surface * canvas, SDL_Surface * snapshot, Uint8 size, SDL_Rect * update_rect) +{ + specular_size = size * 16; +} + + +void specular_line_callback(void *pointer, int which, SDL_Surface * canvas, + SDL_Surface * snapshot, int x, int y) +{ + magic_api *api = (magic_api *) pointer; + int xx, yy; + Uint8 r, g, b, r1, g1, b1, r2, g2, b2, fade; + + for (yy = -specular_size / 16; yy < specular_size / 16; yy++) + { + for (xx = -specular_size; xx < specular_size; xx++) + { + if (api->in_circle(xx, yy * 16, specular_size)) + { + SDL_GetRGB(api->getpixel(snapshot, x + xx + sin((y + yy) / 4) * 4, snapshot->h - y - yy), snapshot->format, &r1, &g1, &b1); + SDL_GetRGB(api->getpixel(snapshot, x + xx + sin((y + yy) / 4) * 4 + 1, snapshot->h - y - yy), snapshot->format, &r2, &g2, &b2); + + fade = (((y + yy) * 255) / canvas->h); + r = (((r1 + r2) * 2) + fade) / 5; + g = (((g1 + g2) * 2) + fade) / 5; + b = (((b1 + b2) * 2) + fade) / 5; + + api->putpixel(canvas, x + xx, y + yy, SDL_MapRGB(canvas->format, r, g, b)); + } + } + } +} + +void specular_switchin(magic_api * api, int which, int mode, + SDL_Surface * canvas) +{ +} + +void specular_switchout(magic_api * api, int which, int mode, + SDL_Surface * canvas) +{ +}