1 /*
2 toothpaste.c
3
4 toothpaste, Add a toothpaste effect to the image
5 Tux Paint - A simple drawing program for children.
6
7 Credits: Andrew Corcoran <akanewbie@gmail.com>
8
9 Copyright (c) 2002-2007 by Bill Kendrick and others; see AUTHORS.txt
10 bill@newbreedsoftware.com
11 http://www.tuxpaint.org/
12
13 This program is free software; you can redistribute it and/or modify
14 it under the terms of the GNU General Public License as published by
15 the Free Software Foundation; either version 2 of the License, or
16 (at your option) any later version.
17
18 This program is distributed in the hope that it will be useful,
19 but WITHOUT ANY WARRANTY; without even the implied warranty of
20 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 GNU General Public License for more details.
22
23 You should have received a copy of the GNU General Public License
24 along with this program; if not, write to the Free Software
25 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
26 (See COPYING.txt)
27
28 Last updated: June 6, 2008
29 $Id$
30 */
31
32 #include <stdio.h>
33 #include <string.h>
34 #include <libintl.h>
35 #include "tp_magic_api.h"
36 #include "SDL_image.h"
37 #include "SDL_mixer.h"
38 #include <math.h>
39 #include <limits.h>
40 #include <time.h>
41
42 #ifndef gettext_noop
43 #define gettext_noop(String) String
44 #endif
45
46 double pi;
47 static Uint8 toothpaste_r, toothpaste_g, toothpaste_b;
48 static const int toothpaste_RADIUS = 10;
49 double *toothpaste_weights = NULL;
50
51 enum
52 {
53 TOOL_toothpaste,
54 toothpaste_NUM_TOOLS
55 };
56
57 static Mix_Chunk *toothpaste_snd_effect[toothpaste_NUM_TOOLS];
58
59 const char *toothpaste_snd_filenames[toothpaste_NUM_TOOLS] = {
60 "toothpaste.ogg",
61 };
62
63 const char *toothpaste_icon_filenames[toothpaste_NUM_TOOLS] = {
64 "toothpaste.png",
65 };
66
67 const char *toothpaste_names[toothpaste_NUM_TOOLS] = {
68 gettext_noop("Toothpaste"),
69 };
70
71 const char *toothpaste_descs[toothpaste_NUM_TOOLS] = {
72 gettext_noop("Click and drag to squirt toothpaste onto your picture."),
73 };
74
75
76 Uint32 toothpaste_api_version(void);
77 int toothpaste_init(magic_api * api);
78 int toothpaste_get_tool_count(magic_api * api);
79 SDL_Surface *toothpaste_get_icon(magic_api * api, int which);
80 char *toothpaste_get_name(magic_api * api, int which);
81 char *toothpaste_get_description(magic_api * api, int which, int mode);
82 static void do_toothpaste(void *ptr, int which, SDL_Surface * canvas, SDL_Surface * last, int x, int y);
83 void toothpaste_drag(magic_api * api, int which, SDL_Surface * canvas,
84 SDL_Surface * last, int ox, int oy, int x, int y, SDL_Rect * update_rect);
85 void toothpaste_click(magic_api * api, int which, int mode,
86 SDL_Surface * canvas, SDL_Surface * last, int x, int y, SDL_Rect * update_rect);
87 void toothpaste_release(magic_api * api, int which,
88 SDL_Surface * canvas, SDL_Surface * last, int x, int y, SDL_Rect * update_rect);
89 void toothpaste_shutdown(magic_api * api);
90 void toothpaste_set_color(magic_api * api, Uint8 r, Uint8 g, Uint8 b);
91 int toothpaste_requires_colors(magic_api * api, int which);
92 void toothpaste_switchin(magic_api * api, int which, int mode, SDL_Surface * canvas);
93 void toothpaste_switchout(magic_api * api, int which, int mode, SDL_Surface * canvas);
94 int toothpaste_modes(magic_api * api, int which);
95
toothpaste_api_version(void)96 Uint32 toothpaste_api_version(void)
97 {
98 return (TP_MAGIC_API_VERSION);
99 }
100
101
toothpaste_init(magic_api * api)102 int toothpaste_init(magic_api * api)
103 {
104
105 int i;
106 char fname[1024];
107 int k, j;
108
109 //Load sounds
110 for (i = 0; i < toothpaste_NUM_TOOLS; i++)
111 {
112 snprintf(fname, sizeof(fname), "%s/sounds/magic/%s", api->data_directory, toothpaste_snd_filenames[i]);
113 toothpaste_snd_effect[i] = Mix_LoadWAV(fname);
114 }
115
116 //Set up weights
117 pi = acos(0.0) * 2;
118 toothpaste_weights = (double *)malloc(toothpaste_RADIUS * 2 * toothpaste_RADIUS * 2 * sizeof(double));
119 if (toothpaste_weights == NULL)
120 {
121 return (0);
122 }
123
124 for (k = -toothpaste_RADIUS; k < +toothpaste_RADIUS; k++)
125 {
126 for (j = -toothpaste_RADIUS; j < +toothpaste_RADIUS; j++)
127 {
128 if (api->in_circle(j, k, toothpaste_RADIUS))
129 {
130 toothpaste_weights[(k + toothpaste_RADIUS) * ((toothpaste_RADIUS * 2) - 1) + (j + toothpaste_RADIUS)] =
131 ((fabs(atan2((double)(j), (double)(k)))) / pi);
132 }
133 }
134 }
135
136 return (1);
137 }
138
toothpaste_get_tool_count(magic_api * api ATTRIBUTE_UNUSED)139 int toothpaste_get_tool_count(magic_api * api ATTRIBUTE_UNUSED)
140 {
141 return (toothpaste_NUM_TOOLS);
142 }
143
144 // Load our icons:
toothpaste_get_icon(magic_api * api,int which ATTRIBUTE_UNUSED)145 SDL_Surface *toothpaste_get_icon(magic_api * api, int which ATTRIBUTE_UNUSED)
146 {
147 char fname[1024];
148
149 snprintf(fname, sizeof(fname), "%simages/magic/%s", api->data_directory, toothpaste_icon_filenames[which]);
150 return (IMG_Load(fname));
151 }
152
153 // Return our names, localized:
toothpaste_get_name(magic_api * api ATTRIBUTE_UNUSED,int which)154 char *toothpaste_get_name(magic_api * api ATTRIBUTE_UNUSED, int which)
155 {
156 return (strdup(gettext_noop(toothpaste_names[which])));
157 }
158
159 // Return our descriptions, localized:
toothpaste_get_description(magic_api * api ATTRIBUTE_UNUSED,int which,int mode ATTRIBUTE_UNUSED)160 char *toothpaste_get_description(magic_api * api ATTRIBUTE_UNUSED, int which, int mode ATTRIBUTE_UNUSED)
161 {
162 return (strdup(gettext_noop(toothpaste_descs[which])));
163 }
164
165 // Do the effect:
do_toothpaste(void * ptr,int which ATTRIBUTE_UNUSED,SDL_Surface * canvas,SDL_Surface * last ATTRIBUTE_UNUSED,int x,int y)166 static void do_toothpaste(void *ptr, int which ATTRIBUTE_UNUSED, SDL_Surface * canvas,
167 SDL_Surface * last ATTRIBUTE_UNUSED, int x, int y)
168 {
169 magic_api *api = (magic_api *) ptr;
170
171 int xx, yy;
172
173 // double colr;
174 float h, s, v;
175 Uint8 r, g, b;
176
177 for (yy = y - toothpaste_RADIUS; yy < y + toothpaste_RADIUS; yy++)
178 {
179 for (xx = x - toothpaste_RADIUS; xx < x + toothpaste_RADIUS; xx++)
180 {
181 if (api->in_circle(xx - x, yy - y, toothpaste_RADIUS) && !api->touched(xx, yy))
182 {
183
184 api->rgbtohsv(toothpaste_r, toothpaste_g, toothpaste_b, &h, &s, &v);
185 api->hsvtorgb(h, s,
186 toothpaste_weights[(yy - y + toothpaste_RADIUS) * ((toothpaste_RADIUS * 2) - 1) +
187 (xx - x + toothpaste_RADIUS)], &r, &g, &b);
188 api->putpixel(canvas, xx, yy, SDL_MapRGB(canvas->format, r, g, b));
189
190 }
191 }
192 }
193
194 }
195
196 // Affect the canvas on drag:
toothpaste_drag(magic_api * api,int which,SDL_Surface * canvas,SDL_Surface * last,int ox,int oy,int x,int y,SDL_Rect * update_rect)197 void toothpaste_drag(magic_api * api, int which, SDL_Surface * canvas,
198 SDL_Surface * last, int ox, int oy, int x, int y, SDL_Rect * update_rect)
199 {
200
201 api->line((void *)api, which, canvas, last, ox, oy, x, y, 1, do_toothpaste);
202
203 api->playsound(toothpaste_snd_effect[which], (x * 255) / canvas->w, 255);
204
205 update_rect->x = 0;
206 update_rect->y = 0;
207 update_rect->w = canvas->w;
208 update_rect->h = canvas->h;
209
210 }
211
212 // Affect the canvas on click:
toothpaste_click(magic_api * api,int which,int mode ATTRIBUTE_UNUSED,SDL_Surface * canvas,SDL_Surface * last,int x,int y,SDL_Rect * update_rect)213 void toothpaste_click(magic_api * api, int which, int mode ATTRIBUTE_UNUSED,
214 SDL_Surface * canvas, SDL_Surface * last, int x, int y, SDL_Rect * update_rect)
215 {
216
217 toothpaste_drag(api, which, canvas, last, x, y, x, y, update_rect);
218 }
219
220 // Affect the canvas on release:
toothpaste_release(magic_api * api ATTRIBUTE_UNUSED,int which ATTRIBUTE_UNUSED,SDL_Surface * canvas ATTRIBUTE_UNUSED,SDL_Surface * last ATTRIBUTE_UNUSED,int x ATTRIBUTE_UNUSED,int y ATTRIBUTE_UNUSED,SDL_Rect * update_rect ATTRIBUTE_UNUSED)221 void toothpaste_release(magic_api * api ATTRIBUTE_UNUSED, int which ATTRIBUTE_UNUSED,
222 SDL_Surface * canvas ATTRIBUTE_UNUSED, SDL_Surface * last ATTRIBUTE_UNUSED,
223 int x ATTRIBUTE_UNUSED, int y ATTRIBUTE_UNUSED, SDL_Rect * update_rect ATTRIBUTE_UNUSED)
224 {
225 }
226
227 // No setup happened:
toothpaste_shutdown(magic_api * api ATTRIBUTE_UNUSED)228 void toothpaste_shutdown(magic_api * api ATTRIBUTE_UNUSED)
229 {
230 //Clean up sounds
231 int i;
232
233 for (i = 0; i < toothpaste_NUM_TOOLS; i++)
234 {
235 if (toothpaste_snd_effect[i] != NULL)
236 {
237 Mix_FreeChunk(toothpaste_snd_effect[i]);
238 }
239 }
240 if (toothpaste_weights != NULL)
241 {
242 free(toothpaste_weights);
243 toothpaste_weights = NULL;
244 }
245 }
246
247 // Record the color from Tux Paint:
toothpaste_set_color(magic_api * api ATTRIBUTE_UNUSED,Uint8 r,Uint8 g,Uint8 b)248 void toothpaste_set_color(magic_api * api ATTRIBUTE_UNUSED, Uint8 r, Uint8 g, Uint8 b)
249 {
250 toothpaste_r = r;
251 toothpaste_g = g;
252 toothpaste_b = b;
253 }
254
255 // Use colors:
toothpaste_requires_colors(magic_api * api ATTRIBUTE_UNUSED,int which ATTRIBUTE_UNUSED)256 int toothpaste_requires_colors(magic_api * api ATTRIBUTE_UNUSED, int which ATTRIBUTE_UNUSED)
257 {
258 return 1;
259 }
260
261
toothpaste_switchin(magic_api * api ATTRIBUTE_UNUSED,int which ATTRIBUTE_UNUSED,int mode ATTRIBUTE_UNUSED,SDL_Surface * canvas ATTRIBUTE_UNUSED)262 void toothpaste_switchin(magic_api * api ATTRIBUTE_UNUSED, int which ATTRIBUTE_UNUSED, int mode ATTRIBUTE_UNUSED,
263 SDL_Surface * canvas ATTRIBUTE_UNUSED)
264 {
265 }
266
toothpaste_switchout(magic_api * api ATTRIBUTE_UNUSED,int which ATTRIBUTE_UNUSED,int mode ATTRIBUTE_UNUSED,SDL_Surface * canvas ATTRIBUTE_UNUSED)267 void toothpaste_switchout(magic_api * api ATTRIBUTE_UNUSED, int which ATTRIBUTE_UNUSED, int mode ATTRIBUTE_UNUSED,
268 SDL_Surface * canvas ATTRIBUTE_UNUSED)
269 {
270 }
271
toothpaste_modes(magic_api * api ATTRIBUTE_UNUSED,int which ATTRIBUTE_UNUSED)272 int toothpaste_modes(magic_api * api ATTRIBUTE_UNUSED, int which ATTRIBUTE_UNUSED)
273 {
274 return (MODE_PAINT);
275 }
276