1 /*
2   light.c
3 
4   Light Magic Tool Plugin
5   Tux Paint - A simple drawing program for children.
6 
7   Copyright (c) 2002-2008 by Bill Kendrick and others; see AUTHORS.txt
8   bill@newbreedsoftware.com
9   http://www.tuxpaint.org/
10 
11   This program is free software; you can redistribute it and/or modify
12   it under the terms of the GNU General Public License as published by
13   the Free Software Foundation; either version 2 of the License, or
14   (at your option) any later version.
15 
16   This program is distributed in the hope that it will be useful,
17   but WITHOUT ANY WARRANTY; without even the implied warranty of
18   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19   GNU General Public License for more details.
20 
21   You should have received a copy of the GNU General Public License
22   along with this program; if not, write to the Free Software
23   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
24   (See COPYING.txt)
25 
26   Last updated: July 8, 2008
27   $Id$
28 */
29 
30 #include <stdio.h>
31 #include <string.h>
32 #include <stdlib.h>
33 #include "tp_magic_api.h"
34 #include "SDL_image.h"
35 #include "SDL_mixer.h"
36 
37 #include "math.h"
38 
39 /* Our globals: */
40 
41 static Mix_Chunk *light1_snd, *light2_snd;
42 static float light_h, light_s, light_v;
43 Uint32 light_api_version(void);
44 int light_init(magic_api * api);
45 int light_get_tool_count(magic_api * api);
46 SDL_Surface *light_get_icon(magic_api * api, int which);
47 char *light_get_name(magic_api * api, int which);
48 char *light_get_description(magic_api * api, int which, int mode);
49 static void do_light(void *ptr, int which, SDL_Surface * canvas, SDL_Surface * last, int x, int y);
50 void light_drag(magic_api * api, int which, SDL_Surface * canvas,
51                 SDL_Surface * last, int ox, int oy, int x, int y, SDL_Rect * update_rect);
52 void light_click(magic_api * api, int which, int mode,
53                  SDL_Surface * canvas, SDL_Surface * last, int x, int y, SDL_Rect * update_rect);
54 void light_release(magic_api * api, int which,
55                    SDL_Surface * canvas, SDL_Surface * last, int x, int y, SDL_Rect * update_rect);
56 void light_shutdown(magic_api * api);
57 void light_set_color(magic_api * api, Uint8 r, Uint8 g, Uint8 b);
58 int light_requires_colors(magic_api * api, int which);
59 void light_switchin(magic_api * api, int which, int mode, SDL_Surface * canvas);
60 void light_switchout(magic_api * api, int which, int mode, SDL_Surface * canvas);
61 int light_modes(magic_api * api, int which);
62 
63 
light_api_version(void)64 Uint32 light_api_version(void)
65 {
66   return (TP_MAGIC_API_VERSION);
67 }
68 
69 
70 // No setup required:
light_init(magic_api * api)71 int light_init(magic_api * api)
72 {
73   char fname[1024];
74 
75   snprintf(fname, sizeof(fname), "%s/sounds/magic/light1.ogg", api->data_directory);
76   light1_snd = Mix_LoadWAV(fname);
77 
78   snprintf(fname, sizeof(fname), "%s/sounds/magic/light2.ogg", api->data_directory);
79   light2_snd = Mix_LoadWAV(fname);
80 
81   return (1);
82 }
83 
84 // We have multiple tools:
light_get_tool_count(magic_api * api ATTRIBUTE_UNUSED)85 int light_get_tool_count(magic_api * api ATTRIBUTE_UNUSED)
86 {
87   return (1);
88 }
89 
90 // Load our icons:
light_get_icon(magic_api * api,int which ATTRIBUTE_UNUSED)91 SDL_Surface *light_get_icon(magic_api * api, int which ATTRIBUTE_UNUSED)
92 {
93   char fname[1024];
94 
95   snprintf(fname, sizeof(fname), "%s/images/magic/light.png", api->data_directory);
96 
97   return (IMG_Load(fname));
98 }
99 
100 // Return our names, localized:
light_get_name(magic_api * api ATTRIBUTE_UNUSED,int which ATTRIBUTE_UNUSED)101 char *light_get_name(magic_api * api ATTRIBUTE_UNUSED, int which ATTRIBUTE_UNUSED)
102 {
103   return (strdup(gettext_noop("Light")));
104 }
105 
106 // Return our descriptions, localized:
light_get_description(magic_api * api ATTRIBUTE_UNUSED,int which ATTRIBUTE_UNUSED,int mode ATTRIBUTE_UNUSED)107 char *light_get_description(magic_api * api ATTRIBUTE_UNUSED, int which ATTRIBUTE_UNUSED, int mode ATTRIBUTE_UNUSED)
108 {
109   return (strdup(gettext_noop("Click and drag to draw a beam of light on your picture.")));
110 }
111 
112 // Do the effect:
113 
do_light(void * ptr,int which ATTRIBUTE_UNUSED,SDL_Surface * canvas,SDL_Surface * last ATTRIBUTE_UNUSED,int x,int y)114 static void do_light(void *ptr, int which ATTRIBUTE_UNUSED, SDL_Surface * canvas, SDL_Surface * last ATTRIBUTE_UNUSED,
115                      int x, int y)
116 {
117   magic_api *api = (magic_api *) ptr;
118   int xx, yy;
119   Uint32 pix;
120   Uint8 r, g, b;
121   float h, s, v, new_h, new_s, new_v;
122   float adj;
123 
124   for (yy = -8; yy < 8; yy++)
125     {
126       for (xx = -8; xx < 8; xx++)
127         {
128           if (api->in_circle(xx, yy, 8))
129             {
130               pix = api->getpixel(canvas, x + xx, y + yy);
131 
132               SDL_GetRGB(pix, canvas->format, &r, &g, &b);
133 
134               adj = (7.99 - sqrt(abs(xx * yy))) / 128.0;
135 
136               api->rgbtohsv(r, g, b, &h, &s, &v);
137 
138               v = min((float)1.0, v + adj);
139 
140               if (light_h == -1 && h == -1)
141                 {
142                   new_h = -1;
143                   new_s = 0;
144                   new_v = v;
145                 }
146               else if (light_h == -1)
147                 {
148                   new_h = h;
149                   new_s = max(0.0, s - adj / 2.0);
150                   new_v = v;
151                 }
152               else if (h == -1)
153                 {
154                   new_h = light_h;
155                   new_s = max(0.0, light_s - adj / 2.0);
156                   new_v = v;
157                 }
158               else
159                 {
160                   new_h = (light_h + h) / 2;
161                   new_s = max(0.0, s - adj / 2.0);
162                   new_v = v;
163                 }
164 
165               api->hsvtorgb(new_h, new_s, new_v, &r, &g, &b);
166 
167               api->putpixel(canvas, x + xx, y + yy, SDL_MapRGB(canvas->format, r, g, b));
168             }
169         }
170     }
171 }
172 
173 // Affect the canvas on drag:
light_drag(magic_api * api,int which,SDL_Surface * canvas,SDL_Surface * last,int ox,int oy,int x,int y,SDL_Rect * update_rect)174 void light_drag(magic_api * api, int which, SDL_Surface * canvas,
175                 SDL_Surface * last, int ox, int oy, int x, int y, SDL_Rect * update_rect)
176 {
177   api->line((void *)api, which, canvas, last, ox, oy, x, y, 1, do_light);
178 
179   if (ox > x)
180     {
181       int tmp = ox;
182 
183       ox = x;
184       x = tmp;
185     }
186   if (oy > y)
187     {
188       int tmp = oy;
189 
190       oy = y;
191       y = tmp;
192     }
193 
194   update_rect->x = ox - 8;
195   update_rect->y = oy - 8;
196   update_rect->w = (x + 8) - update_rect->x;
197   update_rect->h = (y + 8) - update_rect->h;
198 
199   api->playsound(light1_snd, (x * 255) / canvas->w, 255);
200 }
201 
202 // Affect the canvas on click:
light_click(magic_api * api,int which,int mode ATTRIBUTE_UNUSED,SDL_Surface * canvas,SDL_Surface * last,int x,int y,SDL_Rect * update_rect)203 void light_click(magic_api * api, int which, int mode ATTRIBUTE_UNUSED,
204                  SDL_Surface * canvas, SDL_Surface * last, int x, int y, SDL_Rect * update_rect)
205 {
206   light_drag(api, which, canvas, last, x, y, x, y, update_rect);
207 }
208 
209 // Affect the canvas on release:
light_release(magic_api * api,int which ATTRIBUTE_UNUSED,SDL_Surface * canvas,SDL_Surface * last ATTRIBUTE_UNUSED,int x,int y ATTRIBUTE_UNUSED,SDL_Rect * update_rect ATTRIBUTE_UNUSED)210 void light_release(magic_api * api, int which ATTRIBUTE_UNUSED,
211                    SDL_Surface * canvas, SDL_Surface * last ATTRIBUTE_UNUSED,
212                    int x, int y ATTRIBUTE_UNUSED, SDL_Rect * update_rect ATTRIBUTE_UNUSED)
213 {
214   api->playsound(light2_snd, (x * 255) / canvas->w, 255);
215 }
216 
217 // No setup happened:
light_shutdown(magic_api * api ATTRIBUTE_UNUSED)218 void light_shutdown(magic_api * api ATTRIBUTE_UNUSED)
219 {
220   if (light1_snd != NULL)
221     Mix_FreeChunk(light1_snd);
222   if (light2_snd != NULL)
223     Mix_FreeChunk(light2_snd);
224 }
225 
226 // Record the color from Tux Paint:
light_set_color(magic_api * api,Uint8 r,Uint8 g,Uint8 b)227 void light_set_color(magic_api * api, Uint8 r, Uint8 g, Uint8 b)
228 {
229   api->rgbtohsv(r, g, b, &light_h, &light_s, &light_v);
230 }
231 
232 // Use colors:
light_requires_colors(magic_api * api ATTRIBUTE_UNUSED,int which ATTRIBUTE_UNUSED)233 int light_requires_colors(magic_api * api ATTRIBUTE_UNUSED, int which ATTRIBUTE_UNUSED)
234 {
235   return 1;
236 }
237 
light_switchin(magic_api * api ATTRIBUTE_UNUSED,int which ATTRIBUTE_UNUSED,int mode ATTRIBUTE_UNUSED,SDL_Surface * canvas ATTRIBUTE_UNUSED)238 void light_switchin(magic_api * api ATTRIBUTE_UNUSED, int which ATTRIBUTE_UNUSED, int mode ATTRIBUTE_UNUSED,
239                     SDL_Surface * canvas ATTRIBUTE_UNUSED)
240 {
241 }
242 
light_switchout(magic_api * api ATTRIBUTE_UNUSED,int which ATTRIBUTE_UNUSED,int mode ATTRIBUTE_UNUSED,SDL_Surface * canvas ATTRIBUTE_UNUSED)243 void light_switchout(magic_api * api ATTRIBUTE_UNUSED, int which ATTRIBUTE_UNUSED, int mode ATTRIBUTE_UNUSED,
244                      SDL_Surface * canvas ATTRIBUTE_UNUSED)
245 {
246 }
247 
light_modes(magic_api * api ATTRIBUTE_UNUSED,int which ATTRIBUTE_UNUSED)248 int light_modes(magic_api * api ATTRIBUTE_UNUSED, int which ATTRIBUTE_UNUSED)
249 {
250   return (MODE_PAINT);
251 }
252