Syncing tp_magic_example.c (indent & transliteration)

This commit is contained in:
Bill Kendrick 2024-05-10 01:29:05 -07:00
parent bd10e955a1
commit 51d47d554e
14 changed files with 2058 additions and 1988 deletions

View file

@ -9,12 +9,12 @@
/* ---------------------------------------------------------------------- */ /* ---------------------------------------------------------------------- */
#include <stdio.h> #include <stdio.h>
#include <string.h> // For "strdup()" #include <string.h> // For "strdup()"
#include <libintl.h> // For "gettext()" #include <libintl.h> // For "gettext()"
#include "tp_magic_api.h" // Tux Paint "Magic" tool API header #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_image.h" // For IMG_Load(), to load our PNG icon
#include "SDL_mixer.h" // For Mix_LoadWAV(), to load our sound effects #include "SDL_mixer.h" // For Mix_LoadWAV(), to load our sound effects
/* Tool Enumerations: */ /* Tool Enumerations: */
@ -25,9 +25,9 @@
enum enum
{ {
TOOL_ONE, // Becomes '0' TOOL_ONE, // Becomes '0'
TOOL_TWO, // Becomes '1' TOOL_TWO, // Becomes '1'
NUM_TOOLS // Becomes '2' NUM_TOOLS // Becomes '2'
}; };
@ -101,11 +101,11 @@ _before_ them.
*/ */
void example_drag(magic_api * api, int which, SDL_Surface * canvas, void example_drag(magic_api * api, int which, SDL_Surface * canvas,
SDL_Surface * snapshot, int old_x, int old_y, int x, int y, SDL_Surface * snapshot, int old_x, int old_y, int x, int y,
SDL_Rect * update_rect); SDL_Rect * update_rect);
void example_line_callback(void *pointer, int which, SDL_Surface * canvas, void example_line_callback(void *pointer, int which, SDL_Surface * canvas,
SDL_Surface * snapshot, int x, int y); SDL_Surface * snapshot, int x, int y);
/* Setup Functions: */ /* Setup Functions: */
@ -144,7 +144,8 @@ released, aka deallocated) when the user quits Tux Paint, when our
example_shutdown() function is called. example_shutdown() function is called.
*/ */
int example_init(magic_api * api, Uint8 disabled_features, Uint8 complexity_level) int example_init(magic_api * api, Uint8 disabled_features,
Uint8 complexity_level)
{ {
int i; int i;
char filename[1024]; char filename[1024];
@ -152,15 +153,15 @@ int example_init(magic_api * api, Uint8 disabled_features, Uint8 complexity_leve
for (i = 0; i < NUM_TOOLS; i++) for (i = 0; i < NUM_TOOLS; i++)
{ {
/* /*
Assemble the filename from the "sound_filenames[]" array into a full path Assemble the filename from the "sound_filenames[]" array into a full path
to a real file. to a real file.
Use "api->data_directory" to figure out where our sounds should be. (The 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 "tp-magic-config --dataprefix" command would have told us when we installed
our plugin and its data.) our plugin and its data.)
*/ */
snprintf(filename, sizeof(filename), "%ssounds/magic/%s", api->data_directory, snprintf(filename, sizeof(filename), "%ssounds/magic/%s",
sound_filenames[i]); api->data_directory, sound_filenames[i]);
printf("Trying to load %s sound file\n", filename); printf("Trying to load %s sound file\n", filename);
@ -200,16 +201,16 @@ SDL_Surface *example_get_icon(magic_api * api, int which)
char filename[1024]; char filename[1024];
/* /*
Assemble the filename from the "icon_filenames[]" array into a full path to Assemble the filename from the "icon_filenames[]" array into a full path to
a real file. a real file.
Use "api->data_directory" to figure out where our sounds should be. (The 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 "tp-magic-config --dataprefix" command would have told us when we installed
our plugin and its data.) our plugin and its data.)
We use "which" (which of our tools Tux Paint is asking about) as an index We use "which" (which of our tools Tux Paint is asking about) as an index
into the array. into the array.
*/ */
snprintf(filename, sizeof(filename), "%simages/magic/%s", snprintf(filename, sizeof(filename), "%simages/magic/%s",
api->data_directory, icon_filenames[which]); api->data_directory, icon_filenames[which]);
@ -229,31 +230,31 @@ names (labels) for the 'Magic' tool buttons.
*/ */
char *example_get_name(magic_api * api, int which) char *example_get_name(magic_api * api, int which)
{ {
const char *our_name_english; const char *our_name_english;
const char *our_name_localized; const char *our_name_localized;
/* /*
Get our name from the "tool_names[]" array. Get our name from the "tool_names[]" array.
We use 'which' (which of our tools Tux Paint is asking about) as an index We use 'which' (which of our tools Tux Paint is asking about) as an index
into the array. into the array.
*/ */
our_name_english = tool_names[which]; our_name_english = tool_names[which];
/* /*
Return a localized (aka translated) version of our name, if possible. Return a localized (aka translated) version of our name, if possible.
We send "gettext()" the English version of the name from our array. We send "gettext()" the English version of the name from our array.
*/ */
our_name_localized = gettext(our_name_english); our_name_localized = gettext(our_name_english);
/* /*
Finally, duplicate the string into a new section of memory, and send it to 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, 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.) so we have one less thing to keep track of.)
*/ */
return (strdup(our_name_localized)); return (strdup(our_name_localized));
} }
@ -267,11 +268,11 @@ where the tool should be grouped.
int example_get_group(magic_api * api, int which) int example_get_group(magic_api * api, int which)
{ {
/* /*
Return our group, found in the "tool_groups[]" array. Return our group, found in the "tool_groups[]" array.
We use 'which' (which of our tools Tux Paint is asking about) as an index We use 'which' (which of our tools Tux Paint is asking about) as an index
into the array. into the array.
*/ */
return (tool_groups[which]); return (tool_groups[which]);
} }
@ -302,28 +303,28 @@ char *example_get_description(magic_api * api, int which, int mode)
const char *our_desc_localized; const char *our_desc_localized;
/* /*
Get our description from the "tool_descriptions[]" array. Get our description from the "tool_descriptions[]" array.
We use 'which' (which of our tools Tux Paint is asking about) as an index We use 'which' (which of our tools Tux Paint is asking about) as an index
into the array. into the array.
*/ */
our_desc_english = tool_descriptions[which]; our_desc_english = tool_descriptions[which];
/* /*
Return a localized (aka translated) version of our description, if Return a localized (aka translated) version of our description, if
possible. possible.
We send "gettext" the English version of the description from our array. We send "gettext" the English version of the description from our array.
*/ */
our_desc_localized = gettext(our_desc_english); our_desc_localized = gettext(our_desc_english);
/* /*
Finally, duplicate the string into a new section of memory, and send it to 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, 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.) so we have one less thing to keep track of.)
*/ */
return (strdup(our_desc_localized)); return (strdup(our_desc_localized));
} }
@ -345,9 +346,9 @@ int example_requires_colors(magic_api * api, int which)
int example_modes(magic_api * api, int which) int example_modes(magic_api * api, int which)
{ {
/* /*
Both of our tools are painted (neither affect the full-screen), so we're Both of our tools are painted (neither affect the full-screen), so we're
always returning 'MODE_PAINT' always returning 'MODE_PAINT'
*/ */
return MODE_PAINT; return MODE_PAINT;
} }
@ -385,9 +386,9 @@ void example_shutdown(magic_api * api)
int i; int i;
/* /*
Free (aka release, aka deallocate) the memory used to store the sound Free (aka release, aka deallocate) the memory used to store the sound
effects that we loaded during example_init(): effects that we loaded during example_init():
*/ */
for (i = 0; i < NUM_TOOLS; i++) for (i = 0; i < NUM_TOOLS; i++)
Mix_FreeChunk(sound_effects[i]); Mix_FreeChunk(sound_effects[i]);
} }
@ -404,13 +405,13 @@ example_click(magic_api * api, int which, int mode,
SDL_Rect * update_rect) SDL_Rect * update_rect)
{ {
/* /*
In our case, a single click (which is also the start of a drag!) is 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 identical to what dragging does, but just at one point, rather than across
a line. a line.
So we 'cheat' here, by calling our "example_draw()" function with (x,y) for So we 'cheat' here, by calling our "example_draw()" function with (x,y) for
both the beginning and end points of a line. both the beginning and end points of a line.
*/ */
example_drag(api, which, canvas, snapshot, x, y, x, y, update_rect); example_drag(api, which, canvas, snapshot, x, y, x, y, update_rect);
} }
@ -420,34 +421,32 @@ example_click(magic_api * api, int which, int mode,
void void
example_drag(magic_api * api, int which, example_drag(magic_api * api, int which,
SDL_Surface * canvas, SDL_Surface * snapshot, SDL_Surface * canvas, SDL_Surface * snapshot,
int old_x, int old_y, int x, int y, int old_x, int old_y, int x, int y, SDL_Rect * update_rect)
SDL_Rect * update_rect)
{ {
/* /*
Call Tux Paint's "line()" (line-traversing) function. Call Tux Paint's "line()" (line-traversing) function.
It will calculate a straight line between (old_x,old_y) and (x,y). Every It will calculate a straight line between (old_x,old_y) and (x,y). Every
N steps along that line (in this case, N is '1'), it will call _our_ 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 function, "example_line_callback()", and send the current X,Y
coordinates along the line, as well as other useful things (which of our coordinates along the line, as well as other useful things (which of our
'Magic' tools is being used and the current and snapshot canvases). 'Magic' tools is being used and the current and snapshot canvases).
*/ */
SDL_LockSurface(snapshot); SDL_LockSurface(snapshot);
SDL_LockSurface(canvas); SDL_LockSurface(canvas);
api->line((void *) api, which, canvas, snapshot, api->line((void *) api, which, canvas, snapshot,
old_x, old_y, x, y, 1, old_x, old_y, x, y, 1, example_line_callback);
example_line_callback);
SDL_UnlockSurface(canvas); SDL_UnlockSurface(canvas);
SDL_UnlockSurface(snapshot); SDL_UnlockSurface(snapshot);
/* /*
If we need to, swap the X and/or Y values, so that the coordinates If we need to, swap the X and/or Y values, so that the coordinates
(old_x,old_y) is always the top left, and the coordinates (x,y) is (old_x,old_y) is always the top left, and the coordinates (x,y) is
always the bottom right, so the values we put inside "update_rect" make always the bottom right, so the values we put inside "update_rect" make
sense: sense:
*/ */
if (old_x > x) if (old_x > x)
{ {
@ -466,17 +465,20 @@ example_drag(magic_api * api, int which,
/* /*
Fill in the elements of the "update_rect" SDL_Rect structure that Tux Fill in the elements of the "update_rect" SDL_Rect structure that Tux
Paint is sharing with us, therefore telling Tux Paint which part of the Paint is sharing with us, therefore telling Tux Paint which part of the
canvas has been modified and should be updated. canvas has been modified and should be updated.
*/ */
if (which == TOOL_ONE) { if (which == TOOL_ONE)
{
update_rect->x = old_x; update_rect->x = old_x;
update_rect->y = old_y; update_rect->y = old_y;
update_rect->w = (x - old_x) + 1; update_rect->w = (x - old_x) + 1;
update_rect->h = (y - old_y) + 1; update_rect->h = (y - old_y) + 1;
} else { }
else
{
update_rect->x = old_x - example_size; update_rect->x = old_x - example_size;
update_rect->y = old_y - example_size; update_rect->y = old_y - example_size;
update_rect->w = (x + example_size) - update_rect->x + 1; update_rect->w = (x + example_size) - update_rect->x + 1;
@ -484,19 +486,18 @@ example_drag(magic_api * api, int which,
} }
/* /*
Play the appropriate sound effect Play the appropriate sound effect
We're calculating a value between 0-255 for where the mouse is We're calculating a value between 0-255 for where the mouse is
horizontally across the canvas (0 is the left, ~128 is the center, 255 horizontally across the canvas (0 is the left, ~128 is the center, 255
is the right). is the right).
These are the exact values Tux Paint's "playsound()" wants, to determine 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 what speaker to play the sound in. (So the sound will pan from speaker
to speaker as you drag the mouse around the canvas!) to speaker as you drag the mouse around the canvas!)
*/ */
api->playsound(sound_effects[which], api->playsound(sound_effects[which], (x * 255) / canvas->w, /* Left/right pan */
(x * 255) / canvas->w, /* Left/right pan */ 255 /* Near/far distance (loudness) */ );
255 /* Near/far distance (loudness) */);
} }
@ -508,9 +509,9 @@ example_release(magic_api * api, int which,
SDL_Rect * update_rect) SDL_Rect * update_rect)
{ {
/* /*
Neither of our effects do anything special when the mouse is released 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... from a click or click-and-drag, so there's no code here...
*/ */
} }
@ -526,12 +527,14 @@ changes their chosen, we'll be informed of that as well.
The color comes in as RGB (red, green, and blue) values from 0 (darkest) to The color comes in as RGB (red, green, and blue) values from 0 (darkest) to
255 (brightest). 255 (brightest).
*/ */
void example_set_color(magic_api * api, int which, SDL_Surface * canvas, SDL_Surface * snapshot, Uint8 r, Uint8 g, Uint8 b, SDL_Rect * update_rect) void example_set_color(magic_api * api, int which, SDL_Surface * canvas,
SDL_Surface * snapshot, Uint8 r, Uint8 g, Uint8 b,
SDL_Rect * update_rect)
{ {
/* /*
We simply store the RGB values in the global variables we declared at We simply store the RGB values in the global variables we declared at
the top of this file. the top of this file.
*/ */
example_r = r; example_r = r;
example_g = g; example_g = g;
@ -551,12 +554,14 @@ that as well.
The size comes in as an unsigned integer (Uint8) between 1 and the value The size comes in as an unsigned integer (Uint8) between 1 and the value
returned by our example_accepted_sizes() function during setup. returned by our example_accepted_sizes() function during setup.
*/ */
void example_set_size(magic_api * api, int which, int mode, SDL_Surface * canvas, SDL_Surface * snapshot, Uint8 size, SDL_Rect * update_rect) void example_set_size(magic_api * api, int which, int mode,
SDL_Surface * canvas, SDL_Surface * snapshot,
Uint8 size, SDL_Rect * update_rect)
{ {
/* /*
Store the new size into the global variable we declared at the top of Store the new size into the global variable we declared at the top of
this file. this file.
*/ */
example_size = size * 4; example_size = size * 4;
} }
@ -580,51 +585,51 @@ Our callback pays attention to 'which' to determine which of our plugin's
tools is currently selected. tools is currently selected.
*/ */
void example_line_callback(void *pointer, int which, SDL_Surface * canvas, void example_line_callback(void *pointer, int which, SDL_Surface * canvas,
SDL_Surface * snapshot, int x, int y) SDL_Surface * snapshot, int x, int y)
{ {
/* /*
For technical reasons, we can't accept a pointer to the Tux Paint API's For technical reasons, we can't accept a pointer to the Tux Paint API's
"magic_api" struct, like the other functions do. "magic_api" struct, like the other functions do.
Instead, we receive a 'generic' pointer (a "void *"). The line below Instead, we receive a 'generic' pointer (a "void *"). The line below
declares a local "magic_api" pointer variable called "api", and then declares a local "magic_api" pointer variable called "api", and then
assigns it to the value of the 'generic' pointer we received. assigns it to the value of the 'generic' pointer we received.
The "(magic_api *)" seen below casts the generic "void *" pointer into The "(magic_api *)" seen below casts the generic "void *" pointer into
the 'type' of pointer we want, a pointer to a "magic_api" struct.) the 'type' of pointer we want, a pointer to a "magic_api" struct.)
*/ */
magic_api *api = (magic_api *) pointer; magic_api *api = (magic_api *) pointer;
int xx, yy; int xx, yy;
/* /*
This function handles both of our tools, so we need to check which is 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 being used right now. We compare the 'which' argument that Tux Paint
sends to us with the values we enumerated above. sends to us with the values we enumerated above.
*/ */
if (which == TOOL_ONE) if (which == TOOL_ONE)
{ {
/* /*
Tool number 1 simply draws a single pixel at the (x,y) location. It acts Tool number 1 simply draws a single pixel at the (x,y) location. It acts
as a 1x1 pixel brush. as a 1x1 pixel brush.
*/ */
api->putpixel(canvas, x, y, api->putpixel(canvas, x, y,
SDL_MapRGB(canvas->format, SDL_MapRGB(canvas->format,
example_r, example_g, example_b)); example_r, example_g, example_b));
/* /*
We use "SDL_MapRGB()" to convert the RGB value we receive from Tux Paint 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 for the user's current color selection to a 'Uint32' pixel value we can
send to Tux Paint's "putpixel()" function. send to Tux Paint's "putpixel()" function.
*/ */
} }
else if (which == TOOL_TWO) else if (which == TOOL_TWO)
{ {
/* /*
Tool number 2 copies a square of pixels (of the size chosen by the user) Tool number 2 copies a square of pixels (of the size chosen by the user)
from the opposite side of the canvas and puts it under the cursor. from the opposite side of the canvas and puts it under the cursor.
*/ */
for (yy = -example_size; yy < example_size; yy++) for (yy = -example_size; yy < example_size; yy++)
{ {
@ -636,14 +641,14 @@ void example_line_callback(void *pointer, int which, SDL_Surface * canvas,
snapshot->h - y - yy)); snapshot->h - y - yy));
/* /*
Here we have simply use Tux Paint's "getpixel()" routine to pull pixel Here we have simply use Tux Paint's "getpixel()" routine to pull pixel
values from the 'snapshot', and then "putpixel()" to draw them right values from the 'snapshot', and then "putpixel()" to draw them right
into the 'canvas'. into the 'canvas'.
Note: putpixel() and getpixel() are safe to use, even if your X,Y values 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 are outside of the SDL surface (e.g., negative, or greater than the
surface's width and/or height). surface's width and/or height).
*/ */
} }
} }
} }

View file

@ -9,12 +9,12 @@
/* ---------------------------------------------------------------------- */ /* ---------------------------------------------------------------------- */
#include <stdio.h> #include <stdio.h>
#include <string.h> // For "strdup()" #include <string.h> // For "strdup()"
#include <libintl.h> // For "gettext()" #include <libintl.h> // For "gettext()"
#include "tp_magic_api.h" // Tux Paint "Magic" tool API header #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_image.h" // For IMG_Load(), to load our PNG icon
#include "SDL_mixer.h" // For Mix_LoadWAV(), to load our sound effects #include "SDL_mixer.h" // For Mix_LoadWAV(), to load our sound effects
/* Tool Enumerations: */ /* Tool Enumerations: */
@ -25,9 +25,9 @@
enum enum
{ {
TOOL_ONE, // Becomes '0' TOOL_ONE, // Becomes '0'
TOOL_TWO, // Becomes '1' TOOL_TWO, // Becomes '1'
NUM_TOOLS // Becomes '2' NUM_TOOLS // Becomes '2'
}; };
@ -101,11 +101,11 @@ _before_ them.
*/ */
void example_drag(magic_api * api, int which, SDL_Surface * canvas, void example_drag(magic_api * api, int which, SDL_Surface * canvas,
SDL_Surface * snapshot, int old_x, int old_y, int x, int y, SDL_Surface * snapshot, int old_x, int old_y, int x, int y,
SDL_Rect * update_rect); SDL_Rect * update_rect);
void example_line_callback(void *pointer, int which, SDL_Surface * canvas, void example_line_callback(void *pointer, int which, SDL_Surface * canvas,
SDL_Surface * snapshot, int x, int y); SDL_Surface * snapshot, int x, int y);
/* Setup Functions: */ /* Setup Functions: */
@ -144,7 +144,8 @@ released, aka deallocated) when the user quits Tux Paint, when our
example_shutdown() function is called. example_shutdown() function is called.
*/ */
int example_init(magic_api * api, Uint8 disabled_features, Uint8 complexity_level) int example_init(magic_api * api, Uint8 disabled_features,
Uint8 complexity_level)
{ {
int i; int i;
char filename[1024]; char filename[1024];
@ -152,15 +153,15 @@ int example_init(magic_api * api, Uint8 disabled_features, Uint8 complexity_leve
for (i = 0; i < NUM_TOOLS; i++) for (i = 0; i < NUM_TOOLS; i++)
{ {
/* /*
Assemble the filename from the "sound_filenames[]" array into a full path Assemble the filename from the "sound_filenames[]" array into a full path
to a real file. to a real file.
Use "api->data_directory" to figure out where our sounds should be. (The 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 "tp-magic-config --dataprefix" command would have told us when we installed
our plugin and its data.) our plugin and its data.)
*/ */
snprintf(filename, sizeof(filename), "%ssounds/magic/%s", api->data_directory, snprintf(filename, sizeof(filename), "%ssounds/magic/%s",
sound_filenames[i]); api->data_directory, sound_filenames[i]);
printf("Trying to load %s sound file\n", filename); printf("Trying to load %s sound file\n", filename);
@ -200,16 +201,16 @@ SDL_Surface *example_get_icon(magic_api * api, int which)
char filename[1024]; char filename[1024];
/* /*
Assemble the filename from the "icon_filenames[]" array into a full path to Assemble the filename from the "icon_filenames[]" array into a full path to
a real file. a real file.
Use "api->data_directory" to figure out where our sounds should be. (The 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 "tp-magic-config --dataprefix" command would have told us when we installed
our plugin and its data.) our plugin and its data.)
We use "which" (which of our tools Tux Paint is asking about) as an index We use "which" (which of our tools Tux Paint is asking about) as an index
into the array. into the array.
*/ */
snprintf(filename, sizeof(filename), "%simages/magic/%s", snprintf(filename, sizeof(filename), "%simages/magic/%s",
api->data_directory, icon_filenames[which]); api->data_directory, icon_filenames[which]);
@ -229,31 +230,31 @@ names (labels) for the 'Magic' tool buttons.
*/ */
char *example_get_name(magic_api * api, int which) char *example_get_name(magic_api * api, int which)
{ {
const char *our_name_english; const char *our_name_english;
const char *our_name_localized; const char *our_name_localized;
/* /*
Get our name from the "tool_names[]" array. Get our name from the "tool_names[]" array.
We use 'which' (which of our tools Tux Paint is asking about) as an index We use 'which' (which of our tools Tux Paint is asking about) as an index
into the array. into the array.
*/ */
our_name_english = tool_names[which]; our_name_english = tool_names[which];
/* /*
Return a localized (aka translated) version of our name, if possible. Return a localized (aka translated) version of our name, if possible.
We send "gettext()" the English version of the name from our array. We send "gettext()" the English version of the name from our array.
*/ */
our_name_localized = gettext(our_name_english); our_name_localized = gettext(our_name_english);
/* /*
Finally, duplicate the string into a new section of memory, and send it to 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, 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.) so we have one less thing to keep track of.)
*/ */
return (strdup(our_name_localized)); return (strdup(our_name_localized));
} }
@ -267,11 +268,11 @@ where the tool should be grouped.
int example_get_group(magic_api * api, int which) int example_get_group(magic_api * api, int which)
{ {
/* /*
Return our group, found in the "tool_groups[]" array. Return our group, found in the "tool_groups[]" array.
We use 'which' (which of our tools Tux Paint is asking about) as an index We use 'which' (which of our tools Tux Paint is asking about) as an index
into the array. into the array.
*/ */
return (tool_groups[which]); return (tool_groups[which]);
} }
@ -302,28 +303,28 @@ char *example_get_description(magic_api * api, int which, int mode)
const char *our_desc_localized; const char *our_desc_localized;
/* /*
Get our description from the "tool_descriptions[]" array. Get our description from the "tool_descriptions[]" array.
We use 'which' (which of our tools Tux Paint is asking about) as an index We use 'which' (which of our tools Tux Paint is asking about) as an index
into the array. into the array.
*/ */
our_desc_english = tool_descriptions[which]; our_desc_english = tool_descriptions[which];
/* /*
Return a localized (aka translated) version of our description, if Return a localized (aka translated) version of our description, if
possible. possible.
We send "gettext" the English version of the description from our array. We send "gettext" the English version of the description from our array.
*/ */
our_desc_localized = gettext(our_desc_english); our_desc_localized = gettext(our_desc_english);
/* /*
Finally, duplicate the string into a new section of memory, and send it to 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, 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.) so we have one less thing to keep track of.)
*/ */
return (strdup(our_desc_localized)); return (strdup(our_desc_localized));
} }
@ -345,9 +346,9 @@ int example_requires_colors(magic_api * api, int which)
int example_modes(magic_api * api, int which) int example_modes(magic_api * api, int which)
{ {
/* /*
Both of our tools are painted (neither affect the full-screen), so we're Both of our tools are painted (neither affect the full-screen), so we're
always returning 'MODE_PAINT' always returning 'MODE_PAINT'
*/ */
return MODE_PAINT; return MODE_PAINT;
} }
@ -385,9 +386,9 @@ void example_shutdown(magic_api * api)
int i; int i;
/* /*
Free (aka release, aka deallocate) the memory used to store the sound Free (aka release, aka deallocate) the memory used to store the sound
effects that we loaded during example_init(): effects that we loaded during example_init():
*/ */
for (i = 0; i < NUM_TOOLS; i++) for (i = 0; i < NUM_TOOLS; i++)
Mix_FreeChunk(sound_effects[i]); Mix_FreeChunk(sound_effects[i]);
} }
@ -404,13 +405,13 @@ example_click(magic_api * api, int which, int mode,
SDL_Rect * update_rect) SDL_Rect * update_rect)
{ {
/* /*
In our case, a single click (which is also the start of a drag!) is 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 identical to what dragging does, but just at one point, rather than across
a line. a line.
So we 'cheat' here, by calling our "example_draw()" function with (x,y) for So we 'cheat' here, by calling our "example_draw()" function with (x,y) for
both the beginning and end points of a line. both the beginning and end points of a line.
*/ */
example_drag(api, which, canvas, snapshot, x, y, x, y, update_rect); example_drag(api, which, canvas, snapshot, x, y, x, y, update_rect);
} }
@ -420,34 +421,32 @@ example_click(magic_api * api, int which, int mode,
void void
example_drag(magic_api * api, int which, example_drag(magic_api * api, int which,
SDL_Surface * canvas, SDL_Surface * snapshot, SDL_Surface * canvas, SDL_Surface * snapshot,
int old_x, int old_y, int x, int y, int old_x, int old_y, int x, int y, SDL_Rect * update_rect)
SDL_Rect * update_rect)
{ {
/* /*
Call Tux Paint's "line()" (line-traversing) function. Call Tux Paint's "line()" (line-traversing) function.
It will calculate a straight line between (old_x,old_y) and (x,y). Every It will calculate a straight line between (old_x,old_y) and (x,y). Every
N steps along that line (in this case, N is '1'), it will call _our_ 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 function, "example_line_callback()", and send the current X,Y
coordinates along the line, as well as other useful things (which of our coordinates along the line, as well as other useful things (which of our
'Magic' tools is being used and the current and snapshot canvases). 'Magic' tools is being used and the current and snapshot canvases).
*/ */
SDL_LockSurface(snapshot); SDL_LockSurface(snapshot);
SDL_LockSurface(canvas); SDL_LockSurface(canvas);
api->line((void *) api, which, canvas, snapshot, api->line((void *) api, which, canvas, snapshot,
old_x, old_y, x, y, 1, old_x, old_y, x, y, 1, example_line_callback);
example_line_callback);
SDL_UnlockSurface(canvas); SDL_UnlockSurface(canvas);
SDL_UnlockSurface(snapshot); SDL_UnlockSurface(snapshot);
/* /*
If we need to, swap the X and/or Y values, so that the coordinates If we need to, swap the X and/or Y values, so that the coordinates
(old_x,old_y) is always the top left, and the coordinates (x,y) is (old_x,old_y) is always the top left, and the coordinates (x,y) is
always the bottom right, so the values we put inside "update_rect" make always the bottom right, so the values we put inside "update_rect" make
sense: sense:
*/ */
if (old_x > x) if (old_x > x)
{ {
@ -466,17 +465,20 @@ example_drag(magic_api * api, int which,
/* /*
Fill in the elements of the "update_rect" SDL_Rect structure that Tux Fill in the elements of the "update_rect" SDL_Rect structure that Tux
Paint is sharing with us, therefore telling Tux Paint which part of the Paint is sharing with us, therefore telling Tux Paint which part of the
canvas has been modified and should be updated. canvas has been modified and should be updated.
*/ */
if (which == TOOL_ONE) { if (which == TOOL_ONE)
{
update_rect->x = old_x; update_rect->x = old_x;
update_rect->y = old_y; update_rect->y = old_y;
update_rect->w = (x - old_x) + 1; update_rect->w = (x - old_x) + 1;
update_rect->h = (y - old_y) + 1; update_rect->h = (y - old_y) + 1;
} else { }
else
{
update_rect->x = old_x - example_size; update_rect->x = old_x - example_size;
update_rect->y = old_y - example_size; update_rect->y = old_y - example_size;
update_rect->w = (x + example_size) - update_rect->x + 1; update_rect->w = (x + example_size) - update_rect->x + 1;
@ -484,19 +486,18 @@ example_drag(magic_api * api, int which,
} }
/* /*
Play the appropriate sound effect Play the appropriate sound effect
We're calculating a value between 0-255 for where the mouse is We're calculating a value between 0-255 for where the mouse is
horizontally across the canvas (0 is the left, ~128 is the center, 255 horizontally across the canvas (0 is the left, ~128 is the center, 255
is the right). is the right).
These are the exact values Tux Paint's "playsound()" wants, to determine 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 what speaker to play the sound in. (So the sound will pan from speaker
to speaker as you drag the mouse around the canvas!) to speaker as you drag the mouse around the canvas!)
*/ */
api->playsound(sound_effects[which], api->playsound(sound_effects[which], (x * 255) / canvas->w, /* Left/right pan */
(x * 255) / canvas->w, /* Left/right pan */ 255 /* Near/far distance (loudness) */ );
255 /* Near/far distance (loudness) */);
} }
@ -508,9 +509,9 @@ example_release(magic_api * api, int which,
SDL_Rect * update_rect) SDL_Rect * update_rect)
{ {
/* /*
Neither of our effects do anything special when the mouse is released 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... from a click or click-and-drag, so there's no code here...
*/ */
} }
@ -526,12 +527,14 @@ changes their chosen, we'll be informed of that as well.
The color comes in as RGB (red, green, and blue) values from 0 (darkest) to The color comes in as RGB (red, green, and blue) values from 0 (darkest) to
255 (brightest). 255 (brightest).
*/ */
void example_set_color(magic_api * api, int which, SDL_Surface * canvas, SDL_Surface * snapshot, Uint8 r, Uint8 g, Uint8 b, SDL_Rect * update_rect) void example_set_color(magic_api * api, int which, SDL_Surface * canvas,
SDL_Surface * snapshot, Uint8 r, Uint8 g, Uint8 b,
SDL_Rect * update_rect)
{ {
/* /*
We simply store the RGB values in the global variables we declared at We simply store the RGB values in the global variables we declared at
the top of this file. the top of this file.
*/ */
example_r = r; example_r = r;
example_g = g; example_g = g;
@ -551,12 +554,14 @@ that as well.
The size comes in as an unsigned integer (Uint8) between 1 and the value The size comes in as an unsigned integer (Uint8) between 1 and the value
returned by our example_accepted_sizes() function during setup. returned by our example_accepted_sizes() function during setup.
*/ */
void example_set_size(magic_api * api, int which, int mode, SDL_Surface * canvas, SDL_Surface * snapshot, Uint8 size, SDL_Rect * update_rect) void example_set_size(magic_api * api, int which, int mode,
SDL_Surface * canvas, SDL_Surface * snapshot,
Uint8 size, SDL_Rect * update_rect)
{ {
/* /*
Store the new size into the global variable we declared at the top of Store the new size into the global variable we declared at the top of
this file. this file.
*/ */
example_size = size * 4; example_size = size * 4;
} }
@ -580,51 +585,51 @@ Our callback pays attention to 'which' to determine which of our plugin's
tools is currently selected. tools is currently selected.
*/ */
void example_line_callback(void *pointer, int which, SDL_Surface * canvas, void example_line_callback(void *pointer, int which, SDL_Surface * canvas,
SDL_Surface * snapshot, int x, int y) SDL_Surface * snapshot, int x, int y)
{ {
/* /*
For technical reasons, we can't accept a pointer to the Tux Paint API's For technical reasons, we can't accept a pointer to the Tux Paint API's
"magic_api" struct, like the other functions do. "magic_api" struct, like the other functions do.
Instead, we receive a 'generic' pointer (a "void *"). The line below Instead, we receive a 'generic' pointer (a "void *"). The line below
declares a local "magic_api" pointer variable called "api", and then declares a local "magic_api" pointer variable called "api", and then
assigns it to the value of the 'generic' pointer we received. assigns it to the value of the 'generic' pointer we received.
The "(magic_api *)" seen below casts the generic "void *" pointer into The "(magic_api *)" seen below casts the generic "void *" pointer into
the 'type' of pointer we want, a pointer to a "magic_api" struct.) the 'type' of pointer we want, a pointer to a "magic_api" struct.)
*/ */
magic_api *api = (magic_api *) pointer; magic_api *api = (magic_api *) pointer;
int xx, yy; int xx, yy;
/* /*
This function handles both of our tools, so we need to check which is 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 being used right now. We compare the 'which' argument that Tux Paint
sends to us with the values we enumerated above. sends to us with the values we enumerated above.
*/ */
if (which == TOOL_ONE) if (which == TOOL_ONE)
{ {
/* /*
Tool number 1 simply draws a single pixel at the (x,y) location. It acts Tool number 1 simply draws a single pixel at the (x,y) location. It acts
as a 1x1 pixel brush. as a 1x1 pixel brush.
*/ */
api->putpixel(canvas, x, y, api->putpixel(canvas, x, y,
SDL_MapRGB(canvas->format, SDL_MapRGB(canvas->format,
example_r, example_g, example_b)); example_r, example_g, example_b));
/* /*
We use "SDL_MapRGB()" to convert the RGB value we receive from Tux Paint 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 for the user's current color selection to a 'Uint32' pixel value we can
send to Tux Paint's "putpixel()" function. send to Tux Paint's "putpixel()" function.
*/ */
} }
else if (which == TOOL_TWO) else if (which == TOOL_TWO)
{ {
/* /*
Tool number 2 copies a square of pixels (of the size chosen by the user) Tool number 2 copies a square of pixels (of the size chosen by the user)
from the opposite side of the canvas and puts it under the cursor. from the opposite side of the canvas and puts it under the cursor.
*/ */
for (yy = -example_size; yy < example_size; yy++) for (yy = -example_size; yy < example_size; yy++)
{ {
@ -636,14 +641,14 @@ void example_line_callback(void *pointer, int which, SDL_Surface * canvas,
snapshot->h - y - yy)); snapshot->h - y - yy));
/* /*
Here we have simply use Tux Paint's "getpixel()" routine to pull pixel Here we have simply use Tux Paint's "getpixel()" routine to pull pixel
values from the 'snapshot', and then "putpixel()" to draw them right values from the 'snapshot', and then "putpixel()" to draw them right
into the 'canvas'. into the 'canvas'.
Note: putpixel() and getpixel() are safe to use, even if your X,Y values 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 are outside of the SDL surface (e.g., negative, or greater than the
surface's width and/or height). surface's width and/or height).
*/ */
} }
} }
} }

View file

@ -9,12 +9,12 @@
/* ---------------------------------------------------------------------- */ /* ---------------------------------------------------------------------- */
#include <stdio.h> #include <stdio.h>
#include <string.h> // For "strdup()" #include <string.h> // For "strdup()"
#include <libintl.h> // For "gettext()" #include <libintl.h> // For "gettext()"
#include "tp_magic_api.h" // Tux Paint "Magic" tool API header #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_image.h" // For IMG_Load(), to load our PNG icon
#include "SDL_mixer.h" // For Mix_LoadWAV(), to load our sound effects #include "SDL_mixer.h" // For Mix_LoadWAV(), to load our sound effects
/* Tool Enumerations: */ /* Tool Enumerations: */
@ -25,9 +25,9 @@
enum enum
{ {
TOOL_ONE, // Becomes '0' TOOL_ONE, // Becomes '0'
TOOL_TWO, // Becomes '1' TOOL_TWO, // Becomes '1'
NUM_TOOLS // Becomes '2' NUM_TOOLS // Becomes '2'
}; };
@ -101,11 +101,11 @@ _before_ them.
*/ */
void example_drag(magic_api * api, int which, SDL_Surface * canvas, void example_drag(magic_api * api, int which, SDL_Surface * canvas,
SDL_Surface * snapshot, int old_x, int old_y, int x, int y, SDL_Surface * snapshot, int old_x, int old_y, int x, int y,
SDL_Rect * update_rect); SDL_Rect * update_rect);
void example_line_callback(void *pointer, int which, SDL_Surface * canvas, void example_line_callback(void *pointer, int which, SDL_Surface * canvas,
SDL_Surface * snapshot, int x, int y); SDL_Surface * snapshot, int x, int y);
/* Setup Functions: */ /* Setup Functions: */
@ -144,7 +144,8 @@ released, aka deallocated) when the user quits Tux Paint, when our
example_shutdown() function is called. example_shutdown() function is called.
*/ */
int example_init(magic_api * api, Uint8 disabled_features, Uint8 complexity_level) int example_init(magic_api * api, Uint8 disabled_features,
Uint8 complexity_level)
{ {
int i; int i;
char filename[1024]; char filename[1024];
@ -152,15 +153,15 @@ int example_init(magic_api * api, Uint8 disabled_features, Uint8 complexity_leve
for (i = 0; i < NUM_TOOLS; i++) for (i = 0; i < NUM_TOOLS; i++)
{ {
/* /*
Assemble the filename from the "sound_filenames[]" array into a full path Assemble the filename from the "sound_filenames[]" array into a full path
to a real file. to a real file.
Use "api->data_directory" to figure out where our sounds should be. (The 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 "tp-magic-config --dataprefix" command would have told us when we installed
our plugin and its data.) our plugin and its data.)
*/ */
snprintf(filename, sizeof(filename), "%ssounds/magic/%s", api->data_directory, snprintf(filename, sizeof(filename), "%ssounds/magic/%s",
sound_filenames[i]); api->data_directory, sound_filenames[i]);
printf("Trying to load %s sound file\n", filename); printf("Trying to load %s sound file\n", filename);
@ -200,16 +201,16 @@ SDL_Surface *example_get_icon(magic_api * api, int which)
char filename[1024]; char filename[1024];
/* /*
Assemble the filename from the "icon_filenames[]" array into a full path to Assemble the filename from the "icon_filenames[]" array into a full path to
a real file. a real file.
Use "api->data_directory" to figure out where our sounds should be. (The 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 "tp-magic-config --dataprefix" command would have told us when we installed
our plugin and its data.) our plugin and its data.)
We use "which" (which of our tools Tux Paint is asking about) as an index We use "which" (which of our tools Tux Paint is asking about) as an index
into the array. into the array.
*/ */
snprintf(filename, sizeof(filename), "%simages/magic/%s", snprintf(filename, sizeof(filename), "%simages/magic/%s",
api->data_directory, icon_filenames[which]); api->data_directory, icon_filenames[which]);
@ -229,31 +230,31 @@ names (labels) for the 'Magic' tool buttons.
*/ */
char *example_get_name(magic_api * api, int which) char *example_get_name(magic_api * api, int which)
{ {
const char *our_name_english; const char *our_name_english;
const char *our_name_localized; const char *our_name_localized;
/* /*
Get our name from the "tool_names[]" array. Get our name from the "tool_names[]" array.
We use 'which' (which of our tools Tux Paint is asking about) as an index We use 'which' (which of our tools Tux Paint is asking about) as an index
into the array. into the array.
*/ */
our_name_english = tool_names[which]; our_name_english = tool_names[which];
/* /*
Return a localized (aka translated) version of our name, if possible. Return a localized (aka translated) version of our name, if possible.
We send "gettext()" the English version of the name from our array. We send "gettext()" the English version of the name from our array.
*/ */
our_name_localized = gettext(our_name_english); our_name_localized = gettext(our_name_english);
/* /*
Finally, duplicate the string into a new section of memory, and send it to 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, 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.) so we have one less thing to keep track of.)
*/ */
return (strdup(our_name_localized)); return (strdup(our_name_localized));
} }
@ -267,11 +268,11 @@ where the tool should be grouped.
int example_get_group(magic_api * api, int which) int example_get_group(magic_api * api, int which)
{ {
/* /*
Return our group, found in the "tool_groups[]" array. Return our group, found in the "tool_groups[]" array.
We use 'which' (which of our tools Tux Paint is asking about) as an index We use 'which' (which of our tools Tux Paint is asking about) as an index
into the array. into the array.
*/ */
return (tool_groups[which]); return (tool_groups[which]);
} }
@ -302,28 +303,28 @@ char *example_get_description(magic_api * api, int which, int mode)
const char *our_desc_localized; const char *our_desc_localized;
/* /*
Get our description from the "tool_descriptions[]" array. Get our description from the "tool_descriptions[]" array.
We use 'which' (which of our tools Tux Paint is asking about) as an index We use 'which' (which of our tools Tux Paint is asking about) as an index
into the array. into the array.
*/ */
our_desc_english = tool_descriptions[which]; our_desc_english = tool_descriptions[which];
/* /*
Return a localized (aka translated) version of our description, if Return a localized (aka translated) version of our description, if
possible. possible.
We send "gettext" the English version of the description from our array. We send "gettext" the English version of the description from our array.
*/ */
our_desc_localized = gettext(our_desc_english); our_desc_localized = gettext(our_desc_english);
/* /*
Finally, duplicate the string into a new section of memory, and send it to 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, 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.) so we have one less thing to keep track of.)
*/ */
return (strdup(our_desc_localized)); return (strdup(our_desc_localized));
} }
@ -345,9 +346,9 @@ int example_requires_colors(magic_api * api, int which)
int example_modes(magic_api * api, int which) int example_modes(magic_api * api, int which)
{ {
/* /*
Both of our tools are painted (neither affect the full-screen), so we're Both of our tools are painted (neither affect the full-screen), so we're
always returning 'MODE_PAINT' always returning 'MODE_PAINT'
*/ */
return MODE_PAINT; return MODE_PAINT;
} }
@ -385,9 +386,9 @@ void example_shutdown(magic_api * api)
int i; int i;
/* /*
Free (aka release, aka deallocate) the memory used to store the sound Free (aka release, aka deallocate) the memory used to store the sound
effects that we loaded during example_init(): effects that we loaded during example_init():
*/ */
for (i = 0; i < NUM_TOOLS; i++) for (i = 0; i < NUM_TOOLS; i++)
Mix_FreeChunk(sound_effects[i]); Mix_FreeChunk(sound_effects[i]);
} }
@ -404,13 +405,13 @@ example_click(magic_api * api, int which, int mode,
SDL_Rect * update_rect) SDL_Rect * update_rect)
{ {
/* /*
In our case, a single click (which is also the start of a drag!) is 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 identical to what dragging does, but just at one point, rather than across
a line. a line.
So we 'cheat' here, by calling our "example_draw()" function with (x,y) for So we 'cheat' here, by calling our "example_draw()" function with (x,y) for
both the beginning and end points of a line. both the beginning and end points of a line.
*/ */
example_drag(api, which, canvas, snapshot, x, y, x, y, update_rect); example_drag(api, which, canvas, snapshot, x, y, x, y, update_rect);
} }
@ -420,34 +421,32 @@ example_click(magic_api * api, int which, int mode,
void void
example_drag(magic_api * api, int which, example_drag(magic_api * api, int which,
SDL_Surface * canvas, SDL_Surface * snapshot, SDL_Surface * canvas, SDL_Surface * snapshot,
int old_x, int old_y, int x, int y, int old_x, int old_y, int x, int y, SDL_Rect * update_rect)
SDL_Rect * update_rect)
{ {
/* /*
Call Tux Paint's "line()" (line-traversing) function. Call Tux Paint's "line()" (line-traversing) function.
It will calculate a straight line between (old_x,old_y) and (x,y). Every It will calculate a straight line between (old_x,old_y) and (x,y). Every
N steps along that line (in this case, N is '1'), it will call _our_ 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 function, "example_line_callback()", and send the current X,Y
coordinates along the line, as well as other useful things (which of our coordinates along the line, as well as other useful things (which of our
'Magic' tools is being used and the current and snapshot canvases). 'Magic' tools is being used and the current and snapshot canvases).
*/ */
SDL_LockSurface(snapshot); SDL_LockSurface(snapshot);
SDL_LockSurface(canvas); SDL_LockSurface(canvas);
api->line((void *) api, which, canvas, snapshot, api->line((void *) api, which, canvas, snapshot,
old_x, old_y, x, y, 1, old_x, old_y, x, y, 1, example_line_callback);
example_line_callback);
SDL_UnlockSurface(canvas); SDL_UnlockSurface(canvas);
SDL_UnlockSurface(snapshot); SDL_UnlockSurface(snapshot);
/* /*
If we need to, swap the X and/or Y values, so that the coordinates If we need to, swap the X and/or Y values, so that the coordinates
(old_x,old_y) is always the top left, and the coordinates (x,y) is (old_x,old_y) is always the top left, and the coordinates (x,y) is
always the bottom right, so the values we put inside "update_rect" make always the bottom right, so the values we put inside "update_rect" make
sense: sense:
*/ */
if (old_x > x) if (old_x > x)
{ {
@ -466,17 +465,20 @@ example_drag(magic_api * api, int which,
/* /*
Fill in the elements of the "update_rect" SDL_Rect structure that Tux Fill in the elements of the "update_rect" SDL_Rect structure that Tux
Paint is sharing with us, therefore telling Tux Paint which part of the Paint is sharing with us, therefore telling Tux Paint which part of the
canvas has been modified and should be updated. canvas has been modified and should be updated.
*/ */
if (which == TOOL_ONE) { if (which == TOOL_ONE)
{
update_rect->x = old_x; update_rect->x = old_x;
update_rect->y = old_y; update_rect->y = old_y;
update_rect->w = (x - old_x) + 1; update_rect->w = (x - old_x) + 1;
update_rect->h = (y - old_y) + 1; update_rect->h = (y - old_y) + 1;
} else { }
else
{
update_rect->x = old_x - example_size; update_rect->x = old_x - example_size;
update_rect->y = old_y - example_size; update_rect->y = old_y - example_size;
update_rect->w = (x + example_size) - update_rect->x + 1; update_rect->w = (x + example_size) - update_rect->x + 1;
@ -484,19 +486,18 @@ example_drag(magic_api * api, int which,
} }
/* /*
Play the appropriate sound effect Play the appropriate sound effect
We're calculating a value between 0-255 for where the mouse is We're calculating a value between 0-255 for where the mouse is
horizontally across the canvas (0 is the left, ~128 is the center, 255 horizontally across the canvas (0 is the left, ~128 is the center, 255
is the right). is the right).
These are the exact values Tux Paint's "playsound()" wants, to determine 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 what speaker to play the sound in. (So the sound will pan from speaker
to speaker as you drag the mouse around the canvas!) to speaker as you drag the mouse around the canvas!)
*/ */
api->playsound(sound_effects[which], api->playsound(sound_effects[which], (x * 255) / canvas->w, /* Left/right pan */
(x * 255) / canvas->w, /* Left/right pan */ 255 /* Near/far distance (loudness) */ );
255 /* Near/far distance (loudness) */);
} }
@ -508,9 +509,9 @@ example_release(magic_api * api, int which,
SDL_Rect * update_rect) SDL_Rect * update_rect)
{ {
/* /*
Neither of our effects do anything special when the mouse is released 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... from a click or click-and-drag, so there's no code here...
*/ */
} }
@ -526,12 +527,14 @@ changes their chosen, we'll be informed of that as well.
The color comes in as RGB (red, green, and blue) values from 0 (darkest) to The color comes in as RGB (red, green, and blue) values from 0 (darkest) to
255 (brightest). 255 (brightest).
*/ */
void example_set_color(magic_api * api, int which, SDL_Surface * canvas, SDL_Surface * snapshot, Uint8 r, Uint8 g, Uint8 b, SDL_Rect * update_rect) void example_set_color(magic_api * api, int which, SDL_Surface * canvas,
SDL_Surface * snapshot, Uint8 r, Uint8 g, Uint8 b,
SDL_Rect * update_rect)
{ {
/* /*
We simply store the RGB values in the global variables we declared at We simply store the RGB values in the global variables we declared at
the top of this file. the top of this file.
*/ */
example_r = r; example_r = r;
example_g = g; example_g = g;
@ -551,12 +554,14 @@ that as well.
The size comes in as an unsigned integer (Uint8) between 1 and the value The size comes in as an unsigned integer (Uint8) between 1 and the value
returned by our example_accepted_sizes() function during setup. returned by our example_accepted_sizes() function during setup.
*/ */
void example_set_size(magic_api * api, int which, int mode, SDL_Surface * canvas, SDL_Surface * snapshot, Uint8 size, SDL_Rect * update_rect) void example_set_size(magic_api * api, int which, int mode,
SDL_Surface * canvas, SDL_Surface * snapshot,
Uint8 size, SDL_Rect * update_rect)
{ {
/* /*
Store the new size into the global variable we declared at the top of Store the new size into the global variable we declared at the top of
this file. this file.
*/ */
example_size = size * 4; example_size = size * 4;
} }
@ -580,51 +585,51 @@ Our callback pays attention to 'which' to determine which of our plugin's
tools is currently selected. tools is currently selected.
*/ */
void example_line_callback(void *pointer, int which, SDL_Surface * canvas, void example_line_callback(void *pointer, int which, SDL_Surface * canvas,
SDL_Surface * snapshot, int x, int y) SDL_Surface * snapshot, int x, int y)
{ {
/* /*
For technical reasons, we can't accept a pointer to the Tux Paint API's For technical reasons, we can't accept a pointer to the Tux Paint API's
"magic_api" struct, like the other functions do. "magic_api" struct, like the other functions do.
Instead, we receive a 'generic' pointer (a "void *"). The line below Instead, we receive a 'generic' pointer (a "void *"). The line below
declares a local "magic_api" pointer variable called "api", and then declares a local "magic_api" pointer variable called "api", and then
assigns it to the value of the 'generic' pointer we received. assigns it to the value of the 'generic' pointer we received.
The "(magic_api *)" seen below casts the generic "void *" pointer into The "(magic_api *)" seen below casts the generic "void *" pointer into
the 'type' of pointer we want, a pointer to a "magic_api" struct.) the 'type' of pointer we want, a pointer to a "magic_api" struct.)
*/ */
magic_api *api = (magic_api *) pointer; magic_api *api = (magic_api *) pointer;
int xx, yy; int xx, yy;
/* /*
This function handles both of our tools, so we need to check which is 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 being used right now. We compare the 'which' argument that Tux Paint
sends to us with the values we enumerated above. sends to us with the values we enumerated above.
*/ */
if (which == TOOL_ONE) if (which == TOOL_ONE)
{ {
/* /*
Tool number 1 simply draws a single pixel at the (x,y) location. It acts Tool number 1 simply draws a single pixel at the (x,y) location. It acts
as a 1x1 pixel brush. as a 1x1 pixel brush.
*/ */
api->putpixel(canvas, x, y, api->putpixel(canvas, x, y,
SDL_MapRGB(canvas->format, SDL_MapRGB(canvas->format,
example_r, example_g, example_b)); example_r, example_g, example_b));
/* /*
We use "SDL_MapRGB()" to convert the RGB value we receive from Tux Paint 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 for the user's current color selection to a 'Uint32' pixel value we can
send to Tux Paint's "putpixel()" function. send to Tux Paint's "putpixel()" function.
*/ */
} }
else if (which == TOOL_TWO) else if (which == TOOL_TWO)
{ {
/* /*
Tool number 2 copies a square of pixels (of the size chosen by the user) Tool number 2 copies a square of pixels (of the size chosen by the user)
from the opposite side of the canvas and puts it under the cursor. from the opposite side of the canvas and puts it under the cursor.
*/ */
for (yy = -example_size; yy < example_size; yy++) for (yy = -example_size; yy < example_size; yy++)
{ {
@ -636,14 +641,14 @@ void example_line_callback(void *pointer, int which, SDL_Surface * canvas,
snapshot->h - y - yy)); snapshot->h - y - yy));
/* /*
Here we have simply use Tux Paint's "getpixel()" routine to pull pixel Here we have simply use Tux Paint's "getpixel()" routine to pull pixel
values from the 'snapshot', and then "putpixel()" to draw them right values from the 'snapshot', and then "putpixel()" to draw them right
into the 'canvas'. into the 'canvas'.
Note: putpixel() and getpixel() are safe to use, even if your X,Y values 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 are outside of the SDL surface (e.g., negative, or greater than the
surface's width and/or height). surface's width and/or height).
*/ */
} }
} }
} }

View file

@ -9,12 +9,12 @@
/* ---------------------------------------------------------------------- */ /* ---------------------------------------------------------------------- */
#include <stdio.h> #include <stdio.h>
#include <string.h> // For "strdup()" #include <string.h> // For "strdup()"
#include <libintl.h> // For "gettext()" #include <libintl.h> // For "gettext()"
#include "tp_magic_api.h" // Tux Paint "Magic" tool API header #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_image.h" // For IMG_Load(), to load our PNG icon
#include "SDL_mixer.h" // For Mix_LoadWAV(), to load our sound effects #include "SDL_mixer.h" // For Mix_LoadWAV(), to load our sound effects
/* Tool Enumerations: */ /* Tool Enumerations: */
@ -25,9 +25,9 @@
enum enum
{ {
TOOL_ONE, // Becomes '0' TOOL_ONE, // Becomes '0'
TOOL_TWO, // Becomes '1' TOOL_TWO, // Becomes '1'
NUM_TOOLS // Becomes '2' NUM_TOOLS // Becomes '2'
}; };
@ -101,11 +101,11 @@ _before_ them.
*/ */
void example_drag(magic_api * api, int which, SDL_Surface * canvas, void example_drag(magic_api * api, int which, SDL_Surface * canvas,
SDL_Surface * snapshot, int old_x, int old_y, int x, int y, SDL_Surface * snapshot, int old_x, int old_y, int x, int y,
SDL_Rect * update_rect); SDL_Rect * update_rect);
void example_line_callback(void *pointer, int which, SDL_Surface * canvas, void example_line_callback(void *pointer, int which, SDL_Surface * canvas,
SDL_Surface * snapshot, int x, int y); SDL_Surface * snapshot, int x, int y);
/* Setup Functions: */ /* Setup Functions: */
@ -144,7 +144,8 @@ released, aka deallocated) when the user quits Tux Paint, when our
example_shutdown() function is called. example_shutdown() function is called.
*/ */
int example_init(magic_api * api, Uint8 disabled_features, Uint8 complexity_level) int example_init(magic_api * api, Uint8 disabled_features,
Uint8 complexity_level)
{ {
int i; int i;
char filename[1024]; char filename[1024];
@ -152,15 +153,15 @@ int example_init(magic_api * api, Uint8 disabled_features, Uint8 complexity_leve
for (i = 0; i < NUM_TOOLS; i++) for (i = 0; i < NUM_TOOLS; i++)
{ {
/* /*
Assemble the filename from the "sound_filenames[]" array into a full path Assemble the filename from the "sound_filenames[]" array into a full path
to a real file. to a real file.
Use "api->data_directory" to figure out where our sounds should be. (The 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 "tp-magic-config --dataprefix" command would have told us when we installed
our plugin and its data.) our plugin and its data.)
*/ */
snprintf(filename, sizeof(filename), "%ssounds/magic/%s", api->data_directory, snprintf(filename, sizeof(filename), "%ssounds/magic/%s",
sound_filenames[i]); api->data_directory, sound_filenames[i]);
printf("Trying to load %s sound file\n", filename); printf("Trying to load %s sound file\n", filename);
@ -200,16 +201,16 @@ SDL_Surface *example_get_icon(magic_api * api, int which)
char filename[1024]; char filename[1024];
/* /*
Assemble the filename from the "icon_filenames[]" array into a full path to Assemble the filename from the "icon_filenames[]" array into a full path to
a real file. a real file.
Use "api->data_directory" to figure out where our sounds should be. (The 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 "tp-magic-config --dataprefix" command would have told us when we installed
our plugin and its data.) our plugin and its data.)
We use "which" (which of our tools Tux Paint is asking about) as an index We use "which" (which of our tools Tux Paint is asking about) as an index
into the array. into the array.
*/ */
snprintf(filename, sizeof(filename), "%simages/magic/%s", snprintf(filename, sizeof(filename), "%simages/magic/%s",
api->data_directory, icon_filenames[which]); api->data_directory, icon_filenames[which]);
@ -229,31 +230,31 @@ names (labels) for the 'Magic' tool buttons.
*/ */
char *example_get_name(magic_api * api, int which) char *example_get_name(magic_api * api, int which)
{ {
const char *our_name_english; const char *our_name_english;
const char *our_name_localized; const char *our_name_localized;
/* /*
Get our name from the "tool_names[]" array. Get our name from the "tool_names[]" array.
We use 'which' (which of our tools Tux Paint is asking about) as an index We use 'which' (which of our tools Tux Paint is asking about) as an index
into the array. into the array.
*/ */
our_name_english = tool_names[which]; our_name_english = tool_names[which];
/* /*
Return a localized (aka translated) version of our name, if possible. Return a localized (aka translated) version of our name, if possible.
We send "gettext()" the English version of the name from our array. We send "gettext()" the English version of the name from our array.
*/ */
our_name_localized = gettext(our_name_english); our_name_localized = gettext(our_name_english);
/* /*
Finally, duplicate the string into a new section of memory, and send it to 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, 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.) so we have one less thing to keep track of.)
*/ */
return (strdup(our_name_localized)); return (strdup(our_name_localized));
} }
@ -267,11 +268,11 @@ where the tool should be grouped.
int example_get_group(magic_api * api, int which) int example_get_group(magic_api * api, int which)
{ {
/* /*
Return our group, found in the "tool_groups[]" array. Return our group, found in the "tool_groups[]" array.
We use 'which' (which of our tools Tux Paint is asking about) as an index We use 'which' (which of our tools Tux Paint is asking about) as an index
into the array. into the array.
*/ */
return (tool_groups[which]); return (tool_groups[which]);
} }
@ -302,28 +303,28 @@ char *example_get_description(magic_api * api, int which, int mode)
const char *our_desc_localized; const char *our_desc_localized;
/* /*
Get our description from the "tool_descriptions[]" array. Get our description from the "tool_descriptions[]" array.
We use 'which' (which of our tools Tux Paint is asking about) as an index We use 'which' (which of our tools Tux Paint is asking about) as an index
into the array. into the array.
*/ */
our_desc_english = tool_descriptions[which]; our_desc_english = tool_descriptions[which];
/* /*
Return a localized (aka translated) version of our description, if Return a localized (aka translated) version of our description, if
possible. possible.
We send "gettext" the English version of the description from our array. We send "gettext" the English version of the description from our array.
*/ */
our_desc_localized = gettext(our_desc_english); our_desc_localized = gettext(our_desc_english);
/* /*
Finally, duplicate the string into a new section of memory, and send it to 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, 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.) so we have one less thing to keep track of.)
*/ */
return (strdup(our_desc_localized)); return (strdup(our_desc_localized));
} }
@ -345,9 +346,9 @@ int example_requires_colors(magic_api * api, int which)
int example_modes(magic_api * api, int which) int example_modes(magic_api * api, int which)
{ {
/* /*
Both of our tools are painted (neither affect the full-screen), so we're Both of our tools are painted (neither affect the full-screen), so we're
always returning 'MODE_PAINT' always returning 'MODE_PAINT'
*/ */
return MODE_PAINT; return MODE_PAINT;
} }
@ -385,9 +386,9 @@ void example_shutdown(magic_api * api)
int i; int i;
/* /*
Free (aka release, aka deallocate) the memory used to store the sound Free (aka release, aka deallocate) the memory used to store the sound
effects that we loaded during example_init(): effects that we loaded during example_init():
*/ */
for (i = 0; i < NUM_TOOLS; i++) for (i = 0; i < NUM_TOOLS; i++)
Mix_FreeChunk(sound_effects[i]); Mix_FreeChunk(sound_effects[i]);
} }
@ -404,13 +405,13 @@ example_click(magic_api * api, int which, int mode,
SDL_Rect * update_rect) SDL_Rect * update_rect)
{ {
/* /*
In our case, a single click (which is also the start of a drag!) is 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 identical to what dragging does, but just at one point, rather than across
a line. a line.
So we 'cheat' here, by calling our "example_draw()" function with (x,y) for So we 'cheat' here, by calling our "example_draw()" function with (x,y) for
both the beginning and end points of a line. both the beginning and end points of a line.
*/ */
example_drag(api, which, canvas, snapshot, x, y, x, y, update_rect); example_drag(api, which, canvas, snapshot, x, y, x, y, update_rect);
} }
@ -420,34 +421,32 @@ example_click(magic_api * api, int which, int mode,
void void
example_drag(magic_api * api, int which, example_drag(magic_api * api, int which,
SDL_Surface * canvas, SDL_Surface * snapshot, SDL_Surface * canvas, SDL_Surface * snapshot,
int old_x, int old_y, int x, int y, int old_x, int old_y, int x, int y, SDL_Rect * update_rect)
SDL_Rect * update_rect)
{ {
/* /*
Call Tux Paint's "line()" (line-traversing) function. Call Tux Paint's "line()" (line-traversing) function.
It will calculate a straight line between (old_x,old_y) and (x,y). Every It will calculate a straight line between (old_x,old_y) and (x,y). Every
N steps along that line (in this case, N is '1'), it will call _our_ 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 function, "example_line_callback()", and send the current X,Y
coordinates along the line, as well as other useful things (which of our coordinates along the line, as well as other useful things (which of our
'Magic' tools is being used and the current and snapshot canvases). 'Magic' tools is being used and the current and snapshot canvases).
*/ */
SDL_LockSurface(snapshot); SDL_LockSurface(snapshot);
SDL_LockSurface(canvas); SDL_LockSurface(canvas);
api->line((void *) api, which, canvas, snapshot, api->line((void *) api, which, canvas, snapshot,
old_x, old_y, x, y, 1, old_x, old_y, x, y, 1, example_line_callback);
example_line_callback);
SDL_UnlockSurface(canvas); SDL_UnlockSurface(canvas);
SDL_UnlockSurface(snapshot); SDL_UnlockSurface(snapshot);
/* /*
If we need to, swap the X and/or Y values, so that the coordinates If we need to, swap the X and/or Y values, so that the coordinates
(old_x,old_y) is always the top left, and the coordinates (x,y) is (old_x,old_y) is always the top left, and the coordinates (x,y) is
always the bottom right, so the values we put inside "update_rect" make always the bottom right, so the values we put inside "update_rect" make
sense: sense:
*/ */
if (old_x > x) if (old_x > x)
{ {
@ -466,17 +465,20 @@ example_drag(magic_api * api, int which,
/* /*
Fill in the elements of the "update_rect" SDL_Rect structure that Tux Fill in the elements of the "update_rect" SDL_Rect structure that Tux
Paint is sharing with us, therefore telling Tux Paint which part of the Paint is sharing with us, therefore telling Tux Paint which part of the
canvas has been modified and should be updated. canvas has been modified and should be updated.
*/ */
if (which == TOOL_ONE) { if (which == TOOL_ONE)
{
update_rect->x = old_x; update_rect->x = old_x;
update_rect->y = old_y; update_rect->y = old_y;
update_rect->w = (x - old_x) + 1; update_rect->w = (x - old_x) + 1;
update_rect->h = (y - old_y) + 1; update_rect->h = (y - old_y) + 1;
} else { }
else
{
update_rect->x = old_x - example_size; update_rect->x = old_x - example_size;
update_rect->y = old_y - example_size; update_rect->y = old_y - example_size;
update_rect->w = (x + example_size) - update_rect->x + 1; update_rect->w = (x + example_size) - update_rect->x + 1;
@ -484,19 +486,18 @@ example_drag(magic_api * api, int which,
} }
/* /*
Play the appropriate sound effect Play the appropriate sound effect
We're calculating a value between 0-255 for where the mouse is We're calculating a value between 0-255 for where the mouse is
horizontally across the canvas (0 is the left, ~128 is the center, 255 horizontally across the canvas (0 is the left, ~128 is the center, 255
is the right). is the right).
These are the exact values Tux Paint's "playsound()" wants, to determine 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 what speaker to play the sound in. (So the sound will pan from speaker
to speaker as you drag the mouse around the canvas!) to speaker as you drag the mouse around the canvas!)
*/ */
api->playsound(sound_effects[which], api->playsound(sound_effects[which], (x * 255) / canvas->w, /* Left/right pan */
(x * 255) / canvas->w, /* Left/right pan */ 255 /* Near/far distance (loudness) */ );
255 /* Near/far distance (loudness) */);
} }
@ -508,9 +509,9 @@ example_release(magic_api * api, int which,
SDL_Rect * update_rect) SDL_Rect * update_rect)
{ {
/* /*
Neither of our effects do anything special when the mouse is released 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... from a click or click-and-drag, so there's no code here...
*/ */
} }
@ -526,12 +527,14 @@ changes their chosen, we'll be informed of that as well.
The color comes in as RGB (red, green, and blue) values from 0 (darkest) to The color comes in as RGB (red, green, and blue) values from 0 (darkest) to
255 (brightest). 255 (brightest).
*/ */
void example_set_color(magic_api * api, int which, SDL_Surface * canvas, SDL_Surface * snapshot, Uint8 r, Uint8 g, Uint8 b, SDL_Rect * update_rect) void example_set_color(magic_api * api, int which, SDL_Surface * canvas,
SDL_Surface * snapshot, Uint8 r, Uint8 g, Uint8 b,
SDL_Rect * update_rect)
{ {
/* /*
We simply store the RGB values in the global variables we declared at We simply store the RGB values in the global variables we declared at
the top of this file. the top of this file.
*/ */
example_r = r; example_r = r;
example_g = g; example_g = g;
@ -551,12 +554,14 @@ that as well.
The size comes in as an unsigned integer (Uint8) between 1 and the value The size comes in as an unsigned integer (Uint8) between 1 and the value
returned by our example_accepted_sizes() function during setup. returned by our example_accepted_sizes() function during setup.
*/ */
void example_set_size(magic_api * api, int which, int mode, SDL_Surface * canvas, SDL_Surface * snapshot, Uint8 size, SDL_Rect * update_rect) void example_set_size(magic_api * api, int which, int mode,
SDL_Surface * canvas, SDL_Surface * snapshot,
Uint8 size, SDL_Rect * update_rect)
{ {
/* /*
Store the new size into the global variable we declared at the top of Store the new size into the global variable we declared at the top of
this file. this file.
*/ */
example_size = size * 4; example_size = size * 4;
} }
@ -580,51 +585,51 @@ Our callback pays attention to 'which' to determine which of our plugin's
tools is currently selected. tools is currently selected.
*/ */
void example_line_callback(void *pointer, int which, SDL_Surface * canvas, void example_line_callback(void *pointer, int which, SDL_Surface * canvas,
SDL_Surface * snapshot, int x, int y) SDL_Surface * snapshot, int x, int y)
{ {
/* /*
For technical reasons, we can't accept a pointer to the Tux Paint API's For technical reasons, we can't accept a pointer to the Tux Paint API's
"magic_api" struct, like the other functions do. "magic_api" struct, like the other functions do.
Instead, we receive a 'generic' pointer (a "void *"). The line below Instead, we receive a 'generic' pointer (a "void *"). The line below
declares a local "magic_api" pointer variable called "api", and then declares a local "magic_api" pointer variable called "api", and then
assigns it to the value of the 'generic' pointer we received. assigns it to the value of the 'generic' pointer we received.
The "(magic_api *)" seen below casts the generic "void *" pointer into The "(magic_api *)" seen below casts the generic "void *" pointer into
the 'type' of pointer we want, a pointer to a "magic_api" struct.) the 'type' of pointer we want, a pointer to a "magic_api" struct.)
*/ */
magic_api *api = (magic_api *) pointer; magic_api *api = (magic_api *) pointer;
int xx, yy; int xx, yy;
/* /*
This function handles both of our tools, so we need to check which is 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 being used right now. We compare the 'which' argument that Tux Paint
sends to us with the values we enumerated above. sends to us with the values we enumerated above.
*/ */
if (which == TOOL_ONE) if (which == TOOL_ONE)
{ {
/* /*
Tool number 1 simply draws a single pixel at the (x,y) location. It acts Tool number 1 simply draws a single pixel at the (x,y) location. It acts
as a 1x1 pixel brush. as a 1x1 pixel brush.
*/ */
api->putpixel(canvas, x, y, api->putpixel(canvas, x, y,
SDL_MapRGB(canvas->format, SDL_MapRGB(canvas->format,
example_r, example_g, example_b)); example_r, example_g, example_b));
/* /*
We use "SDL_MapRGB()" to convert the RGB value we receive from Tux Paint 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 for the user's current color selection to a 'Uint32' pixel value we can
send to Tux Paint's "putpixel()" function. send to Tux Paint's "putpixel()" function.
*/ */
} }
else if (which == TOOL_TWO) else if (which == TOOL_TWO)
{ {
/* /*
Tool number 2 copies a square of pixels (of the size chosen by the user) Tool number 2 copies a square of pixels (of the size chosen by the user)
from the opposite side of the canvas and puts it under the cursor. from the opposite side of the canvas and puts it under the cursor.
*/ */
for (yy = -example_size; yy < example_size; yy++) for (yy = -example_size; yy < example_size; yy++)
{ {
@ -636,14 +641,14 @@ void example_line_callback(void *pointer, int which, SDL_Surface * canvas,
snapshot->h - y - yy)); snapshot->h - y - yy));
/* /*
Here we have simply use Tux Paint's "getpixel()" routine to pull pixel Here we have simply use Tux Paint's "getpixel()" routine to pull pixel
values from the 'snapshot', and then "putpixel()" to draw them right values from the 'snapshot', and then "putpixel()" to draw them right
into the 'canvas'. into the 'canvas'.
Note: putpixel() and getpixel() are safe to use, even if your X,Y values 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 are outside of the SDL surface (e.g., negative, or greater than the
surface's width and/or height). surface's width and/or height).
*/ */
} }
} }
} }

View file

@ -9,12 +9,12 @@
/* ---------------------------------------------------------------------- */ /* ---------------------------------------------------------------------- */
#include <stdio.h> #include <stdio.h>
#include <string.h> // For "strdup()" #include <string.h> // For "strdup()"
#include <libintl.h> // For "gettext()" #include <libintl.h> // For "gettext()"
#include "tp_magic_api.h" // Tux Paint "Magic" tool API header #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_image.h" // For IMG_Load(), to load our PNG icon
#include "SDL_mixer.h" // For Mix_LoadWAV(), to load our sound effects #include "SDL_mixer.h" // For Mix_LoadWAV(), to load our sound effects
/* Tool Enumerations: */ /* Tool Enumerations: */
@ -25,9 +25,9 @@
enum enum
{ {
TOOL_ONE, // Becomes '0' TOOL_ONE, // Becomes '0'
TOOL_TWO, // Becomes '1' TOOL_TWO, // Becomes '1'
NUM_TOOLS // Becomes '2' NUM_TOOLS // Becomes '2'
}; };
@ -101,11 +101,11 @@ _before_ them.
*/ */
void example_drag(magic_api * api, int which, SDL_Surface * canvas, void example_drag(magic_api * api, int which, SDL_Surface * canvas,
SDL_Surface * snapshot, int old_x, int old_y, int x, int y, SDL_Surface * snapshot, int old_x, int old_y, int x, int y,
SDL_Rect * update_rect); SDL_Rect * update_rect);
void example_line_callback(void *pointer, int which, SDL_Surface * canvas, void example_line_callback(void *pointer, int which, SDL_Surface * canvas,
SDL_Surface * snapshot, int x, int y); SDL_Surface * snapshot, int x, int y);
/* Setup Functions: */ /* Setup Functions: */
@ -144,7 +144,8 @@ released, aka deallocated) when the user quits Tux Paint, when our
example_shutdown() function is called. example_shutdown() function is called.
*/ */
int example_init(magic_api * api, Uint8 disabled_features, Uint8 complexity_level) int example_init(magic_api * api, Uint8 disabled_features,
Uint8 complexity_level)
{ {
int i; int i;
char filename[1024]; char filename[1024];
@ -152,15 +153,15 @@ int example_init(magic_api * api, Uint8 disabled_features, Uint8 complexity_leve
for (i = 0; i < NUM_TOOLS; i++) for (i = 0; i < NUM_TOOLS; i++)
{ {
/* /*
Assemble the filename from the "sound_filenames[]" array into a full path Assemble the filename from the "sound_filenames[]" array into a full path
to a real file. to a real file.
Use "api->data_directory" to figure out where our sounds should be. (The 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 "tp-magic-config --dataprefix" command would have told us when we installed
our plugin and its data.) our plugin and its data.)
*/ */
snprintf(filename, sizeof(filename), "%ssounds/magic/%s", api->data_directory, snprintf(filename, sizeof(filename), "%ssounds/magic/%s",
sound_filenames[i]); api->data_directory, sound_filenames[i]);
printf("Trying to load %s sound file\n", filename); printf("Trying to load %s sound file\n", filename);
@ -200,16 +201,16 @@ SDL_Surface *example_get_icon(magic_api * api, int which)
char filename[1024]; char filename[1024];
/* /*
Assemble the filename from the "icon_filenames[]" array into a full path to Assemble the filename from the "icon_filenames[]" array into a full path to
a real file. a real file.
Use "api->data_directory" to figure out where our sounds should be. (The 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 "tp-magic-config --dataprefix" command would have told us when we installed
our plugin and its data.) our plugin and its data.)
We use "which" (which of our tools Tux Paint is asking about) as an index We use "which" (which of our tools Tux Paint is asking about) as an index
into the array. into the array.
*/ */
snprintf(filename, sizeof(filename), "%simages/magic/%s", snprintf(filename, sizeof(filename), "%simages/magic/%s",
api->data_directory, icon_filenames[which]); api->data_directory, icon_filenames[which]);
@ -229,31 +230,31 @@ names (labels) for the 'Magic' tool buttons.
*/ */
char *example_get_name(magic_api * api, int which) char *example_get_name(magic_api * api, int which)
{ {
const char *our_name_english; const char *our_name_english;
const char *our_name_localized; const char *our_name_localized;
/* /*
Get our name from the "tool_names[]" array. Get our name from the "tool_names[]" array.
We use 'which' (which of our tools Tux Paint is asking about) as an index We use 'which' (which of our tools Tux Paint is asking about) as an index
into the array. into the array.
*/ */
our_name_english = tool_names[which]; our_name_english = tool_names[which];
/* /*
Return a localized (aka translated) version of our name, if possible. Return a localized (aka translated) version of our name, if possible.
We send "gettext()" the English version of the name from our array. We send "gettext()" the English version of the name from our array.
*/ */
our_name_localized = gettext(our_name_english); our_name_localized = gettext(our_name_english);
/* /*
Finally, duplicate the string into a new section of memory, and send it to 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, 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.) so we have one less thing to keep track of.)
*/ */
return (strdup(our_name_localized)); return (strdup(our_name_localized));
} }
@ -267,11 +268,11 @@ where the tool should be grouped.
int example_get_group(magic_api * api, int which) int example_get_group(magic_api * api, int which)
{ {
/* /*
Return our group, found in the "tool_groups[]" array. Return our group, found in the "tool_groups[]" array.
We use 'which' (which of our tools Tux Paint is asking about) as an index We use 'which' (which of our tools Tux Paint is asking about) as an index
into the array. into the array.
*/ */
return (tool_groups[which]); return (tool_groups[which]);
} }
@ -302,28 +303,28 @@ char *example_get_description(magic_api * api, int which, int mode)
const char *our_desc_localized; const char *our_desc_localized;
/* /*
Get our description from the "tool_descriptions[]" array. Get our description from the "tool_descriptions[]" array.
We use 'which' (which of our tools Tux Paint is asking about) as an index We use 'which' (which of our tools Tux Paint is asking about) as an index
into the array. into the array.
*/ */
our_desc_english = tool_descriptions[which]; our_desc_english = tool_descriptions[which];
/* /*
Return a localized (aka translated) version of our description, if Return a localized (aka translated) version of our description, if
possible. possible.
We send "gettext" the English version of the description from our array. We send "gettext" the English version of the description from our array.
*/ */
our_desc_localized = gettext(our_desc_english); our_desc_localized = gettext(our_desc_english);
/* /*
Finally, duplicate the string into a new section of memory, and send it to 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, 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.) so we have one less thing to keep track of.)
*/ */
return (strdup(our_desc_localized)); return (strdup(our_desc_localized));
} }
@ -345,9 +346,9 @@ int example_requires_colors(magic_api * api, int which)
int example_modes(magic_api * api, int which) int example_modes(magic_api * api, int which)
{ {
/* /*
Both of our tools are painted (neither affect the full-screen), so we're Both of our tools are painted (neither affect the full-screen), so we're
always returning 'MODE_PAINT' always returning 'MODE_PAINT'
*/ */
return MODE_PAINT; return MODE_PAINT;
} }
@ -385,9 +386,9 @@ void example_shutdown(magic_api * api)
int i; int i;
/* /*
Free (aka release, aka deallocate) the memory used to store the sound Free (aka release, aka deallocate) the memory used to store the sound
effects that we loaded during example_init(): effects that we loaded during example_init():
*/ */
for (i = 0; i < NUM_TOOLS; i++) for (i = 0; i < NUM_TOOLS; i++)
Mix_FreeChunk(sound_effects[i]); Mix_FreeChunk(sound_effects[i]);
} }
@ -404,13 +405,13 @@ example_click(magic_api * api, int which, int mode,
SDL_Rect * update_rect) SDL_Rect * update_rect)
{ {
/* /*
In our case, a single click (which is also the start of a drag!) is 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 identical to what dragging does, but just at one point, rather than across
a line. a line.
So we 'cheat' here, by calling our "example_draw()" function with (x,y) for So we 'cheat' here, by calling our "example_draw()" function with (x,y) for
both the beginning and end points of a line. both the beginning and end points of a line.
*/ */
example_drag(api, which, canvas, snapshot, x, y, x, y, update_rect); example_drag(api, which, canvas, snapshot, x, y, x, y, update_rect);
} }
@ -420,34 +421,32 @@ example_click(magic_api * api, int which, int mode,
void void
example_drag(magic_api * api, int which, example_drag(magic_api * api, int which,
SDL_Surface * canvas, SDL_Surface * snapshot, SDL_Surface * canvas, SDL_Surface * snapshot,
int old_x, int old_y, int x, int y, int old_x, int old_y, int x, int y, SDL_Rect * update_rect)
SDL_Rect * update_rect)
{ {
/* /*
Call Tux Paint's "line()" (line-traversing) function. Call Tux Paint's "line()" (line-traversing) function.
It will calculate a straight line between (old_x,old_y) and (x,y). Every It will calculate a straight line between (old_x,old_y) and (x,y). Every
N steps along that line (in this case, N is '1'), it will call _our_ 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 function, "example_line_callback()", and send the current X,Y
coordinates along the line, as well as other useful things (which of our coordinates along the line, as well as other useful things (which of our
'Magic' tools is being used and the current and snapshot canvases). 'Magic' tools is being used and the current and snapshot canvases).
*/ */
SDL_LockSurface(snapshot); SDL_LockSurface(snapshot);
SDL_LockSurface(canvas); SDL_LockSurface(canvas);
api->line((void *) api, which, canvas, snapshot, api->line((void *) api, which, canvas, snapshot,
old_x, old_y, x, y, 1, old_x, old_y, x, y, 1, example_line_callback);
example_line_callback);
SDL_UnlockSurface(canvas); SDL_UnlockSurface(canvas);
SDL_UnlockSurface(snapshot); SDL_UnlockSurface(snapshot);
/* /*
If we need to, swap the X and/or Y values, so that the coordinates If we need to, swap the X and/or Y values, so that the coordinates
(old_x,old_y) is always the top left, and the coordinates (x,y) is (old_x,old_y) is always the top left, and the coordinates (x,y) is
always the bottom right, so the values we put inside "update_rect" make always the bottom right, so the values we put inside "update_rect" make
sense: sense:
*/ */
if (old_x > x) if (old_x > x)
{ {
@ -466,17 +465,20 @@ example_drag(magic_api * api, int which,
/* /*
Fill in the elements of the "update_rect" SDL_Rect structure that Tux Fill in the elements of the "update_rect" SDL_Rect structure that Tux
Paint is sharing with us, therefore telling Tux Paint which part of the Paint is sharing with us, therefore telling Tux Paint which part of the
canvas has been modified and should be updated. canvas has been modified and should be updated.
*/ */
if (which == TOOL_ONE) { if (which == TOOL_ONE)
{
update_rect->x = old_x; update_rect->x = old_x;
update_rect->y = old_y; update_rect->y = old_y;
update_rect->w = (x - old_x) + 1; update_rect->w = (x - old_x) + 1;
update_rect->h = (y - old_y) + 1; update_rect->h = (y - old_y) + 1;
} else { }
else
{
update_rect->x = old_x - example_size; update_rect->x = old_x - example_size;
update_rect->y = old_y - example_size; update_rect->y = old_y - example_size;
update_rect->w = (x + example_size) - update_rect->x + 1; update_rect->w = (x + example_size) - update_rect->x + 1;
@ -484,19 +486,18 @@ example_drag(magic_api * api, int which,
} }
/* /*
Play the appropriate sound effect Play the appropriate sound effect
We're calculating a value between 0-255 for where the mouse is We're calculating a value between 0-255 for where the mouse is
horizontally across the canvas (0 is the left, ~128 is the center, 255 horizontally across the canvas (0 is the left, ~128 is the center, 255
is the right). is the right).
These are the exact values Tux Paint's "playsound()" wants, to determine 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 what speaker to play the sound in. (So the sound will pan from speaker
to speaker as you drag the mouse around the canvas!) to speaker as you drag the mouse around the canvas!)
*/ */
api->playsound(sound_effects[which], api->playsound(sound_effects[which], (x * 255) / canvas->w, /* Left/right pan */
(x * 255) / canvas->w, /* Left/right pan */ 255 /* Near/far distance (loudness) */ );
255 /* Near/far distance (loudness) */);
} }
@ -508,9 +509,9 @@ example_release(magic_api * api, int which,
SDL_Rect * update_rect) SDL_Rect * update_rect)
{ {
/* /*
Neither of our effects do anything special when the mouse is released 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... from a click or click-and-drag, so there's no code here...
*/ */
} }
@ -526,12 +527,14 @@ changes their chosen, we'll be informed of that as well.
The color comes in as RGB (red, green, and blue) values from 0 (darkest) to The color comes in as RGB (red, green, and blue) values from 0 (darkest) to
255 (brightest). 255 (brightest).
*/ */
void example_set_color(magic_api * api, int which, SDL_Surface * canvas, SDL_Surface * snapshot, Uint8 r, Uint8 g, Uint8 b, SDL_Rect * update_rect) void example_set_color(magic_api * api, int which, SDL_Surface * canvas,
SDL_Surface * snapshot, Uint8 r, Uint8 g, Uint8 b,
SDL_Rect * update_rect)
{ {
/* /*
We simply store the RGB values in the global variables we declared at We simply store the RGB values in the global variables we declared at
the top of this file. the top of this file.
*/ */
example_r = r; example_r = r;
example_g = g; example_g = g;
@ -551,12 +554,14 @@ that as well.
The size comes in as an unsigned integer (Uint8) between 1 and the value The size comes in as an unsigned integer (Uint8) between 1 and the value
returned by our example_accepted_sizes() function during setup. returned by our example_accepted_sizes() function during setup.
*/ */
void example_set_size(magic_api * api, int which, int mode, SDL_Surface * canvas, SDL_Surface * snapshot, Uint8 size, SDL_Rect * update_rect) void example_set_size(magic_api * api, int which, int mode,
SDL_Surface * canvas, SDL_Surface * snapshot,
Uint8 size, SDL_Rect * update_rect)
{ {
/* /*
Store the new size into the global variable we declared at the top of Store the new size into the global variable we declared at the top of
this file. this file.
*/ */
example_size = size * 4; example_size = size * 4;
} }
@ -580,51 +585,51 @@ Our callback pays attention to 'which' to determine which of our plugin's
tools is currently selected. tools is currently selected.
*/ */
void example_line_callback(void *pointer, int which, SDL_Surface * canvas, void example_line_callback(void *pointer, int which, SDL_Surface * canvas,
SDL_Surface * snapshot, int x, int y) SDL_Surface * snapshot, int x, int y)
{ {
/* /*
For technical reasons, we can't accept a pointer to the Tux Paint API's For technical reasons, we can't accept a pointer to the Tux Paint API's
"magic_api" struct, like the other functions do. "magic_api" struct, like the other functions do.
Instead, we receive a 'generic' pointer (a "void *"). The line below Instead, we receive a 'generic' pointer (a "void *"). The line below
declares a local "magic_api" pointer variable called "api", and then declares a local "magic_api" pointer variable called "api", and then
assigns it to the value of the 'generic' pointer we received. assigns it to the value of the 'generic' pointer we received.
The "(magic_api *)" seen below casts the generic "void *" pointer into The "(magic_api *)" seen below casts the generic "void *" pointer into
the 'type' of pointer we want, a pointer to a "magic_api" struct.) the 'type' of pointer we want, a pointer to a "magic_api" struct.)
*/ */
magic_api *api = (magic_api *) pointer; magic_api *api = (magic_api *) pointer;
int xx, yy; int xx, yy;
/* /*
This function handles both of our tools, so we need to check which is 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 being used right now. We compare the 'which' argument that Tux Paint
sends to us with the values we enumerated above. sends to us with the values we enumerated above.
*/ */
if (which == TOOL_ONE) if (which == TOOL_ONE)
{ {
/* /*
Tool number 1 simply draws a single pixel at the (x,y) location. It acts Tool number 1 simply draws a single pixel at the (x,y) location. It acts
as a 1x1 pixel brush. as a 1x1 pixel brush.
*/ */
api->putpixel(canvas, x, y, api->putpixel(canvas, x, y,
SDL_MapRGB(canvas->format, SDL_MapRGB(canvas->format,
example_r, example_g, example_b)); example_r, example_g, example_b));
/* /*
We use "SDL_MapRGB()" to convert the RGB value we receive from Tux Paint 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 for the user's current color selection to a 'Uint32' pixel value we can
send to Tux Paint's "putpixel()" function. send to Tux Paint's "putpixel()" function.
*/ */
} }
else if (which == TOOL_TWO) else if (which == TOOL_TWO)
{ {
/* /*
Tool number 2 copies a square of pixels (of the size chosen by the user) Tool number 2 copies a square of pixels (of the size chosen by the user)
from the opposite side of the canvas and puts it under the cursor. from the opposite side of the canvas and puts it under the cursor.
*/ */
for (yy = -example_size; yy < example_size; yy++) for (yy = -example_size; yy < example_size; yy++)
{ {
@ -636,14 +641,14 @@ void example_line_callback(void *pointer, int which, SDL_Surface * canvas,
snapshot->h - y - yy)); snapshot->h - y - yy));
/* /*
Here we have simply use Tux Paint's "getpixel()" routine to pull pixel Here we have simply use Tux Paint's "getpixel()" routine to pull pixel
values from the 'snapshot', and then "putpixel()" to draw them right values from the 'snapshot', and then "putpixel()" to draw them right
into the 'canvas'. into the 'canvas'.
Note: putpixel() and getpixel() are safe to use, even if your X,Y values 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 are outside of the SDL surface (e.g., negative, or greater than the
surface's width and/or height). surface's width and/or height).
*/ */
} }
} }
} }

View file

@ -9,12 +9,12 @@
/* ---------------------------------------------------------------------- */ /* ---------------------------------------------------------------------- */
#include <stdio.h> #include <stdio.h>
#include <string.h> // For "strdup()" #include <string.h> // For "strdup()"
#include <libintl.h> // For "gettext()" #include <libintl.h> // For "gettext()"
#include "tp_magic_api.h" // Tux Paint "Magic" tool API header #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_image.h" // For IMG_Load(), to load our PNG icon
#include "SDL_mixer.h" // For Mix_LoadWAV(), to load our sound effects #include "SDL_mixer.h" // For Mix_LoadWAV(), to load our sound effects
/* Tool Enumerations: */ /* Tool Enumerations: */
@ -25,9 +25,9 @@
enum enum
{ {
TOOL_ONE, // Becomes '0' TOOL_ONE, // Becomes '0'
TOOL_TWO, // Becomes '1' TOOL_TWO, // Becomes '1'
NUM_TOOLS // Becomes '2' NUM_TOOLS // Becomes '2'
}; };
@ -101,11 +101,11 @@ _before_ them.
*/ */
void example_drag(magic_api * api, int which, SDL_Surface * canvas, void example_drag(magic_api * api, int which, SDL_Surface * canvas,
SDL_Surface * snapshot, int old_x, int old_y, int x, int y, SDL_Surface * snapshot, int old_x, int old_y, int x, int y,
SDL_Rect * update_rect); SDL_Rect * update_rect);
void example_line_callback(void *pointer, int which, SDL_Surface * canvas, void example_line_callback(void *pointer, int which, SDL_Surface * canvas,
SDL_Surface * snapshot, int x, int y); SDL_Surface * snapshot, int x, int y);
/* Setup Functions: */ /* Setup Functions: */
@ -144,7 +144,8 @@ released, aka deallocated) when the user quits Tux Paint, when our
example_shutdown() function is called. example_shutdown() function is called.
*/ */
int example_init(magic_api * api, Uint8 disabled_features, Uint8 complexity_level) int example_init(magic_api * api, Uint8 disabled_features,
Uint8 complexity_level)
{ {
int i; int i;
char filename[1024]; char filename[1024];
@ -152,15 +153,15 @@ int example_init(magic_api * api, Uint8 disabled_features, Uint8 complexity_leve
for (i = 0; i < NUM_TOOLS; i++) for (i = 0; i < NUM_TOOLS; i++)
{ {
/* /*
Assemble the filename from the "sound_filenames[]" array into a full path Assemble the filename from the "sound_filenames[]" array into a full path
to a real file. to a real file.
Use "api->data_directory" to figure out where our sounds should be. (The 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 "tp-magic-config --dataprefix" command would have told us when we installed
our plugin and its data.) our plugin and its data.)
*/ */
snprintf(filename, sizeof(filename), "%ssounds/magic/%s", api->data_directory, snprintf(filename, sizeof(filename), "%ssounds/magic/%s",
sound_filenames[i]); api->data_directory, sound_filenames[i]);
printf("Trying to load %s sound file\n", filename); printf("Trying to load %s sound file\n", filename);
@ -200,16 +201,16 @@ SDL_Surface *example_get_icon(magic_api * api, int which)
char filename[1024]; char filename[1024];
/* /*
Assemble the filename from the "icon_filenames[]" array into a full path to Assemble the filename from the "icon_filenames[]" array into a full path to
a real file. a real file.
Use "api->data_directory" to figure out where our sounds should be. (The 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 "tp-magic-config --dataprefix" command would have told us when we installed
our plugin and its data.) our plugin and its data.)
We use "which" (which of our tools Tux Paint is asking about) as an index We use "which" (which of our tools Tux Paint is asking about) as an index
into the array. into the array.
*/ */
snprintf(filename, sizeof(filename), "%simages/magic/%s", snprintf(filename, sizeof(filename), "%simages/magic/%s",
api->data_directory, icon_filenames[which]); api->data_directory, icon_filenames[which]);
@ -229,31 +230,31 @@ names (labels) for the 'Magic' tool buttons.
*/ */
char *example_get_name(magic_api * api, int which) char *example_get_name(magic_api * api, int which)
{ {
const char *our_name_english; const char *our_name_english;
const char *our_name_localized; const char *our_name_localized;
/* /*
Get our name from the "tool_names[]" array. Get our name from the "tool_names[]" array.
We use 'which' (which of our tools Tux Paint is asking about) as an index We use 'which' (which of our tools Tux Paint is asking about) as an index
into the array. into the array.
*/ */
our_name_english = tool_names[which]; our_name_english = tool_names[which];
/* /*
Return a localized (aka translated) version of our name, if possible. Return a localized (aka translated) version of our name, if possible.
We send "gettext()" the English version of the name from our array. We send "gettext()" the English version of the name from our array.
*/ */
our_name_localized = gettext(our_name_english); our_name_localized = gettext(our_name_english);
/* /*
Finally, duplicate the string into a new section of memory, and send it to 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, 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.) so we have one less thing to keep track of.)
*/ */
return (strdup(our_name_localized)); return (strdup(our_name_localized));
} }
@ -267,11 +268,11 @@ where the tool should be grouped.
int example_get_group(magic_api * api, int which) int example_get_group(magic_api * api, int which)
{ {
/* /*
Return our group, found in the "tool_groups[]" array. Return our group, found in the "tool_groups[]" array.
We use 'which' (which of our tools Tux Paint is asking about) as an index We use 'which' (which of our tools Tux Paint is asking about) as an index
into the array. into the array.
*/ */
return (tool_groups[which]); return (tool_groups[which]);
} }
@ -302,28 +303,28 @@ char *example_get_description(magic_api * api, int which, int mode)
const char *our_desc_localized; const char *our_desc_localized;
/* /*
Get our description from the "tool_descriptions[]" array. Get our description from the "tool_descriptions[]" array.
We use 'which' (which of our tools Tux Paint is asking about) as an index We use 'which' (which of our tools Tux Paint is asking about) as an index
into the array. into the array.
*/ */
our_desc_english = tool_descriptions[which]; our_desc_english = tool_descriptions[which];
/* /*
Return a localized (aka translated) version of our description, if Return a localized (aka translated) version of our description, if
possible. possible.
We send "gettext" the English version of the description from our array. We send "gettext" the English version of the description from our array.
*/ */
our_desc_localized = gettext(our_desc_english); our_desc_localized = gettext(our_desc_english);
/* /*
Finally, duplicate the string into a new section of memory, and send it to 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, 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.) so we have one less thing to keep track of.)
*/ */
return (strdup(our_desc_localized)); return (strdup(our_desc_localized));
} }
@ -345,9 +346,9 @@ int example_requires_colors(magic_api * api, int which)
int example_modes(magic_api * api, int which) int example_modes(magic_api * api, int which)
{ {
/* /*
Both of our tools are painted (neither affect the full-screen), so we're Both of our tools are painted (neither affect the full-screen), so we're
always returning 'MODE_PAINT' always returning 'MODE_PAINT'
*/ */
return MODE_PAINT; return MODE_PAINT;
} }
@ -385,9 +386,9 @@ void example_shutdown(magic_api * api)
int i; int i;
/* /*
Free (aka release, aka deallocate) the memory used to store the sound Free (aka release, aka deallocate) the memory used to store the sound
effects that we loaded during example_init(): effects that we loaded during example_init():
*/ */
for (i = 0; i < NUM_TOOLS; i++) for (i = 0; i < NUM_TOOLS; i++)
Mix_FreeChunk(sound_effects[i]); Mix_FreeChunk(sound_effects[i]);
} }
@ -404,13 +405,13 @@ example_click(magic_api * api, int which, int mode,
SDL_Rect * update_rect) SDL_Rect * update_rect)
{ {
/* /*
In our case, a single click (which is also the start of a drag!) is 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 identical to what dragging does, but just at one point, rather than across
a line. a line.
So we 'cheat' here, by calling our "example_draw()" function with (x,y) for So we 'cheat' here, by calling our "example_draw()" function with (x,y) for
both the beginning and end points of a line. both the beginning and end points of a line.
*/ */
example_drag(api, which, canvas, snapshot, x, y, x, y, update_rect); example_drag(api, which, canvas, snapshot, x, y, x, y, update_rect);
} }
@ -420,34 +421,32 @@ example_click(magic_api * api, int which, int mode,
void void
example_drag(magic_api * api, int which, example_drag(magic_api * api, int which,
SDL_Surface * canvas, SDL_Surface * snapshot, SDL_Surface * canvas, SDL_Surface * snapshot,
int old_x, int old_y, int x, int y, int old_x, int old_y, int x, int y, SDL_Rect * update_rect)
SDL_Rect * update_rect)
{ {
/* /*
Call Tux Paint's "line()" (line-traversing) function. Call Tux Paint's "line()" (line-traversing) function.
It will calculate a straight line between (old_x,old_y) and (x,y). Every It will calculate a straight line between (old_x,old_y) and (x,y). Every
N steps along that line (in this case, N is '1'), it will call _our_ 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 function, "example_line_callback()", and send the current X,Y
coordinates along the line, as well as other useful things (which of our coordinates along the line, as well as other useful things (which of our
'Magic' tools is being used and the current and snapshot canvases). 'Magic' tools is being used and the current and snapshot canvases).
*/ */
SDL_LockSurface(snapshot); SDL_LockSurface(snapshot);
SDL_LockSurface(canvas); SDL_LockSurface(canvas);
api->line((void *) api, which, canvas, snapshot, api->line((void *) api, which, canvas, snapshot,
old_x, old_y, x, y, 1, old_x, old_y, x, y, 1, example_line_callback);
example_line_callback);
SDL_UnlockSurface(canvas); SDL_UnlockSurface(canvas);
SDL_UnlockSurface(snapshot); SDL_UnlockSurface(snapshot);
/* /*
If we need to, swap the X and/or Y values, so that the coordinates If we need to, swap the X and/or Y values, so that the coordinates
(old_x,old_y) is always the top left, and the coordinates (x,y) is (old_x,old_y) is always the top left, and the coordinates (x,y) is
always the bottom right, so the values we put inside "update_rect" make always the bottom right, so the values we put inside "update_rect" make
sense: sense:
*/ */
if (old_x > x) if (old_x > x)
{ {
@ -466,17 +465,20 @@ example_drag(magic_api * api, int which,
/* /*
Fill in the elements of the "update_rect" SDL_Rect structure that Tux Fill in the elements of the "update_rect" SDL_Rect structure that Tux
Paint is sharing with us, therefore telling Tux Paint which part of the Paint is sharing with us, therefore telling Tux Paint which part of the
canvas has been modified and should be updated. canvas has been modified and should be updated.
*/ */
if (which == TOOL_ONE) { if (which == TOOL_ONE)
{
update_rect->x = old_x; update_rect->x = old_x;
update_rect->y = old_y; update_rect->y = old_y;
update_rect->w = (x - old_x) + 1; update_rect->w = (x - old_x) + 1;
update_rect->h = (y - old_y) + 1; update_rect->h = (y - old_y) + 1;
} else { }
else
{
update_rect->x = old_x - example_size; update_rect->x = old_x - example_size;
update_rect->y = old_y - example_size; update_rect->y = old_y - example_size;
update_rect->w = (x + example_size) - update_rect->x + 1; update_rect->w = (x + example_size) - update_rect->x + 1;
@ -484,19 +486,18 @@ example_drag(magic_api * api, int which,
} }
/* /*
Play the appropriate sound effect Play the appropriate sound effect
We're calculating a value between 0-255 for where the mouse is We're calculating a value between 0-255 for where the mouse is
horizontally across the canvas (0 is the left, ~128 is the center, 255 horizontally across the canvas (0 is the left, ~128 is the center, 255
is the right). is the right).
These are the exact values Tux Paint's "playsound()" wants, to determine 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 what speaker to play the sound in. (So the sound will pan from speaker
to speaker as you drag the mouse around the canvas!) to speaker as you drag the mouse around the canvas!)
*/ */
api->playsound(sound_effects[which], api->playsound(sound_effects[which], (x * 255) / canvas->w, /* Left/right pan */
(x * 255) / canvas->w, /* Left/right pan */ 255 /* Near/far distance (loudness) */ );
255 /* Near/far distance (loudness) */);
} }
@ -508,9 +509,9 @@ example_release(magic_api * api, int which,
SDL_Rect * update_rect) SDL_Rect * update_rect)
{ {
/* /*
Neither of our effects do anything special when the mouse is released 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... from a click or click-and-drag, so there's no code here...
*/ */
} }
@ -526,12 +527,14 @@ changes their chosen, we'll be informed of that as well.
The color comes in as RGB (red, green, and blue) values from 0 (darkest) to The color comes in as RGB (red, green, and blue) values from 0 (darkest) to
255 (brightest). 255 (brightest).
*/ */
void example_set_color(magic_api * api, int which, SDL_Surface * canvas, SDL_Surface * snapshot, Uint8 r, Uint8 g, Uint8 b, SDL_Rect * update_rect) void example_set_color(magic_api * api, int which, SDL_Surface * canvas,
SDL_Surface * snapshot, Uint8 r, Uint8 g, Uint8 b,
SDL_Rect * update_rect)
{ {
/* /*
We simply store the RGB values in the global variables we declared at We simply store the RGB values in the global variables we declared at
the top of this file. the top of this file.
*/ */
example_r = r; example_r = r;
example_g = g; example_g = g;
@ -551,12 +554,14 @@ that as well.
The size comes in as an unsigned integer (Uint8) between 1 and the value The size comes in as an unsigned integer (Uint8) between 1 and the value
returned by our example_accepted_sizes() function during setup. returned by our example_accepted_sizes() function during setup.
*/ */
void example_set_size(magic_api * api, int which, int mode, SDL_Surface * canvas, SDL_Surface * snapshot, Uint8 size, SDL_Rect * update_rect) void example_set_size(magic_api * api, int which, int mode,
SDL_Surface * canvas, SDL_Surface * snapshot,
Uint8 size, SDL_Rect * update_rect)
{ {
/* /*
Store the new size into the global variable we declared at the top of Store the new size into the global variable we declared at the top of
this file. this file.
*/ */
example_size = size * 4; example_size = size * 4;
} }
@ -580,51 +585,51 @@ Our callback pays attention to 'which' to determine which of our plugin's
tools is currently selected. tools is currently selected.
*/ */
void example_line_callback(void *pointer, int which, SDL_Surface * canvas, void example_line_callback(void *pointer, int which, SDL_Surface * canvas,
SDL_Surface * snapshot, int x, int y) SDL_Surface * snapshot, int x, int y)
{ {
/* /*
For technical reasons, we can't accept a pointer to the Tux Paint API's For technical reasons, we can't accept a pointer to the Tux Paint API's
"magic_api" struct, like the other functions do. "magic_api" struct, like the other functions do.
Instead, we receive a 'generic' pointer (a "void *"). The line below Instead, we receive a 'generic' pointer (a "void *"). The line below
declares a local "magic_api" pointer variable called "api", and then declares a local "magic_api" pointer variable called "api", and then
assigns it to the value of the 'generic' pointer we received. assigns it to the value of the 'generic' pointer we received.
The "(magic_api *)" seen below casts the generic "void *" pointer into The "(magic_api *)" seen below casts the generic "void *" pointer into
the 'type' of pointer we want, a pointer to a "magic_api" struct.) the 'type' of pointer we want, a pointer to a "magic_api" struct.)
*/ */
magic_api *api = (magic_api *) pointer; magic_api *api = (magic_api *) pointer;
int xx, yy; int xx, yy;
/* /*
This function handles both of our tools, so we need to check which is 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 being used right now. We compare the 'which' argument that Tux Paint
sends to us with the values we enumerated above. sends to us with the values we enumerated above.
*/ */
if (which == TOOL_ONE) if (which == TOOL_ONE)
{ {
/* /*
Tool number 1 simply draws a single pixel at the (x,y) location. It acts Tool number 1 simply draws a single pixel at the (x,y) location. It acts
as a 1x1 pixel brush. as a 1x1 pixel brush.
*/ */
api->putpixel(canvas, x, y, api->putpixel(canvas, x, y,
SDL_MapRGB(canvas->format, SDL_MapRGB(canvas->format,
example_r, example_g, example_b)); example_r, example_g, example_b));
/* /*
We use "SDL_MapRGB()" to convert the RGB value we receive from Tux Paint 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 for the user's current color selection to a 'Uint32' pixel value we can
send to Tux Paint's "putpixel()" function. send to Tux Paint's "putpixel()" function.
*/ */
} }
else if (which == TOOL_TWO) else if (which == TOOL_TWO)
{ {
/* /*
Tool number 2 copies a square of pixels (of the size chosen by the user) Tool number 2 copies a square of pixels (of the size chosen by the user)
from the opposite side of the canvas and puts it under the cursor. from the opposite side of the canvas and puts it under the cursor.
*/ */
for (yy = -example_size; yy < example_size; yy++) for (yy = -example_size; yy < example_size; yy++)
{ {
@ -636,14 +641,14 @@ void example_line_callback(void *pointer, int which, SDL_Surface * canvas,
snapshot->h - y - yy)); snapshot->h - y - yy));
/* /*
Here we have simply use Tux Paint's "getpixel()" routine to pull pixel Here we have simply use Tux Paint's "getpixel()" routine to pull pixel
values from the 'snapshot', and then "putpixel()" to draw them right values from the 'snapshot', and then "putpixel()" to draw them right
into the 'canvas'. into the 'canvas'.
Note: putpixel() and getpixel() are safe to use, even if your X,Y values 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 are outside of the SDL surface (e.g., negative, or greater than the
surface's width and/or height). surface's width and/or height).
*/ */
} }
} }
} }

View file

@ -9,12 +9,12 @@
/* ---------------------------------------------------------------------- */ /* ---------------------------------------------------------------------- */
#include <stdio.h> #include <stdio.h>
#include <string.h> // For "strdup()" #include <string.h> // For "strdup()"
#include <libintl.h> // For "gettext()" #include <libintl.h> // For "gettext()"
#include "tp_magic_api.h" // Tux Paint "Magic" tool API header #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_image.h" // For IMG_Load(), to load our PNG icon
#include "SDL_mixer.h" // For Mix_LoadWAV(), to load our sound effects #include "SDL_mixer.h" // For Mix_LoadWAV(), to load our sound effects
/* Tool Enumerations: */ /* Tool Enumerations: */
@ -25,9 +25,9 @@
enum enum
{ {
TOOL_ONE, // Becomes '0' TOOL_ONE, // Becomes '0'
TOOL_TWO, // Becomes '1' TOOL_TWO, // Becomes '1'
NUM_TOOLS // Becomes '2' NUM_TOOLS // Becomes '2'
}; };
@ -101,11 +101,11 @@ _before_ them.
*/ */
void example_drag(magic_api * api, int which, SDL_Surface * canvas, void example_drag(magic_api * api, int which, SDL_Surface * canvas,
SDL_Surface * snapshot, int old_x, int old_y, int x, int y, SDL_Surface * snapshot, int old_x, int old_y, int x, int y,
SDL_Rect * update_rect); SDL_Rect * update_rect);
void example_line_callback(void *pointer, int which, SDL_Surface * canvas, void example_line_callback(void *pointer, int which, SDL_Surface * canvas,
SDL_Surface * snapshot, int x, int y); SDL_Surface * snapshot, int x, int y);
/* Setup Functions: */ /* Setup Functions: */
@ -144,7 +144,8 @@ released, aka deallocated) when the user quits Tux Paint, when our
example_shutdown() function is called. example_shutdown() function is called.
*/ */
int example_init(magic_api * api, Uint8 disabled_features, Uint8 complexity_level) int example_init(magic_api * api, Uint8 disabled_features,
Uint8 complexity_level)
{ {
int i; int i;
char filename[1024]; char filename[1024];
@ -152,15 +153,15 @@ int example_init(magic_api * api, Uint8 disabled_features, Uint8 complexity_leve
for (i = 0; i < NUM_TOOLS; i++) for (i = 0; i < NUM_TOOLS; i++)
{ {
/* /*
Assemble the filename from the "sound_filenames[]" array into a full path Assemble the filename from the "sound_filenames[]" array into a full path
to a real file. to a real file.
Use "api->data_directory" to figure out where our sounds should be. (The 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 "tp-magic-config --dataprefix" command would have told us when we installed
our plugin and its data.) our plugin and its data.)
*/ */
snprintf(filename, sizeof(filename), "%ssounds/magic/%s", api->data_directory, snprintf(filename, sizeof(filename), "%ssounds/magic/%s",
sound_filenames[i]); api->data_directory, sound_filenames[i]);
printf("Trying to load %s sound file\n", filename); printf("Trying to load %s sound file\n", filename);
@ -200,16 +201,16 @@ SDL_Surface *example_get_icon(magic_api * api, int which)
char filename[1024]; char filename[1024];
/* /*
Assemble the filename from the "icon_filenames[]" array into a full path to Assemble the filename from the "icon_filenames[]" array into a full path to
a real file. a real file.
Use "api->data_directory" to figure out where our sounds should be. (The 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 "tp-magic-config --dataprefix" command would have told us when we installed
our plugin and its data.) our plugin and its data.)
We use "which" (which of our tools Tux Paint is asking about) as an index We use "which" (which of our tools Tux Paint is asking about) as an index
into the array. into the array.
*/ */
snprintf(filename, sizeof(filename), "%simages/magic/%s", snprintf(filename, sizeof(filename), "%simages/magic/%s",
api->data_directory, icon_filenames[which]); api->data_directory, icon_filenames[which]);
@ -229,31 +230,31 @@ names (labels) for the 'Magic' tool buttons.
*/ */
char *example_get_name(magic_api * api, int which) char *example_get_name(magic_api * api, int which)
{ {
const char *our_name_english; const char *our_name_english;
const char *our_name_localized; const char *our_name_localized;
/* /*
Get our name from the "tool_names[]" array. Get our name from the "tool_names[]" array.
We use 'which' (which of our tools Tux Paint is asking about) as an index We use 'which' (which of our tools Tux Paint is asking about) as an index
into the array. into the array.
*/ */
our_name_english = tool_names[which]; our_name_english = tool_names[which];
/* /*
Return a localized (aka translated) version of our name, if possible. Return a localized (aka translated) version of our name, if possible.
We send "gettext()" the English version of the name from our array. We send "gettext()" the English version of the name from our array.
*/ */
our_name_localized = gettext(our_name_english); our_name_localized = gettext(our_name_english);
/* /*
Finally, duplicate the string into a new section of memory, and send it to 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, 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.) so we have one less thing to keep track of.)
*/ */
return (strdup(our_name_localized)); return (strdup(our_name_localized));
} }
@ -267,11 +268,11 @@ where the tool should be grouped.
int example_get_group(magic_api * api, int which) int example_get_group(magic_api * api, int which)
{ {
/* /*
Return our group, found in the "tool_groups[]" array. Return our group, found in the "tool_groups[]" array.
We use 'which' (which of our tools Tux Paint is asking about) as an index We use 'which' (which of our tools Tux Paint is asking about) as an index
into the array. into the array.
*/ */
return (tool_groups[which]); return (tool_groups[which]);
} }
@ -302,28 +303,28 @@ char *example_get_description(magic_api * api, int which, int mode)
const char *our_desc_localized; const char *our_desc_localized;
/* /*
Get our description from the "tool_descriptions[]" array. Get our description from the "tool_descriptions[]" array.
We use 'which' (which of our tools Tux Paint is asking about) as an index We use 'which' (which of our tools Tux Paint is asking about) as an index
into the array. into the array.
*/ */
our_desc_english = tool_descriptions[which]; our_desc_english = tool_descriptions[which];
/* /*
Return a localized (aka translated) version of our description, if Return a localized (aka translated) version of our description, if
possible. possible.
We send "gettext" the English version of the description from our array. We send "gettext" the English version of the description from our array.
*/ */
our_desc_localized = gettext(our_desc_english); our_desc_localized = gettext(our_desc_english);
/* /*
Finally, duplicate the string into a new section of memory, and send it to 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, 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.) so we have one less thing to keep track of.)
*/ */
return (strdup(our_desc_localized)); return (strdup(our_desc_localized));
} }
@ -345,9 +346,9 @@ int example_requires_colors(magic_api * api, int which)
int example_modes(magic_api * api, int which) int example_modes(magic_api * api, int which)
{ {
/* /*
Both of our tools are painted (neither affect the full-screen), so we're Both of our tools are painted (neither affect the full-screen), so we're
always returning 'MODE_PAINT' always returning 'MODE_PAINT'
*/ */
return MODE_PAINT; return MODE_PAINT;
} }
@ -385,9 +386,9 @@ void example_shutdown(magic_api * api)
int i; int i;
/* /*
Free (aka release, aka deallocate) the memory used to store the sound Free (aka release, aka deallocate) the memory used to store the sound
effects that we loaded during example_init(): effects that we loaded during example_init():
*/ */
for (i = 0; i < NUM_TOOLS; i++) for (i = 0; i < NUM_TOOLS; i++)
Mix_FreeChunk(sound_effects[i]); Mix_FreeChunk(sound_effects[i]);
} }
@ -404,13 +405,13 @@ example_click(magic_api * api, int which, int mode,
SDL_Rect * update_rect) SDL_Rect * update_rect)
{ {
/* /*
In our case, a single click (which is also the start of a drag!) is 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 identical to what dragging does, but just at one point, rather than across
a line. a line.
So we 'cheat' here, by calling our "example_draw()" function with (x,y) for So we 'cheat' here, by calling our "example_draw()" function with (x,y) for
both the beginning and end points of a line. both the beginning and end points of a line.
*/ */
example_drag(api, which, canvas, snapshot, x, y, x, y, update_rect); example_drag(api, which, canvas, snapshot, x, y, x, y, update_rect);
} }
@ -420,34 +421,32 @@ example_click(magic_api * api, int which, int mode,
void void
example_drag(magic_api * api, int which, example_drag(magic_api * api, int which,
SDL_Surface * canvas, SDL_Surface * snapshot, SDL_Surface * canvas, SDL_Surface * snapshot,
int old_x, int old_y, int x, int y, int old_x, int old_y, int x, int y, SDL_Rect * update_rect)
SDL_Rect * update_rect)
{ {
/* /*
Call Tux Paint's "line()" (line-traversing) function. Call Tux Paint's "line()" (line-traversing) function.
It will calculate a straight line between (old_x,old_y) and (x,y). Every It will calculate a straight line between (old_x,old_y) and (x,y). Every
N steps along that line (in this case, N is '1'), it will call _our_ 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 function, "example_line_callback()", and send the current X,Y
coordinates along the line, as well as other useful things (which of our coordinates along the line, as well as other useful things (which of our
'Magic' tools is being used and the current and snapshot canvases). 'Magic' tools is being used and the current and snapshot canvases).
*/ */
SDL_LockSurface(snapshot); SDL_LockSurface(snapshot);
SDL_LockSurface(canvas); SDL_LockSurface(canvas);
api->line((void *) api, which, canvas, snapshot, api->line((void *) api, which, canvas, snapshot,
old_x, old_y, x, y, 1, old_x, old_y, x, y, 1, example_line_callback);
example_line_callback);
SDL_UnlockSurface(canvas); SDL_UnlockSurface(canvas);
SDL_UnlockSurface(snapshot); SDL_UnlockSurface(snapshot);
/* /*
If we need to, swap the X and/or Y values, so that the coordinates If we need to, swap the X and/or Y values, so that the coordinates
(old_x,old_y) is always the top left, and the coordinates (x,y) is (old_x,old_y) is always the top left, and the coordinates (x,y) is
always the bottom right, so the values we put inside "update_rect" make always the bottom right, so the values we put inside "update_rect" make
sense: sense:
*/ */
if (old_x > x) if (old_x > x)
{ {
@ -466,17 +465,20 @@ example_drag(magic_api * api, int which,
/* /*
Fill in the elements of the "update_rect" SDL_Rect structure that Tux Fill in the elements of the "update_rect" SDL_Rect structure that Tux
Paint is sharing with us, therefore telling Tux Paint which part of the Paint is sharing with us, therefore telling Tux Paint which part of the
canvas has been modified and should be updated. canvas has been modified and should be updated.
*/ */
if (which == TOOL_ONE) { if (which == TOOL_ONE)
{
update_rect->x = old_x; update_rect->x = old_x;
update_rect->y = old_y; update_rect->y = old_y;
update_rect->w = (x - old_x) + 1; update_rect->w = (x - old_x) + 1;
update_rect->h = (y - old_y) + 1; update_rect->h = (y - old_y) + 1;
} else { }
else
{
update_rect->x = old_x - example_size; update_rect->x = old_x - example_size;
update_rect->y = old_y - example_size; update_rect->y = old_y - example_size;
update_rect->w = (x + example_size) - update_rect->x + 1; update_rect->w = (x + example_size) - update_rect->x + 1;
@ -484,19 +486,18 @@ example_drag(magic_api * api, int which,
} }
/* /*
Play the appropriate sound effect Play the appropriate sound effect
We're calculating a value between 0-255 for where the mouse is We're calculating a value between 0-255 for where the mouse is
horizontally across the canvas (0 is the left, ~128 is the center, 255 horizontally across the canvas (0 is the left, ~128 is the center, 255
is the right). is the right).
These are the exact values Tux Paint's "playsound()" wants, to determine 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 what speaker to play the sound in. (So the sound will pan from speaker
to speaker as you drag the mouse around the canvas!) to speaker as you drag the mouse around the canvas!)
*/ */
api->playsound(sound_effects[which], api->playsound(sound_effects[which], (x * 255) / canvas->w, /* Left/right pan */
(x * 255) / canvas->w, /* Left/right pan */ 255 /* Near/far distance (loudness) */ );
255 /* Near/far distance (loudness) */);
} }
@ -508,9 +509,9 @@ example_release(magic_api * api, int which,
SDL_Rect * update_rect) SDL_Rect * update_rect)
{ {
/* /*
Neither of our effects do anything special when the mouse is released 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... from a click or click-and-drag, so there's no code here...
*/ */
} }
@ -526,12 +527,14 @@ changes their chosen, we'll be informed of that as well.
The color comes in as RGB (red, green, and blue) values from 0 (darkest) to The color comes in as RGB (red, green, and blue) values from 0 (darkest) to
255 (brightest). 255 (brightest).
*/ */
void example_set_color(magic_api * api, int which, SDL_Surface * canvas, SDL_Surface * snapshot, Uint8 r, Uint8 g, Uint8 b, SDL_Rect * update_rect) void example_set_color(magic_api * api, int which, SDL_Surface * canvas,
SDL_Surface * snapshot, Uint8 r, Uint8 g, Uint8 b,
SDL_Rect * update_rect)
{ {
/* /*
We simply store the RGB values in the global variables we declared at We simply store the RGB values in the global variables we declared at
the top of this file. the top of this file.
*/ */
example_r = r; example_r = r;
example_g = g; example_g = g;
@ -551,12 +554,14 @@ that as well.
The size comes in as an unsigned integer (Uint8) between 1 and the value The size comes in as an unsigned integer (Uint8) between 1 and the value
returned by our example_accepted_sizes() function during setup. returned by our example_accepted_sizes() function during setup.
*/ */
void example_set_size(magic_api * api, int which, int mode, SDL_Surface * canvas, SDL_Surface * snapshot, Uint8 size, SDL_Rect * update_rect) void example_set_size(magic_api * api, int which, int mode,
SDL_Surface * canvas, SDL_Surface * snapshot,
Uint8 size, SDL_Rect * update_rect)
{ {
/* /*
Store the new size into the global variable we declared at the top of Store the new size into the global variable we declared at the top of
this file. this file.
*/ */
example_size = size * 4; example_size = size * 4;
} }
@ -580,51 +585,51 @@ Our callback pays attention to 'which' to determine which of our plugin's
tools is currently selected. tools is currently selected.
*/ */
void example_line_callback(void *pointer, int which, SDL_Surface * canvas, void example_line_callback(void *pointer, int which, SDL_Surface * canvas,
SDL_Surface * snapshot, int x, int y) SDL_Surface * snapshot, int x, int y)
{ {
/* /*
For technical reasons, we can't accept a pointer to the Tux Paint API's For technical reasons, we can't accept a pointer to the Tux Paint API's
"magic_api" struct, like the other functions do. "magic_api" struct, like the other functions do.
Instead, we receive a 'generic' pointer (a "void *"). The line below Instead, we receive a 'generic' pointer (a "void *"). The line below
declares a local "magic_api" pointer variable called "api", and then declares a local "magic_api" pointer variable called "api", and then
assigns it to the value of the 'generic' pointer we received. assigns it to the value of the 'generic' pointer we received.
The "(magic_api *)" seen below casts the generic "void *" pointer into The "(magic_api *)" seen below casts the generic "void *" pointer into
the 'type' of pointer we want, a pointer to a "magic_api" struct.) the 'type' of pointer we want, a pointer to a "magic_api" struct.)
*/ */
magic_api *api = (magic_api *) pointer; magic_api *api = (magic_api *) pointer;
int xx, yy; int xx, yy;
/* /*
This function handles both of our tools, so we need to check which is 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 being used right now. We compare the 'which' argument that Tux Paint
sends to us with the values we enumerated above. sends to us with the values we enumerated above.
*/ */
if (which == TOOL_ONE) if (which == TOOL_ONE)
{ {
/* /*
Tool number 1 simply draws a single pixel at the (x,y) location. It acts Tool number 1 simply draws a single pixel at the (x,y) location. It acts
as a 1x1 pixel brush. as a 1x1 pixel brush.
*/ */
api->putpixel(canvas, x, y, api->putpixel(canvas, x, y,
SDL_MapRGB(canvas->format, SDL_MapRGB(canvas->format,
example_r, example_g, example_b)); example_r, example_g, example_b));
/* /*
We use "SDL_MapRGB()" to convert the RGB value we receive from Tux Paint 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 for the user's current color selection to a 'Uint32' pixel value we can
send to Tux Paint's "putpixel()" function. send to Tux Paint's "putpixel()" function.
*/ */
} }
else if (which == TOOL_TWO) else if (which == TOOL_TWO)
{ {
/* /*
Tool number 2 copies a square of pixels (of the size chosen by the user) Tool number 2 copies a square of pixels (of the size chosen by the user)
from the opposite side of the canvas and puts it under the cursor. from the opposite side of the canvas and puts it under the cursor.
*/ */
for (yy = -example_size; yy < example_size; yy++) for (yy = -example_size; yy < example_size; yy++)
{ {
@ -636,14 +641,14 @@ void example_line_callback(void *pointer, int which, SDL_Surface * canvas,
snapshot->h - y - yy)); snapshot->h - y - yy));
/* /*
Here we have simply use Tux Paint's "getpixel()" routine to pull pixel Here we have simply use Tux Paint's "getpixel()" routine to pull pixel
values from the 'snapshot', and then "putpixel()" to draw them right values from the 'snapshot', and then "putpixel()" to draw them right
into the 'canvas'. into the 'canvas'.
Note: putpixel() and getpixel() are safe to use, even if your X,Y values 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 are outside of the SDL surface (e.g., negative, or greater than the
surface's width and/or height). surface's width and/or height).
*/ */
} }
} }
} }

View file

@ -9,12 +9,12 @@
/* ---------------------------------------------------------------------- */ /* ---------------------------------------------------------------------- */
#include <stdio.h> #include <stdio.h>
#include <string.h> // For "strdup()" #include <string.h> // For "strdup()"
#include <libintl.h> // For "gettext()" #include <libintl.h> // For "gettext()"
#include "tp_magic_api.h" // Tux Paint "Magic" tool API header #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_image.h" // For IMG_Load(), to load our PNG icon
#include "SDL_mixer.h" // For Mix_LoadWAV(), to load our sound effects #include "SDL_mixer.h" // For Mix_LoadWAV(), to load our sound effects
/* Tool Enumerations: */ /* Tool Enumerations: */
@ -25,9 +25,9 @@
enum enum
{ {
TOOL_ONE, // Becomes '0' TOOL_ONE, // Becomes '0'
TOOL_TWO, // Becomes '1' TOOL_TWO, // Becomes '1'
NUM_TOOLS // Becomes '2' NUM_TOOLS // Becomes '2'
}; };
@ -101,11 +101,11 @@ _before_ them.
*/ */
void example_drag(magic_api * api, int which, SDL_Surface * canvas, void example_drag(magic_api * api, int which, SDL_Surface * canvas,
SDL_Surface * snapshot, int old_x, int old_y, int x, int y, SDL_Surface * snapshot, int old_x, int old_y, int x, int y,
SDL_Rect * update_rect); SDL_Rect * update_rect);
void example_line_callback(void *pointer, int which, SDL_Surface * canvas, void example_line_callback(void *pointer, int which, SDL_Surface * canvas,
SDL_Surface * snapshot, int x, int y); SDL_Surface * snapshot, int x, int y);
/* Setup Functions: */ /* Setup Functions: */
@ -144,7 +144,8 @@ released, aka deallocated) when the user quits Tux Paint, when our
example_shutdown() function is called. example_shutdown() function is called.
*/ */
int example_init(magic_api * api, Uint8 disabled_features, Uint8 complexity_level) int example_init(magic_api * api, Uint8 disabled_features,
Uint8 complexity_level)
{ {
int i; int i;
char filename[1024]; char filename[1024];
@ -152,15 +153,15 @@ int example_init(magic_api * api, Uint8 disabled_features, Uint8 complexity_leve
for (i = 0; i < NUM_TOOLS; i++) for (i = 0; i < NUM_TOOLS; i++)
{ {
/* /*
Assemble the filename from the "sound_filenames[]" array into a full path Assemble the filename from the "sound_filenames[]" array into a full path
to a real file. to a real file.
Use "api->data_directory" to figure out where our sounds should be. (The 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 "tp-magic-config --dataprefix" command would have told us when we installed
our plugin and its data.) our plugin and its data.)
*/ */
snprintf(filename, sizeof(filename), "%ssounds/magic/%s", api->data_directory, snprintf(filename, sizeof(filename), "%ssounds/magic/%s",
sound_filenames[i]); api->data_directory, sound_filenames[i]);
printf("Trying to load %s sound file\n", filename); printf("Trying to load %s sound file\n", filename);
@ -200,16 +201,16 @@ SDL_Surface *example_get_icon(magic_api * api, int which)
char filename[1024]; char filename[1024];
/* /*
Assemble the filename from the "icon_filenames[]" array into a full path to Assemble the filename from the "icon_filenames[]" array into a full path to
a real file. a real file.
Use "api->data_directory" to figure out where our sounds should be. (The 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 "tp-magic-config --dataprefix" command would have told us when we installed
our plugin and its data.) our plugin and its data.)
We use "which" (which of our tools Tux Paint is asking about) as an index We use "which" (which of our tools Tux Paint is asking about) as an index
into the array. into the array.
*/ */
snprintf(filename, sizeof(filename), "%simages/magic/%s", snprintf(filename, sizeof(filename), "%simages/magic/%s",
api->data_directory, icon_filenames[which]); api->data_directory, icon_filenames[which]);
@ -229,31 +230,31 @@ names (labels) for the 'Magic' tool buttons.
*/ */
char *example_get_name(magic_api * api, int which) char *example_get_name(magic_api * api, int which)
{ {
const char *our_name_english; const char *our_name_english;
const char *our_name_localized; const char *our_name_localized;
/* /*
Get our name from the "tool_names[]" array. Get our name from the "tool_names[]" array.
We use 'which' (which of our tools Tux Paint is asking about) as an index We use 'which' (which of our tools Tux Paint is asking about) as an index
into the array. into the array.
*/ */
our_name_english = tool_names[which]; our_name_english = tool_names[which];
/* /*
Return a localized (aka translated) version of our name, if possible. Return a localized (aka translated) version of our name, if possible.
We send "gettext()" the English version of the name from our array. We send "gettext()" the English version of the name from our array.
*/ */
our_name_localized = gettext(our_name_english); our_name_localized = gettext(our_name_english);
/* /*
Finally, duplicate the string into a new section of memory, and send it to 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, 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.) so we have one less thing to keep track of.)
*/ */
return (strdup(our_name_localized)); return (strdup(our_name_localized));
} }
@ -267,11 +268,11 @@ where the tool should be grouped.
int example_get_group(magic_api * api, int which) int example_get_group(magic_api * api, int which)
{ {
/* /*
Return our group, found in the "tool_groups[]" array. Return our group, found in the "tool_groups[]" array.
We use 'which' (which of our tools Tux Paint is asking about) as an index We use 'which' (which of our tools Tux Paint is asking about) as an index
into the array. into the array.
*/ */
return (tool_groups[which]); return (tool_groups[which]);
} }
@ -302,28 +303,28 @@ char *example_get_description(magic_api * api, int which, int mode)
const char *our_desc_localized; const char *our_desc_localized;
/* /*
Get our description from the "tool_descriptions[]" array. Get our description from the "tool_descriptions[]" array.
We use 'which' (which of our tools Tux Paint is asking about) as an index We use 'which' (which of our tools Tux Paint is asking about) as an index
into the array. into the array.
*/ */
our_desc_english = tool_descriptions[which]; our_desc_english = tool_descriptions[which];
/* /*
Return a localized (aka translated) version of our description, if Return a localized (aka translated) version of our description, if
possible. possible.
We send "gettext" the English version of the description from our array. We send "gettext" the English version of the description from our array.
*/ */
our_desc_localized = gettext(our_desc_english); our_desc_localized = gettext(our_desc_english);
/* /*
Finally, duplicate the string into a new section of memory, and send it to 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, 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.) so we have one less thing to keep track of.)
*/ */
return (strdup(our_desc_localized)); return (strdup(our_desc_localized));
} }
@ -345,9 +346,9 @@ int example_requires_colors(magic_api * api, int which)
int example_modes(magic_api * api, int which) int example_modes(magic_api * api, int which)
{ {
/* /*
Both of our tools are painted (neither affect the full-screen), so we're Both of our tools are painted (neither affect the full-screen), so we're
always returning 'MODE_PAINT' always returning 'MODE_PAINT'
*/ */
return MODE_PAINT; return MODE_PAINT;
} }
@ -385,9 +386,9 @@ void example_shutdown(magic_api * api)
int i; int i;
/* /*
Free (aka release, aka deallocate) the memory used to store the sound Free (aka release, aka deallocate) the memory used to store the sound
effects that we loaded during example_init(): effects that we loaded during example_init():
*/ */
for (i = 0; i < NUM_TOOLS; i++) for (i = 0; i < NUM_TOOLS; i++)
Mix_FreeChunk(sound_effects[i]); Mix_FreeChunk(sound_effects[i]);
} }
@ -404,13 +405,13 @@ example_click(magic_api * api, int which, int mode,
SDL_Rect * update_rect) SDL_Rect * update_rect)
{ {
/* /*
In our case, a single click (which is also the start of a drag!) is 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 identical to what dragging does, but just at one point, rather than across
a line. a line.
So we 'cheat' here, by calling our "example_draw()" function with (x,y) for So we 'cheat' here, by calling our "example_draw()" function with (x,y) for
both the beginning and end points of a line. both the beginning and end points of a line.
*/ */
example_drag(api, which, canvas, snapshot, x, y, x, y, update_rect); example_drag(api, which, canvas, snapshot, x, y, x, y, update_rect);
} }
@ -420,34 +421,32 @@ example_click(magic_api * api, int which, int mode,
void void
example_drag(magic_api * api, int which, example_drag(magic_api * api, int which,
SDL_Surface * canvas, SDL_Surface * snapshot, SDL_Surface * canvas, SDL_Surface * snapshot,
int old_x, int old_y, int x, int y, int old_x, int old_y, int x, int y, SDL_Rect * update_rect)
SDL_Rect * update_rect)
{ {
/* /*
Call Tux Paint's "line()" (line-traversing) function. Call Tux Paint's "line()" (line-traversing) function.
It will calculate a straight line between (old_x,old_y) and (x,y). Every It will calculate a straight line between (old_x,old_y) and (x,y). Every
N steps along that line (in this case, N is '1'), it will call _our_ 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 function, "example_line_callback()", and send the current X,Y
coordinates along the line, as well as other useful things (which of our coordinates along the line, as well as other useful things (which of our
'Magic' tools is being used and the current and snapshot canvases). 'Magic' tools is being used and the current and snapshot canvases).
*/ */
SDL_LockSurface(snapshot); SDL_LockSurface(snapshot);
SDL_LockSurface(canvas); SDL_LockSurface(canvas);
api->line((void *) api, which, canvas, snapshot, api->line((void *) api, which, canvas, snapshot,
old_x, old_y, x, y, 1, old_x, old_y, x, y, 1, example_line_callback);
example_line_callback);
SDL_UnlockSurface(canvas); SDL_UnlockSurface(canvas);
SDL_UnlockSurface(snapshot); SDL_UnlockSurface(snapshot);
/* /*
If we need to, swap the X and/or Y values, so that the coordinates If we need to, swap the X and/or Y values, so that the coordinates
(old_x,old_y) is always the top left, and the coordinates (x,y) is (old_x,old_y) is always the top left, and the coordinates (x,y) is
always the bottom right, so the values we put inside "update_rect" make always the bottom right, so the values we put inside "update_rect" make
sense: sense:
*/ */
if (old_x > x) if (old_x > x)
{ {
@ -466,17 +465,20 @@ example_drag(magic_api * api, int which,
/* /*
Fill in the elements of the "update_rect" SDL_Rect structure that Tux Fill in the elements of the "update_rect" SDL_Rect structure that Tux
Paint is sharing with us, therefore telling Tux Paint which part of the Paint is sharing with us, therefore telling Tux Paint which part of the
canvas has been modified and should be updated. canvas has been modified and should be updated.
*/ */
if (which == TOOL_ONE) { if (which == TOOL_ONE)
{
update_rect->x = old_x; update_rect->x = old_x;
update_rect->y = old_y; update_rect->y = old_y;
update_rect->w = (x - old_x) + 1; update_rect->w = (x - old_x) + 1;
update_rect->h = (y - old_y) + 1; update_rect->h = (y - old_y) + 1;
} else { }
else
{
update_rect->x = old_x - example_size; update_rect->x = old_x - example_size;
update_rect->y = old_y - example_size; update_rect->y = old_y - example_size;
update_rect->w = (x + example_size) - update_rect->x + 1; update_rect->w = (x + example_size) - update_rect->x + 1;
@ -484,19 +486,18 @@ example_drag(magic_api * api, int which,
} }
/* /*
Play the appropriate sound effect Play the appropriate sound effect
We're calculating a value between 0-255 for where the mouse is We're calculating a value between 0-255 for where the mouse is
horizontally across the canvas (0 is the left, ~128 is the center, 255 horizontally across the canvas (0 is the left, ~128 is the center, 255
is the right). is the right).
These are the exact values Tux Paint's "playsound()" wants, to determine 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 what speaker to play the sound in. (So the sound will pan from speaker
to speaker as you drag the mouse around the canvas!) to speaker as you drag the mouse around the canvas!)
*/ */
api->playsound(sound_effects[which], api->playsound(sound_effects[which], (x * 255) / canvas->w, /* Left/right pan */
(x * 255) / canvas->w, /* Left/right pan */ 255 /* Near/far distance (loudness) */ );
255 /* Near/far distance (loudness) */);
} }
@ -508,9 +509,9 @@ example_release(magic_api * api, int which,
SDL_Rect * update_rect) SDL_Rect * update_rect)
{ {
/* /*
Neither of our effects do anything special when the mouse is released 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... from a click or click-and-drag, so there's no code here...
*/ */
} }
@ -526,12 +527,14 @@ changes their chosen, we'll be informed of that as well.
The color comes in as RGB (red, green, and blue) values from 0 (darkest) to The color comes in as RGB (red, green, and blue) values from 0 (darkest) to
255 (brightest). 255 (brightest).
*/ */
void example_set_color(magic_api * api, int which, SDL_Surface * canvas, SDL_Surface * snapshot, Uint8 r, Uint8 g, Uint8 b, SDL_Rect * update_rect) void example_set_color(magic_api * api, int which, SDL_Surface * canvas,
SDL_Surface * snapshot, Uint8 r, Uint8 g, Uint8 b,
SDL_Rect * update_rect)
{ {
/* /*
We simply store the RGB values in the global variables we declared at We simply store the RGB values in the global variables we declared at
the top of this file. the top of this file.
*/ */
example_r = r; example_r = r;
example_g = g; example_g = g;
@ -551,12 +554,14 @@ that as well.
The size comes in as an unsigned integer (Uint8) between 1 and the value The size comes in as an unsigned integer (Uint8) between 1 and the value
returned by our example_accepted_sizes() function during setup. returned by our example_accepted_sizes() function during setup.
*/ */
void example_set_size(magic_api * api, int which, int mode, SDL_Surface * canvas, SDL_Surface * snapshot, Uint8 size, SDL_Rect * update_rect) void example_set_size(magic_api * api, int which, int mode,
SDL_Surface * canvas, SDL_Surface * snapshot,
Uint8 size, SDL_Rect * update_rect)
{ {
/* /*
Store the new size into the global variable we declared at the top of Store the new size into the global variable we declared at the top of
this file. this file.
*/ */
example_size = size * 4; example_size = size * 4;
} }
@ -580,51 +585,51 @@ Our callback pays attention to 'which' to determine which of our plugin's
tools is currently selected. tools is currently selected.
*/ */
void example_line_callback(void *pointer, int which, SDL_Surface * canvas, void example_line_callback(void *pointer, int which, SDL_Surface * canvas,
SDL_Surface * snapshot, int x, int y) SDL_Surface * snapshot, int x, int y)
{ {
/* /*
For technical reasons, we can't accept a pointer to the Tux Paint API's For technical reasons, we can't accept a pointer to the Tux Paint API's
"magic_api" struct, like the other functions do. "magic_api" struct, like the other functions do.
Instead, we receive a 'generic' pointer (a "void *"). The line below Instead, we receive a 'generic' pointer (a "void *"). The line below
declares a local "magic_api" pointer variable called "api", and then declares a local "magic_api" pointer variable called "api", and then
assigns it to the value of the 'generic' pointer we received. assigns it to the value of the 'generic' pointer we received.
The "(magic_api *)" seen below casts the generic "void *" pointer into The "(magic_api *)" seen below casts the generic "void *" pointer into
the 'type' of pointer we want, a pointer to a "magic_api" struct.) the 'type' of pointer we want, a pointer to a "magic_api" struct.)
*/ */
magic_api *api = (magic_api *) pointer; magic_api *api = (magic_api *) pointer;
int xx, yy; int xx, yy;
/* /*
This function handles both of our tools, so we need to check which is 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 being used right now. We compare the 'which' argument that Tux Paint
sends to us with the values we enumerated above. sends to us with the values we enumerated above.
*/ */
if (which == TOOL_ONE) if (which == TOOL_ONE)
{ {
/* /*
Tool number 1 simply draws a single pixel at the (x,y) location. It acts Tool number 1 simply draws a single pixel at the (x,y) location. It acts
as a 1x1 pixel brush. as a 1x1 pixel brush.
*/ */
api->putpixel(canvas, x, y, api->putpixel(canvas, x, y,
SDL_MapRGB(canvas->format, SDL_MapRGB(canvas->format,
example_r, example_g, example_b)); example_r, example_g, example_b));
/* /*
We use "SDL_MapRGB()" to convert the RGB value we receive from Tux Paint 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 for the user's current color selection to a 'Uint32' pixel value we can
send to Tux Paint's "putpixel()" function. send to Tux Paint's "putpixel()" function.
*/ */
} }
else if (which == TOOL_TWO) else if (which == TOOL_TWO)
{ {
/* /*
Tool number 2 copies a square of pixels (of the size chosen by the user) Tool number 2 copies a square of pixels (of the size chosen by the user)
from the opposite side of the canvas and puts it under the cursor. from the opposite side of the canvas and puts it under the cursor.
*/ */
for (yy = -example_size; yy < example_size; yy++) for (yy = -example_size; yy < example_size; yy++)
{ {
@ -636,14 +641,14 @@ void example_line_callback(void *pointer, int which, SDL_Surface * canvas,
snapshot->h - y - yy)); snapshot->h - y - yy));
/* /*
Here we have simply use Tux Paint's "getpixel()" routine to pull pixel Here we have simply use Tux Paint's "getpixel()" routine to pull pixel
values from the 'snapshot', and then "putpixel()" to draw them right values from the 'snapshot', and then "putpixel()" to draw them right
into the 'canvas'. into the 'canvas'.
Note: putpixel() and getpixel() are safe to use, even if your X,Y values 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 are outside of the SDL surface (e.g., negative, or greater than the
surface's width and/or height). surface's width and/or height).
*/ */
} }
} }
} }

View file

@ -9,12 +9,12 @@
/* ---------------------------------------------------------------------- */ /* ---------------------------------------------------------------------- */
#include <stdio.h> #include <stdio.h>
#include <string.h> // Fyrir "strdup()" #include <string.h> // Fyrir "strdup()"
#include <libintl.h> // Fyrir "gettext()" #include <libintl.h> // Fyrir "gettext()"
#include "tp_magic_api.h" // Tux Paint "Magic" tool API header #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_image.h" // For IMG_Load(), to load our PNG icon
#include "SDL_mixer.h" // For Mix_LoadWAV(), to load our sound effects #include "SDL_mixer.h" // For Mix_LoadWAV(), to load our sound effects
/* Tool Enumerations: */ /* Tool Enumerations: */
@ -25,9 +25,9 @@
enum enum
{ {
TOOL_ONE, // Becomes '0' TOOL_ONE, // Becomes '0'
TOOL_TWO, // Becomes '1' TOOL_TWO, // Becomes '1'
NUM_TOOLS // Becomes '2' NUM_TOOLS // Becomes '2'
}; };
@ -101,11 +101,11 @@ _before_ them.
*/ */
void example_drag(magic_api * api, int which, SDL_Surface * canvas, void example_drag(magic_api * api, int which, SDL_Surface * canvas,
SDL_Surface * skjamynd, int old_x, int old_y, int x, int y, SDL_Surface * skjamynd, int old_x, int old_y, int x, int y,
SDL_Rect * update_rect); SDL_Rect * update_rect);
void example_line_callback(void *pointer, int which, SDL_Surface * canvas, void example_line_callback(void *pointer, int which, SDL_Surface * canvas,
SDL_Surface * skjamynd, int x, int y); SDL_Surface * skjamynd, int x, int y);
/* Setup Functions: */ /* Setup Functions: */
@ -144,7 +144,8 @@ released, aka deallocated) when the user quits Tux Paint, when our
example_shutdown() function is called. example_shutdown() function is called.
*/ */
int example_init(magic_api * api, Uint8 disabled_features, Uint8 complexity_level) int example_init(magic_api * api, Uint8 disabled_features,
Uint8 complexity_level)
{ {
int i; int i;
char filename[1024]; char filename[1024];
@ -152,15 +153,15 @@ int example_init(magic_api * api, Uint8 disabled_features, Uint8 complexity_leve
for (i = 0; i < NUM_TOOLS; i++) for (i = 0; i < NUM_TOOLS; i++)
{ {
/* /*
Assemble the filename from the "sound_filenames[]" array into a full path Assemble the filename from the "sound_filenames[]" array into a full path
to a real file. to a real file.
Use "api->data_directory" to figure out where our sounds should be. (The 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 "tp-magic-config --dataprefix" command would have told us when we installed
our plugin and its data.) our plugin and its data.)
*/ */
snprintf(filename, sizeof(filename), "%ssounds/magic/%s", api->data_directory, snprintf(filename, sizeof(filename), "%ssounds/magic/%s",
sound_filenames[i]); api->data_directory, sound_filenames[i]);
printf("Trying to load %s sound file\n", filename); printf("Trying to load %s sound file\n", filename);
@ -200,16 +201,16 @@ SDL_Surface *example_get_icon(magic_api * api, int which)
char filename[1024]; char filename[1024];
/* /*
Assemble the filename from the "icon_filenames[]" array into a full path to Assemble the filename from the "icon_filenames[]" array into a full path to
a real file. a real file.
Use "api->data_directory" to figure out where our sounds should be. (The 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 "tp-magic-config --dataprefix" command would have told us when we installed
our plugin and its data.) our plugin and its data.)
We use "which" (which of our tools Tux Paint is asking about) as an index We use "which" (which of our tools Tux Paint is asking about) as an index
into the array. into the array.
*/ */
snprintf(filename, sizeof(filename), "%simages/magic/%s", snprintf(filename, sizeof(filename), "%simages/magic/%s",
api->data_directory, icon_filenames[which]); api->data_directory, icon_filenames[which]);
@ -229,31 +230,31 @@ names (labels) for the 'Magic' tool buttons.
*/ */
char *example_get_name(magic_api * api, int which) char *example_get_name(magic_api * api, int which)
{ {
const char *our_name_english; const char *our_name_english;
const char *our_name_localized; const char *our_name_localized;
/* /*
Get our name from the "tool_names[]" array. Get our name from the "tool_names[]" array.
We use 'which' (which of our tools Tux Paint is asking about) as an index We use 'which' (which of our tools Tux Paint is asking about) as an index
into the array. into the array.
*/ */
our_name_english = tool_names[which]; our_name_english = tool_names[which];
/* /*
Return a localized (aka translated) version of our name, if possible. Return a localized (aka translated) version of our name, if possible.
We send "gettext()" the English version of the name from our array. We send "gettext()" the English version of the name from our array.
*/ */
our_name_localized = gettext(our_name_english); our_name_localized = gettext(our_name_english);
/* /*
Finally, duplicate the string into a new section of memory, and send it to 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, 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.) so we have one less thing to keep track of.)
*/ */
return (strdup(our_name_localized)); return (strdup(our_name_localized));
} }
@ -267,11 +268,11 @@ where the tool should be grouped.
int example_get_group(magic_api * api, int which) int example_get_group(magic_api * api, int which)
{ {
/* /*
Return our group, found in the "tool_groups[]" array. Return our group, found in the "tool_groups[]" array.
We use 'which' (which of our tools Tux Paint is asking about) as an index We use 'which' (which of our tools Tux Paint is asking about) as an index
into the array. into the array.
*/ */
return (tool_groups[which]); return (tool_groups[which]);
} }
@ -302,28 +303,28 @@ char *example_get_description(magic_api * api, int which, int hamur)
const char *our_desc_localized; const char *our_desc_localized;
/* /*
Get our description from the "tool_descriptions[]" array. Get our description from the "tool_descriptions[]" array.
We use 'which' (which of our tools Tux Paint is asking about) as an index We use 'which' (which of our tools Tux Paint is asking about) as an index
into the array. into the array.
*/ */
our_desc_english = tool_descriptions[which]; our_desc_english = tool_descriptions[which];
/* /*
Return a localized (aka translated) version of our description, if Return a localized (aka translated) version of our description, if
possible. possible.
We send "gettext" the English version of the description from our array. We send "gettext" the English version of the description from our array.
*/ */
our_desc_localized = gettext(our_desc_english); our_desc_localized = gettext(our_desc_english);
/* /*
Finally, duplicate the string into a new section of memory, and send it to 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, 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.) so we have one less thing to keep track of.)
*/ */
return (strdup(our_desc_localized)); return (strdup(our_desc_localized));
} }
@ -345,9 +346,9 @@ int example_requires_colors(magic_api * api, int which)
int example_modes(magic_api * api, int which) int example_modes(magic_api * api, int which)
{ {
/* /*
Both of our tools are painted (neither affect the full-screen), so we're Both of our tools are painted (neither affect the full-screen), so we're
always returning 'MODE_PAINT' always returning 'MODE_PAINT'
*/ */
return MODE_PAINT; return MODE_PAINT;
} }
@ -385,9 +386,9 @@ void example_shutdown(magic_api * api)
int i; int i;
/* /*
Free (aka release, aka deallocate) the memory used to store the sound Free (aka release, aka deallocate) the memory used to store the sound
effects that we loaded during example_init(): effects that we loaded during example_init():
*/ */
for (i = 0; i < NUM_TOOLS; i++) for (i = 0; i < NUM_TOOLS; i++)
Mix_FreeChunk(sound_effects[i]); Mix_FreeChunk(sound_effects[i]);
} }
@ -404,13 +405,13 @@ example_click(magic_api * api, int which, int hamur,
SDL_Rect * update_rect) SDL_Rect * update_rect)
{ {
/* /*
In our case, a single click (which is also the start of a drag!) is 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 identical to what dragging does, but just at one point, rather than across
a line. a line.
So we 'cheat' here, by calling our "example_draw()" function with (x,y) for So we 'cheat' here, by calling our "example_draw()" function with (x,y) for
both the beginning and end points of a line. both the beginning and end points of a line.
*/ */
example_drag(api, which, canvas, skjamynd, x, y, x, y, update_rect); example_drag(api, which, canvas, skjamynd, x, y, x, y, update_rect);
} }
@ -420,34 +421,32 @@ example_click(magic_api * api, int which, int hamur,
void void
example_drag(magic_api * api, int which, example_drag(magic_api * api, int which,
SDL_Surface * canvas, SDL_Surface * skjamynd, SDL_Surface * canvas, SDL_Surface * skjamynd,
int old_x, int old_y, int x, int y, int old_x, int old_y, int x, int y, SDL_Rect * update_rect)
SDL_Rect * update_rect)
{ {
/* /*
Call Tux Paint's "line()" (line-traversing) function. Call Tux Paint's "line()" (line-traversing) function.
It will calculate a straight line between (old_x,old_y) and (x,y). Every It will calculate a straight line between (old_x,old_y) and (x,y). Every
N steps along that line (in this case, N is '1'), it will call _our_ 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 function, "example_line_callback()", and send the current X,Y
coordinates along the line, as well as other useful things (which of our coordinates along the line, as well as other useful things (which of our
'Magic' tools is being used and the current and snapshot canvases). 'Magic' tools is being used and the current and snapshot canvases).
*/ */
SDL_LockSurface(skjamynd); SDL_LockSurface(skjamynd);
SDL_LockSurface(canvas); SDL_LockSurface(canvas);
api->line((void *) api, which, canvas, skjamynd, api->line((void *) api, which, canvas, skjamynd,
old_x, old_y, x, y, 1, old_x, old_y, x, y, 1, example_line_callback);
example_line_callback);
SDL_UnlockSurface(canvas); SDL_UnlockSurface(canvas);
SDL_UnlockSurface(skjamynd); SDL_UnlockSurface(skjamynd);
/* /*
If we need to, swap the X and/or Y values, so that the coordinates If we need to, swap the X and/or Y values, so that the coordinates
(old_x,old_y) is always the top left, and the coordinates (x,y) is (old_x,old_y) is always the top left, and the coordinates (x,y) is
always the bottom right, so the values we put inside "update_rect" make always the bottom right, so the values we put inside "update_rect" make
sense: sense:
*/ */
if (old_x > x) if (old_x > x)
{ {
@ -466,17 +465,20 @@ example_drag(magic_api * api, int which,
/* /*
Fill in the elements of the "update_rect" SDL_Rect structure that Tux Fill in the elements of the "update_rect" SDL_Rect structure that Tux
Paint is sharing with us, therefore telling Tux Paint which part of the Paint is sharing with us, therefore telling Tux Paint which part of the
canvas has been modified and should be updated. canvas has been modified and should be updated.
*/ */
if (which == TOOL_ONE) { if (which == TOOL_ONE)
{
update_rect->x = old_x; update_rect->x = old_x;
update_rect->y = old_y; update_rect->y = old_y;
update_rect->w = (x - old_x) + 1; update_rect->w = (x - old_x) + 1;
update_rect->h = (y - old_y) + 1; update_rect->h = (y - old_y) + 1;
} else { }
else
{
update_rect->x = old_x - example_staerd; update_rect->x = old_x - example_staerd;
update_rect->y = old_y - example_staerd; update_rect->y = old_y - example_staerd;
update_rect->w = (x + example_staerd) - update_rect->x + 1; update_rect->w = (x + example_staerd) - update_rect->x + 1;
@ -484,19 +486,18 @@ example_drag(magic_api * api, int which,
} }
/* /*
Play the appropriate sound effect Play the appropriate sound effect
We're calculating a value between 0-255 for where the mouse is We're calculating a value between 0-255 for where the mouse is
horizontally across the canvas (0 is the left, ~128 is the center, 255 horizontally across the canvas (0 is the left, ~128 is the center, 255
is the right). is the right).
These are the exact values Tux Paint's "playsound()" wants, to determine 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 what speaker to play the sound in. (So the sound will pan from speaker
to speaker as you drag the mouse around the canvas!) to speaker as you drag the mouse around the canvas!)
*/ */
api->playsound(sound_effects[which], api->playsound(sound_effects[which], (x * 255) / canvas->w, /* vinstri/hægri hliðrun */
(x * 255) / canvas->w, /* vinstri/hægri hliðrun */ 255 /* Near/far distance (loudness) */ );
255 /* Near/far distance (loudness) */);
} }
@ -508,9 +509,9 @@ example_release(magic_api * api, int which,
SDL_Rect * update_rect) SDL_Rect * update_rect)
{ {
/* /*
Neither of our effects do anything special when the mouse is released 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... from a click or click-and-drag, so there's no code here...
*/ */
} }
@ -526,12 +527,14 @@ changes their chosen, we'll be informed of that as well.
The color comes in as RGB (red, green, and blue) values from 0 (darkest) to The color comes in as RGB (red, green, and blue) values from 0 (darkest) to
255 (brightest). 255 (brightest).
*/ */
void example_set_color(magic_api * api, int which, SDL_Surface * canvas, SDL_Surface * skjamynd, Uint8 r, Uint8 g, Uint8 b, SDL_Rect * update_rect) void example_set_color(magic_api * api, int which, SDL_Surface * canvas,
SDL_Surface * skjamynd, Uint8 r, Uint8 g, Uint8 b,
SDL_Rect * update_rect)
{ {
/* /*
We simply store the RGB values in the global variables we declared at We simply store the RGB values in the global variables we declared at
the top of this file. the top of this file.
*/ */
example_r = r; example_r = r;
example_g = g; example_g = g;
@ -551,12 +554,14 @@ that as well.
The size comes in as an unsigned integer (Uint8) between 1 and the value The size comes in as an unsigned integer (Uint8) between 1 and the value
returned by our example_accepted_sizes() function during setup. returned by our example_accepted_sizes() function during setup.
*/ */
void example_set_size(magic_api * api, int which, int mode, SDL_Surface * canvas, SDL_Surface * skjamynd, Uint8 staerd, SDL_Rect * update_rect) void example_set_size(magic_api * api, int which, int mode,
SDL_Surface * canvas, SDL_Surface * skjamynd,
Uint8 staerd, SDL_Rect * update_rect)
{ {
/* /*
Store the new size into the global variable we declared at the top of Store the new size into the global variable we declared at the top of
this file. this file.
*/ */
example_staerd = staerd * 4; example_staerd = staerd * 4;
} }
@ -580,51 +585,51 @@ Our callback pays attention to 'which' to determine which of our plugin's
tools is currently selected. tools is currently selected.
*/ */
void example_line_callback(void *pointer, int which, SDL_Surface * canvas, void example_line_callback(void *pointer, int which, SDL_Surface * canvas,
SDL_Surface * skjamynd, int x, int y) SDL_Surface * skjamynd, int x, int y)
{ {
/* /*
For technical reasons, we can't accept a pointer to the Tux Paint API's For technical reasons, we can't accept a pointer to the Tux Paint API's
"magic_api" struct, like the other functions do. "magic_api" struct, like the other functions do.
Instead, we receive a 'generic' pointer (a "void *"). The line below Instead, we receive a 'generic' pointer (a "void *"). The line below
declares a local "magic_api" pointer variable called "api", and then declares a local "magic_api" pointer variable called "api", and then
assigns it to the value of the 'generic' pointer we received. assigns it to the value of the 'generic' pointer we received.
The "(magic_api *)" seen below casts the generic "void *" pointer into The "(magic_api *)" seen below casts the generic "void *" pointer into
the 'type' of pointer we want, a pointer to a "magic_api" struct.) the 'type' of pointer we want, a pointer to a "magic_api" struct.)
*/ */
magic_api *api = (magic_api *) pointer; magic_api *api = (magic_api *) pointer;
int xx, yy; int xx, yy;
/* /*
This function handles both of our tools, so we need to check which is 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 being used right now. We compare the 'which' argument that Tux Paint
sends to us with the values we enumerated above. sends to us with the values we enumerated above.
*/ */
if (which == TOOL_ONE) if (which == TOOL_ONE)
{ {
/* /*
Tool number 1 simply draws a single pixel at the (x,y) location. It acts Tool number 1 simply draws a single pixel at the (x,y) location. It acts
as a 1x1 pixel brush. as a 1x1 pixel brush.
*/ */
api->putpixel(canvas, x, y, api->putpixel(canvas, x, y,
SDL_MapRGB(canvas->format, SDL_MapRGB(canvas->format,
example_r, example_g, example_b)); example_r, example_g, example_b));
/* /*
We use "SDL_MapRGB()" to convert the RGB value we receive from Tux Paint 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 for the user's current color selection to a 'Uint32' pixel value we can
send to Tux Paint's "putpixel()" function. send to Tux Paint's "putpixel()" function.
*/ */
} }
else if (which == TOOL_TWO) else if (which == TOOL_TWO)
{ {
/* /*
Tool number 2 copies a square of pixels (of the size chosen by the user) Tool number 2 copies a square of pixels (of the size chosen by the user)
from the opposite side of the canvas and puts it under the cursor. from the opposite side of the canvas and puts it under the cursor.
*/ */
for (yy = -example_staerd; yy < example_staerd; yy++) for (yy = -example_staerd; yy < example_staerd; yy++)
{ {
@ -636,14 +641,14 @@ void example_line_callback(void *pointer, int which, SDL_Surface * canvas,
skjamynd->h - y - yy)); skjamynd->h - y - yy));
/* /*
Here we have simply use Tux Paint's "getpixel()" routine to pull pixel Here we have simply use Tux Paint's "getpixel()" routine to pull pixel
values from the 'snapshot', and then "putpixel()" to draw them right values from the 'snapshot', and then "putpixel()" to draw them right
into the 'canvas'. into the 'canvas'.
Note: putpixel() and getpixel() are safe to use, even if your X,Y values 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 are outside of the SDL surface (e.g., negative, or greater than the
surface's width and/or height). surface's width and/or height).
*/ */
} }
} }
} }

View file

@ -9,12 +9,12 @@
/* ---------------------------------------------------------------------- */ /* ---------------------------------------------------------------------- */
#include <stdio.h> #include <stdio.h>
#include <string.h> // Fyrir "strdup()" #include <string.h> // Fyrir "strdup()"
#include <libintl.h> // Fyrir "gettext()" #include <libintl.h> // Fyrir "gettext()"
#include "tp_magic_api.h" // Tux Paint "Magic" tool API header #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_image.h" // For IMG_Load(), to load our PNG icon
#include "SDL_mixer.h" // For Mix_LoadWAV(), to load our sound effects #include "SDL_mixer.h" // For Mix_LoadWAV(), to load our sound effects
/* Tool Enumerations: */ /* Tool Enumerations: */
@ -25,9 +25,9 @@
enum enum
{ {
TOOL_ONE, // Becomes '0' TOOL_ONE, // Becomes '0'
TOOL_TWO, // Becomes '1' TOOL_TWO, // Becomes '1'
NUM_TOOLS // Becomes '2' NUM_TOOLS // Becomes '2'
}; };
@ -101,11 +101,11 @@ _before_ them.
*/ */
void example_drag(magic_api * api, int which, SDL_Surface * canvas, void example_drag(magic_api * api, int which, SDL_Surface * canvas,
SDL_Surface * skjamynd, int old_x, int old_y, int x, int y, SDL_Surface * skjamynd, int old_x, int old_y, int x, int y,
SDL_Rect * update_rect); SDL_Rect * update_rect);
void example_line_callback(void *pointer, int which, SDL_Surface * canvas, void example_line_callback(void *pointer, int which, SDL_Surface * canvas,
SDL_Surface * skjamynd, int x, int y); SDL_Surface * skjamynd, int x, int y);
/* Setup Functions: */ /* Setup Functions: */
@ -144,7 +144,8 @@ released, aka deallocated) when the user quits Tux Paint, when our
example_shutdown() function is called. example_shutdown() function is called.
*/ */
int example_init(magic_api * api, Uint8 disabled_features, Uint8 complexity_level) int example_init(magic_api * api, Uint8 disabled_features,
Uint8 complexity_level)
{ {
int i; int i;
char filename[1024]; char filename[1024];
@ -152,15 +153,15 @@ int example_init(magic_api * api, Uint8 disabled_features, Uint8 complexity_leve
for (i = 0; i < NUM_TOOLS; i++) for (i = 0; i < NUM_TOOLS; i++)
{ {
/* /*
Assemble the filename from the "sound_filenames[]" array into a full path Assemble the filename from the "sound_filenames[]" array into a full path
to a real file. to a real file.
Use "api->data_directory" to figure out where our sounds should be. (The 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 "tp-magic-config --dataprefix" command would have told us when we installed
our plugin and its data.) our plugin and its data.)
*/ */
snprintf(filename, sizeof(filename), "%ssounds/magic/%s", api->data_directory, snprintf(filename, sizeof(filename), "%ssounds/magic/%s",
sound_filenames[i]); api->data_directory, sound_filenames[i]);
printf("Trying to load %s sound file\n", filename); printf("Trying to load %s sound file\n", filename);
@ -200,16 +201,16 @@ SDL_Surface *example_get_icon(magic_api * api, int which)
char filename[1024]; char filename[1024];
/* /*
Assemble the filename from the "icon_filenames[]" array into a full path to Assemble the filename from the "icon_filenames[]" array into a full path to
a real file. a real file.
Use "api->data_directory" to figure out where our sounds should be. (The 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 "tp-magic-config --dataprefix" command would have told us when we installed
our plugin and its data.) our plugin and its data.)
We use "which" (which of our tools Tux Paint is asking about) as an index We use "which" (which of our tools Tux Paint is asking about) as an index
into the array. into the array.
*/ */
snprintf(filename, sizeof(filename), "%simages/magic/%s", snprintf(filename, sizeof(filename), "%simages/magic/%s",
api->data_directory, icon_filenames[which]); api->data_directory, icon_filenames[which]);
@ -229,31 +230,31 @@ names (labels) for the 'Magic' tool buttons.
*/ */
char *example_get_name(magic_api * api, int which) char *example_get_name(magic_api * api, int which)
{ {
const char *our_name_english; const char *our_name_english;
const char *our_name_localized; const char *our_name_localized;
/* /*
Get our name from the "tool_names[]" array. Get our name from the "tool_names[]" array.
We use 'which' (which of our tools Tux Paint is asking about) as an index We use 'which' (which of our tools Tux Paint is asking about) as an index
into the array. into the array.
*/ */
our_name_english = tool_names[which]; our_name_english = tool_names[which];
/* /*
Return a localized (aka translated) version of our name, if possible. Return a localized (aka translated) version of our name, if possible.
We send "gettext()" the English version of the name from our array. We send "gettext()" the English version of the name from our array.
*/ */
our_name_localized = gettext(our_name_english); our_name_localized = gettext(our_name_english);
/* /*
Finally, duplicate the string into a new section of memory, and send it to 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, 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.) so we have one less thing to keep track of.)
*/ */
return (strdup(our_name_localized)); return (strdup(our_name_localized));
} }
@ -267,11 +268,11 @@ where the tool should be grouped.
int example_get_group(magic_api * api, int which) int example_get_group(magic_api * api, int which)
{ {
/* /*
Return our group, found in the "tool_groups[]" array. Return our group, found in the "tool_groups[]" array.
We use 'which' (which of our tools Tux Paint is asking about) as an index We use 'which' (which of our tools Tux Paint is asking about) as an index
into the array. into the array.
*/ */
return (tool_groups[which]); return (tool_groups[which]);
} }
@ -302,28 +303,28 @@ char *example_get_description(magic_api * api, int which, int hamur)
const char *our_desc_localized; const char *our_desc_localized;
/* /*
Get our description from the "tool_descriptions[]" array. Get our description from the "tool_descriptions[]" array.
We use 'which' (which of our tools Tux Paint is asking about) as an index We use 'which' (which of our tools Tux Paint is asking about) as an index
into the array. into the array.
*/ */
our_desc_english = tool_descriptions[which]; our_desc_english = tool_descriptions[which];
/* /*
Return a localized (aka translated) version of our description, if Return a localized (aka translated) version of our description, if
possible. possible.
We send "gettext" the English version of the description from our array. We send "gettext" the English version of the description from our array.
*/ */
our_desc_localized = gettext(our_desc_english); our_desc_localized = gettext(our_desc_english);
/* /*
Finally, duplicate the string into a new section of memory, and send it to 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, 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.) so we have one less thing to keep track of.)
*/ */
return (strdup(our_desc_localized)); return (strdup(our_desc_localized));
} }
@ -345,9 +346,9 @@ int example_requires_colors(magic_api * api, int which)
int example_modes(magic_api * api, int which) int example_modes(magic_api * api, int which)
{ {
/* /*
Both of our tools are painted (neither affect the full-screen), so we're Both of our tools are painted (neither affect the full-screen), so we're
always returning 'MODE_PAINT' always returning 'MODE_PAINT'
*/ */
return MODE_PAINT; return MODE_PAINT;
} }
@ -385,9 +386,9 @@ void example_shutdown(magic_api * api)
int i; int i;
/* /*
Free (aka release, aka deallocate) the memory used to store the sound Free (aka release, aka deallocate) the memory used to store the sound
effects that we loaded during example_init(): effects that we loaded during example_init():
*/ */
for (i = 0; i < NUM_TOOLS; i++) for (i = 0; i < NUM_TOOLS; i++)
Mix_FreeChunk(sound_effects[i]); Mix_FreeChunk(sound_effects[i]);
} }
@ -404,13 +405,13 @@ example_click(magic_api * api, int which, int hamur,
SDL_Rect * update_rect) SDL_Rect * update_rect)
{ {
/* /*
In our case, a single click (which is also the start of a drag!) is 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 identical to what dragging does, but just at one point, rather than across
a line. a line.
So we 'cheat' here, by calling our "example_draw()" function with (x,y) for So we 'cheat' here, by calling our "example_draw()" function with (x,y) for
both the beginning and end points of a line. both the beginning and end points of a line.
*/ */
example_drag(api, which, canvas, skjamynd, x, y, x, y, update_rect); example_drag(api, which, canvas, skjamynd, x, y, x, y, update_rect);
} }
@ -420,34 +421,32 @@ example_click(magic_api * api, int which, int hamur,
void void
example_drag(magic_api * api, int which, example_drag(magic_api * api, int which,
SDL_Surface * canvas, SDL_Surface * skjamynd, SDL_Surface * canvas, SDL_Surface * skjamynd,
int old_x, int old_y, int x, int y, int old_x, int old_y, int x, int y, SDL_Rect * update_rect)
SDL_Rect * update_rect)
{ {
/* /*
Call Tux Paint's "line()" (line-traversing) function. Call Tux Paint's "line()" (line-traversing) function.
It will calculate a straight line between (old_x,old_y) and (x,y). Every It will calculate a straight line between (old_x,old_y) and (x,y). Every
N steps along that line (in this case, N is '1'), it will call _our_ 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 function, "example_line_callback()", and send the current X,Y
coordinates along the line, as well as other useful things (which of our coordinates along the line, as well as other useful things (which of our
'Magic' tools is being used and the current and snapshot canvases). 'Magic' tools is being used and the current and snapshot canvases).
*/ */
SDL_LockSurface(skjamynd); SDL_LockSurface(skjamynd);
SDL_LockSurface(canvas); SDL_LockSurface(canvas);
api->line((void *) api, which, canvas, skjamynd, api->line((void *) api, which, canvas, skjamynd,
old_x, old_y, x, y, 1, old_x, old_y, x, y, 1, example_line_callback);
example_line_callback);
SDL_UnlockSurface(canvas); SDL_UnlockSurface(canvas);
SDL_UnlockSurface(skjamynd); SDL_UnlockSurface(skjamynd);
/* /*
If we need to, swap the X and/or Y values, so that the coordinates If we need to, swap the X and/or Y values, so that the coordinates
(old_x,old_y) is always the top left, and the coordinates (x,y) is (old_x,old_y) is always the top left, and the coordinates (x,y) is
always the bottom right, so the values we put inside "update_rect" make always the bottom right, so the values we put inside "update_rect" make
sense: sense:
*/ */
if (old_x > x) if (old_x > x)
{ {
@ -466,17 +465,20 @@ example_drag(magic_api * api, int which,
/* /*
Fill in the elements of the "update_rect" SDL_Rect structure that Tux Fill in the elements of the "update_rect" SDL_Rect structure that Tux
Paint is sharing with us, therefore telling Tux Paint which part of the Paint is sharing with us, therefore telling Tux Paint which part of the
canvas has been modified and should be updated. canvas has been modified and should be updated.
*/ */
if (which == TOOL_ONE) { if (which == TOOL_ONE)
{
update_rect->x = old_x; update_rect->x = old_x;
update_rect->y = old_y; update_rect->y = old_y;
update_rect->w = (x - old_x) + 1; update_rect->w = (x - old_x) + 1;
update_rect->h = (y - old_y) + 1; update_rect->h = (y - old_y) + 1;
} else { }
else
{
update_rect->x = old_x - example_staerd; update_rect->x = old_x - example_staerd;
update_rect->y = old_y - example_staerd; update_rect->y = old_y - example_staerd;
update_rect->w = (x + example_staerd) - update_rect->x + 1; update_rect->w = (x + example_staerd) - update_rect->x + 1;
@ -484,19 +486,18 @@ example_drag(magic_api * api, int which,
} }
/* /*
Play the appropriate sound effect Play the appropriate sound effect
We're calculating a value between 0-255 for where the mouse is We're calculating a value between 0-255 for where the mouse is
horizontally across the canvas (0 is the left, ~128 is the center, 255 horizontally across the canvas (0 is the left, ~128 is the center, 255
is the right). is the right).
These are the exact values Tux Paint's "playsound()" wants, to determine 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 what speaker to play the sound in. (So the sound will pan from speaker
to speaker as you drag the mouse around the canvas!) to speaker as you drag the mouse around the canvas!)
*/ */
api->playsound(sound_effects[which], api->playsound(sound_effects[which], (x * 255) / canvas->w, /* vinstri/hægri hliðrun */
(x * 255) / canvas->w, /* vinstri/hægri hliðrun */ 255 /* Near/far distance (loudness) */ );
255 /* Near/far distance (loudness) */);
} }
@ -508,9 +509,9 @@ example_release(magic_api * api, int which,
SDL_Rect * update_rect) SDL_Rect * update_rect)
{ {
/* /*
Neither of our effects do anything special when the mouse is released 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... from a click or click-and-drag, so there's no code here...
*/ */
} }
@ -526,12 +527,14 @@ changes their chosen, we'll be informed of that as well.
The color comes in as RGB (red, green, and blue) values from 0 (darkest) to The color comes in as RGB (red, green, and blue) values from 0 (darkest) to
255 (brightest). 255 (brightest).
*/ */
void example_set_color(magic_api * api, int which, SDL_Surface * canvas, SDL_Surface * skjamynd, Uint8 r, Uint8 g, Uint8 b, SDL_Rect * update_rect) void example_set_color(magic_api * api, int which, SDL_Surface * canvas,
SDL_Surface * skjamynd, Uint8 r, Uint8 g, Uint8 b,
SDL_Rect * update_rect)
{ {
/* /*
We simply store the RGB values in the global variables we declared at We simply store the RGB values in the global variables we declared at
the top of this file. the top of this file.
*/ */
example_r = r; example_r = r;
example_g = g; example_g = g;
@ -551,12 +554,14 @@ that as well.
The size comes in as an unsigned integer (Uint8) between 1 and the value The size comes in as an unsigned integer (Uint8) between 1 and the value
returned by our example_accepted_sizes() function during setup. returned by our example_accepted_sizes() function during setup.
*/ */
void example_set_size(magic_api * api, int which, int mode, SDL_Surface * canvas, SDL_Surface * skjamynd, Uint8 staerd, SDL_Rect * update_rect) void example_set_size(magic_api * api, int which, int mode,
SDL_Surface * canvas, SDL_Surface * skjamynd,
Uint8 staerd, SDL_Rect * update_rect)
{ {
/* /*
Store the new size into the global variable we declared at the top of Store the new size into the global variable we declared at the top of
this file. this file.
*/ */
example_staerd = staerd * 4; example_staerd = staerd * 4;
} }
@ -580,51 +585,51 @@ Our callback pays attention to 'which' to determine which of our plugin's
tools is currently selected. tools is currently selected.
*/ */
void example_line_callback(void *pointer, int which, SDL_Surface * canvas, void example_line_callback(void *pointer, int which, SDL_Surface * canvas,
SDL_Surface * skjamynd, int x, int y) SDL_Surface * skjamynd, int x, int y)
{ {
/* /*
For technical reasons, we can't accept a pointer to the Tux Paint API's For technical reasons, we can't accept a pointer to the Tux Paint API's
"magic_api" struct, like the other functions do. "magic_api" struct, like the other functions do.
Instead, we receive a 'generic' pointer (a "void *"). The line below Instead, we receive a 'generic' pointer (a "void *"). The line below
declares a local "magic_api" pointer variable called "api", and then declares a local "magic_api" pointer variable called "api", and then
assigns it to the value of the 'generic' pointer we received. assigns it to the value of the 'generic' pointer we received.
The "(magic_api *)" seen below casts the generic "void *" pointer into The "(magic_api *)" seen below casts the generic "void *" pointer into
the 'type' of pointer we want, a pointer to a "magic_api" struct.) the 'type' of pointer we want, a pointer to a "magic_api" struct.)
*/ */
magic_api *api = (magic_api *) pointer; magic_api *api = (magic_api *) pointer;
int xx, yy; int xx, yy;
/* /*
This function handles both of our tools, so we need to check which is 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 being used right now. We compare the 'which' argument that Tux Paint
sends to us with the values we enumerated above. sends to us with the values we enumerated above.
*/ */
if (which == TOOL_ONE) if (which == TOOL_ONE)
{ {
/* /*
Tool number 1 simply draws a single pixel at the (x,y) location. It acts Tool number 1 simply draws a single pixel at the (x,y) location. It acts
as a 1x1 pixel brush. as a 1x1 pixel brush.
*/ */
api->putpixel(canvas, x, y, api->putpixel(canvas, x, y,
SDL_MapRGB(canvas->format, SDL_MapRGB(canvas->format,
example_r, example_g, example_b)); example_r, example_g, example_b));
/* /*
We use "SDL_MapRGB()" to convert the RGB value we receive from Tux Paint 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 for the user's current color selection to a 'Uint32' pixel value we can
send to Tux Paint's "putpixel()" function. send to Tux Paint's "putpixel()" function.
*/ */
} }
else if (which == TOOL_TWO) else if (which == TOOL_TWO)
{ {
/* /*
Tool number 2 copies a square of pixels (of the size chosen by the user) Tool number 2 copies a square of pixels (of the size chosen by the user)
from the opposite side of the canvas and puts it under the cursor. from the opposite side of the canvas and puts it under the cursor.
*/ */
for (yy = -example_staerd; yy < example_staerd; yy++) for (yy = -example_staerd; yy < example_staerd; yy++)
{ {
@ -636,14 +641,14 @@ void example_line_callback(void *pointer, int which, SDL_Surface * canvas,
skjamynd->h - y - yy)); skjamynd->h - y - yy));
/* /*
Here we have simply use Tux Paint's "getpixel()" routine to pull pixel Here we have simply use Tux Paint's "getpixel()" routine to pull pixel
values from the 'snapshot', and then "putpixel()" to draw them right values from the 'snapshot', and then "putpixel()" to draw them right
into the 'canvas'. into the 'canvas'.
Note: putpixel() and getpixel() are safe to use, even if your X,Y values 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 are outside of the SDL surface (e.g., negative, or greater than the
surface's width and/or height). surface's width and/or height).
*/ */
} }
} }
} }

View file

@ -9,12 +9,12 @@
/* ---------------------------------------------------------------------- */ /* ---------------------------------------------------------------------- */
#include <stdio.h> #include <stdio.h>
#include <string.h> // For "strdup()" #include <string.h> // For "strdup()"
#include <libintl.h> // For "gettext()" #include <libintl.h> // For "gettext()"
#include "tp_magic_api.h" // Tux Paint "Magic" tool API header #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_image.h" // For IMG_Load(), to load our PNG icon
#include "SDL_mixer.h" // For Mix_LoadWAV(), to load our sound effects #include "SDL_mixer.h" // For Mix_LoadWAV(), to load our sound effects
/* Tool Enumerations: */ /* Tool Enumerations: */
@ -25,9 +25,9 @@
enum enum
{ {
TOOL_ONE, // Becomes '0' TOOL_ONE, // Becomes '0'
TOOL_TWO, // Becomes '1' TOOL_TWO, // Becomes '1'
NUM_TOOLS // Becomes '2' NUM_TOOLS // Becomes '2'
}; };
@ -101,11 +101,11 @@ _before_ them.
*/ */
void example_drag(magic_api * api, int which, SDL_Surface * canvas, void example_drag(magic_api * api, int which, SDL_Surface * canvas,
SDL_Surface * snapshot, int old_x, int old_y, int x, int y, SDL_Surface * snapshot, int old_x, int old_y, int x, int y,
SDL_Rect * update_rect); SDL_Rect * update_rect);
void example_line_callback(void *pointer, int which, SDL_Surface * canvas, void example_line_callback(void *pointer, int which, SDL_Surface * canvas,
SDL_Surface * snapshot, int x, int y); SDL_Surface * snapshot, int x, int y);
/* Setup Functions: */ /* Setup Functions: */
@ -144,7 +144,8 @@ released, aka deallocated) when the user quits Tux Paint, when our
example_shutdown() function is called. example_shutdown() function is called.
*/ */
int example_init(magic_api * api, Uint8 disabled_features, Uint8 complexity_level) int example_init(magic_api * api, Uint8 disabled_features,
Uint8 complexity_level)
{ {
int i; int i;
char filename[1024]; char filename[1024];
@ -152,15 +153,15 @@ int example_init(magic_api * api, Uint8 disabled_features, Uint8 complexity_leve
for (i = 0; i < NUM_TOOLS; i++) for (i = 0; i < NUM_TOOLS; i++)
{ {
/* /*
Assemble the filename from the "sound_filenames[]" array into a full path Assemble the filename from the "sound_filenames[]" array into a full path
to a real file. to a real file.
Use "api->data_directory" to figure out where our sounds should be. (The 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 "tp-magic-config --dataprefix" command would have told us when we installed
our plugin and its data.) our plugin and its data.)
*/ */
snprintf(filename, sizeof(filename), "%ssounds/magic/%s", api->data_directory, snprintf(filename, sizeof(filename), "%ssounds/magic/%s",
sound_filenames[i]); api->data_directory, sound_filenames[i]);
printf("Trying to load %s sound file\n", filename); printf("Trying to load %s sound file\n", filename);
@ -200,16 +201,16 @@ SDL_Surface *example_get_icon(magic_api * api, int which)
char filename[1024]; char filename[1024];
/* /*
Assemble the filename from the "icon_filenames[]" array into a full path to Assemble the filename from the "icon_filenames[]" array into a full path to
a real file. a real file.
Use "api->data_directory" to figure out where our sounds should be. (The 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 "tp-magic-config --dataprefix" command would have told us when we installed
our plugin and its data.) our plugin and its data.)
We use "which" (which of our tools Tux Paint is asking about) as an index We use "which" (which of our tools Tux Paint is asking about) as an index
into the array. into the array.
*/ */
snprintf(filename, sizeof(filename), "%simages/magic/%s", snprintf(filename, sizeof(filename), "%simages/magic/%s",
api->data_directory, icon_filenames[which]); api->data_directory, icon_filenames[which]);
@ -229,31 +230,31 @@ names (labels) for the 'Magic' tool buttons.
*/ */
char *example_get_name(magic_api * api, int which) char *example_get_name(magic_api * api, int which)
{ {
const char *our_name_english; const char *our_name_english;
const char *our_name_localized; const char *our_name_localized;
/* /*
Get our name from the "tool_names[]" array. Get our name from the "tool_names[]" array.
We use 'which' (which of our tools Tux Paint is asking about) as an index We use 'which' (which of our tools Tux Paint is asking about) as an index
into the array. into the array.
*/ */
our_name_english = tool_names[which]; our_name_english = tool_names[which];
/* /*
Return a localized (aka translated) version of our name, if possible. Return a localized (aka translated) version of our name, if possible.
We send "gettext()" the English version of the name from our array. We send "gettext()" the English version of the name from our array.
*/ */
our_name_localized = gettext(our_name_english); our_name_localized = gettext(our_name_english);
/* /*
Finally, duplicate the string into a new section of memory, and send it to 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, 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.) so we have one less thing to keep track of.)
*/ */
return (strdup(our_name_localized)); return (strdup(our_name_localized));
} }
@ -267,11 +268,11 @@ where the tool should be grouped.
int example_get_group(magic_api * api, int which) int example_get_group(magic_api * api, int which)
{ {
/* /*
Return our group, found in the "tool_groups[]" array. Return our group, found in the "tool_groups[]" array.
We use 'which' (which of our tools Tux Paint is asking about) as an index We use 'which' (which of our tools Tux Paint is asking about) as an index
into the array. into the array.
*/ */
return (tool_groups[which]); return (tool_groups[which]);
} }
@ -302,28 +303,28 @@ char *example_get_description(magic_api * api, int which, int mode)
const char *our_desc_localized; const char *our_desc_localized;
/* /*
Get our description from the "tool_descriptions[]" array. Get our description from the "tool_descriptions[]" array.
We use 'which' (which of our tools Tux Paint is asking about) as an index We use 'which' (which of our tools Tux Paint is asking about) as an index
into the array. into the array.
*/ */
our_desc_english = tool_descriptions[which]; our_desc_english = tool_descriptions[which];
/* /*
Return a localized (aka translated) version of our description, if Return a localized (aka translated) version of our description, if
possible. possible.
We send "gettext" the English version of the description from our array. We send "gettext" the English version of the description from our array.
*/ */
our_desc_localized = gettext(our_desc_english); our_desc_localized = gettext(our_desc_english);
/* /*
Finally, duplicate the string into a new section of memory, and send it to 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, 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.) so we have one less thing to keep track of.)
*/ */
return (strdup(our_desc_localized)); return (strdup(our_desc_localized));
} }
@ -345,9 +346,9 @@ int example_requires_colors(magic_api * api, int which)
int example_modes(magic_api * api, int which) int example_modes(magic_api * api, int which)
{ {
/* /*
Both of our tools are painted (neither affect the full-screen), so we're Both of our tools are painted (neither affect the full-screen), so we're
always returning 'MODE_PAINT' always returning 'MODE_PAINT'
*/ */
return MODE_PAINT; return MODE_PAINT;
} }
@ -385,9 +386,9 @@ void example_shutdown(magic_api * api)
int i; int i;
/* /*
Free (aka release, aka deallocate) the memory used to store the sound Free (aka release, aka deallocate) the memory used to store the sound
effects that we loaded during example_init(): effects that we loaded during example_init():
*/ */
for (i = 0; i < NUM_TOOLS; i++) for (i = 0; i < NUM_TOOLS; i++)
Mix_FreeChunk(sound_effects[i]); Mix_FreeChunk(sound_effects[i]);
} }
@ -404,13 +405,13 @@ example_click(magic_api * api, int which, int mode,
SDL_Rect * update_rect) SDL_Rect * update_rect)
{ {
/* /*
In our case, a single click (which is also the start of a drag!) is 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 identical to what dragging does, but just at one point, rather than across
a line. a line.
So we 'cheat' here, by calling our "example_draw()" function with (x,y) for So we 'cheat' here, by calling our "example_draw()" function with (x,y) for
both the beginning and end points of a line. both the beginning and end points of a line.
*/ */
example_drag(api, which, canvas, snapshot, x, y, x, y, update_rect); example_drag(api, which, canvas, snapshot, x, y, x, y, update_rect);
} }
@ -420,34 +421,32 @@ example_click(magic_api * api, int which, int mode,
void void
example_drag(magic_api * api, int which, example_drag(magic_api * api, int which,
SDL_Surface * canvas, SDL_Surface * snapshot, SDL_Surface * canvas, SDL_Surface * snapshot,
int old_x, int old_y, int x, int y, int old_x, int old_y, int x, int y, SDL_Rect * update_rect)
SDL_Rect * update_rect)
{ {
/* /*
Call Tux Paint's "line()" (line-traversing) function. Call Tux Paint's "line()" (line-traversing) function.
It will calculate a straight line between (old_x,old_y) and (x,y). Every It will calculate a straight line between (old_x,old_y) and (x,y). Every
N steps along that line (in this case, N is '1'), it will call _our_ 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 function, "example_line_callback()", and send the current X,Y
coordinates along the line, as well as other useful things (which of our coordinates along the line, as well as other useful things (which of our
'Magic' tools is being used and the current and snapshot canvases). 'Magic' tools is being used and the current and snapshot canvases).
*/ */
SDL_LockSurface(snapshot); SDL_LockSurface(snapshot);
SDL_LockSurface(canvas); SDL_LockSurface(canvas);
api->line((void *) api, which, canvas, snapshot, api->line((void *) api, which, canvas, snapshot,
old_x, old_y, x, y, 1, old_x, old_y, x, y, 1, example_line_callback);
example_line_callback);
SDL_UnlockSurface(canvas); SDL_UnlockSurface(canvas);
SDL_UnlockSurface(snapshot); SDL_UnlockSurface(snapshot);
/* /*
If we need to, swap the X and/or Y values, so that the coordinates If we need to, swap the X and/or Y values, so that the coordinates
(old_x,old_y) is always the top left, and the coordinates (x,y) is (old_x,old_y) is always the top left, and the coordinates (x,y) is
always the bottom right, so the values we put inside "update_rect" make always the bottom right, so the values we put inside "update_rect" make
sense: sense:
*/ */
if (old_x > x) if (old_x > x)
{ {
@ -466,17 +465,20 @@ example_drag(magic_api * api, int which,
/* /*
Fill in the elements of the "update_rect" SDL_Rect structure that Tux Fill in the elements of the "update_rect" SDL_Rect structure that Tux
Paint is sharing with us, therefore telling Tux Paint which part of the Paint is sharing with us, therefore telling Tux Paint which part of the
canvas has been modified and should be updated. canvas has been modified and should be updated.
*/ */
if (which == TOOL_ONE) { if (which == TOOL_ONE)
{
update_rect->x = old_x; update_rect->x = old_x;
update_rect->y = old_y; update_rect->y = old_y;
update_rect->w = (x - old_x) + 1; update_rect->w = (x - old_x) + 1;
update_rect->h = (y - old_y) + 1; update_rect->h = (y - old_y) + 1;
} else { }
else
{
update_rect->x = old_x - example_size; update_rect->x = old_x - example_size;
update_rect->y = old_y - example_size; update_rect->y = old_y - example_size;
update_rect->w = (x + example_size) - update_rect->x + 1; update_rect->w = (x + example_size) - update_rect->x + 1;
@ -484,19 +486,18 @@ example_drag(magic_api * api, int which,
} }
/* /*
Play the appropriate sound effect Play the appropriate sound effect
We're calculating a value between 0-255 for where the mouse is We're calculating a value between 0-255 for where the mouse is
horizontally across the canvas (0 is the left, ~128 is the center, 255 horizontally across the canvas (0 is the left, ~128 is the center, 255
is the right). is the right).
These are the exact values Tux Paint's "playsound()" wants, to determine 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 what speaker to play the sound in. (So the sound will pan from speaker
to speaker as you drag the mouse around the canvas!) to speaker as you drag the mouse around the canvas!)
*/ */
api->playsound(sound_effects[which], api->playsound(sound_effects[which], (x * 255) / canvas->w, /* Left/right pan */
(x * 255) / canvas->w, /* Left/right pan */ 255 /* Near/far distance (loudness) */ );
255 /* Near/far distance (loudness) */);
} }
@ -508,9 +509,9 @@ example_release(magic_api * api, int which,
SDL_Rect * update_rect) SDL_Rect * update_rect)
{ {
/* /*
Neither of our effects do anything special when the mouse is released 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... from a click or click-and-drag, so there's no code here...
*/ */
} }
@ -526,12 +527,14 @@ changes their chosen, we'll be informed of that as well.
The color comes in as RGB (red, green, and blue) values from 0 (darkest) to The color comes in as RGB (red, green, and blue) values from 0 (darkest) to
255 (brightest). 255 (brightest).
*/ */
void example_set_color(magic_api * api, int which, SDL_Surface * canvas, SDL_Surface * snapshot, Uint8 r, Uint8 g, Uint8 b, SDL_Rect * update_rect) void example_set_color(magic_api * api, int which, SDL_Surface * canvas,
SDL_Surface * snapshot, Uint8 r, Uint8 g, Uint8 b,
SDL_Rect * update_rect)
{ {
/* /*
We simply store the RGB values in the global variables we declared at We simply store the RGB values in the global variables we declared at
the top of this file. the top of this file.
*/ */
example_r = r; example_r = r;
example_g = g; example_g = g;
@ -551,12 +554,14 @@ that as well.
The size comes in as an unsigned integer (Uint8) between 1 and the value The size comes in as an unsigned integer (Uint8) between 1 and the value
returned by our example_accepted_sizes() function during setup. returned by our example_accepted_sizes() function during setup.
*/ */
void example_set_size(magic_api * api, int which, int mode, SDL_Surface * canvas, SDL_Surface * snapshot, Uint8 size, SDL_Rect * update_rect) void example_set_size(magic_api * api, int which, int mode,
SDL_Surface * canvas, SDL_Surface * snapshot,
Uint8 size, SDL_Rect * update_rect)
{ {
/* /*
Store the new size into the global variable we declared at the top of Store the new size into the global variable we declared at the top of
this file. this file.
*/ */
example_size = size * 4; example_size = size * 4;
} }
@ -580,51 +585,51 @@ Our callback pays attention to 'which' to determine which of our plugin's
tools is currently selected. tools is currently selected.
*/ */
void example_line_callback(void *pointer, int which, SDL_Surface * canvas, void example_line_callback(void *pointer, int which, SDL_Surface * canvas,
SDL_Surface * snapshot, int x, int y) SDL_Surface * snapshot, int x, int y)
{ {
/* /*
For technical reasons, we can't accept a pointer to the Tux Paint API's For technical reasons, we can't accept a pointer to the Tux Paint API's
"magic_api" struct, like the other functions do. "magic_api" struct, like the other functions do.
Instead, we receive a 'generic' pointer (a "void *"). The line below Instead, we receive a 'generic' pointer (a "void *"). The line below
declares a local "magic_api" pointer variable called "api", and then declares a local "magic_api" pointer variable called "api", and then
assigns it to the value of the 'generic' pointer we received. assigns it to the value of the 'generic' pointer we received.
The "(magic_api *)" seen below casts the generic "void *" pointer into The "(magic_api *)" seen below casts the generic "void *" pointer into
the 'type' of pointer we want, a pointer to a "magic_api" struct.) the 'type' of pointer we want, a pointer to a "magic_api" struct.)
*/ */
magic_api *api = (magic_api *) pointer; magic_api *api = (magic_api *) pointer;
int xx, yy; int xx, yy;
/* /*
This function handles both of our tools, so we need to check which is 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 being used right now. We compare the 'which' argument that Tux Paint
sends to us with the values we enumerated above. sends to us with the values we enumerated above.
*/ */
if (which == TOOL_ONE) if (which == TOOL_ONE)
{ {
/* /*
Tool number 1 simply draws a single pixel at the (x,y) location. It acts Tool number 1 simply draws a single pixel at the (x,y) location. It acts
as a 1x1 pixel brush. as a 1x1 pixel brush.
*/ */
api->putpixel(canvas, x, y, api->putpixel(canvas, x, y,
SDL_MapRGB(canvas->format, SDL_MapRGB(canvas->format,
example_r, example_g, example_b)); example_r, example_g, example_b));
/* /*
We use "SDL_MapRGB()" to convert the RGB value we receive from Tux Paint 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 for the user's current color selection to a 'Uint32' pixel value we can
send to Tux Paint's "putpixel()" function. send to Tux Paint's "putpixel()" function.
*/ */
} }
else if (which == TOOL_TWO) else if (which == TOOL_TWO)
{ {
/* /*
Tool number 2 copies a square of pixels (of the size chosen by the user) Tool number 2 copies a square of pixels (of the size chosen by the user)
from the opposite side of the canvas and puts it under the cursor. from the opposite side of the canvas and puts it under the cursor.
*/ */
for (yy = -example_size; yy < example_size; yy++) for (yy = -example_size; yy < example_size; yy++)
{ {
@ -636,14 +641,14 @@ void example_line_callback(void *pointer, int which, SDL_Surface * canvas,
snapshot->h - y - yy)); snapshot->h - y - yy));
/* /*
Here we have simply use Tux Paint's "getpixel()" routine to pull pixel Here we have simply use Tux Paint's "getpixel()" routine to pull pixel
values from the 'snapshot', and then "putpixel()" to draw them right values from the 'snapshot', and then "putpixel()" to draw them right
into the 'canvas'. into the 'canvas'.
Note: putpixel() and getpixel() are safe to use, even if your X,Y values 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 are outside of the SDL surface (e.g., negative, or greater than the
surface's width and/or height). surface's width and/or height).
*/ */
} }
} }
} }

View file

@ -9,12 +9,12 @@
/* ---------------------------------------------------------------------- */ /* ---------------------------------------------------------------------- */
#include <stdio.h> #include <stdio.h>
#include <string.h> // For "strdup()" #include <string.h> // For "strdup()"
#include <libintl.h> // For "gettext()" #include <libintl.h> // For "gettext()"
#include "tp_magic_api.h" // Tux Paint "Magic" tool API header #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_image.h" // For IMG_Load(), to load our PNG icon
#include "SDL_mixer.h" // For Mix_LoadWAV(), to load our sound effects #include "SDL_mixer.h" // For Mix_LoadWAV(), to load our sound effects
/* Tool Enumerations: */ /* Tool Enumerations: */
@ -25,9 +25,9 @@
enum enum
{ {
TOOL_ONE, // Becomes '0' TOOL_ONE, // Becomes '0'
TOOL_TWO, // Becomes '1' TOOL_TWO, // Becomes '1'
NUM_TOOLS // Becomes '2' NUM_TOOLS // Becomes '2'
}; };
@ -101,11 +101,11 @@ _before_ them.
*/ */
void example_drag(magic_api * api, int which, SDL_Surface * canvas, void example_drag(magic_api * api, int which, SDL_Surface * canvas,
SDL_Surface * snapshot, int old_x, int old_y, int x, int y, SDL_Surface * snapshot, int old_x, int old_y, int x, int y,
SDL_Rect * update_rect); SDL_Rect * update_rect);
void example_line_callback(void *pointer, int which, SDL_Surface * canvas, void example_line_callback(void *pointer, int which, SDL_Surface * canvas,
SDL_Surface * snapshot, int x, int y); SDL_Surface * snapshot, int x, int y);
/* Setup Functions: */ /* Setup Functions: */
@ -144,7 +144,8 @@ released, aka deallocated) when the user quits Tux Paint, when our
example_shutdown() function is called. example_shutdown() function is called.
*/ */
int example_init(magic_api * api, Uint8 disabled_features, Uint8 complexity_level) int example_init(magic_api * api, Uint8 disabled_features,
Uint8 complexity_level)
{ {
int i; int i;
char filename[1024]; char filename[1024];
@ -152,15 +153,15 @@ int example_init(magic_api * api, Uint8 disabled_features, Uint8 complexity_leve
for (i = 0; i < NUM_TOOLS; i++) for (i = 0; i < NUM_TOOLS; i++)
{ {
/* /*
Assemble the filename from the "sound_filenames[]" array into a full path Assemble the filename from the "sound_filenames[]" array into a full path
to a real file. to a real file.
Use "api->data_directory" to figure out where our sounds should be. (The 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 "tp-magic-config --dataprefix" command would have told us when we installed
our plugin and its data.) our plugin and its data.)
*/ */
snprintf(filename, sizeof(filename), "%ssounds/magic/%s", api->data_directory, snprintf(filename, sizeof(filename), "%ssounds/magic/%s",
sound_filenames[i]); api->data_directory, sound_filenames[i]);
printf("Trying to load %s sound file\n", filename); printf("Trying to load %s sound file\n", filename);
@ -200,16 +201,16 @@ SDL_Surface *example_get_icon(magic_api * api, int which)
char filename[1024]; char filename[1024];
/* /*
Assemble the filename from the "icon_filenames[]" array into a full path to Assemble the filename from the "icon_filenames[]" array into a full path to
a real file. a real file.
Use "api->data_directory" to figure out where our sounds should be. (The 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 "tp-magic-config --dataprefix" command would have told us when we installed
our plugin and its data.) our plugin and its data.)
We use "which" (which of our tools Tux Paint is asking about) as an index We use "which" (which of our tools Tux Paint is asking about) as an index
into the array. into the array.
*/ */
snprintf(filename, sizeof(filename), "%simages/magic/%s", snprintf(filename, sizeof(filename), "%simages/magic/%s",
api->data_directory, icon_filenames[which]); api->data_directory, icon_filenames[which]);
@ -229,31 +230,31 @@ names (labels) for the 'Magic' tool buttons.
*/ */
char *example_get_name(magic_api * api, int which) char *example_get_name(magic_api * api, int which)
{ {
const char *our_name_english; const char *our_name_english;
const char *our_name_localized; const char *our_name_localized;
/* /*
Get our name from the "tool_names[]" array. Get our name from the "tool_names[]" array.
We use 'which' (which of our tools Tux Paint is asking about) as an index We use 'which' (which of our tools Tux Paint is asking about) as an index
into the array. into the array.
*/ */
our_name_english = tool_names[which]; our_name_english = tool_names[which];
/* /*
Return a localized (aka translated) version of our name, if possible. Return a localized (aka translated) version of our name, if possible.
We send "gettext()" the English version of the name from our array. We send "gettext()" the English version of the name from our array.
*/ */
our_name_localized = gettext(our_name_english); our_name_localized = gettext(our_name_english);
/* /*
Finally, duplicate the string into a new section of memory, and send it to 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, 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.) so we have one less thing to keep track of.)
*/ */
return (strdup(our_name_localized)); return (strdup(our_name_localized));
} }
@ -267,11 +268,11 @@ where the tool should be grouped.
int example_get_group(magic_api * api, int which) int example_get_group(magic_api * api, int which)
{ {
/* /*
Return our group, found in the "tool_groups[]" array. Return our group, found in the "tool_groups[]" array.
We use 'which' (which of our tools Tux Paint is asking about) as an index We use 'which' (which of our tools Tux Paint is asking about) as an index
into the array. into the array.
*/ */
return (tool_groups[which]); return (tool_groups[which]);
} }
@ -302,28 +303,28 @@ char *example_get_description(magic_api * api, int which, int mode)
const char *our_desc_localized; const char *our_desc_localized;
/* /*
Get our description from the "tool_descriptions[]" array. Get our description from the "tool_descriptions[]" array.
We use 'which' (which of our tools Tux Paint is asking about) as an index We use 'which' (which of our tools Tux Paint is asking about) as an index
into the array. into the array.
*/ */
our_desc_english = tool_descriptions[which]; our_desc_english = tool_descriptions[which];
/* /*
Return a localized (aka translated) version of our description, if Return a localized (aka translated) version of our description, if
possible. possible.
We send "gettext" the English version of the description from our array. We send "gettext" the English version of the description from our array.
*/ */
our_desc_localized = gettext(our_desc_english); our_desc_localized = gettext(our_desc_english);
/* /*
Finally, duplicate the string into a new section of memory, and send it to 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, 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.) so we have one less thing to keep track of.)
*/ */
return (strdup(our_desc_localized)); return (strdup(our_desc_localized));
} }
@ -345,9 +346,9 @@ int example_requires_colors(magic_api * api, int which)
int example_modes(magic_api * api, int which) int example_modes(magic_api * api, int which)
{ {
/* /*
Both of our tools are painted (neither affect the full-screen), so we're Both of our tools are painted (neither affect the full-screen), so we're
always returning 'MODE_PAINT' always returning 'MODE_PAINT'
*/ */
return MODE_PAINT; return MODE_PAINT;
} }
@ -385,9 +386,9 @@ void example_shutdown(magic_api * api)
int i; int i;
/* /*
Free (aka release, aka deallocate) the memory used to store the sound Free (aka release, aka deallocate) the memory used to store the sound
effects that we loaded during example_init(): effects that we loaded during example_init():
*/ */
for (i = 0; i < NUM_TOOLS; i++) for (i = 0; i < NUM_TOOLS; i++)
Mix_FreeChunk(sound_effects[i]); Mix_FreeChunk(sound_effects[i]);
} }
@ -404,13 +405,13 @@ example_click(magic_api * api, int which, int mode,
SDL_Rect * update_rect) SDL_Rect * update_rect)
{ {
/* /*
In our case, a single click (which is also the start of a drag!) is 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 identical to what dragging does, but just at one point, rather than across
a line. a line.
So we 'cheat' here, by calling our "example_draw()" function with (x,y) for So we 'cheat' here, by calling our "example_draw()" function with (x,y) for
both the beginning and end points of a line. both the beginning and end points of a line.
*/ */
example_drag(api, which, canvas, snapshot, x, y, x, y, update_rect); example_drag(api, which, canvas, snapshot, x, y, x, y, update_rect);
} }
@ -420,34 +421,32 @@ example_click(magic_api * api, int which, int mode,
void void
example_drag(magic_api * api, int which, example_drag(magic_api * api, int which,
SDL_Surface * canvas, SDL_Surface * snapshot, SDL_Surface * canvas, SDL_Surface * snapshot,
int old_x, int old_y, int x, int y, int old_x, int old_y, int x, int y, SDL_Rect * update_rect)
SDL_Rect * update_rect)
{ {
/* /*
Call Tux Paint's "line()" (line-traversing) function. Call Tux Paint's "line()" (line-traversing) function.
It will calculate a straight line between (old_x,old_y) and (x,y). Every It will calculate a straight line between (old_x,old_y) and (x,y). Every
N steps along that line (in this case, N is '1'), it will call _our_ 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 function, "example_line_callback()", and send the current X,Y
coordinates along the line, as well as other useful things (which of our coordinates along the line, as well as other useful things (which of our
'Magic' tools is being used and the current and snapshot canvases). 'Magic' tools is being used and the current and snapshot canvases).
*/ */
SDL_LockSurface(snapshot); SDL_LockSurface(snapshot);
SDL_LockSurface(canvas); SDL_LockSurface(canvas);
api->line((void *) api, which, canvas, snapshot, api->line((void *) api, which, canvas, snapshot,
old_x, old_y, x, y, 1, old_x, old_y, x, y, 1, example_line_callback);
example_line_callback);
SDL_UnlockSurface(canvas); SDL_UnlockSurface(canvas);
SDL_UnlockSurface(snapshot); SDL_UnlockSurface(snapshot);
/* /*
If we need to, swap the X and/or Y values, so that the coordinates If we need to, swap the X and/or Y values, so that the coordinates
(old_x,old_y) is always the top left, and the coordinates (x,y) is (old_x,old_y) is always the top left, and the coordinates (x,y) is
always the bottom right, so the values we put inside "update_rect" make always the bottom right, so the values we put inside "update_rect" make
sense: sense:
*/ */
if (old_x > x) if (old_x > x)
{ {
@ -466,17 +465,20 @@ example_drag(magic_api * api, int which,
/* /*
Fill in the elements of the "update_rect" SDL_Rect structure that Tux Fill in the elements of the "update_rect" SDL_Rect structure that Tux
Paint is sharing with us, therefore telling Tux Paint which part of the Paint is sharing with us, therefore telling Tux Paint which part of the
canvas has been modified and should be updated. canvas has been modified and should be updated.
*/ */
if (which == TOOL_ONE) { if (which == TOOL_ONE)
{
update_rect->x = old_x; update_rect->x = old_x;
update_rect->y = old_y; update_rect->y = old_y;
update_rect->w = (x - old_x) + 1; update_rect->w = (x - old_x) + 1;
update_rect->h = (y - old_y) + 1; update_rect->h = (y - old_y) + 1;
} else { }
else
{
update_rect->x = old_x - example_size; update_rect->x = old_x - example_size;
update_rect->y = old_y - example_size; update_rect->y = old_y - example_size;
update_rect->w = (x + example_size) - update_rect->x + 1; update_rect->w = (x + example_size) - update_rect->x + 1;
@ -484,19 +486,18 @@ example_drag(magic_api * api, int which,
} }
/* /*
Play the appropriate sound effect Play the appropriate sound effect
We're calculating a value between 0-255 for where the mouse is We're calculating a value between 0-255 for where the mouse is
horizontally across the canvas (0 is the left, ~128 is the center, 255 horizontally across the canvas (0 is the left, ~128 is the center, 255
is the right). is the right).
These are the exact values Tux Paint's "playsound()" wants, to determine 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 what speaker to play the sound in. (So the sound will pan from speaker
to speaker as you drag the mouse around the canvas!) to speaker as you drag the mouse around the canvas!)
*/ */
api->playsound(sound_effects[which], api->playsound(sound_effects[which], (x * 255) / canvas->w, /* Left/right pan */
(x * 255) / canvas->w, /* Left/right pan */ 255 /* Near/far distance (loudness) */ );
255 /* Near/far distance (loudness) */);
} }
@ -508,9 +509,9 @@ example_release(magic_api * api, int which,
SDL_Rect * update_rect) SDL_Rect * update_rect)
{ {
/* /*
Neither of our effects do anything special when the mouse is released 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... from a click or click-and-drag, so there's no code here...
*/ */
} }
@ -526,12 +527,14 @@ changes their chosen, we'll be informed of that as well.
The color comes in as RGB (red, green, and blue) values from 0 (darkest) to The color comes in as RGB (red, green, and blue) values from 0 (darkest) to
255 (brightest). 255 (brightest).
*/ */
void example_set_color(magic_api * api, int which, SDL_Surface * canvas, SDL_Surface * snapshot, Uint8 r, Uint8 g, Uint8 b, SDL_Rect * update_rect) void example_set_color(magic_api * api, int which, SDL_Surface * canvas,
SDL_Surface * snapshot, Uint8 r, Uint8 g, Uint8 b,
SDL_Rect * update_rect)
{ {
/* /*
We simply store the RGB values in the global variables we declared at We simply store the RGB values in the global variables we declared at
the top of this file. the top of this file.
*/ */
example_r = r; example_r = r;
example_g = g; example_g = g;
@ -551,12 +554,14 @@ that as well.
The size comes in as an unsigned integer (Uint8) between 1 and the value The size comes in as an unsigned integer (Uint8) between 1 and the value
returned by our example_accepted_sizes() function during setup. returned by our example_accepted_sizes() function during setup.
*/ */
void example_set_size(magic_api * api, int which, int mode, SDL_Surface * canvas, SDL_Surface * snapshot, Uint8 size, SDL_Rect * update_rect) void example_set_size(magic_api * api, int which, int mode,
SDL_Surface * canvas, SDL_Surface * snapshot,
Uint8 size, SDL_Rect * update_rect)
{ {
/* /*
Store the new size into the global variable we declared at the top of Store the new size into the global variable we declared at the top of
this file. this file.
*/ */
example_size = size * 4; example_size = size * 4;
} }
@ -580,51 +585,51 @@ Our callback pays attention to 'which' to determine which of our plugin's
tools is currently selected. tools is currently selected.
*/ */
void example_line_callback(void *pointer, int which, SDL_Surface * canvas, void example_line_callback(void *pointer, int which, SDL_Surface * canvas,
SDL_Surface * snapshot, int x, int y) SDL_Surface * snapshot, int x, int y)
{ {
/* /*
For technical reasons, we can't accept a pointer to the Tux Paint API's For technical reasons, we can't accept a pointer to the Tux Paint API's
"magic_api" struct, like the other functions do. "magic_api" struct, like the other functions do.
Instead, we receive a 'generic' pointer (a "void *"). The line below Instead, we receive a 'generic' pointer (a "void *"). The line below
declares a local "magic_api" pointer variable called "api", and then declares a local "magic_api" pointer variable called "api", and then
assigns it to the value of the 'generic' pointer we received. assigns it to the value of the 'generic' pointer we received.
The "(magic_api *)" seen below casts the generic "void *" pointer into The "(magic_api *)" seen below casts the generic "void *" pointer into
the 'type' of pointer we want, a pointer to a "magic_api" struct.) the 'type' of pointer we want, a pointer to a "magic_api" struct.)
*/ */
magic_api *api = (magic_api *) pointer; magic_api *api = (magic_api *) pointer;
int xx, yy; int xx, yy;
/* /*
This function handles both of our tools, so we need to check which is 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 being used right now. We compare the 'which' argument that Tux Paint
sends to us with the values we enumerated above. sends to us with the values we enumerated above.
*/ */
if (which == TOOL_ONE) if (which == TOOL_ONE)
{ {
/* /*
Tool number 1 simply draws a single pixel at the (x,y) location. It acts Tool number 1 simply draws a single pixel at the (x,y) location. It acts
as a 1x1 pixel brush. as a 1x1 pixel brush.
*/ */
api->putpixel(canvas, x, y, api->putpixel(canvas, x, y,
SDL_MapRGB(canvas->format, SDL_MapRGB(canvas->format,
example_r, example_g, example_b)); example_r, example_g, example_b));
/* /*
We use "SDL_MapRGB()" to convert the RGB value we receive from Tux Paint 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 for the user's current color selection to a 'Uint32' pixel value we can
send to Tux Paint's "putpixel()" function. send to Tux Paint's "putpixel()" function.
*/ */
} }
else if (which == TOOL_TWO) else if (which == TOOL_TWO)
{ {
/* /*
Tool number 2 copies a square of pixels (of the size chosen by the user) Tool number 2 copies a square of pixels (of the size chosen by the user)
from the opposite side of the canvas and puts it under the cursor. from the opposite side of the canvas and puts it under the cursor.
*/ */
for (yy = -example_size; yy < example_size; yy++) for (yy = -example_size; yy < example_size; yy++)
{ {
@ -636,14 +641,14 @@ void example_line_callback(void *pointer, int which, SDL_Surface * canvas,
snapshot->h - y - yy)); snapshot->h - y - yy));
/* /*
Here we have simply use Tux Paint's "getpixel()" routine to pull pixel Here we have simply use Tux Paint's "getpixel()" routine to pull pixel
values from the 'snapshot', and then "putpixel()" to draw them right values from the 'snapshot', and then "putpixel()" to draw them right
into the 'canvas'. into the 'canvas'.
Note: putpixel() and getpixel() are safe to use, even if your X,Y values 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 are outside of the SDL surface (e.g., negative, or greater than the
surface's width and/or height). surface's width and/or height).
*/ */
} }
} }
} }

View file

@ -9,12 +9,12 @@
/* ---------------------------------------------------------------------- */ /* ---------------------------------------------------------------------- */
#include <stdio.h> #include <stdio.h>
#include <string.h> // For "strdup()" #include <string.h> // For "strdup()"
#include <libintl.h> // For "gettext()" #include <libintl.h> // For "gettext()"
#include "tp_magic_api.h" // Tux Paint "Magic" tool API header #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_image.h" // For IMG_Load(), to load our PNG icon
#include "SDL_mixer.h" // For Mix_LoadWAV(), to load our sound effects #include "SDL_mixer.h" // For Mix_LoadWAV(), to load our sound effects
/* Tool Enumerations: */ /* Tool Enumerations: */
@ -25,9 +25,9 @@
enum enum
{ {
TOOL_ONE, // Becomes '0' TOOL_ONE, // Becomes '0'
TOOL_TWO, // Becomes '1' TOOL_TWO, // Becomes '1'
NUM_TOOLS // Becomes '2' NUM_TOOLS // Becomes '2'
}; };
@ -101,11 +101,11 @@ _before_ them.
*/ */
void example_drag(magic_api * api, int which, SDL_Surface * canvas, void example_drag(magic_api * api, int which, SDL_Surface * canvas,
SDL_Surface * snapshot, int old_x, int old_y, int x, int y, SDL_Surface * snapshot, int old_x, int old_y, int x, int y,
SDL_Rect * update_rect); SDL_Rect * update_rect);
void example_line_callback(void *pointer, int which, SDL_Surface * canvas, void example_line_callback(void *pointer, int which, SDL_Surface * canvas,
SDL_Surface * snapshot, int x, int y); SDL_Surface * snapshot, int x, int y);
/* Setup Functions: */ /* Setup Functions: */
@ -144,7 +144,8 @@ released, aka deallocated) when the user quits Tux Paint, when our
example_shutdown() function is called. example_shutdown() function is called.
*/ */
int example_init(magic_api * api, Uint8 disabled_features, Uint8 complexity_level) int example_init(magic_api * api, Uint8 disabled_features,
Uint8 complexity_level)
{ {
int i; int i;
char filename[1024]; char filename[1024];
@ -152,15 +153,15 @@ int example_init(magic_api * api, Uint8 disabled_features, Uint8 complexity_leve
for (i = 0; i < NUM_TOOLS; i++) for (i = 0; i < NUM_TOOLS; i++)
{ {
/* /*
Assemble the filename from the "sound_filenames[]" array into a full path Assemble the filename from the "sound_filenames[]" array into a full path
to a real file. to a real file.
Use "api->data_directory" to figure out where our sounds should be. (The 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 "tp-magic-config --dataprefix" command would have told us when we installed
our plugin and its data.) our plugin and its data.)
*/ */
snprintf(filename, sizeof(filename), "%ssounds/magic/%s", api->data_directory, snprintf(filename, sizeof(filename), "%ssounds/magic/%s",
sound_filenames[i]); api->data_directory, sound_filenames[i]);
printf("Trying to load %s sound file\n", filename); printf("Trying to load %s sound file\n", filename);
@ -200,16 +201,16 @@ SDL_Surface *example_get_icon(magic_api * api, int which)
char filename[1024]; char filename[1024];
/* /*
Assemble the filename from the "icon_filenames[]" array into a full path to Assemble the filename from the "icon_filenames[]" array into a full path to
a real file. a real file.
Use "api->data_directory" to figure out where our sounds should be. (The 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 "tp-magic-config --dataprefix" command would have told us when we installed
our plugin and its data.) our plugin and its data.)
We use "which" (which of our tools Tux Paint is asking about) as an index We use "which" (which of our tools Tux Paint is asking about) as an index
into the array. into the array.
*/ */
snprintf(filename, sizeof(filename), "%simages/magic/%s", snprintf(filename, sizeof(filename), "%simages/magic/%s",
api->data_directory, icon_filenames[which]); api->data_directory, icon_filenames[which]);
@ -229,31 +230,31 @@ names (labels) for the 'Magic' tool buttons.
*/ */
char *example_get_name(magic_api * api, int which) char *example_get_name(magic_api * api, int which)
{ {
const char *our_name_english; const char *our_name_english;
const char *our_name_localized; const char *our_name_localized;
/* /*
Get our name from the "tool_names[]" array. Get our name from the "tool_names[]" array.
We use 'which' (which of our tools Tux Paint is asking about) as an index We use 'which' (which of our tools Tux Paint is asking about) as an index
into the array. into the array.
*/ */
our_name_english = tool_names[which]; our_name_english = tool_names[which];
/* /*
Return a localized (aka translated) version of our name, if possible. Return a localized (aka translated) version of our name, if possible.
We send "gettext()" the English version of the name from our array. We send "gettext()" the English version of the name from our array.
*/ */
our_name_localized = gettext(our_name_english); our_name_localized = gettext(our_name_english);
/* /*
Finally, duplicate the string into a new section of memory, and send it to 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, 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.) so we have one less thing to keep track of.)
*/ */
return (strdup(our_name_localized)); return (strdup(our_name_localized));
} }
@ -267,11 +268,11 @@ where the tool should be grouped.
int example_get_group(magic_api * api, int which) int example_get_group(magic_api * api, int which)
{ {
/* /*
Return our group, found in the "tool_groups[]" array. Return our group, found in the "tool_groups[]" array.
We use 'which' (which of our tools Tux Paint is asking about) as an index We use 'which' (which of our tools Tux Paint is asking about) as an index
into the array. into the array.
*/ */
return (tool_groups[which]); return (tool_groups[which]);
} }
@ -302,28 +303,28 @@ char *example_get_description(magic_api * api, int which, int mode)
const char *our_desc_localized; const char *our_desc_localized;
/* /*
Get our description from the "tool_descriptions[]" array. Get our description from the "tool_descriptions[]" array.
We use 'which' (which of our tools Tux Paint is asking about) as an index We use 'which' (which of our tools Tux Paint is asking about) as an index
into the array. into the array.
*/ */
our_desc_english = tool_descriptions[which]; our_desc_english = tool_descriptions[which];
/* /*
Return a localized (aka translated) version of our description, if Return a localized (aka translated) version of our description, if
possible. possible.
We send "gettext" the English version of the description from our array. We send "gettext" the English version of the description from our array.
*/ */
our_desc_localized = gettext(our_desc_english); our_desc_localized = gettext(our_desc_english);
/* /*
Finally, duplicate the string into a new section of memory, and send it to 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, 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.) so we have one less thing to keep track of.)
*/ */
return (strdup(our_desc_localized)); return (strdup(our_desc_localized));
} }
@ -345,9 +346,9 @@ int example_requires_colors(magic_api * api, int which)
int example_modes(magic_api * api, int which) int example_modes(magic_api * api, int which)
{ {
/* /*
Both of our tools are painted (neither affect the full-screen), so we're Both of our tools are painted (neither affect the full-screen), so we're
always returning 'MODE_PAINT' always returning 'MODE_PAINT'
*/ */
return MODE_PAINT; return MODE_PAINT;
} }
@ -385,9 +386,9 @@ void example_shutdown(magic_api * api)
int i; int i;
/* /*
Free (aka release, aka deallocate) the memory used to store the sound Free (aka release, aka deallocate) the memory used to store the sound
effects that we loaded during example_init(): effects that we loaded during example_init():
*/ */
for (i = 0; i < NUM_TOOLS; i++) for (i = 0; i < NUM_TOOLS; i++)
Mix_FreeChunk(sound_effects[i]); Mix_FreeChunk(sound_effects[i]);
} }
@ -404,13 +405,13 @@ example_click(magic_api * api, int which, int mode,
SDL_Rect * update_rect) SDL_Rect * update_rect)
{ {
/* /*
In our case, a single click (which is also the start of a drag!) is 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 identical to what dragging does, but just at one point, rather than across
a line. a line.
So we 'cheat' here, by calling our "example_draw()" function with (x,y) for So we 'cheat' here, by calling our "example_draw()" function with (x,y) for
both the beginning and end points of a line. both the beginning and end points of a line.
*/ */
example_drag(api, which, canvas, snapshot, x, y, x, y, update_rect); example_drag(api, which, canvas, snapshot, x, y, x, y, update_rect);
} }
@ -420,34 +421,32 @@ example_click(magic_api * api, int which, int mode,
void void
example_drag(magic_api * api, int which, example_drag(magic_api * api, int which,
SDL_Surface * canvas, SDL_Surface * snapshot, SDL_Surface * canvas, SDL_Surface * snapshot,
int old_x, int old_y, int x, int y, int old_x, int old_y, int x, int y, SDL_Rect * update_rect)
SDL_Rect * update_rect)
{ {
/* /*
Call Tux Paint's "line()" (line-traversing) function. Call Tux Paint's "line()" (line-traversing) function.
It will calculate a straight line between (old_x,old_y) and (x,y). Every It will calculate a straight line between (old_x,old_y) and (x,y). Every
N steps along that line (in this case, N is '1'), it will call _our_ 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 function, "example_line_callback()", and send the current X,Y
coordinates along the line, as well as other useful things (which of our coordinates along the line, as well as other useful things (which of our
'Magic' tools is being used and the current and snapshot canvases). 'Magic' tools is being used and the current and snapshot canvases).
*/ */
SDL_LockSurface(snapshot); SDL_LockSurface(snapshot);
SDL_LockSurface(canvas); SDL_LockSurface(canvas);
api->line((void *) api, which, canvas, snapshot, api->line((void *) api, which, canvas, snapshot,
old_x, old_y, x, y, 1, old_x, old_y, x, y, 1, example_line_callback);
example_line_callback);
SDL_UnlockSurface(canvas); SDL_UnlockSurface(canvas);
SDL_UnlockSurface(snapshot); SDL_UnlockSurface(snapshot);
/* /*
If we need to, swap the X and/or Y values, so that the coordinates If we need to, swap the X and/or Y values, so that the coordinates
(old_x,old_y) is always the top left, and the coordinates (x,y) is (old_x,old_y) is always the top left, and the coordinates (x,y) is
always the bottom right, so the values we put inside "update_rect" make always the bottom right, so the values we put inside "update_rect" make
sense: sense:
*/ */
if (old_x > x) if (old_x > x)
{ {
@ -466,17 +465,20 @@ example_drag(magic_api * api, int which,
/* /*
Fill in the elements of the "update_rect" SDL_Rect structure that Tux Fill in the elements of the "update_rect" SDL_Rect structure that Tux
Paint is sharing with us, therefore telling Tux Paint which part of the Paint is sharing with us, therefore telling Tux Paint which part of the
canvas has been modified and should be updated. canvas has been modified and should be updated.
*/ */
if (which == TOOL_ONE) { if (which == TOOL_ONE)
{
update_rect->x = old_x; update_rect->x = old_x;
update_rect->y = old_y; update_rect->y = old_y;
update_rect->w = (x - old_x) + 1; update_rect->w = (x - old_x) + 1;
update_rect->h = (y - old_y) + 1; update_rect->h = (y - old_y) + 1;
} else { }
else
{
update_rect->x = old_x - example_size; update_rect->x = old_x - example_size;
update_rect->y = old_y - example_size; update_rect->y = old_y - example_size;
update_rect->w = (x + example_size) - update_rect->x + 1; update_rect->w = (x + example_size) - update_rect->x + 1;
@ -484,19 +486,18 @@ example_drag(magic_api * api, int which,
} }
/* /*
Play the appropriate sound effect Play the appropriate sound effect
We're calculating a value between 0-255 for where the mouse is We're calculating a value between 0-255 for where the mouse is
horizontally across the canvas (0 is the left, ~128 is the center, 255 horizontally across the canvas (0 is the left, ~128 is the center, 255
is the right). is the right).
These are the exact values Tux Paint's "playsound()" wants, to determine 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 what speaker to play the sound in. (So the sound will pan from speaker
to speaker as you drag the mouse around the canvas!) to speaker as you drag the mouse around the canvas!)
*/ */
api->playsound(sound_effects[which], api->playsound(sound_effects[which], (x * 255) / canvas->w, /* Left/right pan */
(x * 255) / canvas->w, /* Left/right pan */ 255 /* Near/far distance (loudness) */ );
255 /* Near/far distance (loudness) */);
} }
@ -508,9 +509,9 @@ example_release(magic_api * api, int which,
SDL_Rect * update_rect) SDL_Rect * update_rect)
{ {
/* /*
Neither of our effects do anything special when the mouse is released 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... from a click or click-and-drag, so there's no code here...
*/ */
} }
@ -526,12 +527,14 @@ changes their chosen, we'll be informed of that as well.
The color comes in as RGB (red, green, and blue) values from 0 (darkest) to The color comes in as RGB (red, green, and blue) values from 0 (darkest) to
255 (brightest). 255 (brightest).
*/ */
void example_set_color(magic_api * api, int which, SDL_Surface * canvas, SDL_Surface * snapshot, Uint8 r, Uint8 g, Uint8 b, SDL_Rect * update_rect) void example_set_color(magic_api * api, int which, SDL_Surface * canvas,
SDL_Surface * snapshot, Uint8 r, Uint8 g, Uint8 b,
SDL_Rect * update_rect)
{ {
/* /*
We simply store the RGB values in the global variables we declared at We simply store the RGB values in the global variables we declared at
the top of this file. the top of this file.
*/ */
example_r = r; example_r = r;
example_g = g; example_g = g;
@ -551,12 +554,14 @@ that as well.
The size comes in as an unsigned integer (Uint8) between 1 and the value The size comes in as an unsigned integer (Uint8) between 1 and the value
returned by our example_accepted_sizes() function during setup. returned by our example_accepted_sizes() function during setup.
*/ */
void example_set_size(magic_api * api, int which, int mode, SDL_Surface * canvas, SDL_Surface * snapshot, Uint8 size, SDL_Rect * update_rect) void example_set_size(magic_api * api, int which, int mode,
SDL_Surface * canvas, SDL_Surface * snapshot,
Uint8 size, SDL_Rect * update_rect)
{ {
/* /*
Store the new size into the global variable we declared at the top of Store the new size into the global variable we declared at the top of
this file. this file.
*/ */
example_size = size * 4; example_size = size * 4;
} }
@ -580,51 +585,51 @@ Our callback pays attention to 'which' to determine which of our plugin's
tools is currently selected. tools is currently selected.
*/ */
void example_line_callback(void *pointer, int which, SDL_Surface * canvas, void example_line_callback(void *pointer, int which, SDL_Surface * canvas,
SDL_Surface * snapshot, int x, int y) SDL_Surface * snapshot, int x, int y)
{ {
/* /*
For technical reasons, we can't accept a pointer to the Tux Paint API's For technical reasons, we can't accept a pointer to the Tux Paint API's
"magic_api" struct, like the other functions do. "magic_api" struct, like the other functions do.
Instead, we receive a 'generic' pointer (a "void *"). The line below Instead, we receive a 'generic' pointer (a "void *"). The line below
declares a local "magic_api" pointer variable called "api", and then declares a local "magic_api" pointer variable called "api", and then
assigns it to the value of the 'generic' pointer we received. assigns it to the value of the 'generic' pointer we received.
The "(magic_api *)" seen below casts the generic "void *" pointer into The "(magic_api *)" seen below casts the generic "void *" pointer into
the 'type' of pointer we want, a pointer to a "magic_api" struct.) the 'type' of pointer we want, a pointer to a "magic_api" struct.)
*/ */
magic_api *api = (magic_api *) pointer; magic_api *api = (magic_api *) pointer;
int xx, yy; int xx, yy;
/* /*
This function handles both of our tools, so we need to check which is 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 being used right now. We compare the 'which' argument that Tux Paint
sends to us with the values we enumerated above. sends to us with the values we enumerated above.
*/ */
if (which == TOOL_ONE) if (which == TOOL_ONE)
{ {
/* /*
Tool number 1 simply draws a single pixel at the (x,y) location. It acts Tool number 1 simply draws a single pixel at the (x,y) location. It acts
as a 1x1 pixel brush. as a 1x1 pixel brush.
*/ */
api->putpixel(canvas, x, y, api->putpixel(canvas, x, y,
SDL_MapRGB(canvas->format, SDL_MapRGB(canvas->format,
example_r, example_g, example_b)); example_r, example_g, example_b));
/* /*
We use "SDL_MapRGB()" to convert the RGB value we receive from Tux Paint 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 for the user's current color selection to a 'Uint32' pixel value we can
send to Tux Paint's "putpixel()" function. send to Tux Paint's "putpixel()" function.
*/ */
} }
else if (which == TOOL_TWO) else if (which == TOOL_TWO)
{ {
/* /*
Tool number 2 copies a square of pixels (of the size chosen by the user) Tool number 2 copies a square of pixels (of the size chosen by the user)
from the opposite side of the canvas and puts it under the cursor. from the opposite side of the canvas and puts it under the cursor.
*/ */
for (yy = -example_size; yy < example_size; yy++) for (yy = -example_size; yy < example_size; yy++)
{ {
@ -636,14 +641,14 @@ void example_line_callback(void *pointer, int which, SDL_Surface * canvas,
snapshot->h - y - yy)); snapshot->h - y - yy));
/* /*
Here we have simply use Tux Paint's "getpixel()" routine to pull pixel Here we have simply use Tux Paint's "getpixel()" routine to pull pixel
values from the 'snapshot', and then "putpixel()" to draw them right values from the 'snapshot', and then "putpixel()" to draw them right
into the 'canvas'. into the 'canvas'.
Note: putpixel() and getpixel() are safe to use, even if your X,Y values 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 are outside of the SDL surface (e.g., negative, or greater than the
surface's width and/or height). surface's width and/or height).
*/ */
} }
} }
} }

View file

@ -9,12 +9,12 @@
/* ---------------------------------------------------------------------- */ /* ---------------------------------------------------------------------- */
#include <stdio.h> #include <stdio.h>
#include <string.h> // For "strdup()" #include <string.h> // For "strdup()"
#include <libintl.h> // For "gettext()" #include <libintl.h> // For "gettext()"
#include "tp_magic_api.h" // Tux Paint "Magic" tool API header #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_image.h" // For IMG_Load(), to load our PNG icon
#include "SDL_mixer.h" // For Mix_LoadWAV(), to load our sound effects #include "SDL_mixer.h" // For Mix_LoadWAV(), to load our sound effects
/* Tool Enumerations: */ /* Tool Enumerations: */
@ -25,9 +25,9 @@
enum enum
{ {
TOOL_ONE, // Becomes '0' TOOL_ONE, // Becomes '0'
TOOL_TWO, // Becomes '1' TOOL_TWO, // Becomes '1'
NUM_TOOLS // Becomes '2' NUM_TOOLS // Becomes '2'
}; };
@ -101,11 +101,11 @@ _before_ them.
*/ */
void example_drag(magic_api * api, int which, SDL_Surface * canvas, void example_drag(magic_api * api, int which, SDL_Surface * canvas,
SDL_Surface * snapshot, int old_x, int old_y, int x, int y, SDL_Surface * snapshot, int old_x, int old_y, int x, int y,
SDL_Rect * update_rect); SDL_Rect * update_rect);
void example_line_callback(void *pointer, int which, SDL_Surface * canvas, void example_line_callback(void *pointer, int which, SDL_Surface * canvas,
SDL_Surface * snapshot, int x, int y); SDL_Surface * snapshot, int x, int y);
/* Setup Functions: */ /* Setup Functions: */
@ -144,7 +144,8 @@ released, aka deallocated) when the user quits Tux Paint, when our
example_shutdown() function is called. example_shutdown() function is called.
*/ */
int example_init(magic_api * api, Uint8 disabled_features, Uint8 complexity_level) int example_init(magic_api * api, Uint8 disabled_features,
Uint8 complexity_level)
{ {
int i; int i;
char filename[1024]; char filename[1024];
@ -152,15 +153,15 @@ int example_init(magic_api * api, Uint8 disabled_features, Uint8 complexity_leve
for (i = 0; i < NUM_TOOLS; i++) for (i = 0; i < NUM_TOOLS; i++)
{ {
/* /*
Assemble the filename from the "sound_filenames[]" array into a full path Assemble the filename from the "sound_filenames[]" array into a full path
to a real file. to a real file.
Use "api->data_directory" to figure out where our sounds should be. (The 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 "tp-magic-config --dataprefix" command would have told us when we installed
our plugin and its data.) our plugin and its data.)
*/ */
snprintf(filename, sizeof(filename), "%ssounds/magic/%s", api->data_directory, snprintf(filename, sizeof(filename), "%ssounds/magic/%s",
sound_filenames[i]); api->data_directory, sound_filenames[i]);
printf("Trying to load %s sound file\n", filename); printf("Trying to load %s sound file\n", filename);
@ -200,16 +201,16 @@ SDL_Surface *example_get_icon(magic_api * api, int which)
char filename[1024]; char filename[1024];
/* /*
Assemble the filename from the "icon_filenames[]" array into a full path to Assemble the filename from the "icon_filenames[]" array into a full path to
a real file. a real file.
Use "api->data_directory" to figure out where our sounds should be. (The 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 "tp-magic-config --dataprefix" command would have told us when we installed
our plugin and its data.) our plugin and its data.)
We use "which" (which of our tools Tux Paint is asking about) as an index We use "which" (which of our tools Tux Paint is asking about) as an index
into the array. into the array.
*/ */
snprintf(filename, sizeof(filename), "%simages/magic/%s", snprintf(filename, sizeof(filename), "%simages/magic/%s",
api->data_directory, icon_filenames[which]); api->data_directory, icon_filenames[which]);
@ -229,31 +230,31 @@ names (labels) for the 'Magic' tool buttons.
*/ */
char *example_get_name(magic_api * api, int which) char *example_get_name(magic_api * api, int which)
{ {
const char *our_name_english; const char *our_name_english;
const char *our_name_localized; const char *our_name_localized;
/* /*
Get our name from the "tool_names[]" array. Get our name from the "tool_names[]" array.
We use 'which' (which of our tools Tux Paint is asking about) as an index We use 'which' (which of our tools Tux Paint is asking about) as an index
into the array. into the array.
*/ */
our_name_english = tool_names[which]; our_name_english = tool_names[which];
/* /*
Return a localized (aka translated) version of our name, if possible. Return a localized (aka translated) version of our name, if possible.
We send "gettext()" the English version of the name from our array. We send "gettext()" the English version of the name from our array.
*/ */
our_name_localized = gettext(our_name_english); our_name_localized = gettext(our_name_english);
/* /*
Finally, duplicate the string into a new section of memory, and send it to 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, 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.) so we have one less thing to keep track of.)
*/ */
return (strdup(our_name_localized)); return (strdup(our_name_localized));
} }
@ -267,11 +268,11 @@ where the tool should be grouped.
int example_get_group(magic_api * api, int which) int example_get_group(magic_api * api, int which)
{ {
/* /*
Return our group, found in the "tool_groups[]" array. Return our group, found in the "tool_groups[]" array.
We use 'which' (which of our tools Tux Paint is asking about) as an index We use 'which' (which of our tools Tux Paint is asking about) as an index
into the array. into the array.
*/ */
return (tool_groups[which]); return (tool_groups[which]);
} }
@ -302,28 +303,28 @@ char *example_get_description(magic_api * api, int which, int mode)
const char *our_desc_localized; const char *our_desc_localized;
/* /*
Get our description from the "tool_descriptions[]" array. Get our description from the "tool_descriptions[]" array.
We use 'which' (which of our tools Tux Paint is asking about) as an index We use 'which' (which of our tools Tux Paint is asking about) as an index
into the array. into the array.
*/ */
our_desc_english = tool_descriptions[which]; our_desc_english = tool_descriptions[which];
/* /*
Return a localized (aka translated) version of our description, if Return a localized (aka translated) version of our description, if
possible. possible.
We send "gettext" the English version of the description from our array. We send "gettext" the English version of the description from our array.
*/ */
our_desc_localized = gettext(our_desc_english); our_desc_localized = gettext(our_desc_english);
/* /*
Finally, duplicate the string into a new section of memory, and send it to 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, 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.) so we have one less thing to keep track of.)
*/ */
return (strdup(our_desc_localized)); return (strdup(our_desc_localized));
} }
@ -345,9 +346,9 @@ int example_requires_colors(magic_api * api, int which)
int example_modes(magic_api * api, int which) int example_modes(magic_api * api, int which)
{ {
/* /*
Both of our tools are painted (neither affect the full-screen), so we're Both of our tools are painted (neither affect the full-screen), so we're
always returning 'MODE_PAINT' always returning 'MODE_PAINT'
*/ */
return MODE_PAINT; return MODE_PAINT;
} }
@ -385,9 +386,9 @@ void example_shutdown(magic_api * api)
int i; int i;
/* /*
Free (aka release, aka deallocate) the memory used to store the sound Free (aka release, aka deallocate) the memory used to store the sound
effects that we loaded during example_init(): effects that we loaded during example_init():
*/ */
for (i = 0; i < NUM_TOOLS; i++) for (i = 0; i < NUM_TOOLS; i++)
Mix_FreeChunk(sound_effects[i]); Mix_FreeChunk(sound_effects[i]);
} }
@ -404,13 +405,13 @@ example_click(magic_api * api, int which, int mode,
SDL_Rect * update_rect) SDL_Rect * update_rect)
{ {
/* /*
In our case, a single click (which is also the start of a drag!) is 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 identical to what dragging does, but just at one point, rather than across
a line. a line.
So we 'cheat' here, by calling our "example_draw()" function with (x,y) for So we 'cheat' here, by calling our "example_draw()" function with (x,y) for
both the beginning and end points of a line. both the beginning and end points of a line.
*/ */
example_drag(api, which, canvas, snapshot, x, y, x, y, update_rect); example_drag(api, which, canvas, snapshot, x, y, x, y, update_rect);
} }
@ -420,34 +421,32 @@ example_click(magic_api * api, int which, int mode,
void void
example_drag(magic_api * api, int which, example_drag(magic_api * api, int which,
SDL_Surface * canvas, SDL_Surface * snapshot, SDL_Surface * canvas, SDL_Surface * snapshot,
int old_x, int old_y, int x, int y, int old_x, int old_y, int x, int y, SDL_Rect * update_rect)
SDL_Rect * update_rect)
{ {
/* /*
Call Tux Paint's "line()" (line-traversing) function. Call Tux Paint's "line()" (line-traversing) function.
It will calculate a straight line between (old_x,old_y) and (x,y). Every It will calculate a straight line between (old_x,old_y) and (x,y). Every
N steps along that line (in this case, N is '1'), it will call _our_ 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 function, "example_line_callback()", and send the current X,Y
coordinates along the line, as well as other useful things (which of our coordinates along the line, as well as other useful things (which of our
'Magic' tools is being used and the current and snapshot canvases). 'Magic' tools is being used and the current and snapshot canvases).
*/ */
SDL_LockSurface(snapshot); SDL_LockSurface(snapshot);
SDL_LockSurface(canvas); SDL_LockSurface(canvas);
api->line((void *) api, which, canvas, snapshot, api->line((void *) api, which, canvas, snapshot,
old_x, old_y, x, y, 1, old_x, old_y, x, y, 1, example_line_callback);
example_line_callback);
SDL_UnlockSurface(canvas); SDL_UnlockSurface(canvas);
SDL_UnlockSurface(snapshot); SDL_UnlockSurface(snapshot);
/* /*
If we need to, swap the X and/or Y values, so that the coordinates If we need to, swap the X and/or Y values, so that the coordinates
(old_x,old_y) is always the top left, and the coordinates (x,y) is (old_x,old_y) is always the top left, and the coordinates (x,y) is
always the bottom right, so the values we put inside "update_rect" make always the bottom right, so the values we put inside "update_rect" make
sense: sense:
*/ */
if (old_x > x) if (old_x > x)
{ {
@ -466,17 +465,20 @@ example_drag(magic_api * api, int which,
/* /*
Fill in the elements of the "update_rect" SDL_Rect structure that Tux Fill in the elements of the "update_rect" SDL_Rect structure that Tux
Paint is sharing with us, therefore telling Tux Paint which part of the Paint is sharing with us, therefore telling Tux Paint which part of the
canvas has been modified and should be updated. canvas has been modified and should be updated.
*/ */
if (which == TOOL_ONE) { if (which == TOOL_ONE)
{
update_rect->x = old_x; update_rect->x = old_x;
update_rect->y = old_y; update_rect->y = old_y;
update_rect->w = (x - old_x) + 1; update_rect->w = (x - old_x) + 1;
update_rect->h = (y - old_y) + 1; update_rect->h = (y - old_y) + 1;
} else { }
else
{
update_rect->x = old_x - example_size; update_rect->x = old_x - example_size;
update_rect->y = old_y - example_size; update_rect->y = old_y - example_size;
update_rect->w = (x + example_size) - update_rect->x + 1; update_rect->w = (x + example_size) - update_rect->x + 1;
@ -484,19 +486,18 @@ example_drag(magic_api * api, int which,
} }
/* /*
Play the appropriate sound effect Play the appropriate sound effect
We're calculating a value between 0-255 for where the mouse is We're calculating a value between 0-255 for where the mouse is
horizontally across the canvas (0 is the left, ~128 is the center, 255 horizontally across the canvas (0 is the left, ~128 is the center, 255
is the right). is the right).
These are the exact values Tux Paint's "playsound()" wants, to determine 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 what speaker to play the sound in. (So the sound will pan from speaker
to speaker as you drag the mouse around the canvas!) to speaker as you drag the mouse around the canvas!)
*/ */
api->playsound(sound_effects[which], api->playsound(sound_effects[which], (x * 255) / canvas->w, /* Left/right pan */
(x * 255) / canvas->w, /* Left/right pan */ 255 /* Near/far distance (loudness) */ );
255 /* Near/far distance (loudness) */);
} }
@ -508,9 +509,9 @@ example_release(magic_api * api, int which,
SDL_Rect * update_rect) SDL_Rect * update_rect)
{ {
/* /*
Neither of our effects do anything special when the mouse is released 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... from a click or click-and-drag, so there's no code here...
*/ */
} }
@ -526,12 +527,14 @@ changes their chosen, we'll be informed of that as well.
The color comes in as RGB (red, green, and blue) values from 0 (darkest) to The color comes in as RGB (red, green, and blue) values from 0 (darkest) to
255 (brightest). 255 (brightest).
*/ */
void example_set_color(magic_api * api, int which, SDL_Surface * canvas, SDL_Surface * snapshot, Uint8 r, Uint8 g, Uint8 b, SDL_Rect * update_rect) void example_set_color(magic_api * api, int which, SDL_Surface * canvas,
SDL_Surface * snapshot, Uint8 r, Uint8 g, Uint8 b,
SDL_Rect * update_rect)
{ {
/* /*
We simply store the RGB values in the global variables we declared at We simply store the RGB values in the global variables we declared at
the top of this file. the top of this file.
*/ */
example_r = r; example_r = r;
example_g = g; example_g = g;
@ -551,12 +554,14 @@ that as well.
The size comes in as an unsigned integer (Uint8) between 1 and the value The size comes in as an unsigned integer (Uint8) between 1 and the value
returned by our example_accepted_sizes() function during setup. returned by our example_accepted_sizes() function during setup.
*/ */
void example_set_size(magic_api * api, int which, int mode, SDL_Surface * canvas, SDL_Surface * snapshot, Uint8 size, SDL_Rect * update_rect) void example_set_size(magic_api * api, int which, int mode,
SDL_Surface * canvas, SDL_Surface * snapshot,
Uint8 size, SDL_Rect * update_rect)
{ {
/* /*
Store the new size into the global variable we declared at the top of Store the new size into the global variable we declared at the top of
this file. this file.
*/ */
example_size = size * 4; example_size = size * 4;
} }
@ -580,51 +585,51 @@ Our callback pays attention to 'which' to determine which of our plugin's
tools is currently selected. tools is currently selected.
*/ */
void example_line_callback(void *pointer, int which, SDL_Surface * canvas, void example_line_callback(void *pointer, int which, SDL_Surface * canvas,
SDL_Surface * snapshot, int x, int y) SDL_Surface * snapshot, int x, int y)
{ {
/* /*
For technical reasons, we can't accept a pointer to the Tux Paint API's For technical reasons, we can't accept a pointer to the Tux Paint API's
"magic_api" struct, like the other functions do. "magic_api" struct, like the other functions do.
Instead, we receive a 'generic' pointer (a "void *"). The line below Instead, we receive a 'generic' pointer (a "void *"). The line below
declares a local "magic_api" pointer variable called "api", and then declares a local "magic_api" pointer variable called "api", and then
assigns it to the value of the 'generic' pointer we received. assigns it to the value of the 'generic' pointer we received.
The "(magic_api *)" seen below casts the generic "void *" pointer into The "(magic_api *)" seen below casts the generic "void *" pointer into
the 'type' of pointer we want, a pointer to a "magic_api" struct.) the 'type' of pointer we want, a pointer to a "magic_api" struct.)
*/ */
magic_api *api = (magic_api *) pointer; magic_api *api = (magic_api *) pointer;
int xx, yy; int xx, yy;
/* /*
This function handles both of our tools, so we need to check which is 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 being used right now. We compare the 'which' argument that Tux Paint
sends to us with the values we enumerated above. sends to us with the values we enumerated above.
*/ */
if (which == TOOL_ONE) if (which == TOOL_ONE)
{ {
/* /*
Tool number 1 simply draws a single pixel at the (x,y) location. It acts Tool number 1 simply draws a single pixel at the (x,y) location. It acts
as a 1x1 pixel brush. as a 1x1 pixel brush.
*/ */
api->putpixel(canvas, x, y, api->putpixel(canvas, x, y,
SDL_MapRGB(canvas->format, SDL_MapRGB(canvas->format,
example_r, example_g, example_b)); example_r, example_g, example_b));
/* /*
We use "SDL_MapRGB()" to convert the RGB value we receive from Tux Paint 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 for the user's current color selection to a 'Uint32' pixel value we can
send to Tux Paint's "putpixel()" function. send to Tux Paint's "putpixel()" function.
*/ */
} }
else if (which == TOOL_TWO) else if (which == TOOL_TWO)
{ {
/* /*
Tool number 2 copies a square of pixels (of the size chosen by the user) Tool number 2 copies a square of pixels (of the size chosen by the user)
from the opposite side of the canvas and puts it under the cursor. from the opposite side of the canvas and puts it under the cursor.
*/ */
for (yy = -example_size; yy < example_size; yy++) for (yy = -example_size; yy < example_size; yy++)
{ {
@ -636,14 +641,14 @@ void example_line_callback(void *pointer, int which, SDL_Surface * canvas,
snapshot->h - y - yy)); snapshot->h - y - yy));
/* /*
Here we have simply use Tux Paint's "getpixel()" routine to pull pixel Here we have simply use Tux Paint's "getpixel()" routine to pull pixel
values from the 'snapshot', and then "putpixel()" to draw them right values from the 'snapshot', and then "putpixel()" to draw them right
into the 'canvas'. into the 'canvas'.
Note: putpixel() and getpixel() are safe to use, even if your X,Y values 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 are outside of the SDL surface (e.g., negative, or greater than the
surface's width and/or height). surface's width and/or height).
*/ */
} }
} }
} }