diff --git a/Makefile b/Makefile index bfa7a6902..63b9be61a 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -# Makefile for tuxpaint + # $Id$ # Tux Paint - A simple drawing program for children. @@ -39,13 +39,16 @@ DATA_PREFIX=$(PKG_ROOT)$(PREFIX)/share/tuxpaint # Magic Tool plug-ins +INCLUDE_PREFIX=$(PKG_ROOT)$(PREFIX)/include MAGIC_PREFIX=$(PKG_ROOT)$(PREFIX)/lib/tuxpaint # Docs and man page: DOC_PREFIX=$(PKG_ROOT)$(PREFIX)/share/doc/tuxpaint +DEVDOC_PREFIX=$(PKG_ROOT)$(PREFIX)/share/doc/tuxpaint-dev MAN_PREFIX=$(PKG_ROOT)$(PREFIX)/share/man +DEVMAN_PREFIX=$(PKG_ROOT)$(PREFIX)/share/man # 'System-wide' Config file: @@ -291,6 +294,7 @@ include Makefile-i18n install: install-bin install-data install-man install-doc \ install-magic-plugins \ + install-magic-plugin-dev \ install-icon install-gettext install-im install-importscript \ install-default-config install-example-stamps \ install-example-starters \ @@ -322,7 +326,24 @@ install-magic-plugins: @install -d $(DATA_PREFIX)/images/magic @cp magic/icons/*.png $(DATA_PREFIX)/images/magic @chmod a+r,g-w,o-w $(DATA_PREFIX)/images/magic/*.png + @install -d $(DATA_PREFIX)/sounds/magic + @cp magic/sounds/*.wav $(DATA_PREFIX)/sounds/magic + @chmod a+r,g-w,o-w $(DATA_PREFIX)/sounds/magic/*.wav +install-magic-plugin-dev: + @echo + @echo "...Installing Magic Tool plug-in development files and docs..." + @-rm $(BIN_PREFIX)/tp-magic-config + @sed src/tp-magic-config.sh -e s/__VERSION__/$(VER_VERSION)/ \ + -e s=__INCLUDE__=$(INCLUDE_PREFIX)/tuxpaint= > \ + $(BIN_PREFIX)/tp-magic-config + @chmod a+rx,g-w,o-w $(BIN_PREFIX)/tp-magic-config + @install -d $(INCLUDE_PREFIX)/tuxpaint + @cp src/tp_magic_api.h $(INCLUDE_PREFIX)/tuxpaint + @chmod a+r,g-w,o-w $(INCLUDE_PREFIX)/tuxpaint/tp_magic_api.h + @install -d $(DEVDOC_PREFIX) + @cp -R magic/docs/* $(DEVDOC_PREFIX) + @chmod a=rX,g=rX,u=rwX $(DEVDOC_PREFIX) # Installs the various parts for the MinGW/MSYS development/testing environment. @@ -493,6 +514,9 @@ uninstall: uninstall-i18n -rm $(MAN_PREFIX)/man1/tuxpaint-import.1.gz -rm -f -r $(CONFDIR) -rm -r $(MAGIC_PREFIX) + -rm -r $(INCLUDE_PREFIX)/tuxpaint + -rm $(BIN_PREFIX)/tp-magic-config + -rm -r $(DEVDOC_PREFIX) # Install default config file: @@ -759,6 +783,7 @@ obj/tuxpaint.o: src/tuxpaint.c \ src/compiler.h src/debug.h \ src/tools.h src/titles.h src/colors.h src/shapes.h \ src/sounds.h src/tip_tux.h src/great.h \ + src/tp_magic_api.h \ $(HQXX_H) \ src/$(MOUSEDIR)/arrow.xbm src/$(MOUSEDIR)/arrow-mask.xbm \ src/$(MOUSEDIR)/hand.xbm src/$(MOUSEDIR)/hand-mask.xbm \ @@ -882,7 +907,7 @@ obj/resource.o: visualc/resources.rc obj visualc/resource.h # Go into 'magic' subdirectory and buld magic plug-ins magic-plugins: - @cd magic ; make DATA_PREFIX="$(DATA_PREFIX)" + @cd magic ; make # Make the "obj" directory to throw the object(s) into: # (not necessary any more; bjk 2006.02.20) diff --git a/data/images/ui/flip.png b/data/images/ui/flip.png new file mode 100644 index 000000000..b6ee7ceff Binary files /dev/null and b/data/images/ui/flip.png differ diff --git a/data/images/ui/mirror.png b/data/images/ui/mirror.png new file mode 100644 index 000000000..f37c4cc88 Binary files /dev/null and b/data/images/ui/mirror.png differ diff --git a/docs/CHANGES.txt b/docs/CHANGES.txt index 4844958b1..3201a2a32 100644 --- a/docs/CHANGES.txt +++ b/docs/CHANGES.txt @@ -9,13 +9,31 @@ http://www.tuxpaint.org/ $Id$ -2007.July.4 (0.9.18) +2007.July.5 (0.9.18) * System-Related Improvements: ---------------------------- - * Adding an API for developing Magic tools as plug-ins. - (e.g., '.so' shared objects under Linux) + * Added an API for developing Magic tools as plug-ins. + ('.so' shared objects under Linux, '.dll' libraries under Windows, etc.) + Plugins must provide a number of functions that Tux Paint calls, + and Tux Paint provides a structure ("magic_api") that includes info. + (e.g., the running Tux Paint's version number) and pointers to + useful functions (e.g., getpixel(), putpixel(), etc.) - * Ported (most of) 'Negative' magic tool to Magic tool plug-in system. + * Magic plugin development can be done outside of Tux Paint base + source-code by using new "tp-magic-config" shell script to query + for C compiler flags, which points to where "tp_magic_api.h" header + file is installed. + + * Magic plugin development docs created. On Linux/Unix, installed into + /usr/[local/]share/docs/tuxpaint-dev/ by default. + + * Ported existing magic tools to the new Magic tool plug-in system: + - Negative + - Mirror + - Flip + - Fade + - Darken + [[ FIXME: Do the rest ]] * New Translations: ----------------- diff --git a/magic/Makefile b/magic/Makefile index 7401c8315..aeabc872e 100644 --- a/magic/Makefile +++ b/magic/Makefile @@ -1,35 +1,40 @@ # Makefile for magic plugins -SDL_CFLAGS=$(shell sdl-config --cflags) -CFLAGS=-g -Wall $(SDL_CFLAGS) -DDATA_PREFIX=\"$(DATA_PREFIX)\" -#-fPIC ? +# Places to pick up Tux Paint Magic Plugin Dev header and SDL headers +# (can't assume plugin dev stuff has been installed yet, since we're +# part of Tux Paint base, so "install-plugin-dev" probably hasn't +# been run yet; hence "-I../src/" to find 'tp_magic_api.h') -all: negative.so +SO_TYPE=so + +TP_MAGIC_CFLAGS=$(shell sdl-config --cflags) \ + -I../src/ \ + $(shell tp-magic-config --cflags) +CFLAGS=-g -Wall $(TP_MAGIC_CFLAGS) + + +all: negative.$(SO_TYPE) \ + fade_darken.$(SO_TYPE) \ + mirror_flip.$(SO_TYPE) \ clean: @echo @echo "Cleaning up the Magic plug-ins directory ($(PWD))" - @-rm -f *.so - @-rm -f obj/* + @-rm -f *.$(SO_TYPE) -# Negative tool -# ------------------------------------------------------------------------ +# Shared objects: +# --------------- -negative.so: obj obj/negative.o obj/magic_helpers.o - @echo "Linking Negative magic tool" - @$(CC) -shared -o negative.so obj/negative.o obj/magic_helpers.o +negative.$(SO_TYPE): src/negative.c + @echo "Building Negative magic tool" + @$(CC) $(CFLAGS) -shared -o negative.$(SO_TYPE) src/negative.c -obj/negative.o: src/negative.c src/magic_helpers.h - @echo "Compiling Negative magic tool" - @$(CC) $(CFLAGS) src/negative.c -c -o obj/negative.o +fade_darken.$(SO_TYPE): src/fade_darken.c + @echo "Building Fade and Darken magic tools" + @$(CC) $(CFLAGS) -shared -o fade_darken.$(SO_TYPE) src/fade_darken.c - - -obj/magic_helpers.o: src/magic_helpers.c src/magic_helpers.h - @echo "Compiling Magic tool helper routines" - @$(CC) $(CFLAGS) src/magic_helpers.c -c -o obj/magic_helpers.o - -obj: - @-mkdir obj +mirror_flip.$(SO_TYPE): src/mirror_flip.c + @echo "Building Mirror and Flip magic tools" + @$(CC) $(CFLAGS) -shared -o mirror_flip.$(SO_TYPE) src/mirror_flip.c diff --git a/magic/docs/README.txt b/magic/docs/README.txt new file mode 100644 index 000000000..dd632f7f6 --- /dev/null +++ b/magic/docs/README.txt @@ -0,0 +1,131 @@ +Stub docs for Tux Paint Magic Plugin Development + +#include "tp_magic_api.h" + + +build plugins with: +------------------- + Linux/Unix: + ----------- + $(CC) -shared `tp-magic-config --cflags` plugin.c -o plugin.so + + Then install globally into: /usr/[local/]lib/tuxpaint/. + Or locally into: ~/.tuxpaint/magic/ [[FIXME]] + + Windows: + -------- + ??? [[FIXME]] + + Mac OS X: + --------- + ??? [[FIXME]] + + +magic plugins must provide: +--------------------------- + NOTE: Each function name should be preceded with the name of the + shared object file, e.g. "negative.so" or "negative.dll" would have + a function called "negative_init()". + + int get_tool_count(magic_api * api) + return the number of Magic tools this plugin provides + (used below as the 'which' values sent to each function) + + char * get_name(magic_api * api, int which) + return the name of a/the magic tool (for 'Magic' tool buttons in UI) + Tux Paint will free() the string; + example: + return (strdup(gettext("Fun"))); + + SDL_Surface * get_icon(magic_api * api, int which) + return the icon of a/the magic tool (for 'Magic' tool buttons in UI) + Tux Paint will SDL_FreeSurface() the surface: + example: + sprintf(fname, "%s/images/magic/funtool.png", api->data_directory); + return(IMG_Load(fname)); + + char * get_description(magic_api * api, int which) + return the description of a/the magic tool (for Tux help text in UI); + Tux Paint will free() the string; + example: + return (strdup(gettext("A fun tool"))); + + int requires_colors(magic_api * api, int which) + return whether a/the magic tool accepts colors + ('1' for true; activates color palette in UI; + '0' for false; disables color palette in UI) + + void set_color(magic_api * api, Uint8 r, Uint8 g, Uint8 g) + accept the color palette choice from Tux Paint + (only called if requires_colors() for the current tool returned true) + + int init(magic_api * api) + initialization function; called once, during Tux Paint startup + return 1 if success; + return 0 if failure (tool(s) will be disabled in Magic tool); + + void shutdown(magic_api * api) + cleanup function; should free any alloc'd memory, etc.; + happens once, at Tux Paint shutdown + + void click(magic_api * api, int which, + SDL_Surface * snapshot, SDL_Surface * canvas, + int x, int y) + should affect 'canvas' at (x,y) location; may use 'snapshot' to fetch + pixels from most recent undo buffer; + Tux Paint's undo buffer is updated prior to this call + + void drag(magic_api * api, int which, + SDL_Surface * snapshot, SDL_Surface * canvas, + int ox, int oy, int x, int y) + should affect 'canvas' between (ox,oy) and (x,y) locations; + may use 'snapshot' to fetch pixels from most recent undo buffer; + Tux Paint's undo buffer is NOT updated prior to this call; the + 'snapshot' buffer will contain the same contents as when click() was + last called + + +tp provides, via magic_api structure ("api" arg to magic tool functions): +------------------------------------------------------------------------- + void putpixel(SDL_Surface * surf, int x, int y, Uint32 pixel) + function that puts a pixel at an (x,y) position in a surface + + Uint32 getpixel(SDL_Surface * surf, int x, int y) + function that returns a pixel value from an (x,y) position on a surface + + int in_circle(int x, int y, int radius) + function that returns whether an x/y position (centered at (0,0)) is + within a circle of 'radius' + + void show_progress_bar(void) + draws the Tux Paint progress bar animation; use while you're busy + + void tuxpaint_version(int * major, int * minor, int * revision) + returns the version of Tux Paint being used + + void line(int which, SDL_Surface * canvas, SDL_Surface * snapshot, + int x1, int y1, int x2, int y2, int step, FUNC callback) + function that calls calculates a line between (x1,y1) and (x2,y2) + and calls 'callback' every 'step' iterations; + sends to the callback: Tux Paint's 'magic_api' structure, along with the + 'which', 'canvas' and 'snapshot' values sent to line(), and the (x,y) + coordinates + + +FIXME: Implement these: + + void playsound(Mix_Chunk * snd, int pan, int dist) + function that plays a sound, panned left/right 'pan' + and at distance 'dist'. pan may be SNDPOS_LEFT, SNDPOS_CENTER or + SNDPOS_RIGHT, and dist may be SNDDIST_NEAR. + + void special_notify(int flag) + notifies tux paint of special events; SPECIAL_FLIP and SPECIAL_MIRROR + flags may be sent + + float sRGB_to_linear_table[256] + sRGB-to-linear look-up table + + unsigned char linear_to_sRGB(float linear) + linear-to-sRGB look-up helper function + diff --git a/data/sounds/blur.wav b/magic/sounds/blur.wav similarity index 100% rename from data/sounds/blur.wav rename to magic/sounds/blur.wav diff --git a/data/sounds/brick.wav b/magic/sounds/brick.wav similarity index 100% rename from data/sounds/brick.wav rename to magic/sounds/brick.wav diff --git a/data/sounds/cartoon.wav b/magic/sounds/cartoon.wav similarity index 100% rename from data/sounds/cartoon.wav rename to magic/sounds/cartoon.wav diff --git a/data/sounds/chalk.wav b/magic/sounds/chalk.wav similarity index 100% rename from data/sounds/chalk.wav rename to magic/sounds/chalk.wav diff --git a/data/sounds/darken.wav b/magic/sounds/darken.wav similarity index 100% rename from data/sounds/darken.wav rename to magic/sounds/darken.wav diff --git a/data/sounds/drip.wav b/magic/sounds/drip.wav similarity index 100% rename from data/sounds/drip.wav rename to magic/sounds/drip.wav diff --git a/data/sounds/fade.wav b/magic/sounds/fade.wav similarity index 100% rename from data/sounds/fade.wav rename to magic/sounds/fade.wav diff --git a/magic/sounds/flip.wav b/magic/sounds/flip.wav new file mode 100644 index 000000000..18af71a16 Binary files /dev/null and b/magic/sounds/flip.wav differ diff --git a/data/sounds/grass.wav b/magic/sounds/grass.wav similarity index 100% rename from data/sounds/grass.wav rename to magic/sounds/grass.wav diff --git a/magic/sounds/mirror.wav b/magic/sounds/mirror.wav new file mode 100644 index 000000000..201cf52c0 Binary files /dev/null and b/magic/sounds/mirror.wav differ diff --git a/data/sounds/negative.wav b/magic/sounds/negative.wav similarity index 100% rename from data/sounds/negative.wav rename to magic/sounds/negative.wav diff --git a/data/sounds/rainbow.wav b/magic/sounds/rainbow.wav similarity index 100% rename from data/sounds/rainbow.wav rename to magic/sounds/rainbow.wav diff --git a/data/sounds/smudge.wav b/magic/sounds/smudge.wav similarity index 100% rename from data/sounds/smudge.wav rename to magic/sounds/smudge.wav diff --git a/data/sounds/sparkles1.wav b/magic/sounds/sparkles1.wav similarity index 100% rename from data/sounds/sparkles1.wav rename to magic/sounds/sparkles1.wav diff --git a/data/sounds/sparkles2.wav b/magic/sounds/sparkles2.wav similarity index 100% rename from data/sounds/sparkles2.wav rename to magic/sounds/sparkles2.wav diff --git a/data/sounds/thick.wav b/magic/sounds/thick.wav similarity index 100% rename from data/sounds/thick.wav rename to magic/sounds/thick.wav diff --git a/data/sounds/thin.wav b/magic/sounds/thin.wav similarity index 100% rename from data/sounds/thin.wav rename to magic/sounds/thin.wav diff --git a/data/sounds/tint.wav b/magic/sounds/tint.wav similarity index 100% rename from data/sounds/tint.wav rename to magic/sounds/tint.wav diff --git a/magic/src/fade_darken.c b/magic/src/fade_darken.c new file mode 100644 index 000000000..18c3b5c04 --- /dev/null +++ b/magic/src/fade_darken.c @@ -0,0 +1,144 @@ +#include +#include +#include +#include "tp_magic_api.h" +#include "SDL_image.h" + +enum { + TOOL_FADE, + TOOL_DARKEN, + NUM_TOOLS +}; + +#define min(a,b) ((a) < (b) ? (a) : (b)) +#define max(a,b) ((a) > (b) ? (a) : (b)) + +// No setup required: +int fade_darken_init(magic_api * api) +{ + return(1); +} + +// Multiple tools: +int fade_darken_get_tool_count(magic_api * api) +{ + return(NUM_TOOLS); +} + +// Load our icon: +SDL_Surface * fade_darken_get_icon(magic_api * api, int which) +{ + char fname[1024]; + + if (which == TOOL_FADE) + { + snprintf(fname, sizeof(fname), "%s/images/magic/fade.png", + api->data_directory); + } + else if (which == TOOL_DARKEN) + { + snprintf(fname, sizeof(fname), "%s/images/magic/darken.png", + api->data_directory); + } + + return(IMG_Load(fname)); +} + +// Return our name, localized: +char * fade_darken_get_name(magic_api * api, int which) +{ + if (which == TOOL_FADE) + return(strdup(gettext("Lighten"))); + else if (which == TOOL_DARKEN) + return(strdup(gettext("Darken"))); + + return(NULL); +} + +// Return our description, localized: +char * fade_darken_get_description(magic_api * api, int which) +{ + if (which == TOOL_FADE) + return(strdup( + gettext("Click and move to fade the colors."))); + else if (which == TOOL_DARKEN) + return(strdup( + gettext("Click and move to darken the colors."))); + + return(NULL); +} + +// Callback that does the fade_darken color effect on a circle centered around x,y +void do_fade_darken(void * ptr, int which, + SDL_Surface * canvas, SDL_Surface * last, + int x, int y) +{ + int xx, yy; + Uint8 r, g, b; + magic_api * api = (magic_api *) ptr; + + for (yy = y - 16; yy < y + 16; yy++) + { + for (xx = x - 16; xx < x + 16; xx++) + { + if (api->in_circle(xx - x, yy - y, 16)) + { + SDL_GetRGB(api->getpixel(last, xx, yy), last->format, &r, &g, &b); + + if (which == TOOL_FADE) + { + r = min(r + 48, 255); + g = min(g + 48, 255); + b = min(b + 48, 255); + } + else if (which == TOOL_DARKEN) + { + r = max(r - 48, 0); + g = max(g - 48, 0); + b = max(b - 48, 0); + } + + api->putpixel(canvas, xx, yy, SDL_MapRGB(canvas->format, r, g, b)); + } + } + } +} + +// Ask Tux Paint to call our 'do_fade_darken()' callback over a line +void fade_darken_drag(magic_api * api, int which, SDL_Surface * canvas, + SDL_Surface * last, int ox, int oy, int x, int y) +{ + SDL_LockSurface(last); + SDL_LockSurface(canvas); + + api->line(which, canvas, last, ox, oy, x, y, 1, do_fade_darken); + + SDL_UnlockSurface(canvas); + SDL_UnlockSurface(last); +} + +// Ask Tux Paint to call our 'do_fade_darken()' callback at a single point +void fade_darken_click(magic_api * api, int which, + SDL_Surface * canvas, SDL_Surface * last, + int x, int y) +{ + fade_darken_drag(api, which, canvas, last, x, y, x, y); +} + + +// No setup happened: +void fade_darken_shutdown(magic_api * api) +{ +} + +// We don't use colors +void fade_darken_set_color(magic_api * api, Uint8 r, Uint8 g, Uint8 b) +{ +} + +// We don't use colors +int fade_darken_requires_colors(magic_api * api, int which) +{ + return 0; +} + diff --git a/magic/src/magic_helpers.c b/magic/src/magic_helpers.c deleted file mode 100644 index 5dfc3ac84..000000000 --- a/magic/src/magic_helpers.c +++ /dev/null @@ -1,238 +0,0 @@ -#include "../../src/compiler.h" -#include "magic_helpers.h" - -int MAGIC_in_circle(int x, int y, int radius) -{ - if ((x * x) + (y * y) - (radius * radius) < 0) - return (1); - else - return (0); -} - - -/* Draw a single pixel into the surface: */ - -void MAGIC_putpixel8(SDL_Surface * surface, int x, int y, Uint32 pixel) -{ - Uint8 *p; - - /* Assuming the X/Y values are within the bounds of this surface... */ - if (likely - (likely((unsigned) x < (unsigned) surface->w) - && likely((unsigned) y < (unsigned) surface->h))) - { - // Set a pointer to the exact location in memory of the pixel - p = (Uint8 *) (((Uint8 *) surface->pixels) + /* Start: beginning of RAM */ - (y * surface->pitch) + /* Go down Y lines */ - x); /* Go in X pixels */ - - - /* Set the (correctly-sized) piece of data in the surface's RAM - * to the pixel value sent in: */ - - *p = pixel; - } -} - -/* Draw a single pixel into the surface: */ -void MAGIC_putpixel16(SDL_Surface * surface, int x, int y, Uint32 pixel) -{ - Uint8 *p; - - /* Assuming the X/Y values are within the bounds of this surface... */ - if (likely - (likely((unsigned) x < (unsigned) surface->w) - && likely((unsigned) y < (unsigned) surface->h))) - { - // Set a pointer to the exact location in memory of the pixel - p = (Uint8 *) (((Uint8 *) surface->pixels) + /* Start: beginning of RAM */ - (y * surface->pitch) + /* Go down Y lines */ - (x * 2)); /* Go in X pixels */ - - - /* Set the (correctly-sized) piece of data in the surface's RAM - * to the pixel value sent in: */ - - *(Uint16 *) p = pixel; - } -} - -/* Draw a single pixel into the surface: */ -void MAGIC_putpixel24(SDL_Surface * surface, int x, int y, Uint32 pixel) -{ - Uint8 *p; - - /* Assuming the X/Y values are within the bounds of this surface... */ - if (likely - (likely((unsigned) x < (unsigned) surface->w) - && likely((unsigned) y < (unsigned) surface->h))) - { - // Set a pointer to the exact location in memory of the pixel - p = (Uint8 *) (((Uint8 *) surface->pixels) + /* Start: beginning of RAM */ - (y * surface->pitch) + /* Go down Y lines */ - (x * 3)); /* Go in X pixels */ - - - /* Set the (correctly-sized) piece of data in the surface's RAM - * to the pixel value sent in: */ - - if (SDL_BYTEORDER == SDL_BIG_ENDIAN) - { - p[0] = (pixel >> 16) & 0xff; - p[1] = (pixel >> 8) & 0xff; - p[2] = pixel & 0xff; - } - else - { - p[0] = pixel & 0xff; - p[1] = (pixel >> 8) & 0xff; - p[2] = (pixel >> 16) & 0xff; - } - - } -} - -/* Draw a single pixel into the surface: */ -void MAGIC_putpixel32(SDL_Surface * surface, int x, int y, Uint32 pixel) -{ - Uint8 *p; - - /* Assuming the X/Y values are within the bounds of this surface... */ - if (likely - (likely((unsigned) x < (unsigned) surface->w) - && likely((unsigned) y < (unsigned) surface->h))) - { - // Set a pointer to the exact location in memory of the pixel - p = (Uint8 *) (((Uint8 *) surface->pixels) + /* Start: beginning of RAM */ - (y * surface->pitch) + /* Go down Y lines */ - (x * 4)); /* Go in X pixels */ - - - /* Set the (correctly-sized) piece of data in the surface's RAM - * to the pixel value sent in: */ - - *(Uint32 *) p = pixel; // 32-bit display - } -} - -/* Get a pixel: */ -Uint32 MAGIC_getpixel8(SDL_Surface * surface, int x, int y) -{ - Uint8 *p; - - /* get the X/Y values within the bounds of this surface */ - if (unlikely((unsigned) x > (unsigned) surface->w - 1u)) - x = (x < 0) ? 0 : surface->w - 1; - if (unlikely((unsigned) y > (unsigned) surface->h - 1u)) - y = (y < 0) ? 0 : surface->h - 1; - - /* Set a pointer to the exact location in memory of the pixel - in question: */ - - p = (Uint8 *) (((Uint8 *) surface->pixels) + /* Start at top of RAM */ - (y * surface->pitch) + /* Go down Y lines */ - x); /* Go in X pixels */ - - - /* Return the correctly-sized piece of data containing the - * pixel's value (an 8-bit palette value, or a 16-, 24- or 32-bit - * RGB value) */ - - return (*p); -} - -/* Get a pixel: */ -Uint32 MAGIC_getpixel16(SDL_Surface * surface, int x, int y) -{ - Uint8 *p; - - /* get the X/Y values within the bounds of this surface */ - if (unlikely((unsigned) x > (unsigned) surface->w - 1u)) - x = (x < 0) ? 0 : surface->w - 1; - if (unlikely((unsigned) y > (unsigned) surface->h - 1u)) - y = (y < 0) ? 0 : surface->h - 1; - - /* Set a pointer to the exact location in memory of the pixel - in question: */ - - p = (Uint8 *) (((Uint8 *) surface->pixels) + /* Start at top of RAM */ - (y * surface->pitch) + /* Go down Y lines */ - (x * 2)); /* Go in X pixels */ - - - /* Return the correctly-sized piece of data containing the - * pixel's value (an 8-bit palette value, or a 16-, 24- or 32-bit - * RGB value) */ - - return (*(Uint16 *) p); -} - -/* Get a pixel: */ -Uint32 MAGIC_getpixel24(SDL_Surface * surface, int x, int y) -{ - Uint8 *p; - Uint32 pixel; - - /* get the X/Y values within the bounds of this surface */ - if (unlikely((unsigned) x > (unsigned) surface->w - 1u)) - x = (x < 0) ? 0 : surface->w - 1; - if (unlikely((unsigned) y > (unsigned) surface->h - 1u)) - y = (y < 0) ? 0 : surface->h - 1; - - /* Set a pointer to the exact location in memory of the pixel - in question: */ - - p = (Uint8 *) (((Uint8 *) surface->pixels) + /* Start at top of RAM */ - (y * surface->pitch) + /* Go down Y lines */ - (x * 3)); /* Go in X pixels */ - - - /* Return the correctly-sized piece of data containing the - * pixel's value (an 8-bit palette value, or a 16-, 24- or 32-bit - * RGB value) */ - - /* Depending on the byte-order, it could be stored RGB or BGR! */ - - if (SDL_BYTEORDER == SDL_BIG_ENDIAN) - pixel = p[0] << 16 | p[1] << 8 | p[2]; - else - pixel = p[0] | p[1] << 8 | p[2] << 16; - - return pixel; -} - -/* Get a pixel: */ -Uint32 MAGIC_getpixel32(SDL_Surface * surface, int x, int y) -{ - Uint8 *p; - - /* get the X/Y values within the bounds of this surface */ - if (unlikely((unsigned) x > (unsigned) surface->w - 1u)) - x = (x < 0) ? 0 : surface->w - 1; - if (unlikely((unsigned) y > (unsigned) surface->h - 1u)) - y = (y < 0) ? 0 : surface->h - 1; - - /* Set a pointer to the exact location in memory of the pixel - in question: */ - - p = (Uint8 *) (((Uint8 *) surface->pixels) + /* Start at top of RAM */ - (y * surface->pitch) + /* Go down Y lines */ - (x * 4)); /* Go in X pixels */ - - - /* Return the correctly-sized piece of data containing the - * pixel's value (an 8-bit palette value, or a 16-, 24- or 32-bit - * RGB value) */ - - return *(Uint32 *) p; // 32-bit display -} - -void (*MAGIC_putpixels[]) (SDL_Surface *, int, int, Uint32) = -{ -MAGIC_putpixel8, MAGIC_putpixel8, MAGIC_putpixel16, MAGIC_putpixel24, MAGIC_putpixel32}; - - -Uint32(*MAGIC_getpixels[])(SDL_Surface *, int, int) = -{ -MAGIC_getpixel8, MAGIC_getpixel8, MAGIC_getpixel16, MAGIC_getpixel24, MAGIC_getpixel32}; - diff --git a/magic/src/magic_helpers.h b/magic/src/magic_helpers.h deleted file mode 100644 index d97653a05..000000000 --- a/magic/src/magic_helpers.h +++ /dev/null @@ -1,23 +0,0 @@ -#ifndef MAGIC_HELPERS_H -#define MAGIC_HELPERS_H - -#include "SDL.h" -#include - -int MAGIC_in_circle(int x, int y, int radius); - -void MAGIC_putpixel8(SDL_Surface * surface, int x, int y, Uint32 pixel); -void MAGIC_putpixel16(SDL_Surface * surface, int x, int y, Uint32 pixel); -void MAGIC_putpixel24(SDL_Surface * surface, int x, int y, Uint32 pixel); -void MAGIC_putpixel32(SDL_Surface * surface, int x, int y, Uint32 pixel); - -extern void (*MAGIC_putpixels[]) (SDL_Surface *, int, int, Uint32); - -Uint32 MAGIC_getpixel8(SDL_Surface * surface, int x, int y); -Uint32 MAGIC_getpixel16(SDL_Surface * surface, int x, int y); -Uint32 MAGIC_getpixel24(SDL_Surface * surface, int x, int y); -Uint32 MAGIC_getpixel32(SDL_Surface * surface, int x, int y); - -extern Uint32(*MAGIC_getpixels[]) (SDL_Surface *, int, int); - -#endif diff --git a/magic/src/mirror_flip.c b/magic/src/mirror_flip.c new file mode 100644 index 000000000..8f37f39a3 --- /dev/null +++ b/magic/src/mirror_flip.c @@ -0,0 +1,136 @@ +#include +#include +#include +#include "tp_magic_api.h" +#include "SDL_image.h" + +/* What tools we contain: */ + +enum { + TOOL_MIRROR, + TOOL_FLIP, + NUM_TOOLS +}; + +// No setup required: +int mirror_flip_init(magic_api * api) +{ + return(1); +} + +// We have multiple tools: +int mirror_flip_get_tool_count(magic_api * api) +{ + return(NUM_TOOLS); +} + +// Load our icons: +SDL_Surface * mirror_flip_get_icon(magic_api * api, int which) +{ + char fname[1024]; + + if (which == TOOL_MIRROR) + { + snprintf(fname, sizeof(fname), "%s/images/magic/mirror.png", + api->data_directory); + } + else if (which == TOOL_FLIP) + { + snprintf(fname, sizeof(fname), "%s/images/magic/flip.png", + api->data_directory); + } + + return(IMG_Load(fname)); +} + +// Return our names, localized: +char * mirror_flip_get_name(magic_api * api, int which) +{ + if (which == TOOL_MIRROR) + return(strdup(gettext("Mirror"))); + else if (which == TOOL_FLIP) + return(strdup(gettext("Flip"))); + + return(NULL); +} + +// Return our descriptions, localized: +char * mirror_flip_get_description(magic_api * api, int which) +{ + if (which == TOOL_MIRROR) + return(strdup( + gettext("Click to flip the picture upside-down."))); + else + return(strdup( + gettext("Click to make a mirror image."))); + + return(NULL); +} + +// We affect the whole canvas, so only do things on click, not drag: +void mirror_flip_drag(magic_api * api, int which, SDL_Surface * canvas, + SDL_Surface * last, int ox, int oy, int x, int y) +{ + // No-op +} + +// Affect the canvas on click: +void mirror_flip_click(magic_api * api, int which, + SDL_Surface * canvas, SDL_Surface * last, + int x, int y) +{ + int xx, yy; + SDL_Rect src, dest; + + if (which == TOOL_MIRROR) + { + for (xx = 0; xx < canvas->w; xx++) + { + src.x = xx; + src.y = 0; + src.w = 1; + src.h = canvas->h; + + dest.x = canvas->w - xx - 1; + dest.y = 0; + + SDL_BlitSurface(last, &src, canvas, &dest); + } + + api->special_notify(SPECIAL_MIRROR); + } + else if (which == TOOL_FLIP) + { + for (yy = 0; yy < canvas->h; yy++) + { + src.x = 0; + src.y = yy; + src.w = canvas->w; + src.h = 1; + + dest.x = 0; + dest.y = canvas->h - yy - 1; + + SDL_BlitSurface(last, &src, canvas, &dest); + } + + api->special_notify(SPECIAL_FLIP); + } +} + +// No setup happened: +void mirror_flip_shutdown(magic_api * api) +{ +} + +// We don't use colors: +void mirror_flip_set_color(magic_api * api, Uint8 r, Uint8 g, Uint8 b) +{ +} + +// We don't use colors: +int mirror_flip_requires_colors(magic_api * api, int which) +{ + return 0; +} + diff --git a/magic/src/negative.c b/magic/src/negative.c index fed671b12..569b94158 100644 --- a/magic/src/negative.c +++ b/magic/src/negative.c @@ -1,111 +1,106 @@ #include #include +#include +#include "tp_magic_api.h" #include "SDL_image.h" -#include "magic_helpers.h" -void init() +// No setup required: +int negative_init(magic_api * api) { - printf("negative plugin initializing\n"); -} - -int get_tool_count(void) -{ - printf("negative tool reporting tool count: 1\n"); return(1); } -SDL_Surface * get_icon(int which) +// Only one tool: +int negative_get_tool_count(magic_api * api) { - printf("Loading icon: " DATA_PREFIX "/images/magic/negative.png\n"); - return(IMG_Load(DATA_PREFIX "/images/magic/negative.png")); + return(1); } -char * get_name(int which) +// Load our icon: +SDL_Surface * negative_get_icon(magic_api * api, int which) { - /* Only 1 tool; ignoring 'which' */ + char fname[1024]; + snprintf(fname, sizeof(fname), "%s/images/magic/negative.png", + api->data_directory); + return(IMG_Load(fname)); +} + +// Return our name, localized: +char * negative_get_name(magic_api * api, int which) +{ return(strdup(gettext("Negative"))); } -char * get_description(int which) +// Return our description, localized: +char * negative_get_description(magic_api * api, int which) { - /* Only 1 tool; ignoring 'which' */ - - return(strdup(gettext("Click and move the mouse around to draw a negative."))); + return(strdup( + gettext("Click and move the mouse around to draw a negative."))); } -void drag(int which, SDL_Surface * canvas, SDL_Surface * last, int ox, int oy, int x, int y); - -void click(int which, SDL_Surface * canvas, SDL_Surface * last, int x, int y) -{ -/* - SDL_Rect src, dest; - - src.x = x - 12; - src.y = y - 12; - src.w = 16; - src.h = 16; - - dest.x = x - 8; - dest.y = y - 8; - dest.w = 16; - dest.h = 16; - - SDL_BlitSurface(last, &src, canvas, &dest); -*/ - - drag(which, canvas, last, x, y, x, y); -} - -void drag(int which, SDL_Surface * canvas, SDL_Surface * last, int ox, int oy, int x, int y) +// Callback that does the negative color effect on a circle centered around x,y +void do_negative(void * ptr, int which, + SDL_Surface * canvas, SDL_Surface * last, + int x, int y) { int xx, yy; Uint8 r, g, b; - void (*putpixel) (SDL_Surface *, int, int, Uint32) = - MAGIC_putpixels[canvas->format->BytesPerPixel]; - Uint32(*getpixel_last) (SDL_Surface *, int, int); - - getpixel_last = MAGIC_getpixels[last->format->BytesPerPixel]; - - - SDL_LockSurface(last); - SDL_LockSurface(canvas); + magic_api * api = (magic_api *) ptr; for (yy = y - 16; yy < y + 16; yy++) { for (xx = x - 16; xx < x + 16; xx++) { - if (MAGIC_in_circle(xx - x, yy - y, 16)) + if (api->in_circle(xx - x, yy - y, 16)) { - SDL_GetRGB(getpixel_last(last, xx, yy), last->format, &r, &g, &b); + SDL_GetRGB(api->getpixel(last, xx, yy), last->format, &r, &g, &b); r = 0xFF - r; g = 0xFF - g; b = 0xFF - b; - putpixel(canvas, xx, yy, SDL_MapRGB(canvas->format, r, g, b)); + api->putpixel(canvas, xx, yy, SDL_MapRGB(canvas->format, r, g, b)); } } } +} + +// Ask Tux Paint to call our 'do_negative()' callback over a line +void negative_drag(magic_api * api, int which, SDL_Surface * canvas, + SDL_Surface * last, int ox, int oy, int x, int y) +{ + SDL_LockSurface(last); + SDL_LockSurface(canvas); + + api->line(which, canvas, last, ox, oy, x, y, 1, do_negative); SDL_UnlockSurface(canvas); SDL_UnlockSurface(last); } -void shutdown() +// Ask Tux Paint to call our 'do_negative()' callback at a single point +void negative_click(magic_api * api, int which, + SDL_Surface * canvas, SDL_Surface * last, + int x, int y) { - printf("negative plugin shutting down\n"); + negative_drag(api, which, canvas, last, x, y, x, y); } -void set_color(Uint8 r, Uint8 g, Uint8 b) + +// No setup happened: +void negative_shutdown(magic_api * api) { - /* Doesn't use color; ignoring */ } -int requires_colors(int which) +// We don't use colors +void negative_set_color(magic_api * api, Uint8 r, Uint8 g, Uint8 b) { - /* (Only 1 tool; ignoring 'which') */ - - return 0; // Don't need a color palette +} + +// We don't use colors +int negative_requires_colors(magic_api * api, int which) +{ + return 0; } diff --git a/src/magic.h b/src/magic.h index 80d6883e3..9763183b8 100644 --- a/src/magic.h +++ b/src/magic.h @@ -44,21 +44,14 @@ enum MAGIC_BLUR, MAGIC_SMUDGE, - MAGIC_FADE, - MAGIC_DARKEN, - MAGIC_CHALK, MAGIC_BLOCKS, - MAGIC_NEGATIVE, MAGIC_TINT, MAGIC_DRIP, MAGIC_CARTOON, - MAGIC_MIRROR, - MAGIC_FLIP, - NUM_MAGICS }; @@ -72,26 +65,19 @@ const int magic_colors[] = { COLORSEL_ENABLE, // large bricks COLORSEL_ENABLE, // small bricks - COLORSEL_DISABLE, + COLORSEL_DISABLE, // rainbow COLORSEL_ENABLE, // sparkles - COLORSEL_DISABLE, - COLORSEL_DISABLE, + COLORSEL_DISABLE, // blur + COLORSEL_DISABLE, // smudge - COLORSEL_DISABLE, - COLORSEL_DISABLE, + COLORSEL_DISABLE, // chalk + COLORSEL_DISABLE, // blocks - COLORSEL_DISABLE, - COLORSEL_DISABLE, - - COLORSEL_DISABLE, COLORSEL_ENABLE, // tint - COLORSEL_DISABLE, - COLORSEL_DISABLE, - - COLORSEL_DISABLE, - COLORSEL_DISABLE, + COLORSEL_DISABLE, // drip + COLORSEL_DISABLE, // cartoon }; /* Magic tool names: */ @@ -109,20 +95,13 @@ const char *const magic_names[NUM_MAGICS] = { gettext_noop("Blur"), gettext_noop("Smudge"), - gettext_noop("Lighten"), - gettext_noop("Darken"), - gettext_noop("Chalk"), gettext_noop("Blocks"), - gettext_noop("Negative"), gettext_noop("Tint"), gettext_noop("Drip"), gettext_noop("Cartoon"), - - gettext_noop("Mirror"), - gettext_noop("Flip"), }; @@ -141,23 +120,16 @@ const char *const magic_tips[NUM_MAGICS] = { gettext_noop("Click and move the mouse around to blur the picture."), gettext_noop("Click and move the mouse around to smudge the picture."), - gettext_noop("Click and move to fade the colors."), - gettext_noop("Click and move to darken the colors."), - gettext_noop ("Click and move the mouse around to turn the picture into a chalk drawing."), gettext_noop("Click and move the mouse around to make the picture blocky."), - gettext_noop("Click and move the mouse around to draw a negative."), gettext_noop ("Click and move the mouse around to change the picture’s color."), gettext_noop("Click and move the mouse around to make the picture drip."), gettext_noop ("Click and move the mouse around to turn the picture into a cartoon."), - - gettext_noop("Click to make a mirror image."), - gettext_noop("Click to flip the picture upside-down."), }; @@ -176,20 +148,13 @@ const char *const magic_img_fnames[NUM_MAGICS] = { DATA_PREFIX "images/magic/blur.png", DATA_PREFIX "images/magic/smudge.png", - DATA_PREFIX "images/magic/fade.png", - DATA_PREFIX "images/magic/darken.png", - DATA_PREFIX "images/magic/chalk.png", DATA_PREFIX "images/magic/blocks.png", - DATA_PREFIX "images/magic/negative.png", DATA_PREFIX "images/magic/tint.png", DATA_PREFIX "images/magic/drip.png", DATA_PREFIX "images/magic/cartoon.png", - - DATA_PREFIX "images/magic/mirror.png", - DATA_PREFIX "images/magic/flip.png", }; diff --git a/src/tp-magic-config.sh b/src/tp-magic-config.sh new file mode 100755 index 000000000..c11efc179 --- /dev/null +++ b/src/tp-magic-config.sh @@ -0,0 +1,51 @@ +#!/bin/sh + +# tp-magic-config + +# "Tux Paint Magic Config" +# Tool that reports compiler options used when buidling Magic Tool +# shared objects for Tux Paint + +# (c) Copyright 2007, by Bill Kendrick +# bill@newbreedsoftware.com +# http://www.tuxpaint.org/ + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# (See COPYING.txt) + +# Note: "__VERSION__" and "__INCLUDE__" are replaced by values +# in Tux Paint's Makefile, via 'sed', by the 'make install-magic-plugin-dev' +# target. + +# July 5, 2007 - July 5, 2007 + + +if [ $# -ne 0 ]; then + if [ $1 = "--version" ]; then + echo "__VERSION__" + exit + fi + if [ $1 = "--cflags" ]; then + echo `sdl-config --cflags` -I__INCLUDE__ + exit + fi + if [ $1 = "--libs" ]; then + echo `sdl-config --libs` + exit + fi +fi + +echo "Usage: tp-magic-config [--version] [--cflags] [--libs]" + diff --git a/src/tuxpaint.c b/src/tuxpaint.c index f10ebe9d1..84c8497a1 100644 --- a/src/tuxpaint.c +++ b/src/tuxpaint.c @@ -22,7 +22,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA (See COPYING.txt) - June 14, 2002 - July 3, 2007 + June 14, 2002 - July 5, 2007 $Id$ */ @@ -845,26 +845,41 @@ static int recording, playing; static char *playfile; static FILE *demofi; + +/* Magic tools API and tool handles: */ + +#include "tp_magic_api.h" + +void update_progress_bar(void); +void special_notify(int flags); + typedef struct magic_funcs_s { - int (*get_tool_count)(void); - char * (*get_name)(int); - SDL_Surface * (*get_icon)(int); - char * (*get_description)(int); - int (*requires_colors)(int); - void (*set_color)(Uint8, Uint8, Uint8); - int (*init)(void); - void (*shutdown)(void); - void (*click)(int, SDL_Surface *, SDL_Surface *, int, int); - void (*drag)(int, SDL_Surface *, SDL_Surface *, int, int, int, int); + int (*get_tool_count)(magic_api *); + char * (*get_name)(magic_api *, int); + SDL_Surface * (*get_icon)(magic_api *, int); + char * (*get_description)(magic_api *, int); + int (*requires_colors)(magic_api *, int); + void (*set_color)(magic_api *, Uint8, Uint8, Uint8); + int (*init)(magic_api *); + void (*shutdown)(magic_api *); + void (*click)(magic_api *, int, SDL_Surface *, SDL_Surface *, int, int); + void (*drag)(magic_api *, int, SDL_Surface *, SDL_Surface *, int, int, int, int); } magic_funcs_t; -static int num_plugin_files; -static int num_magics; -void * magic_handle[512]; -magic_funcs_t magic_funcs[512]; -static int magic_colors[512]; -static char * magic_names[512]; -static char * magic_tips[512]; +// FIXME: Drop the 512 constant :P + +static int num_plugin_files; // How many shared object files we went through +void * magic_handle[512]; // Handle to shared object (to be unloaded later) // FIXME: Unload them! +magic_funcs_t magic_funcs[512]; // Pointer to shared objects' functions +static int num_magics; // How many magic tools were loaded (note: shared objs may report more than 1 tool) +int magic_idx[512]; // Index to magic tools within shared objects (shared objs may report more than 1 tool) +int magic_handle_idx[512]; // Index to magic funcs for each magic tool (shared objs may report more than 1 tool) +static int magic_colors[512]; // Whether magic tool accepts colors +static char * magic_names[512]; // Name of magic tool +static char * magic_tips[512]; // Description of magic tool + +magic_api * magic_api_struct; // Pointer to our internal functions; passed to shared object's functions when we call them + #if !defined(WIN32) && !defined(__APPLE__) && !defined(__BEOS__) static const char *printcommand = PRINTCOMMAND; @@ -889,6 +904,7 @@ static SDL_Surface *img_title, *img_title_credits, *img_title_tuxpaint; static SDL_Surface *img_btn_up, *img_btn_down, *img_btn_off; static SDL_Surface *img_btnsm_up, *img_btnsm_off; static SDL_Surface *img_prev, *img_next; +static SDL_Surface *img_mirror, *img_flip; static SDL_Surface *img_dead40x40; static SDL_Surface *img_black, *img_grey; static SDL_Surface *img_yes, *img_no; @@ -1166,8 +1182,6 @@ typedef struct dirent2 static void mainloop(void); static void brush_draw(int x1, int y1, int x2, int y2, int update); static void blit_brush(int x, int y, int direction); -static void magic_draw(int x1, int y1, int x2, int y2, int button_down); -static void blit_magic(int x, int y, int button_down); static void stamp_draw(int x, int y); static void rec_undo_buffer(void); static void show_usage(FILE * f, char *prg); @@ -1318,9 +1332,15 @@ static void mirror_starter(void); static void flip_starter(void); int valid_click(Uint8 button); int in_circle(int x, int y); +int in_circle_rad(int x, int y, int rad); int paintsound(int size); void load_magic_plugins(void); +void magic_line_func(int which, SDL_Surface * canvas, SDL_Surface * last, + int x1, int y1, int x2, int y2, int step, + void (*cb)(void *, int, SDL_Surface *, SDL_Surface *, + int, int)); + #ifdef DEBUG static char *debug_gettext(const char *str); static int charsize(Uint16 c); @@ -2956,32 +2976,38 @@ static void mainloop(void) } else if (cur_tool == TOOL_MAGIC) { + int undo_ctr; + SDL_Surface * last; + + /* Start doing magic! */ tmp_int = cur_undo; rec_undo_buffer(); + if (cur_undo > 0) + undo_ctr = cur_undo - 1; + else + undo_ctr = NUM_UNDO_BUFS - 1; + + last = undo_bufs[undo_ctr]; + + magic_funcs[magic_handle_idx[cur_magic]].click(magic_api_struct, + magic_idx[cur_magic], + canvas, last, + old_x, old_y); + + // FIXME: Maybe 'click' should return an update rect? + update_canvas(0, 0, canvas->w, canvas->h); - /* Mirror or flip, make a note so we record it for - the starters, too! */ #if 0 /* MAGIC_ME */ - if (cur_magic == MAGIC_MIRROR) - undo_starters[tmp_int] = UNDO_STARTER_MIRRORED; - else if (cur_magic == MAGIC_FLIP) - undo_starters[tmp_int] = UNDO_STARTER_FLIPPED; -#endif - - /* (Arbitrarily large, so we draw once now) */ reset_brush_counter(); -#if 0 /* MAGIC_ME */ if (cur_magic != MAGIC_FILL) { -#endif magic_draw(old_x, old_y, old_x, old_y, button_down); -#if 0 /* MAGIC_ME */ } else { @@ -2997,14 +3023,6 @@ static void mainloop(void) draw_tux_text(TUX_GREAT, magic_tips[MAGIC_FILL], 1); } #endif - -#if 0 - if (cur_magic == MAGIC_FLIP || - cur_magic == MAGIC_MIRROR || cur_magic == MAGIC_FILL) - { - update_canvas(0, 0, canvas->w, canvas->h); - } -#endif } else if (cur_tool == TOOL_ERASER) { @@ -3530,15 +3548,26 @@ static void mainloop(void) } else if (cur_tool == TOOL_MAGIC) { - /* Pushing button and moving: Do the magic: */ + int undo_ctr; + SDL_Surface * last; -#if 0 // MAGIC_ME - if (cur_magic != MAGIC_FLIP && - cur_magic != MAGIC_MIRROR && cur_magic != MAGIC_FILL) -#endif - { - magic_draw(old_x, old_y, new_x, new_y, button_down); - } + /* Pushing button and moving: Continue doing the magic: */ + + if (cur_undo > 0) + undo_ctr = cur_undo - 1; + else + undo_ctr = NUM_UNDO_BUFS - 1; + + last = undo_bufs[undo_ctr]; + + magic_funcs[magic_handle_idx[cur_magic]].drag(magic_api_struct, + magic_idx[cur_magic], + canvas, last, + old_x, old_y, + new_x, new_y); + + // FIXME: Maybe 'drag' should return an update rect? + update_canvas(0, 0, canvas->w, canvas->h); } else if (cur_tool == TOOL_ERASER) { @@ -4397,86 +4426,6 @@ static void stamp_draw(int x, int y) /* Draw using the current brush: */ -static void magic_draw(int x1, int y1, int x2, int y2, int button_down) -{ - int dx, dy, y; - int orig_x1, orig_y1, orig_x2, orig_y2, tmp; - float m, b; - -#if 0 /* MAGIC_ME */ - if (cur_magic == MAGIC_RAINBOW) - rainbow_color = (rainbow_color + 1) % NUM_RAINBOW_COLORS; -#endif - - orig_x1 = x1; - orig_y1 = y1; - - orig_x2 = x2; - orig_y2 = y2; - - - dx = x2 - x1; - dy = y2 - y1; - - if (dx != 0) - { - m = ((float) dy) / ((float) dx); - b = y1 - m * x1; - - if (x2 >= x1) - dx = 1; - else - dx = -1; - - - while (x1 != x2) - { - y1 = m * x1 + b; - y2 = m * (x1 + dx) + b; - - if (y1 > y2) - { - for (y = y1; y >= y2; y--) - blit_magic(x1, y, button_down); - } - else - { - for (y = y1; y <= y2; y++) - blit_magic(x1, y, button_down); - } - - x1 = x1 + dx; - } - } - else - { - if (y1 > y2) - { - for (y = y1; y >= y2; y--) - blit_magic(x1, y, button_down); - } - else - { - for (y = y1; y <= y2; y++) - blit_magic(x1, y, button_down); - } - } - - if (orig_x1 > orig_x2) - { - tmp = orig_x1; - orig_x1 = orig_x2; - orig_x2 = tmp; - } - - if (orig_y1 > orig_y2) - { - tmp = orig_y1; - orig_y1 = orig_y2; - orig_y2 = tmp; - } - - #if 0 /* MAGIC_ME */ /* Play sound: */ @@ -4512,12 +4461,11 @@ static void magic_draw(int x1, int y1, int x2, int y2, int button_down) else if (cur_magic == MAGIC_GRASS) playsound(screen, 0, SND_GRASS, 0, x1, y1); -#endif - /* FIXME: Arbitrary? */ update_canvas(orig_x1 - 32, orig_y1 - 32, orig_x2 + 32, orig_y2 + 64); } +#endif // this one rounds down @@ -4580,40 +4528,12 @@ static void do_brick(int x, int y, int w, int h) /* Draw the current brush in the current color: */ +#if 0 // MAGIC_ME + static void blit_magic(int x, int y, int button_down) { - int xx, yy, w, h; - Uint32 colr; - Uint8 r, g, b, a; - SDL_Surface *last; - SDL_Rect src, dest; - int undo_ctr; - Uint32(*getpixel_canvas) (SDL_Surface *, int, int) = - getpixels[canvas->format->BytesPerPixel]; - void (*putpixel) (SDL_Surface *, int, int, Uint32) = - putpixels[canvas->format->BytesPerPixel]; - Uint32(*getpixel_last) (SDL_Surface *, int, int); - - - /* In case we need to use the current canvas (just saved to undo buf)... */ - - if (cur_undo > 0) - undo_ctr = cur_undo - 1; - else - undo_ctr = NUM_UNDO_BUFS - 1; - - last = undo_bufs[undo_ctr]; - getpixel_last = getpixels[last->format->BytesPerPixel]; - - - brush_counter++; - - if (brush_counter >= 4) /* FIXME: Arbitrary? */ - { - brush_counter = 0; - - magic_funcs[cur_magic].click(0 /* MAGIC_ME */, canvas, last, x, y); +// PORT THESE TO MAGIC PLUGIN API: #if 0 // MAGIC_ME if (cur_magic == MAGIC_BLUR) @@ -4761,25 +4681,6 @@ static void blit_magic(int x, int y, int button_down) static int y_count; unsigned char *mybrick; -#if 0 - if (cur_magic == MAGIC_SMALLBRICK) - { - vertical_joint = 1; // between a brick and the one above/below - horizontal_joint = 1; // between a brick and the one to the side - nominal_width = 9; - nominal_height = 6; // 11 to 14, for joints of 2 - } -#endif -#if 0 - if (cur_magic == MAGIC_LARGEBRICK) - { - vertical_joint = 3; // between a brick and the one above/below - horizontal_joint = 3; // between a brick and the one to the side - nominal_width = 27; - nominal_height = 18; // 11 to 14, for joints of 2 - } -#endif -#if 1 if (cur_magic == MAGIC_LARGEBRICK) { vertical_joint = 4; // between a brick and the one above/below @@ -4787,7 +4688,6 @@ static void blit_magic(int x, int y, int button_down) nominal_width = 36; nominal_height = 24; // 11 to 14, for joints of 2 } -#endif nominal_length = 2 * nominal_width; specified_width = nominal_width - horizontal_joint; @@ -4869,67 +4769,6 @@ static void blit_magic(int x, int y, int button_down) } SDL_UnlockSurface(canvas); } - else if (cur_magic == MAGIC_NEGATIVE) - { - SDL_LockSurface(last); - SDL_LockSurface(canvas); - - for (yy = y - 16; yy < y + 16; yy++) - { - for (xx = x - 16; xx < x + 16; xx++) - { - if (in_circle(xx - x, yy - y)) - { - SDL_GetRGB(getpixel_last(last, xx, yy), last->format, &r, &g, &b); - - r = 0xFF - r; - g = 0xFF - g; - b = 0xFF - b; - - putpixel(canvas, xx, yy, SDL_MapRGB(canvas->format, r, g, b)); - } - } - } - - SDL_UnlockSurface(canvas); - SDL_UnlockSurface(last); - } - else if (cur_magic == MAGIC_FADE || cur_magic == MAGIC_DARKEN) - { - SDL_LockSurface(last); - SDL_LockSurface(canvas); - - for (yy = y - 16; yy < y + 16; yy++) - { - for (xx = x - 16; xx < x + 16; xx++) - { - if (in_circle(xx - x, yy - y)) - { - /* Get original color: */ - - SDL_GetRGB(getpixel_last(last, xx, yy), last->format, &r, &g, &b); - - if (cur_magic == MAGIC_FADE) - { - r = min(r + 48, 255); - g = min(g + 48, 255); - b = min(b + 48, 255); - } - else - { - r = max(r - 48, 0); - g = max(g - 48, 0); - b = max(b - 48, 0); - } - - putpixel(canvas, xx, yy, SDL_MapRGB(canvas->format, r, g, b)); - } - } - } - - SDL_UnlockSurface(canvas); - SDL_UnlockSurface(last); - } else if (cur_magic == MAGIC_TINT) { double rd = sRGB_to_linear_table[color_hexes[cur_color][0]]; @@ -5256,56 +5095,6 @@ static void blit_magic(int x, int y, int button_down) #endif } } - else if (cur_magic == MAGIC_FLIP) - { - /* Flip the canvas: */ - - for (yy = 0; yy < canvas->h; yy++) - { - src.x = 0; - src.y = yy; - src.w = canvas->w; - src.h = 1; - - dest.x = 0; - dest.y = canvas->h - yy - 1; - - SDL_BlitSurface(last, &src, canvas, &dest); - } - - - /* Flip starter, too! */ - - starter_flipped = !starter_flipped; - - if (img_starter != NULL) - flip_starter(); - } - else if (cur_magic == MAGIC_MIRROR) - { - /* Mirror-image the canvas: */ - - for (xx = 0; xx < canvas->w; xx++) - { - src.x = xx; - src.y = 0; - src.w = 1; - src.h = canvas->h; - - dest.x = canvas->w - xx - 1; - dest.y = 0; - - SDL_BlitSurface(last, &src, canvas, &dest); - } - - - /* Mirror starter, too! */ - - starter_mirrored = !starter_mirrored; - - if (img_starter != NULL) - mirror_starter(); - } else if (cur_magic == MAGIC_THIN || cur_magic == MAGIC_THICK) { SDL_LockSurface(last); @@ -5362,6 +5151,8 @@ static void blit_magic(int x, int y, int button_down) } } +#endif + /* Store canvas into undo buffer: */ @@ -7567,6 +7358,9 @@ static void setup(int argc, char *argv[]) img_prev = loadimage(DATA_PREFIX "images/ui/prev.png"); img_next = loadimage(DATA_PREFIX "images/ui/next.png"); + img_mirror = loadimage(DATA_PREFIX "images/ui/mirror.png"); + img_flip = loadimage(DATA_PREFIX "images/ui/flip.png"); + img_open = loadimage(DATA_PREFIX "images/ui/open.png"); img_erase = loadimage(DATA_PREFIX "images/ui/erase.png"); img_back = loadimage(DATA_PREFIX "images/ui/back.png"); @@ -8193,12 +7987,6 @@ static void draw_magic(void) int magic, i, max, off_y; SDL_Rect dest; -#if 0 // MAGIC_ME - // restore these to black (stamp and text controls borrow them) - SDL_BlitSurface(img_black, NULL, img_magics[MAGIC_FLIP], NULL); - SDL_BlitSurface(img_black, NULL, img_magics[MAGIC_MIRROR], NULL); -#endif - draw_image_title(TITLE_MAGIC, r_ttoolopt); @@ -8825,7 +8613,6 @@ static void draw_stamps(void) if (!disable_stamp_controls) { -#if 0 // MAGIC_ME /* Show mirror button: */ dest.x = WINDOW_WIDTH - 96; @@ -8851,12 +8638,12 @@ static void draw_stamps(void) } SDL_BlitSurface(button_body, NULL, screen, &dest); - dest.x = WINDOW_WIDTH - 96 + (48 - img_magics[MAGIC_MIRROR]->w) / 2; + dest.x = WINDOW_WIDTH - 96 + (48 - img_mirror->w) / 2; dest.y = (40 + ((5 + TOOLOFFSET / 2) * 48) + - (48 - img_magics[MAGIC_MIRROR]->h) / 2); + (48 - img_mirror->h) / 2); - SDL_BlitSurface(button_color, NULL, img_magics[MAGIC_MIRROR], NULL); - SDL_BlitSurface(img_magics[MAGIC_MIRROR], NULL, screen, &dest); + SDL_BlitSurface(button_color, NULL, img_mirror, NULL); + SDL_BlitSurface(img_mirror, NULL, screen, &dest); /* Show flip button: */ @@ -8883,14 +8670,12 @@ static void draw_stamps(void) } SDL_BlitSurface(button_body, NULL, screen, &dest); - dest.x = WINDOW_WIDTH - 48 + (48 - img_magics[MAGIC_FLIP]->w) / 2; + dest.x = WINDOW_WIDTH - 48 + (48 - img_flip->w) / 2; dest.y = (40 + ((5 + TOOLOFFSET / 2) * 48) + - (48 - img_magics[MAGIC_FLIP]->h) / 2); + (48 - img_flip->h) / 2); - SDL_BlitSurface(button_color, NULL, img_magics[MAGIC_FLIP], NULL); - SDL_BlitSurface(img_magics[MAGIC_FLIP], NULL, screen, &dest); - -#endif + SDL_BlitSurface(button_color, NULL, img_flip, NULL); + SDL_BlitSurface(img_flip, NULL, screen, &dest); #ifdef OLD_STAMP_GROW_SHRINK @@ -11755,6 +11540,9 @@ static void cleanup(void) free_surface(&img_prev); free_surface(&img_next); + free_surface(&img_mirror); + free_surface(&img_flip); + free_surface(&img_title_on); free_surface(&img_title_off); free_surface(&img_title_large_on); @@ -16330,6 +16118,14 @@ int in_circle(int x, int y) return (0); } +int in_circle_rad(int x, int y, int rad) +{ + if ((x * x) + (y * y) - (rad * rad) < 0) + return (1); + else + return (0); +} + int paintsound(int size) { if (SND_PAINT1 + (size / 12) >= SND_PAINT4) @@ -16787,13 +16583,33 @@ void load_magic_plugins(void) DIR *d; struct dirent *f; char fname[512]; + char objname[512]; + char funcname[512]; num_plugin_files = 0; num_magics = 0; +#ifdef DEBUG printf("\n"); printf("Loading magic plug-ins from %s\n", MAGIC_PREFIX); fflush(stdout); +#endif + + /* Set magic API hooks: */ + + magic_api_struct = (magic_api *) malloc(sizeof(magic_api)); + magic_api_struct->tp_version = strdup(VER_VERSION); + magic_api_struct->data_directory = strdup(DATA_PREFIX); + magic_api_struct->update_progress_bar = update_progress_bar; + // FIXME: magic_api_struct->sRGB_to_linear_table = sRGB_to_linear_table; + // FIXME: magic_api_struct->linear_to_sRGB = linear_to_sRGB; + magic_api_struct->in_circle = in_circle_rad; + magic_api_struct->getpixel = getpixels[canvas->format->BytesPerPixel]; + magic_api_struct->putpixel = putpixels[canvas->format->BytesPerPixel]; + magic_api_struct->line = magic_line_func; + magic_api_struct->playsound = NULL; // FIXME + magic_api_struct->special_notify = special_notify; + d = opendir(MAGIC_PREFIX); @@ -16811,52 +16627,71 @@ void load_magic_plugins(void) { snprintf(fname, sizeof(fname), "%s%s", MAGIC_PREFIX, f->d_name); + /* Get just the name of the object (e.g., "negative"), w/o filename + extension: */ + + strcpy(objname, f->d_name); + strcpy(strchr(objname, '.'), ""); + + magic_handle[num_plugin_files] = SDL_LoadObject(fname); if (magic_handle[num_plugin_files] != NULL) { +#ifdef DEBUG printf("loading: %s\n", fname); fflush(stdout); +#endif - magic_funcs[num_plugin_files].get_tool_count = - SDL_LoadFunction(magic_handle[num_plugin_files], + snprintf(funcname, sizeof(funcname), "%s_%s", objname, "get_tool_count"); + magic_funcs[num_plugin_files].get_tool_count = + SDL_LoadFunction(magic_handle[num_plugin_files], funcname); - magic_funcs[num_plugin_files].get_name = - SDL_LoadFunction(magic_handle[num_plugin_files], + snprintf(funcname, sizeof(funcname), "%s_%s", objname, "get_name"); + magic_funcs[num_plugin_files].get_name = + SDL_LoadFunction(magic_handle[num_plugin_files], funcname); - magic_funcs[num_plugin_files].get_icon = - SDL_LoadFunction(magic_handle[num_plugin_files], + snprintf(funcname, sizeof(funcname), "%s_%s", objname, "get_icon"); + magic_funcs[num_plugin_files].get_icon = + SDL_LoadFunction(magic_handle[num_plugin_files], funcname); - magic_funcs[num_plugin_files].get_description = - SDL_LoadFunction(magic_handle[num_plugin_files], + snprintf(funcname, sizeof(funcname), "%s_%s", objname, "get_description"); + magic_funcs[num_plugin_files].get_description = + SDL_LoadFunction(magic_handle[num_plugin_files], funcname); - magic_funcs[num_plugin_files].requires_colors = - SDL_LoadFunction(magic_handle[num_plugin_files], + snprintf(funcname, sizeof(funcname), "%s_%s", objname, "requires_colors"); + magic_funcs[num_plugin_files].requires_colors = + SDL_LoadFunction(magic_handle[num_plugin_files], funcname); - magic_funcs[num_plugin_files].set_color = - SDL_LoadFunction(magic_handle[num_plugin_files], + snprintf(funcname, sizeof(funcname), "%s_%s", objname, "set_color"); + magic_funcs[num_plugin_files].set_color = + SDL_LoadFunction(magic_handle[num_plugin_files], funcname); - magic_funcs[num_plugin_files].init = - SDL_LoadFunction(magic_handle[num_plugin_files], + snprintf(funcname, sizeof(funcname), "%s_%s", objname, "init"); + magic_funcs[num_plugin_files].init = + SDL_LoadFunction(magic_handle[num_plugin_files], funcname); - magic_funcs[num_plugin_files].shutdown = - SDL_LoadFunction(magic_handle[num_plugin_files], + snprintf(funcname, sizeof(funcname), "%s_%s", objname, "shutdown"); + magic_funcs[num_plugin_files].shutdown = + SDL_LoadFunction(magic_handle[num_plugin_files], funcname); - magic_funcs[num_plugin_files].click = - SDL_LoadFunction(magic_handle[num_plugin_files], + snprintf(funcname, sizeof(funcname), "%s_%s", objname, "click"); + magic_funcs[num_plugin_files].click = + SDL_LoadFunction(magic_handle[num_plugin_files], funcname); - magic_funcs[num_plugin_files].drag = - SDL_LoadFunction(magic_handle[num_plugin_files], + snprintf(funcname, sizeof(funcname), "%s_%s", objname, "drag"); + magic_funcs[num_plugin_files].drag = + SDL_LoadFunction(magic_handle[num_plugin_files], funcname); #ifdef DEBUG printf("get_tool_count = 0x%x\n", @@ -16898,13 +16733,13 @@ void load_magic_plugins(void) } else { - res = magic_funcs[num_plugin_files].init(); + res = magic_funcs[num_plugin_files].init(magic_api_struct); if (res != 0) - n = magic_funcs[num_plugin_files].get_tool_count(); + n = magic_funcs[num_plugin_files].get_tool_count(magic_api_struct); else { - magic_funcs[num_plugin_files].shutdown(); + magic_funcs[num_plugin_files].shutdown(magic_api_struct); n = 0; } @@ -16919,13 +16754,17 @@ void load_magic_plugins(void) { for (i = 0; i < n; i++) { - magic_names[num_magics] = magic_funcs[num_plugin_files].get_name(i); - magic_tips[num_magics] = magic_funcs[num_plugin_files].get_description(i); - magic_colors[num_magics] = magic_funcs[num_plugin_files].requires_colors(i); + magic_idx[num_magics] = i; + magic_handle_idx[num_magics] = num_plugin_files; + magic_names[num_magics] = magic_funcs[num_plugin_files].get_name(magic_api_struct, i); + magic_tips[num_magics] = magic_funcs[num_plugin_files].get_description(magic_api_struct, i); + magic_colors[num_magics] = magic_funcs[num_plugin_files].requires_colors(magic_api_struct, i); - img_magics[num_magics] = magic_funcs[num_plugin_files].get_icon(i); + img_magics[num_magics] = magic_funcs[num_plugin_files].get_icon(magic_api_struct, i); - printf("-- %s\n", magic_names[i]); +#ifdef DEBUG + printf("-- %s\n", magic_names[num_magics]); +#endif num_magics++; } @@ -16947,11 +16786,151 @@ void load_magic_plugins(void) closedir(d); } +#ifdef DEBUG printf("Loaded %d magic tools from %d plug-in files\n", num_magics, num_plugin_files); printf("\n"); fflush(stdout); +#endif /* FIXME: Sort it? -bjk 2007.07.03 */ } +void update_progress_bar(void) +{ + show_progress_bar(screen); +} + +void magic_line_func(int which, SDL_Surface * canvas, SDL_Surface * last, + int x1, int y1, int x2, int y2, int step, + void (*cb)(void *, int, SDL_Surface *, SDL_Surface *, + int, int)) +{ + int dx, dy, y; + int orig_x1, orig_y1, orig_x2, orig_y2, tmp; + float m, b; + int cnt; + + orig_x1 = x1; + orig_y1 = y1; + + orig_x2 = x2; + orig_y2 = y2; + + + dx = x2 - x1; + dy = y2 - y1; + + cnt = step - 1; + + if (dx != 0) + { + m = ((float) dy) / ((float) dx); + b = y1 - m * x1; + + if (x2 >= x1) + dx = 1; + else + dx = -1; + + + while (x1 != x2) + { + y1 = m * x1 + b; + y2 = m * (x1 + dx) + b; + + if (y1 > y2) + { + for (y = y1; y >= y2; y--) + { + cnt = (cnt + 1) % step; + if (cnt == 0) + cb((void *) magic_api_struct, which, canvas, last, x1, y); + } + } + else + { + for (y = y1; y <= y2; y++) + { + cnt = (cnt + 1) % step; + if (cnt == 0) + cb((void *) magic_api_struct, which, canvas, last, x1, y); + } + } + + x1 = x1 + dx; + } + } + else + { + if (y1 > y2) + { + for (y = y1; y >= y2; y--) + { + cnt = (cnt + 1) % step; + if (cnt == 0) + cb((void *) magic_api_struct, which, canvas, last, x1, y); + } + } + else + { + for (y = y1; y <= y2; y++) + { + cnt = (cnt + 1) % step; + if (cnt == 0) + cb((void *) magic_api_struct, which, canvas, last, x1, y); + } + } + } + + if (orig_x1 > orig_x2) + { + tmp = orig_x1; + orig_x1 = orig_x2; + orig_x2 = tmp; + } + + if (orig_y1 > orig_y2) + { + tmp = orig_y1; + orig_y1 = orig_y2; + orig_y2 = tmp; + } + + /* FIXME: Set and return an update rect? */ +} + + +/* Handle special things that some magic tools do that + need to affect more than just the current canvas: */ + +void special_notify(int flags) +{ + int tmp_int; + + tmp_int = (cur_undo - 1) % NUM_UNDO_BUFS; + + if (flags & SPECIAL_MIRROR) + { + /* Mirror starter, too! */ + + starter_mirrored = !starter_mirrored; + + if (img_starter != NULL) + mirror_starter(); + + undo_starters[tmp_int] = UNDO_STARTER_MIRRORED; + } + + if (flags & SPECIAL_FLIP) + { + /* Flip starter, too! */ + + starter_flipped = !starter_flipped; + + if (img_starter != NULL) + flip_starter(); + + undo_starters[tmp_int] = UNDO_STARTER_FLIPPED; + } +}