1 /*
2   mosaic_shaped.c
3 
4   mosaic_shaped, Add a mosaic_shaped effect to the image using a combination of other tools.
5   Tux Paint - A simple drawing program for children.
6 
7   Credits:
8   * Andrew Corcoran <akanewbie@gmail.com> for the edge step used in hexagon
9   * Whoever who wrote the "Fill" magic tool
10   * Bill Kendrick for the code derived from api->touched
11   * Pere Pujal for joining all toghether
12   * Caroline Ford for the text descriptions
13 
14   Copyright (c) 2002-2009 by Bill Kendrick and others; see AUTHORS.txt
15   bill@newbreedsoftware.com
16   http://www.tuxpaint.org/
17 
18   This program is free software; you can redistribute it and/or modify
19   it under the terms of the GNU General Public License as published by
20   the Free Software Foundation; either version 2 of the License, or
21   (at your option) any later version.
22 
23   This program is distributed in the hope that it will be useful,
24   but WITHOUT ANY WARRANTY; without even the implied warranty of
25   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
26   GNU General Public License for more details.
27 
28   You should have received a copy of the GNU General Public License
29   along with this program; if not, write to the Free Software
30   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
31   (See COPYING.txt)
32 
33   Last updated: May 6, 2009
34   $Id$
35 */
36 
37 #include <stdio.h>
38 #include <string.h>
39 #include <libintl.h>
40 #include "tp_magic_api.h"
41 #include "SDL_image.h"
42 #include "SDL_mixer.h"
43 #include <math.h>
44 #include <limits.h>
45 #include <time.h>
46 
47 
48 #ifndef gettext_noop
49 #define gettext_noop(String) String
50 #endif
51 
52 static void mosaic_shaped_sharpen_pixel(void *ptr, SDL_Surface * canvas, SDL_Surface * last, int x, int y);
53 static void reset_counter(SDL_Surface * canvas, Uint8 * counter);
54 static void fill_square(magic_api * api, SDL_Surface * canvas, int x, int y, int size, Uint32 color);
55 static void deform(magic_api * api, SDL_Surface * srfc);
56 static void do_mosaic_shaped_full(void *ptr, SDL_Surface * canvas, SDL_Surface * last, int which,
57                                   SDL_Rect * update_rect);
58 static void mosaic_shaped_fill(void *ptr_to_api, int which, SDL_Surface * canvas, SDL_Surface * last, int x, int y);
59 static void mosaic_shaped_paint(void *ptr, int which, SDL_Surface * canvas, SDL_Surface * last, int x, int y);
60 
61 Uint32 mosaic_shaped_api_version(void);
62 int mosaic_shaped_init(magic_api * api);
63 int mosaic_shaped_get_tool_count(magic_api * api);
64 SDL_Surface *mosaic_shaped_get_icon(magic_api * api, int which);
65 char *mosaic_shaped_get_name(magic_api * api, int which);
66 
67 char *mosaic_shaped_get_description(magic_api * api, int which, int mode);
68 
69 void mosaic_shaped_drag(magic_api * api, int which, SDL_Surface * canvas,
70                         SDL_Surface * last, int ox, int oy, int x, int y, SDL_Rect * update_rect);
71 
72 void mosaic_shaped_click(magic_api * api, int which, int mode,
73                          SDL_Surface * canvas, SDL_Surface * last, int x, int y, SDL_Rect * update_rect);
74 
75 void mosaic_shaped_release(magic_api * api, int which,
76                            SDL_Surface * canvas, SDL_Surface * last, int x, int y, SDL_Rect * update_rect);
77 
78 void mosaic_shaped_shutdown(magic_api * api);
79 
80 void mosaic_shaped_set_color(magic_api * api, Uint8 r, Uint8 g, Uint8 b);
81 
82 int mosaic_shaped_requires_colors(magic_api * api, int which);
83 
84 void mosaic_shaped_switchin(magic_api * api, int which, int mode, SDL_Surface * canvas);
85 
86 void mosaic_shaped_switchout(magic_api * api, int which, int mode, SDL_Surface * canvas);
87 
88 int mosaic_shaped_modes(magic_api * api, int which);
89 
90 int scan_fill(magic_api * api, SDL_Surface * canvas, SDL_Surface * srfc, int x, int y, int fill_edge, int fill_tile,
91               int size, Uint32 color);
92 
93 Uint8 *mosaic_shaped_counted;
94 Uint8 *mosaic_shaped_done;
95 Uint8 mosaic_shaped_r, mosaic_shaped_g, mosaic_shaped_b;
96 
97 int mosaic_shaped_average_r, mosaic_shaped_average_g, mosaic_shaped_average_b, mosaic_shaped_average_count;
98 Uint32 pixel_average, black, white;
99 
100 enum
101 {
102   TOOL_SQUARE,
103   TOOL_HEX,
104   TOOL_IRREGULAR,
105   mosaic_shaped_NUM_TOOLS
106 };
107 
108 static Mix_Chunk *mosaic_shaped_snd_effect[mosaic_shaped_NUM_TOOLS];
109 static SDL_Surface *canvas_shaped;
110 static SDL_Surface *canvas_back;
111 static SDL_Surface *mosaic_shaped_pattern;
112 
113 const char *mosaic_shaped_snd_filenames[mosaic_shaped_NUM_TOOLS] = {
114   "mosaic_shaped_square.ogg",
115   "mosaic_shaped_hex.ogg",
116   "mosaic_shaped_irregular.ogg",        /* FIXME *//*what's problem? */
117 };
118 
119 const char *mosaic_shaped_icon_filenames[mosaic_shaped_NUM_TOOLS] = {
120   "mosaic_shaped_square.png",
121   "mosaic_shaped_hex.png",
122   "mosaic_shaped_irregular.png",
123 };
124 
125 const char *mosaic_shaped_pattern_filenames[mosaic_shaped_NUM_TOOLS] = {
126   "mosaic_shaped_square_pattern.png",
127   "mosaic_shaped_hex_pattern.png",
128   "mosaic_shaped_irregular_pattern.png",
129 };
130 
131 const char *mosaic_shaped_names[mosaic_shaped_NUM_TOOLS] = {
132   gettext_noop("Square Mosaic"),
133   gettext_noop("Hexagon Mosaic"),
134   gettext_noop("Irregular Mosaic"),
135 
136 };
137 
138 const char *mosaic_shaped_descs[mosaic_shaped_NUM_TOOLS][2] = {
139   {
140    gettext_noop("Click and drag the mouse to add a square mosaic to parts of your picture."),
141    gettext_noop("Click to add a square mosaic to your entire picture."),
142    },
143 
144   {
145    gettext_noop("Click and drag the mouse to add a hexagonal mosaic to parts of your picture."),
146    gettext_noop("Click to add a hexagonal mosaic to your entire picture."),
147    },
148 
149   {
150    gettext_noop("Click and drag the mouse to add an irregular mosaic to parts of your picture."),
151    gettext_noop("Click to add an irregular mosaic to your entire picture."),
152    },
153 };
154 
mosaic_shaped_api_version(void)155 Uint32 mosaic_shaped_api_version(void)
156 {
157   return (TP_MAGIC_API_VERSION);
158 }
159 
160 //Load sounds
mosaic_shaped_init(magic_api * api)161 int mosaic_shaped_init(magic_api * api)
162 {
163   int i;
164   char fname[1024];
165 
166   mosaic_shaped_pattern = NULL;
167 
168   for (i = 0; i < mosaic_shaped_NUM_TOOLS; i++)
169     {
170       snprintf(fname, sizeof(fname), "%s/sounds/magic/%s", api->data_directory, mosaic_shaped_snd_filenames[i]);
171       mosaic_shaped_snd_effect[i] = Mix_LoadWAV(fname);
172     }
173 
174   return (1);
175 }
176 
mosaic_shaped_get_tool_count(magic_api * api ATTRIBUTE_UNUSED)177 int mosaic_shaped_get_tool_count(magic_api * api ATTRIBUTE_UNUSED)
178 {
179   return (mosaic_shaped_NUM_TOOLS);
180 }
181 
182 // Load our icons:
mosaic_shaped_get_icon(magic_api * api,int which)183 SDL_Surface *mosaic_shaped_get_icon(magic_api * api, int which)
184 {
185   char fname[1024];
186 
187   snprintf(fname, sizeof(fname), "%simages/magic/%s", api->data_directory, mosaic_shaped_icon_filenames[which]);
188   return (IMG_Load(fname));
189 }
190 
191 // Return our names, localized:
mosaic_shaped_get_name(magic_api * api ATTRIBUTE_UNUSED,int which)192 char *mosaic_shaped_get_name(magic_api * api ATTRIBUTE_UNUSED, int which)
193 {
194   return (strdup(gettext_noop(mosaic_shaped_names[which])));
195 }
196 
197 // Return our descriptions, localized:
mosaic_shaped_get_description(magic_api * api ATTRIBUTE_UNUSED,int which,int mode)198 char *mosaic_shaped_get_description(magic_api * api ATTRIBUTE_UNUSED, int which, int mode)
199 {
200   return (strdup(gettext_noop(mosaic_shaped_descs[which][mode - 1])));
201 }
202 
203 //Calculates the grey scale value for a rgb pixel
mosaic_shaped_grey(Uint8 r1,Uint8 g1,Uint8 b1)204 static int mosaic_shaped_grey(Uint8 r1, Uint8 g1, Uint8 b1)
205 {
206   return 0.3 * r1 + .59 * g1 + 0.11 * b1;
207 }
208 
209 // Do the effect for the full image
do_mosaic_shaped_full(void * ptr,SDL_Surface * canvas,SDL_Surface * last ATTRIBUTE_UNUSED,int which ATTRIBUTE_UNUSED,SDL_Rect * update_rect ATTRIBUTE_UNUSED)210 static void do_mosaic_shaped_full(void *ptr, SDL_Surface * canvas, SDL_Surface * last ATTRIBUTE_UNUSED,
211                                   int which ATTRIBUTE_UNUSED, SDL_Rect * update_rect ATTRIBUTE_UNUSED)
212 {
213   int i, j, size;
214   Uint32 mosaic_shaped_color;
215   magic_api *api = (magic_api *) ptr;
216 
217   mosaic_shaped_color = SDL_MapRGBA(canvas->format, mosaic_shaped_r, mosaic_shaped_g, mosaic_shaped_b, 0);
218 
219   for (i = 3; i < canvas->w - 3; i += 2)
220     {
221       api->playsound(mosaic_shaped_snd_effect[which], 128, 255);
222       api->update_progress_bar();
223 
224       for (j = 3; j < canvas->h - 3; j += 2)
225         {
226           if (!mosaic_shaped_done[canvas->w * j + i])
227             if (!mosaic_shaped_counted[canvas->w * j + i])
228               if (api->getpixel(canvas_shaped, i, j) != black)
229                 {
230                   mosaic_shaped_average_r = 0;
231                   mosaic_shaped_average_g = 0;
232                   mosaic_shaped_average_b = 0;
233                   mosaic_shaped_average_count = 0;
234                   scan_fill(api, canvas, canvas_shaped, i, j, 1, 0, 1, mosaic_shaped_color);
235 
236                   if (mosaic_shaped_average_count > 0)
237                     {
238                       reset_counter(canvas, mosaic_shaped_counted);
239                       size = 0;
240                       pixel_average =
241                         SDL_MapRGB(canvas->format, mosaic_shaped_average_r / mosaic_shaped_average_count,
242                                    mosaic_shaped_average_g / mosaic_shaped_average_count,
243                                    mosaic_shaped_average_b / mosaic_shaped_average_count);
244                       scan_fill(api, canvas, canvas_shaped, i, j, 0, 1, size, pixel_average);
245                     }
246                 }
247         }
248     }
249 }
250 
251 /* Fills a tesera */
mosaic_shaped_fill(void * ptr_to_api,int which ATTRIBUTE_UNUSED,SDL_Surface * canvas,SDL_Surface * last ATTRIBUTE_UNUSED,int x,int y)252 static void mosaic_shaped_fill(void *ptr_to_api, int which ATTRIBUTE_UNUSED, SDL_Surface * canvas,
253                                SDL_Surface * last ATTRIBUTE_UNUSED, int x, int y)
254 {
255   Uint32 mosaic_shaped_color;
256   int size;
257   magic_api *api = (magic_api *) ptr_to_api;
258 
259   x = clamp(0, x, canvas->w - 1);
260   y = clamp(0, y, canvas->h - 1);
261   mosaic_shaped_color = SDL_MapRGBA(canvas->format, mosaic_shaped_r, mosaic_shaped_g, mosaic_shaped_b, 0);
262   mosaic_shaped_average_r = 0;
263   mosaic_shaped_average_g = 0;
264   mosaic_shaped_average_b = 0;
265   mosaic_shaped_average_count = 0;
266 
267   if (api->getpixel(canvas_shaped, x, y) == black)
268     {
269       return;
270     }
271 
272   scan_fill(api, canvas, canvas_shaped, x, y, 1, 0, 1, mosaic_shaped_color);
273 
274   if (mosaic_shaped_average_count > 0)
275     {
276       size = 0;
277       pixel_average =
278         SDL_MapRGB(canvas->format, mosaic_shaped_average_r / mosaic_shaped_average_count,
279                    mosaic_shaped_average_g / mosaic_shaped_average_count,
280                    mosaic_shaped_average_b / mosaic_shaped_average_count);
281       reset_counter(canvas, mosaic_shaped_counted);
282       scan_fill(api, canvas, canvas_shaped, x, y, 0, 1, size, pixel_average);
283     }
284 }
285 
286 // Affect the canvas on drag:
mosaic_shaped_drag(magic_api * api,int which,SDL_Surface * canvas,SDL_Surface * last,int ox,int oy,int x,int y,SDL_Rect * update_rect)287 void mosaic_shaped_drag(magic_api * api, int which, SDL_Surface * canvas,
288                         SDL_Surface * last, int ox, int oy, int x, int y, SDL_Rect * update_rect)
289 {
290   api->line(api, which, canvas, last, ox, oy, x, y, 1, mosaic_shaped_fill);
291   update_rect->x = min(ox, x) - mosaic_shaped_pattern->w;
292   update_rect->y = min(oy, y) - mosaic_shaped_pattern->h;
293   update_rect->w = max(ox, x) + mosaic_shaped_pattern->w - update_rect->x;
294   update_rect->h = max(oy, y) + mosaic_shaped_pattern->h - update_rect->y;
295   api->playsound(mosaic_shaped_snd_effect[which], (x * 255) / canvas->w, 255);
296 }
297 
298 // Affect the canvas on click:
mosaic_shaped_click(magic_api * api,int which,int mode,SDL_Surface * canvas,SDL_Surface * last,int x,int y,SDL_Rect * update_rect)299 void mosaic_shaped_click(magic_api * api, int which, int mode,
300                          SDL_Surface * canvas, SDL_Surface * last, int x, int y, SDL_Rect * update_rect)
301 {
302   if (mode == MODE_FULLSCREEN)
303     {
304       update_rect->x = 0;
305       update_rect->y = 0;
306       update_rect->w = canvas->w;
307       update_rect->h = canvas->h;
308       do_mosaic_shaped_full(api, canvas, last, which, update_rect);
309       api->playsound(mosaic_shaped_snd_effect[which], 128, 255);
310     }
311   else
312     {
313       mosaic_shaped_drag(api, which, canvas, last, x, y, x, y, update_rect);
314     }
315 }
316 
317 // Affect the canvas on release:
mosaic_shaped_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)318 void mosaic_shaped_release(magic_api * api ATTRIBUTE_UNUSED, int which ATTRIBUTE_UNUSED,
319                            SDL_Surface * canvas ATTRIBUTE_UNUSED, SDL_Surface * last ATTRIBUTE_UNUSED,
320                            int x ATTRIBUTE_UNUSED, int y ATTRIBUTE_UNUSED, SDL_Rect * update_rect ATTRIBUTE_UNUSED)
321 {
322 }
323 
324 // No setup happened:
mosaic_shaped_shutdown(magic_api * api ATTRIBUTE_UNUSED)325 void mosaic_shaped_shutdown(magic_api * api ATTRIBUTE_UNUSED)
326 {
327   //Clean up sounds
328   int i;
329 
330   for (i = 0; i < mosaic_shaped_NUM_TOOLS; i++)
331     {
332       if (mosaic_shaped_snd_effect[i] != NULL)
333         {
334           Mix_FreeChunk(mosaic_shaped_snd_effect[i]);
335         }
336     }
337 }
338 
339 // Record the color from Tux Paint:
mosaic_shaped_set_color(magic_api * api ATTRIBUTE_UNUSED,Uint8 r,Uint8 g,Uint8 b)340 void mosaic_shaped_set_color(magic_api * api ATTRIBUTE_UNUSED, Uint8 r, Uint8 g, Uint8 b)
341 {
342   mosaic_shaped_r = r;
343   mosaic_shaped_g = g;
344   mosaic_shaped_b = b;
345 }
346 
347 // Use colors:
mosaic_shaped_requires_colors(magic_api * api ATTRIBUTE_UNUSED,int which ATTRIBUTE_UNUSED)348 int mosaic_shaped_requires_colors(magic_api * api ATTRIBUTE_UNUSED, int which ATTRIBUTE_UNUSED)
349 {
350   return 1;
351 }
352 
353 //Sharpen a pixel
mosaic_shaped_sharpen_pixel(void * ptr,SDL_Surface * canvas ATTRIBUTE_UNUSED,SDL_Surface * last,int x,int y)354 static void mosaic_shaped_sharpen_pixel(void *ptr,
355                                         SDL_Surface * canvas ATTRIBUTE_UNUSED, SDL_Surface * last, int x, int y)
356 {
357   magic_api *api = (magic_api *) ptr;
358   Uint8 r1, g1, b1;
359   int grey;
360   int i, j;
361   double sobel_1 = 0, sobel_2 = 0;
362   double temp;
363 
364   //Sobel weighting masks
365   const int sobel_weights_1[3][3] = { {1, 2, 1},
366   {0, 0, 0},
367   {-1, -2, -1}
368   };
369   const int sobel_weights_2[3][3] = { {-1, 0, 1},
370   {-2, 0, 2},
371   {-1, 0, 1}
372   };
373   sobel_1 = 0;
374   sobel_2 = 0;
375 
376   for (i = -1; i < 2; i++)
377     {
378       for (j = -1; j < 2; j++)
379         {
380           //No need to check if inside canvas, getpixel does it for us.
381           SDL_GetRGB(api->getpixel(last, x + i, y + j), last->format, &r1, &g1, &b1);
382           grey = mosaic_shaped_grey(r1, g1, b1);
383           sobel_1 += grey * sobel_weights_1[i + 1][j + 1];
384           sobel_2 += grey * sobel_weights_2[i + 1][j + 1];
385         }
386     }
387 
388   temp = sqrt(sobel_1 * sobel_1 + sobel_2 * sobel_2);
389   temp = (temp / 1443) * 255.0;
390 
391   if (temp > 25)
392     {
393       api->putpixel(canvas_shaped, x, y, SDL_MapRGBA(canvas_shaped->format, 0, 0, 0, 0));
394     }
395 }
396 
397 
398 
mosaic_shaped_switchin(magic_api * api,int which,int mode ATTRIBUTE_UNUSED,SDL_Surface * canvas)399 void mosaic_shaped_switchin(magic_api * api, int which, int mode ATTRIBUTE_UNUSED, SDL_Surface * canvas)
400 {
401   int y, x;
402   int i, j;
403   SDL_Rect rect;
404   SDL_Surface *surf_aux;
405   Uint32 amask;
406 
407   mosaic_shaped_counted = (Uint8 *) malloc(sizeof(Uint8) * (canvas->w * canvas->h));
408 
409   if (mosaic_shaped_counted == NULL)
410     {
411       fprintf(stderr, "\nError: Can't build drawing touch mask!\n");
412       exit(1);
413     }
414 
415   mosaic_shaped_done = (Uint8 *) malloc(sizeof(Uint8) * (canvas->w * canvas->h));
416 
417   if (mosaic_shaped_done == NULL)
418     {
419       fprintf(stderr, "\nError: Can't build drawing touch mask!\n");
420       exit(1);
421     }
422 
423   amask = ~(canvas->format->Rmask | canvas->format->Gmask | canvas->format->Bmask);
424   canvas_shaped = SDL_CreateRGBSurface(SDL_SWSURFACE,
425                                        canvas->w,
426                                        canvas->h,
427                                        canvas->format->BitsPerPixel,
428                                        canvas->format->Rmask, canvas->format->Gmask, canvas->format->Bmask, amask);
429   surf_aux = SDL_CreateRGBSurface(SDL_SWSURFACE,
430                                   canvas->w + 10,
431                                   canvas->h + 10,
432                                   canvas->format->BitsPerPixel,
433                                   canvas->format->Rmask, canvas->format->Gmask, canvas->format->Bmask, amask);
434 
435   /* Generation of patterns now in the program, solves #210 */
436   if (which == TOOL_SQUARE)
437     {
438       mosaic_shaped_pattern = SDL_CreateRGBSurface(SDL_SWSURFACE,
439                                                    16,
440                                                    16,
441                                                    canvas->format->BitsPerPixel,
442                                                    canvas->format->Rmask,
443                                                    canvas->format->Gmask, canvas->format->Bmask, amask);
444       SDL_FillRect(mosaic_shaped_pattern, NULL,
445                    SDL_MapRGBA(mosaic_shaped_pattern->format, 255, 255, 255, SDL_ALPHA_OPAQUE));
446       /* Shape */
447       for (i = 0; i < mosaic_shaped_pattern->w; i++)
448         {
449           api->putpixel(mosaic_shaped_pattern, 0, i,
450                         SDL_MapRGBA(mosaic_shaped_pattern->format, 0, 0, 0, SDL_ALPHA_OPAQUE));
451           api->putpixel(mosaic_shaped_pattern, mosaic_shaped_pattern->w - 1, i,
452                         SDL_MapRGBA(mosaic_shaped_pattern->format, 0, 0, 0, SDL_ALPHA_OPAQUE));
453           api->putpixel(mosaic_shaped_pattern, i, 0,
454                         SDL_MapRGBA(mosaic_shaped_pattern->format, 0, 0, 0, SDL_ALPHA_OPAQUE));
455           api->putpixel(mosaic_shaped_pattern, i, mosaic_shaped_pattern->w - 1,
456                         SDL_MapRGBA(mosaic_shaped_pattern->format, 0, 0, 0, SDL_ALPHA_OPAQUE));
457         }
458       /* Shadow */
459       for (i = 1; i < mosaic_shaped_pattern->w - 1; i++)
460         {
461           api->putpixel(mosaic_shaped_pattern, 1, i,
462                         SDL_MapRGBA(mosaic_shaped_pattern->format, 128, 128, 128, SDL_ALPHA_OPAQUE));
463           api->putpixel(mosaic_shaped_pattern, mosaic_shaped_pattern->w - 2, i,
464                         SDL_MapRGBA(mosaic_shaped_pattern->format, 128, 128, 128, SDL_ALPHA_OPAQUE));
465           api->putpixel(mosaic_shaped_pattern, i, 1,
466                         SDL_MapRGBA(mosaic_shaped_pattern->format, 128, 128, 128, SDL_ALPHA_OPAQUE));
467           api->putpixel(mosaic_shaped_pattern, i, mosaic_shaped_pattern->w - 2,
468                         SDL_MapRGBA(mosaic_shaped_pattern->format, 128, 128, 128, SDL_ALPHA_OPAQUE));
469 
470         }
471       api->putpixel(mosaic_shaped_pattern, 2, 2,
472                     SDL_MapRGBA(mosaic_shaped_pattern->format, 152, 152, 152, SDL_ALPHA_OPAQUE));
473       api->putpixel(mosaic_shaped_pattern, 2, mosaic_shaped_pattern->h - 3,
474                     SDL_MapRGBA(mosaic_shaped_pattern->format, 152, 152, 152, SDL_ALPHA_OPAQUE));
475       api->putpixel(mosaic_shaped_pattern, mosaic_shaped_pattern->w - 3, 2,
476                     SDL_MapRGBA(mosaic_shaped_pattern->format, 152, 152, 152, SDL_ALPHA_OPAQUE));
477       api->putpixel(mosaic_shaped_pattern, mosaic_shaped_pattern->w - 3, mosaic_shaped_pattern->h - 3,
478                     SDL_MapRGBA(mosaic_shaped_pattern->format, 152, 152, 152, SDL_ALPHA_OPAQUE));
479     }
480   else if (which == TOOL_IRREGULAR)
481     {
482       mosaic_shaped_pattern = SDL_CreateRGBSurface(SDL_SWSURFACE,
483                                                    64,
484                                                    64,
485                                                    canvas->format->BitsPerPixel,
486                                                    canvas->format->Rmask,
487                                                    canvas->format->Gmask, canvas->format->Bmask, amask);
488       SDL_FillRect(mosaic_shaped_pattern, NULL,
489                    SDL_MapRGBA(mosaic_shaped_pattern->format, 255, 255, 255, SDL_ALPHA_OPAQUE));
490 
491       /* Start/end of lines taken from the original mosaic_shaped_irregular_pattern.png */
492       api->line(api, which, mosaic_shaped_pattern, NULL, 0, 8, 36, 23, 1, mosaic_shaped_paint);
493       api->line(api, which, mosaic_shaped_pattern, NULL, 0, 43, 36, 23, 1, mosaic_shaped_paint);
494       api->line(api, which, mosaic_shaped_pattern, NULL, 0, 26, 28, 53, 1, mosaic_shaped_paint);
495       api->line(api, which, mosaic_shaped_pattern, NULL, 0, 54, 10, 63, 1, mosaic_shaped_paint);
496       api->line(api, which, mosaic_shaped_pattern, NULL, 55, 0, 36, 23, 1, mosaic_shaped_paint);
497       api->line(api, which, mosaic_shaped_pattern, NULL, 63, 43, 28, 53, 1, mosaic_shaped_paint);
498       api->line(api, which, mosaic_shaped_pattern, NULL, 24, 63, 28, 53, 1, mosaic_shaped_paint);
499       api->line(api, which, mosaic_shaped_pattern, NULL, 24, 0, 27, 19, 1, mosaic_shaped_paint);
500       api->line(api, which, mosaic_shaped_pattern, NULL, 63, 8, 50, 6, 1, mosaic_shaped_paint);
501       api->line(api, which, mosaic_shaped_pattern, NULL, 10, 0, 4, 10, 1, mosaic_shaped_paint);
502       api->line(api, which, mosaic_shaped_pattern, NULL, 10, 0, 25, 7, 1, mosaic_shaped_paint);
503       api->line(api, which, mosaic_shaped_pattern, NULL, 41, 0, 26, 12, 1, mosaic_shaped_paint);
504       api->line(api, which, mosaic_shaped_pattern, NULL, 41, 63, 28, 53, 1, mosaic_shaped_paint);
505       api->line(api, which, mosaic_shaped_pattern, NULL, 41, 63, 56, 58, 1, mosaic_shaped_paint);
506       api->line(api, which, mosaic_shaped_pattern, NULL, 63, 53, 55, 45, 1, mosaic_shaped_paint);
507       api->line(api, which, mosaic_shaped_pattern, NULL, 55, 63, 59, 49, 1, mosaic_shaped_paint);
508       api->line(api, which, mosaic_shaped_pattern, NULL, 10, 63, 20, 45, 1, mosaic_shaped_paint);
509       api->line(api, which, mosaic_shaped_pattern, NULL, 63, 26, 40, 18, 1, mosaic_shaped_paint);
510       api->line(api, which, mosaic_shaped_pattern, NULL, 4, 30, 14, 14, 1, mosaic_shaped_paint);
511       api->line(api, which, mosaic_shaped_pattern, NULL, 18, 33, 21, 17, 1, mosaic_shaped_paint);
512       api->line(api, which, mosaic_shaped_pattern, NULL, 23, 48, 29, 27, 1, mosaic_shaped_paint);
513       api->line(api, which, mosaic_shaped_pattern, NULL, 37, 50, 36, 23, 1, mosaic_shaped_paint);
514       api->line(api, which, mosaic_shaped_pattern, NULL, 44, 13, 37, 3, 1, mosaic_shaped_paint);
515       api->line(api, which, mosaic_shaped_pattern, NULL, 59, 24, 55, 7, 1, mosaic_shaped_paint);
516       api->line(api, which, mosaic_shaped_pattern, NULL, 49, 47, 54, 23, 1, mosaic_shaped_paint);
517       api->line(api, which, mosaic_shaped_pattern, NULL, 36, 35, 51, 37, 1, mosaic_shaped_paint);
518       api->line(api, which, mosaic_shaped_pattern, NULL, 61, 44, 52, 31, 1, mosaic_shaped_paint);
519     }
520 
521   else if (which == TOOL_HEX)
522     {
523       mosaic_shaped_pattern = SDL_CreateRGBSurface(SDL_SWSURFACE,
524                                                    48,
525                                                    28,
526                                                    canvas->format->BitsPerPixel,
527                                                    canvas->format->Rmask,
528                                                    canvas->format->Gmask, canvas->format->Bmask, amask);
529       SDL_FillRect(mosaic_shaped_pattern, NULL,
530                    SDL_MapRGBA(mosaic_shaped_pattern->format, 255, 255, 255, SDL_ALPHA_OPAQUE));
531 
532       api->line(api, which, mosaic_shaped_pattern, NULL, 0, 16, 8, 0, 1, mosaic_shaped_paint);
533       api->line(api, which, mosaic_shaped_pattern, NULL, 8, 0, 26, 0, 1, mosaic_shaped_paint);
534       api->line(api, which, mosaic_shaped_pattern, NULL, 26, 0, 32, 14, 1, mosaic_shaped_paint);
535       api->line(api, which, mosaic_shaped_pattern, NULL, 32, 14, 26, 27, 1, mosaic_shaped_paint);
536       api->line(api, which, mosaic_shaped_pattern, NULL, 32, 14, 47, 14, 1, mosaic_shaped_paint);
537       api->line(api, which, mosaic_shaped_pattern, NULL, 0, 13, 8, 27, 1, mosaic_shaped_paint);
538 
539       //make pattern more accurate
540       api->putpixel(mosaic_shaped_pattern, 9, 27,
541                     SDL_MapRGBA(mosaic_shaped_pattern->format, 0, 0, 0, SDL_ALPHA_OPAQUE));
542       api->putpixel(mosaic_shaped_pattern, 9, 26,
543                     SDL_MapRGBA(mosaic_shaped_pattern->format, 0, 0, 0, SDL_ALPHA_OPAQUE));
544       api->putpixel(mosaic_shaped_pattern, 26, 27,
545                     SDL_MapRGBA(mosaic_shaped_pattern->format, 0, 0, 0, SDL_ALPHA_OPAQUE));
546       api->putpixel(mosaic_shaped_pattern, 26, 26,
547                     SDL_MapRGBA(mosaic_shaped_pattern->format, 0, 0, 0, SDL_ALPHA_OPAQUE));
548       api->putpixel(mosaic_shaped_pattern, 26, 25,
549                     SDL_MapRGBA(mosaic_shaped_pattern->format, 0, 0, 0, SDL_ALPHA_OPAQUE));
550       api->putpixel(mosaic_shaped_pattern, 25, 27,
551                     SDL_MapRGBA(mosaic_shaped_pattern->format, 0, 0, 0, SDL_ALPHA_OPAQUE));
552 
553     }
554 
555 
556   rect.w = mosaic_shaped_pattern->w;
557   rect.h = mosaic_shaped_pattern->h;
558 
559   for (i = 0; i < surf_aux->w; i += mosaic_shaped_pattern->w)
560     for (j = 0; j < surf_aux->h; j += mosaic_shaped_pattern->h)
561       {
562         rect.x = i;
563         rect.y = j;
564         SDL_BlitSurface(mosaic_shaped_pattern, NULL, surf_aux, &rect);
565       }
566 
567   if (which == TOOL_IRREGULAR)
568     {
569       deform(api, surf_aux);
570     }
571 
572   SDL_SetAlpha(surf_aux, 0, SDL_ALPHA_OPAQUE);
573   SDL_BlitSurface(surf_aux, NULL, canvas_shaped, NULL);
574   SDL_FreeSurface(surf_aux);
575   black = SDL_MapRGBA(canvas->format, 0, 0, 0, 0);
576   white = SDL_MapRGBA(canvas->format, 255, 255, 255, 0);
577 
578   /* Two black lines at the edges */
579   for (i = 0; i < canvas->w; i++)
580     {
581       api->putpixel(canvas_shaped, i, 0, black);
582       api->putpixel(canvas_shaped, i, 1, black);
583       api->putpixel(canvas_shaped, i, canvas->h - 1, black);
584       api->putpixel(canvas_shaped, i, canvas->h - 2, black);
585     }
586 
587   for (j = 0; j < canvas->h; j++)
588     {
589       api->putpixel(canvas_shaped, 0, j, black);
590       api->putpixel(canvas_shaped, 1, j, black);
591       api->putpixel(canvas_shaped, canvas->w - 1, j, black);
592       api->putpixel(canvas_shaped, canvas->w - 2, j, black);
593     }
594 
595   /* A copy of canvas at switchin, will be used to draw from it as snapshot changes at each click */
596   canvas_back = SDL_CreateRGBSurface(SDL_SWSURFACE,
597                                      canvas->w,
598                                      canvas->h,
599                                      canvas->format->BitsPerPixel,
600                                      canvas->format->Rmask, canvas->format->Gmask, canvas->format->Bmask, amask);
601   SDL_BlitSurface(canvas, NULL, canvas_back, NULL);
602 
603   if (which != TOOL_SQUARE)     /* The pattern for square is small enouth to not need an additional shape */
604     for (y = 0; y < canvas->h; y++)
605       {
606         for (x = 0; x < canvas->w; x++)
607           {
608             mosaic_shaped_sharpen_pixel(api, canvas_shaped, canvas, x, y);
609           }
610       }
611 
612   reset_counter(canvas, mosaic_shaped_counted);
613   reset_counter(canvas, mosaic_shaped_done);
614 }
615 
mosaic_shaped_switchout(magic_api * api ATTRIBUTE_UNUSED,int which ATTRIBUTE_UNUSED,int mode ATTRIBUTE_UNUSED,SDL_Surface * canvas ATTRIBUTE_UNUSED)616 void mosaic_shaped_switchout(magic_api * api ATTRIBUTE_UNUSED, int which ATTRIBUTE_UNUSED, int mode ATTRIBUTE_UNUSED,
617                              SDL_Surface * canvas ATTRIBUTE_UNUSED)
618 {
619   SDL_FreeSurface(canvas_shaped);
620   SDL_FreeSurface(canvas_back);
621   SDL_FreeSurface(mosaic_shaped_pattern);
622   free(mosaic_shaped_counted);
623 }
624 
mosaic_shaped_modes(magic_api * api ATTRIBUTE_UNUSED,int which ATTRIBUTE_UNUSED)625 int mosaic_shaped_modes(magic_api * api ATTRIBUTE_UNUSED, int which ATTRIBUTE_UNUSED)
626 {
627   return (MODE_PAINT | MODE_FULLSCREEN);
628 }
629 
reset_counter(SDL_Surface * canvas,Uint8 * counter)630 void reset_counter(SDL_Surface * canvas, Uint8 * counter)
631 {
632   int i, j;
633 
634   for (j = 0; j < canvas->h; j++)
635     for (i = 0; i < canvas->w; i++)
636       {
637         counter[j * canvas->w + i] = 0;
638       }
639 }
640 
641 
642 int scan_fill_count;
643 
scan_fill(magic_api * api,SDL_Surface * canvas,SDL_Surface * srfc,int x,int y,int fill_edge,int fill_tile,int size,Uint32 color)644 int scan_fill(magic_api * api, SDL_Surface * canvas, SDL_Surface * srfc, int x, int y, int fill_edge, int fill_tile,
645               int size, Uint32 color)
646 {
647   int leftx, rightx;
648   Uint8 r, g, b, a;
649   int i;
650 
651   leftx = x - 1;
652   rightx = x + 1;
653 
654   /* Abort, if we recurse too deep! -bjk 2014.08.05 */
655   scan_fill_count++;
656   if (scan_fill_count > 50000 && 0)
657     {
658       scan_fill_count--;
659       return (0);
660     }
661 
662   if (mosaic_shaped_counted[y * canvas->w + x] == 1)
663     {
664       scan_fill_count--;
665       return (0);
666     }
667 
668   if (api->getpixel(srfc, x, y) == black)
669     {
670       if (fill_edge == 1)
671         {
672           fill_square(api, canvas, x, y, size, color);
673         }
674 
675       scan_fill_count--;
676       return (0);               /* No need to check more */
677     }
678 
679   if (fill_tile == 1)
680     {
681       Uint32 shadow;
682       Uint8 shr, shg, shb, sha;
683       Uint8 cnvsr, cnvsg, cnvsb, cnvsa;
684 
685       shadow = api->getpixel(srfc, x, y);
686       SDL_GetRGBA(shadow, srfc->format, &shr, &shg, &shb, &sha);
687       SDL_GetRGBA(pixel_average, srfc->format, &cnvsr, &cnvsg, &cnvsb, &cnvsa);
688       shadow = SDL_MapRGBA(canvas->format, (shr * cnvsr) / 255, (shg * cnvsg) / 255, (shb * cnvsb) / 255, 0);   //(shr + cnvsr) /2, ;
689       api->putpixel(canvas, x, y, shadow);
690       mosaic_shaped_counted[y * canvas->w + x] = 1;
691       mosaic_shaped_done[y * canvas->w + x] = 1;
692     }
693   else
694     {
695       SDL_GetRGBA(api->getpixel(canvas_back, x, y), canvas_back->format, &r, &g, &b, &a);
696       mosaic_shaped_average_r += r;
697       mosaic_shaped_average_g += g;
698       mosaic_shaped_average_b += b;
699       mosaic_shaped_average_count += 1;
700       mosaic_shaped_counted[y * canvas->w + x] = 1;
701     }
702 
703   /* Search right */
704   while (scan_fill(api, canvas, srfc, rightx, y, fill_edge, fill_tile, size, color) && (rightx < canvas->w))
705     {
706       rightx++;
707     }
708 
709   /* Search left */
710   while (scan_fill(api, canvas, srfc, leftx, y, fill_edge, fill_tile, size, color) && (leftx >= 0))
711     {
712       leftx--;
713     }
714 
715   /* Top / bottom */
716   for (i = leftx; i <= rightx; i++)
717     {
718       if (y > 0)
719         {
720           scan_fill(api, canvas, srfc, i, y - 1, fill_edge, fill_tile, size, color);
721         }
722 
723       if (y + 1 < canvas->w)
724         {
725           scan_fill(api, canvas, srfc, i, y + 1, fill_edge, fill_tile, size, color);
726         }
727     }
728 
729   scan_fill_count--;
730   return (1);
731 }
732 
733 
fill_square(magic_api * api,SDL_Surface * canvas,int x,int y,int size,Uint32 color)734 void fill_square(magic_api * api, SDL_Surface * canvas, int x, int y, int size, Uint32 color)
735 {
736   int i, j;
737 
738   for (i = (x - size); i < (x + 1 + size); i++)
739     for (j = (y - size); j < (y + 1 + size); j++)
740       {
741         api->putpixel(canvas, i, j, color);
742       }
743 }
744 
deform(magic_api * api,SDL_Surface * srfc)745 void deform(magic_api * api, SDL_Surface * srfc)
746 {
747   int i, j;
748 
749   for (j = 0; j < srfc->h; j++)
750     for (i = 0; i < srfc->w; i++)
751       {
752         api->putpixel(srfc, i, j, api->getpixel(srfc, i + sin(j * M_PI / 90) * 10 + 10, j));
753       }
754 
755   for (i = 0; i < srfc->w; i++)
756     for (j = 0; j < srfc->h; j++)
757       {
758         api->putpixel(srfc, i, j, api->getpixel(srfc, i, j + sin(i * M_PI / 90) * 10 + 10));
759       }
760 }
761 
762 /* Paints a 2 pixel square with black and  shadows around 3 more pixels */
mosaic_shaped_paint(void * ptr,int which ATTRIBUTE_UNUSED,SDL_Surface * canvas,SDL_Surface * last ATTRIBUTE_UNUSED,int x,int y)763 static void mosaic_shaped_paint(void *ptr, int which ATTRIBUTE_UNUSED, SDL_Surface * canvas,
764                                 SDL_Surface * last ATTRIBUTE_UNUSED, int x, int y)
765 {
766   magic_api *api = (magic_api *) ptr;
767   int radius, shadow;
768   int i, j, ii, jj;
769   Uint8 r, g, b, a;
770   Uint32 shadow_tone;
771 
772   black = SDL_MapRGBA(canvas->format, 0, 0, 0, SDL_ALPHA_OPAQUE);
773 
774   radius = 1;
775   shadow = 3;
776 
777   for (i = -(radius + shadow); i < (radius + shadow); i++)
778     for (j = -(radius + shadow); j < (radius + shadow); j++)
779       {
780         /* Ensure effects on the edges reaches the opposite side if necessary */
781         ii = x + i;
782         if (ii < 0)
783           ii += canvas->w;
784         if (ii >= canvas->w)
785           ii -= canvas->w;
786         jj = y + j;
787         if (jj < 0)
788           jj += canvas->h;
789         if (jj >= canvas->h)
790           ii -= canvas->h;
791 
792         /* Shadow_tone is also used as a marker, anything already painted on black must finally be black */
793         shadow_tone = api->getpixel(canvas, ii, jj);
794 
795         //      if (abs(i) <= radius && abs(j) <= radius)
796         if (0 <= i && i <= 1 && 0 <= j && j <= 1)
797           api->putpixel(canvas, ii, jj, black);
798 
799         else if (api->in_circle(i, j, radius + shadow) && shadow_tone != black)
800           {
801             SDL_GetRGBA(shadow_tone, canvas->format, &r, &g, &b, &a);
802 
803             /* Shadows should be shadows, not black */
804             if (r > 10)
805               r -= 9;
806             if (g > 10)
807               g -= 9;
808             if (b > 10)
809               b -= 9;
810 
811             api->putpixel(canvas, ii, jj, SDL_MapRGBA(canvas->format, r, g, b, SDL_ALPHA_OPAQUE));
812 
813           }
814 
815       }
816 }
817