From 26c7051c072dc565a1719271978ddbbf49c75aeb Mon Sep 17 00:00:00 2001 From: William Kendrick Date: Fri, 3 Aug 2007 16:17:46 +0000 Subject: [PATCH] Stamps can now be pre-flipped and/or pre-mirrored-and-flipped now (in addition to pre-mirrored). Updated version # in some docs. Expanded comments in tp_magic_example.c Magic plugin example code. --- docs/ADVANCED-STAMPS-HOWTO.txt | 4 +- docs/CHANGES.txt | 7 +- docs/EXTENDING.txt | 23 +- docs/FAQ.txt | 4 +- docs/OPTIONS.txt | 2 +- docs/README.txt | 2 +- docs/html/ADVANCED-STAMPS-HOWTO.html | 4 +- docs/html/EXTENDING.html | 28 +- docs/html/FAQ.html | 4 +- docs/html/OPTIONS.html | 2 +- docs/html/README.html | 2 +- magic/docs/tp_magic_example.c | 483 ++++++++++++++++++++++----- src/tuxpaint.c | 380 ++++++++++++++++++--- 13 files changed, 783 insertions(+), 162 deletions(-) diff --git a/docs/ADVANCED-STAMPS-HOWTO.txt b/docs/ADVANCED-STAMPS-HOWTO.txt index d28c4ee7d..7443df2f3 100644 --- a/docs/ADVANCED-STAMPS-HOWTO.txt +++ b/docs/ADVANCED-STAMPS-HOWTO.txt @@ -1,5 +1,5 @@ Tux Paint - version 0.9.17 + version 0.9.18 Advanced Stamps HOWTO Copyright 2006 by Albert Cahalan for the Tux Paint project @@ -8,7 +8,7 @@ albert@users.sf.net http://www.tuxpaint.org/ - March 8, 2006 - October 26, 2006 + March 8, 2006 - August 2, 2007 About this HOWTO diff --git a/docs/CHANGES.txt b/docs/CHANGES.txt index 5c0d7d4d1..07809af33 100644 --- a/docs/CHANGES.txt +++ b/docs/CHANGES.txt @@ -9,7 +9,7 @@ http://www.tuxpaint.org/ $Id$ -2007.July.19 (0.9.18) +2007.August.2 (0.9.18) * Interface Improvements: ----------------------- * Improved 'New' and 'Open' interface: @@ -27,6 +27,11 @@ $Id$ * Added an Octagon shape to the 'Shapes' tool. + * Stamps can now be pre-flipped and/or pre-mirrored-and-flipped now + (in addition to pre-mirrored). + Use "_flip.png"/"_flip.svg" and "_mirror_flip.png"/"_mirror_flip.png", + respectively. + * Documentation Imrpovements: --------------------------- * Improved --usage output. diff --git a/docs/EXTENDING.txt b/docs/EXTENDING.txt index 7f00e7d54..aa6505b98 100644 --- a/docs/EXTENDING.txt +++ b/docs/EXTENDING.txt @@ -1,5 +1,5 @@ Tux Paint - version 0.9.17 + version 0.9.18 Extending Tux Paint Copyright 2002-2007 by Bill Kendrick and others @@ -8,7 +8,7 @@ bill@newbreedsoftware.com http://www.tuxpaint.org/ - June 14, 2002 - May 6, 2007 + June 14, 2002 - August 2, 2007 -------------------------------------------------------------------------- @@ -428,22 +428,31 @@ Stamps it as Plain Text, and make sure the filename has ".dat" at the end, and not ".txt"... - Pre-Mirrored Images + Pre-Mirrored and Flipped Images In some cases, you may wish to provide a pre-drawn version of a - stamp's mirror-image. For example, imagine a picture of a fire truck - with the words "Fire Department" written across the side. You probably - do not want that text to appear backwards when the image is flipped! + stamp's mirror-image, flipped image, or even both. For example, + imagine a picture of a fire truck with the words "Fire Department" + written across the side. You probably do not want that text to appear + backwards when the image is flipped! To create a mirrored version of a stamp that you want Tux Paint to use, rather than mirroring one on its own, simply create a second - ".png" graphics file with the same name, except with the string + ".png" or ".svg" graphics file with the same name, except with "_mirror" before the filename extension. For example, for the stamp "truck.png" you would create another file named "truck_mirror.png", which will be used when the stamp is mirrored (rather than using a backwards version of 'truck.png'). + As of Tux Paint 0.9.18, you may similarly provide a pre-flipped image + with "_flip" in the name, and/or an image that is both mirrored and + flipped, by naming it "_mirror_flip". + + Note: If the user flips and mirrors an image, and a pre-drawn + "_mirror_flip" doesn't exist, but either "_flip" or "_mirror" does, it + will be used, and mirrored or flipped, respectively. + -------------------------------------------------------------------------- Fonts diff --git a/docs/FAQ.txt b/docs/FAQ.txt index eaad42f4d..fe39a1940 100644 --- a/docs/FAQ.txt +++ b/docs/FAQ.txt @@ -1,5 +1,5 @@ Tux Paint - version 0.9.17 + version 0.9.18 Frequently Asked Questions Copyright 2002-2007 by Bill Kendrick and others @@ -8,7 +8,7 @@ bill@newbreedsoftware.com http://www.tuxpaint.org/ - September 14, 2002 - June 27, 2007 + September 14, 2002 - August 2, 2007 Drawing-related diff --git a/docs/OPTIONS.txt b/docs/OPTIONS.txt index 5ab0fd415..326920375 100644 --- a/docs/OPTIONS.txt +++ b/docs/OPTIONS.txt @@ -1,5 +1,5 @@ Tux Paint - version 0.9.17 + version 0.9.18 Options Documentation diff --git a/docs/README.txt b/docs/README.txt index 84a3e9176..b2e5c976a 100644 --- a/docs/README.txt +++ b/docs/README.txt @@ -1,5 +1,5 @@ Tux Paint - version 0.9.17 + version 0.9.18 A simple drawing program for children diff --git a/docs/html/ADVANCED-STAMPS-HOWTO.html b/docs/html/ADVANCED-STAMPS-HOWTO.html index f24ae07af..3fc736e9c 100644 --- a/docs/html/ADVANCED-STAMPS-HOWTO.html +++ b/docs/html/ADVANCED-STAMPS-HOWTO.html @@ -11,7 +11,7 @@ alink="#FF00FF"> alt="Tux Paint">
version -0.9.17 +0.9.18
Advanced Stamps HOWTO @@ -21,7 +21,7 @@ New Breed Software

albert@users.sf.net
http://www.tuxpaint.org/

-

March 8, 2006 - October 26, 2006

+

March 8, 2006 - August 2, 2007

diff --git a/docs/html/EXTENDING.html b/docs/html/EXTENDING.html index f5cee893c..4fa134e40 100644 --- a/docs/html/EXTENDING.html +++ b/docs/html/EXTENDING.html @@ -12,7 +12,7 @@ alt="Tux Paint">
version -0.9.17 +0.9.18
Extending Tux Paint @@ -23,7 +23,7 @@ New Breed Software

bill@newbreedsoftware.com
http://www.tuxpaint.org/

-

June 14, 2002 - May 6, 2007

+

June 14, 2002 - August 2, 2007


@@ -558,24 +558,34 @@ effect.

-

Pre-Mirrored Images

+

Pre-Mirrored and Flipped Images

In some cases, you may wish to provide a pre-drawn version of - a stamp's mirror-image. For example, imagine a picture of a fire - truck with the words "Fire Department" written across - the side. You probably do not want that text to appear backwards - when the image is flipped!

+ a stamp's mirror-image, flipped image, or even both. For example, + imagine a picture of a fire truck with the words + "Fire Department" written across the side. You probably + do not want that text to appear backwards when the image is flipped!

To create a mirrored version of a stamp that you want Tux Paint to use, rather than mirroring one on its own, simply create a second - ".png" graphics file with the same name, except with - the string "_mirror" before the filename + ".png" or ".svg" graphics file with the + same name, except with "_mirror" before the filename extension.

For example, for the stamp "truck.png" you would create another file named "truck_mirror.png", which will be used when the stamp is mirrored (rather than using a backwards version of 'truck.png').

+ +

As of Tux Paint 0.9.18, you may similarly provide a pre-flipped + image with "_flip" in the name, and/or an image that + is both mirrored and flipped, by naming it + "_mirror_flip".

+ +

Note: If the user flips and mirrors an image, and a pre-drawn + "_mirror_flip" doesn't exist, but either "_flip" + or "_mirror" does, it will be used, and mirrored or flipped, + respectively.

diff --git a/docs/html/FAQ.html b/docs/html/FAQ.html index f95d188ab..2d17eac10 100644 --- a/docs/html/FAQ.html +++ b/docs/html/FAQ.html @@ -11,7 +11,7 @@ alink="#FF00FF"> alt="Tux Paint">
version -0.9.17 +0.9.18
Frequently Asked Questions @@ -22,7 +22,7 @@ New Breed Software

bill@newbreedsoftware.com
http://www.tuxpaint.org/

-

September 14, 2002 - June 27, 2007

+

September 14, 2002 - August 2, 2007

Drawing-related

diff --git a/docs/html/OPTIONS.html b/docs/html/OPTIONS.html index ec2beb2a6..23dfdcdf9 100644 --- a/docs/html/OPTIONS.html +++ b/docs/html/OPTIONS.html @@ -11,7 +11,7 @@ alink="#FF00FF"> version -0.9.17 +0.9.18

Options Documentation

diff --git a/docs/html/README.html b/docs/html/README.html index 1cf25d98f..41da88783 100644 --- a/docs/html/README.html +++ b/docs/html/README.html @@ -12,7 +12,7 @@ alt="Tux Paint">
version -0.9.17 +0.9.18

A simple drawing program for children

diff --git a/magic/docs/tp_magic_example.c b/magic/docs/tp_magic_example.c index c2118d27b..d73bb1266 100644 --- a/magic/docs/tp_magic_example.c +++ b/magic/docs/tp_magic_example.c @@ -1,176 +1,481 @@ +/* tp_magic_example.c + + An example of a "Magic" tool plugin for Tux Paint +*/ + + +/* Inclusion of header files: */ +/* -------------------------- */ + #include -#include -#include -#include "tp_magic_api.h" -#include "SDL_image.h" -#include "SDL_mixer.h" +#include // For "strdup()" +#include // For "gettext()" + +#include "tp_magic_api.h" // Tux Paint "Magic" tool API header +#include "SDL_image.h" // For IMG_Load(), to load our PNG icon +#include "SDL_mixer.h" // For Mix_LoadWAV(), to load our sound effects + + +/* Tool Enumerations: */ +/* ------------------ */ /* What tools we contain: */ enum { - TOOL_ONE, - TOOL_TWO, - NUM_TOOLS + TOOL_ONE, // Becomes '0' + TOOL_TWO, // Becomes '1' + NUM_TOOLS // Becomes '2' }; -/* Our globals: */ +/* A list of filenames for sounds and icons to load at startup: */ +const char * snd_filenames[NUM_TOOLS] = { + "one.wav", + "two.wav" +}; + +const char * icon_filenames[NUM_TOOLS] = { + "one.png", + "two.png" +}; + + +// Below, we define a macro called "gettext_noop()" that does nothing in our +// code when compiled (it simply disappears; e.g., 'gettext_noop("foo")' +// becomes simply "foo"), but is useful because the gettext localization +// tools will look for it and create a catalog of strings that should be +// translated into other languages. + +#ifndef gettext_noop +#define gettext_noop(String) String +#endif + +// We'll use this macro below, in some arrays of strings (char *'s) that +// hold the names and descriptions of our "Magic" tools. + + +/* A list of names for the tools */ + +const char * names[NUM_TOOLS] = { + gettext_noop("A tool"), + gettext_noop("Another tool") +}; + + +/* A list of descriptions of the tools */ + +const char * descs[NUM_TOOLS] = { + gettext_noop("This is example tool number 1."), + gettext_noop("This is example tool number 2.") +}; + + + +/* Our global variables: */ +/* --------------------- */ + +/* Sound effects: */ Mix_Chunk * snd_effect[NUM_TOOLS]; + +/* The current color (an "RGB" value) the user has selected in Tux Paint: */ Uint8 example_r, example_g, example_b; -Uint32 example_api_version(void) { return(TP_MAGIC_API_VERSION); } +/* Our local function prototypes: */ +/* ------------------------------ */ + +// These functions are called by other functions within our plugin, +// so we provide a 'prototype' of them, so the compiler knows what +// they accept and return. This lets us use them in other functions +// that are declared _before_ them. + +void example_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 example_line_callback(void * ptr, int which, + SDL_Surface * canvas, SDL_Surface * snapshot, + int x, int y); -// No setup required: +/* Setup Functions: */ +/* ---------------- */ + +// API Version check +// +// The running copy of Tux Paint that has loaded us first asks us what +// version of the Tux Paint "Magic" tool plugin API we were built against. +// If it deems us compatible, we'll be used! +// +// All we need to do here is return "TP_MAGIC_API_VERSION", +// which is #define'd in tp_magic_api.h. + +Uint32 example_api_version(void) +{ + return(TP_MAGIC_API_VERSION); +} + + +// Initialization +// +// This happens once, when Tux Paint starts up and is loading all of the +// "Magic" tool plugins. (Assuming what we returned from api_version() was +// acceptable!) +// +// All we're doing in this example is loading our sound effects, +// which we'll use later (in click(), drag() and release()) +// when the user is using our Magic tools. +// +// The memory we allocate here to store the sounds will be +// freed (aka released, aka deallocated) when the user quits Tux Paint, +// when our shutdown() function is called. + int example_init(magic_api * api) { + int i; char fname[1024]; - snprintf(fname, sizeof(fname), "%s/sounds/magic/one.wav", - api->data_directory); - snd_effect[0] = Mix_LoadWAV(fname); + for (i = 0; i < NUM_TOOLS; i++) + { + // Assemble the filename from the "snd_filenames[]" array into + // a full path to a real file. + // + // Use "api->data_directory" to figure out where our sounds should be. + // (The "tp-magic-config --dataprefix" command would have told us when + // we installed our plugin and its data.) - snprintf(fname, sizeof(fname), "%s/sounds/magic/two.wav", - api->data_directory); - snd_effect[1] = Mix_LoadWAV(fname); + snprintf(fname, sizeof(fname), + "%s/sounds/magic/%s.wav", + api->data_directory, snd_filenames[i]); + + + // Try to load the file! + + snd_effect[i] = Mix_LoadWAV(fname); + } return(1); } -// We have multiple tools: + +// Report our tool count +// +// Tux Paint needs to know how many "Magic" tools we'll be providing. +// Return that number here. (We simply grab the value of "NUM_TOOLS" +// from our 'enum' above!) +// +// When Tux Paint is starting up and loading plugins, it will call +// some of the following setup functions once for each tool we report. + int example_get_tool_count(magic_api * api) { return(NUM_TOOLS); } -// Load our icons: + +// Load icons +// +// When Tux Paint is starting up and loading plugins, it asks us to +// provide icons for the "Magic" tool buttons. + SDL_Surface * example_get_icon(magic_api * api, int which) { char fname[1024]; - if (which == TOOL_ONE) - { - snprintf(fname, sizeof(fname), "%s/images/magic/one.png", - api->data_directory); - } - else if (which == TOOL_TWO) - { - snprintf(fname, sizeof(fname), "%s/images/magic/two.png", - api->data_directory); - } + // Assemble the filename from the "icon_filenames[]" array into + // a full path to a real file. + // + // Use "api->data_directory" to figure out where our sounds should be. + // (The "tp-magic-config --dataprefix" command would have told us when + // we installed our plugin and its data.) + // + // We use 'which' (which of our tools Tux Paint is asking about) + // as an index into the array. + + snprintf(fname, sizeof(fname), "%s/images/magic/%s.png", + api->data_directory, icon_filenames[which]); + + + // Try to load the image, and return the results to Tux Paint: return(IMG_Load(fname)); } -// Return our names, localized: + +// Report our "Magic" tool names +// +// When Tux Paint is starting up and loading plugins, it asks us to +// provide names (labels) for the "Magic" tool buttons. + char * example_get_name(magic_api * api, int which) { - if (which == TOOL_ONE) - return(strdup(gettext("One"))); - else if (which == TOOL_TWO) - return(strdup(gettext("Two"))); + const char * our_name_english; + const char * our_name_localized; - return(NULL); + // Get our name from the "names[]" array. + // + // We use 'which' (which of our tools Tux Paint is asking about) + // as an index into the array. + + our_name_english = names[which]; + + + // Return a localized (aka translated) version of our name, + // if possible. + // + // We send "gettext()" the English version of the name from our array. + + our_name_localized = gettext(our_name_english); + + + // Finally, duplicate the string into a new section of memory, and + // send it to Tux Paint. (Tux Paint keeps track of the string and + // will free it for us, so we have one less thing to keep track of.) + + return(strdup(our_name_localized)); } -// Return our descriptions, localized: + +// Report our "Magic" tool descriptions +// +// When Tux Paint is starting up and loading plugins, it asks us to +// provide names (labels) for the "Magic" tool buttons. + char * example_get_description(magic_api * api, int which) { - if (which == TOOL_ONE) - return(strdup(gettext("Tool one."))); - else - return(strdup(gettext("Tool two."))); + const char * our_desc_english; + const char * our_desc_localized; - return(NULL); + // Get our desc from the "descs[]" array. + // + // We use 'which' (which of our tools Tux Paint is asking about) + // as an index into the array. + + our_desc_english = descs[which]; + + + // Return a localized (aka translated) version of our description, + // if possible. + // + // We send "gettext()" the English version of the description from our array. + + our_desc_localized = gettext(our_desc_english); + + + // Finally, duplicate the string into a new section of memory, and + // send it to Tux Paint. (Tux Paint keeps track of the string and + // will free it for us, so we have one less thing to keep track of.) + + return(strdup(our_desc_localized)); } -// Do the effect: +// Report whether we accept colors -void do_example(void * ptr, int which, SDL_Surface * canvas, SDL_Surface * last, - int x, int y) +int example_requires_colors(magic_api * api, int which) { - magic_api * api = (magic_api *) ptr; - int xx, yy; + // Both of our tools accept colors, so we're always returning '1' (for "true") - if (which == TOOL_ONE) - { - api->putpixel(canvas, x, y, SDL_MapRGB(canvas->format, - example_r, - example_g, - example_b)); - } - else if (which == TOOL_TWO) - { - for (yy = -4; yy < 4; yy++) - { - for (xx = -4; xx < 4; xx++) - { - api->putpixel(canvas, x + xx, y + yy, - api->getpixel(last, - canvas->w - x - xx, - canvas->h - y - yy)); - } - } - } + return 1; } + +// Shut down +// +// Tux Paint is quitting. When it quits, it asks all of the plugins +// to 'clean up' after themselves. We, for example, loaded some sound +// effects at startup (in our init() function), so we should free the +// memory used by them now. + +void example_shutdown(magic_api * api) +{ + int i; + + // Free (aka release, aka deallocate) the memory used to store the + // sound effects that we loaded during init(): + + for (i = 0; i < NUM_TOOLS; i++) + Mix_FreeChunk(snd_effect[i]); +} + + +/* Functions that respond to events in Tux Paint: */ +/* ---------------------------------------------- */ + +// Affect the canvas on click: + +void example_click(magic_api * api, int which, + SDL_Surface * canvas, SDL_Surface * snapshot, + int x, int y, SDL_Rect * update_rect) +{ + // In our case, a single click (which is also the start of a drag!) + // is identical to what dragging does, but just at one point, rather + // than across a line. + // + // So we 'cheat' here, by calling our draw() function with + // (x,y) for both the beginning and end points of a line. + + example_drag(api, which, canvas, snapshot, x, y, x, y, update_rect); +} + + // Affect the canvas on drag: + void example_drag(magic_api * api, int which, SDL_Surface * canvas, - SDL_Surface * last, int ox, int oy, int x, int y, + SDL_Surface * snapshot, int ox, int oy, int x, int y, SDL_Rect * update_rect) { - api->line(which, canvas, last, ox, oy, x, y, 1, do_example); + // Call Tux Paint's "line()" function. + // + // It will calculate a straight line between (ox,ox) and (x,y). + // Every N steps along that line (in this case, N is '1'), it + // will call _our_ function, "example_line_callback()", and send + // the current X,Y coordinates along the line, as well as other + // useful things (which of our "Magic" tools is being used and + // the current and snapshot canvases). + + api->line(which, canvas, snapshot, ox, oy, x, y, 1, example_line_callback); + + + // If we need to, swap the X and/or Y values, so that + // (ox,oy) is always the top left, and (x,y) is always the bottom right, + // so the values we put inside "update_rect" make sense: if (ox > x) { int tmp = ox; ox = x; x = tmp; } if (oy > y) { int tmp = oy; oy = y; y = tmp; } + + // Fill in the elements of the "update_rect" SDL_Rect structure + // that Tux Paint is sharing with us. + update_rect->x = ox - 4; update_rect->y = oy - 4; update_rect->w = (x + 4) - update_rect->x; update_rect->h = (y + 4) - update_rect->h; + + // Play the appropriate sound effect + // + // We're calculating a value between 0-255 for where the mouse is + // across the canvas (0 is the left, ~128 is the center, 255 is the right). + // + // These are the exact values Tux Paint's "playsound()" wants, + // to determine what speaker to play the sound in. + // (So the sound will pan from speaker to speaker as you drag the + // mouse around the canvas!) + api->playsound(snd_effect[which], - (x * 255) / canvas->w, (y * 255) / canvas->h); + (x * 255) / canvas->w, // pan + 255); // distance } -// Affect the canvas on click: -void example_click(magic_api * api, int which, - SDL_Surface * canvas, SDL_Surface * last, - int x, int y, SDL_Rect * update_rect) -{ - example_drag(api, which, canvas, last, x, y, x, y, update_rect); -} // Affect the canvas on release: + void example_release(magic_api * api, int which, - SDL_Surface * canvas, SDL_Surface * last, + SDL_Surface * canvas, SDL_Surface * snapshot, int x, int y, SDL_Rect * update_rect) { + // Neither of our effects do anything special when the mouse is released + // from a click or click-and-drag, so there's no code here... } -// No setup happened: -void example_shutdown(magic_api * api) -{ - if (snd_effect[0] != NULL) - Mix_FreeChunk(snd_effect[0]); - if (snd_effect[1] != NULL) - Mix_FreeChunk(snd_effect[1]); -} +// Accept colors +// +// When any of our "Magic" tools are activated by the user, +// if that tool accepts colors, the current color selection is sent to us. +// +// Additionally, if one of our color-accepting tools is active when the +// user changes colors, we'll be informed of that, as well. +// +// The color comes in as RGB values. -// Record the color from Tux Paint: void example_set_color(magic_api * api, Uint8 r, Uint8 g, Uint8 b) { + // We simply store the RGB values in the global variables we + // declared at the top of this file. + example_r = r; example_g = g; example_b = b; } -// Use colors: -int example_requires_colors(magic_api * api, int which) + +/* The Magic Effect Routines! */ +/* -------------------------- */ + +// Our "callback" function +// +// We do the 'work' in this callback. Our plugin file has just one. +// Some "Magic" tool plugins may have more, depending on the tools they're +// providing. Some have none (since they're not click-and-drag +// painting-style tools). +// +// Our callback function gets called once for every point along a line between +// the mouse's previous and current position, as it's being dragged. +// +// It pays attention to 'which' to determine which of our plugin's tools +// is currently selected. + +void example_line_callback(void * ptr, int which, + SDL_Surface * canvas, SDL_Surface * snapshot, + int x, int y) { - return 1; + // For technical reasons, we can't accept a pointer to the "magic_api" + // struct, like the other functions do. + // + // Instead, we receive a 'generic' pointer (a "void *"). + // The line below declares a local "magic_api" pointer variable called "api", + // and then assigns it to the value of the 'generic' pointer we received. + // + // (The "(magic_api *)" casts the generic pointer into the 'type' of + // pointer we want, a pointer to a "magic_api".) + magic_api * api = (magic_api *) ptr; + int xx, yy; + + + // This function handles both of our tools, so we need to check which + // is being used right now. We compare the 'which' argument that + // Tux Paint sends to us with the values we enumerated above. + + if (which == TOOL_ONE) + { + // Tool number 1 simply draws a single pixel at the (x,y) location. + // It's a 1x1 pixel brush + + api->putpixel(canvas, x, y, SDL_MapRGB(canvas->format, + example_r, + example_g, + example_b)); + + // We use "SDL_MapRGB()" to convert the RGB value we receive from Tux Paint + // for the user's current color selection to a 'Uint32' pixel value + // we can send to Tux Paint's "putpixel()" function. + } + else if (which == TOOL_TWO) + { + // Tool number 2 copies an 8x8 square of pixels from the opposite side + // of the canvas and puts it under the cursor + + for (yy = -4; yy < 4; yy++) + { + for (xx = -4; xx < 4; xx++) + { + api->putpixel(canvas, x + xx, y + yy, + api->getpixel(snapshot, + canvas->w - x - xx, + canvas->h - y - yy)); + + // We simply use Tux Paint's "getpixel()" routine to pull pixel + // values from the 'snapshot', and then "putpixel()" to draw them + // right into the 'canvas'. + + // Note: putpixel() and getpixel() are safe to use, even if your + // X,Y values are outside of the SDL surface (e.g., negative, or + // greater than the surface's width or height). + } + } + } } diff --git a/src/tuxpaint.c b/src/tuxpaint.c index c23dd0f32..ca306a532 100644 --- a/src/tuxpaint.c +++ b/src/tuxpaint.c @@ -1160,7 +1160,10 @@ typedef struct stamp_type SDL_Surface *thumbnail; unsigned thumb_mirrored:1; unsigned thumb_flipped:1; + unsigned thumb_mirrored_flipped:1; unsigned no_premirror:1; + unsigned no_preflip:1; + unsigned no_premirrorflip:1; unsigned processed:1; // got *.dat, computed size limits, etc. @@ -5206,9 +5209,8 @@ static void set_active_stamp(void) { stamp_type *sd = stamp_data[stamp_group][cur_stamp[stamp_group]]; unsigned len = strlen(sd->stampname); - char *buf = alloca(len + strlen("_mirror.EXT") + 1); - - /* FIXME: Add support for pre-flipped stamps! -bjk 2007.03.22 */ + char *buf = alloca(len + strlen("_mirror_flip.EXT") + 1); + int needs_mirror, needs_flip; if (active_stamp) SDL_FreeSurface(active_stamp); @@ -5216,8 +5218,129 @@ static void set_active_stamp(void) memcpy(buf, sd->stampname, len); - if (sd->mirrored && !sd->no_premirror) + printf("\nset_active_stamp()\n"); + + /* Look for pre-mirrored and pre-flipped version: */ + + needs_mirror = sd->mirrored; + needs_flip = sd->flipped; + + if (sd->mirrored && sd->flipped) { + /* Want mirrored and flipped, both */ + + printf("want both mirrored & flipped\n"); + + if (!sd->no_premirrorflip) + { +#ifndef NOSVG + memcpy(buf + len, "_mirror_flip.svg", 17); + active_stamp = do_loadimage(buf, 0); +#endif + + if (active_stamp == NULL) + { + memcpy(buf + len, "_mirror_flip.png", 17); + active_stamp = do_loadimage(buf, 0); + } + } + + + if (active_stamp != NULL) + { + printf("found a _mirror_flip!\n"); + + needs_mirror = 0; + needs_flip = 0; + } + else + { + /* Couldn't get one that was both, look for _mirror then _flip and + flip or mirror it: */ + + printf("didn't find a _mirror_flip\n"); + + if (!sd->no_premirror) + { +#ifndef NOSVG + memcpy(buf + len, "_mirror.svg", 12); + active_stamp = do_loadimage(buf, 0); +#endif + + if (active_stamp == NULL) + { + memcpy(buf + len, "_mirror.png", 12); + active_stamp = do_loadimage(buf, 0); + } + } + + if (active_stamp != NULL) + { + printf("found a _mirror!\n"); + needs_mirror = 0; + } + else + { + /* Couldn't get one that was just pre-mirrored, look for a + pre-flipped */ + + printf("didn't find a _mirror, either\n"); + + if (!sd->no_preflip) + { +#ifndef NOSVG + memcpy(buf + len, "_flip.svg", 10); + active_stamp = do_loadimage(buf, 0); +#endif + + if (active_stamp == NULL) + { + memcpy(buf + len, "_flip.png", 10); + active_stamp = do_loadimage(buf, 0); + } + } + + if (active_stamp != NULL) + { + printf("found a _flip!\n"); + needs_flip = 0; + } + else + printf("didn't find a _flip, either\n"); + } + } + } + else if (sd->flipped && !sd->no_preflip) + { + /* Want flipped only */ + + printf("want flipped only\n"); + +#ifndef NOSVG + memcpy(buf + len, "_flip.svg", 10); + active_stamp = do_loadimage(buf, 0); +#endif + + if (active_stamp == NULL) + { + memcpy(buf + len, "_flip.png", 10); + active_stamp = do_loadimage(buf, 0); + } + + if (active_stamp != NULL) + { + printf("found a _flip!\n"); + needs_flip = 0; + } + else + printf("didn't find a _flip\n"); + } + else if (sd->mirrored && !sd->no_premirror) + { + /* Want mirrored only */ + + printf("want mirrored only\n"); + #ifndef NOSVG memcpy(buf + len, "_mirror.svg", 12); active_stamp = do_loadimage(buf, 0); @@ -5228,11 +5351,25 @@ static void set_active_stamp(void) memcpy(buf + len, "_mirror.png", 12); active_stamp = do_loadimage(buf, 0); } + + if (active_stamp != NULL) + { + printf("found a _mirror!\n"); + needs_mirror = 0; + } + else + printf("didn't find a _mirror\n"); } + + /* Didn't want mirrored, or flipped, or couldn't load anything + that was pre-rendered: */ + if (!active_stamp) { -#ifndef NOSVG + printf("loading normal\n"); + +#ifndef NOSVG memcpy(buf + len, ".svg", 5); active_stamp = do_loadimage(buf, 0); #endif @@ -5243,27 +5380,44 @@ static void set_active_stamp(void) active_stamp = do_loadimage(buf, 0); } - if (!active_stamp) - active_stamp = thumbnail(img_dead40x40, 40, 40, 1); // copy it - if (sd->mirrored) - active_stamp = mirror_surface(active_stamp); } - if (sd->flipped) + /* Never allow a NULL image! */ + + if (!active_stamp) + active_stamp = thumbnail(img_dead40x40, 40, 40, 1); // copy it + + + /* If we wanted mirrored or flipped, and didn't get something pre-rendered, + do it to the image we did load: */ + + if (needs_mirror) + { + printf("mirroring\n"); + active_stamp = mirror_surface(active_stamp); + } + + if (needs_flip) + { + printf("flipping\n"); active_stamp = flip_surface(active_stamp); + } + + printf("\n\n"); } static void get_stamp_thumb(stamp_type * sd) { SDL_Surface *bigimg = NULL; unsigned len = strlen(sd->stampname); - char *buf = alloca(len + strlen("_mirror.EXT") + 1); - SDL_Surface *wrongmirror = NULL; - int need_mirror = 0; + char *buf = alloca(len + strlen("_mirror_flip.EXT") + 1); + int need_mirror, need_flip; double ratio; unsigned w; unsigned h; + printf("\nget_stamp_thumb()\n"); + memcpy(buf, sd->stampname, len); if (!sd->processed) @@ -5302,25 +5456,111 @@ static void get_stamp_thumb(stamp_type * sd) sd->no_txt = !sd->stxt; } + // first see if we can re-use an existing thumbnail if (sd->thumbnail) { - if (sd->mirrored == sd->thumb_mirrored) + printf("have an sd->thumbnail\n"); + + if (sd->thumb_mirrored_flipped == sd->flipped && + sd->thumb_mirrored_flipped == sd->mirrored && + sd->mirrored == sd->thumb_mirrored && + sd->flipped == sd->thumb_flipped) { - if (sd->flipped == sd->thumb_flipped) - return; - sd->thumbnail = flip_surface(sd->thumbnail); - sd->thumb_flipped = !sd->thumb_flipped; + // It's already the way we want + printf("mirrored == flipped == thumb_mirrored_flipped [bye]\n"); return; } - wrongmirror = sd->thumbnail; } - /* FIXME: Add support for pre-flipped stamps! -bjk 2007.03.22 */ - // nope, unless perhaps it can be mirrored - if (sd->mirrored && !sd->no_premirror) + // nope, see if there's a pre-rendered one we can use + + need_mirror = sd->mirrored; + need_flip = sd->flipped; + bigimg = NULL; + + if (sd->mirrored && sd->flipped) { + printf("want mirrored & flipped\n"); + + if (!sd->no_premirrorflip) + { + memcpy(buf + len, "_mirror_flip.png", 17); + bigimg = do_loadimage(buf, 0); + +#ifndef NOSVG + if (bigimg == NULL) + { + memcpy(buf + len, "_mirror_flip.svg", 17); + bigimg = do_loadimage(buf, 0); + } +#endif + } + + if (bigimg) + { + printf("found a _mirror_flip!\n"); + + need_mirror = 0; + need_flip = 0; + } + else + { + printf("didn't find a mirror_flip\n"); + sd->no_premirrorflip = 1; + + if (!sd->no_premirror) + { + memcpy(buf + len, "_mirror.png", 12); + bigimg = do_loadimage(buf, 0); + +#ifndef NOSVG + if (bigimg == NULL) + { + memcpy(buf + len, "_mirror.svg", 12); + bigimg = do_loadimage(buf, 0); + } +#endif + } + + if (bigimg) + { + printf("found a _mirror\n"); + + need_mirror = 0; + } + else + { + printf("didn't find a mirror\n"); + + if (!sd->no_preflip) + { + memcpy(buf + len, "_flip.png", 10); + bigimg = do_loadimage(buf, 0); + +#ifndef NOSVG + if (bigimg == NULL) + { + memcpy(buf + len, "_flip.svg", 10); + bigimg = do_loadimage(buf, 0); + } +#endif + } + + if (bigimg) + { + printf("found a _flip\n"); + + need_flip = 0; + } + } + } + } + else if (sd->mirrored && !sd->no_premirror) + { + printf("want mirrored only\n"); + memcpy(buf + len, "_mirror.png", 12); bigimg = do_loadimage(buf, 0); @@ -5334,26 +5574,49 @@ static void get_stamp_thumb(stamp_type * sd) if (bigimg) { - if (wrongmirror) - SDL_FreeSurface(wrongmirror); + printf("found a _mirror!\n"); + need_mirror = 0; } else + { + printf("didn't find a mirror\n"); sd->no_premirror = 1; + } } - if (wrongmirror && sd->no_premirror) + else if (sd->flipped && !sd->no_preflip) { - wrongmirror = mirror_surface(wrongmirror); - sd->thumbnail = wrongmirror; - sd->thumb_mirrored = !sd->thumb_mirrored; + printf("want flipped only\n"); - if (sd->flipped == sd->thumb_flipped) - return; - sd->thumbnail = flip_surface(sd->thumbnail); - sd->thumb_flipped = !sd->thumb_flipped; - return; + memcpy(buf + len, "_flip.png", 10); + bigimg = do_loadimage(buf, 0); + +#ifndef NOSVG + if (bigimg == NULL) + { + memcpy(buf + len, "_flip.svg", 10); + bigimg = do_loadimage(buf, 0); + } +#endif + + if (bigimg) + { + printf("found a _flip!\n"); + need_flip = 0; + } + else + { + printf("didn't find a flip\n"); + sd->no_preflip = 1; + } } + + + /* If we didn't load a pre-rendered, load the normal one: */ + if (!bigimg) { + printf("loading normal...\n"); + memcpy(buf + len, ".png", 5); bigimg = do_loadimage(buf, 0); @@ -5364,11 +5627,11 @@ static void get_stamp_thumb(stamp_type * sd) bigimg = do_loadimage(buf, 0); } #endif - - if (sd->mirrored) - need_mirror = 1; // want to mirror after scaling } + + /* Scale the stamp down to its thumbnail size: */ + w = 40; h = 40; if (bigimg) @@ -5387,16 +5650,41 @@ static void get_stamp_thumb(stamp_type * sd) else sd->thumbnail = bigimg; - if (need_mirror) - sd->thumbnail = mirror_surface(sd->thumbnail); - sd->thumb_mirrored = sd->mirrored; - if (sd->flipped) + /* Mirror and/or flip the thumbnail, if we still need to do so: */ + + if (need_mirror) + { + printf("mirroring\n"); + sd->thumbnail = mirror_surface(sd->thumbnail); + } + + if (need_flip) + { + printf("flipping\n"); sd->thumbnail = flip_surface(sd->thumbnail); + } + + + /* Note the fact that the thumbnail's mirror/flip is the same as the main + stamp: */ + + if (sd->mirrored && sd->flipped) + sd->thumb_mirrored_flipped = 1; + else + sd->thumb_mirrored_flipped = 0; + + sd->thumb_mirrored = sd->mirrored; sd->thumb_flipped = sd->flipped; + printf("\n\n"); + + + /* Finish up, if we need to: */ + if (sd->processed) return; + sd->processed = 1; // not really, but on the next line... loadstamp_finisher(sd, w, h, ratio); } @@ -5451,12 +5739,12 @@ static void loadstamp_callback(SDL_Surface * screen, while (i--) { char fname[512]; - const char *dotext, *ext, *mirror_ext; - - /* FIXME: Support pre-flipped stamps -bjk 2007.03.22 */ + const char *dotext, *ext, *mirror_ext, *flip_ext, *mirrorflip_ext; ext = ".png"; mirror_ext = "_mirror.png"; + flip_ext = "_flip.png"; + mirrorflip_ext = "_mirror_flip.png"; dotext = (char *) strcasestr(files[i].str, ext); #ifndef NOSVG @@ -5464,6 +5752,8 @@ static void loadstamp_callback(SDL_Surface * screen, { ext = ".svg"; mirror_ext = "_mirror.svg"; + flip_ext = "_flip.svg"; + mirrorflip_ext = "_mirror_flip.svg"; dotext = (char *) strcasestr(files[i].str, ext); } else @@ -5494,7 +5784,9 @@ static void loadstamp_callback(SDL_Surface * screen, if (dotext > files[i].str && !strcasecmp(dotext, ext) && (dotext - files[i].str + 1 + dirlen < sizeof fname) - && !strcasestr(files[i].str, mirror_ext)) + && !strcasestr(files[i].str, mirror_ext) + && !strcasestr(files[i].str, flip_ext) + && !strcasestr(files[i].str, mirrorflip_ext)) { snprintf(fname, sizeof fname, "%s/%s", dir, files[i].str); if (num_stamps[stamp_group] == max_stamps[stamp_group])