source: tuxpaint/trunk/fuentes/magic/src/calligraphy.c @ 219

Last change on this file since 219 was 219, checked in by mabarracus, 4 years ago

added sources from trusty

File size: 13.3 KB
Line 
1/*
2  calligraphy.c
3
4  Calligraphy 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: calligraphy.c,v 1.11 2011/11/26 22:04:50 perepujal Exp $
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
39typedef struct
40{
41  float x, y;
42} Point2D;
43
44static Mix_Chunk * calligraphy_snd;
45static Point2D calligraphy_control_points[4];
46static int calligraphy_r, calligraphy_g, calligraphy_b;
47static int calligraphy_old_thick;
48static Uint32 calligraphy_last_time;
49static SDL_Surface * calligraphy_brush, * calligraphy_colored_brush;
50
51/* Local Function Prototypes */
52static Point2D calligraphy_PointOnCubicBezier(Point2D* cp, float t);
53static void calligraphy_ComputeBezier(Point2D* cp, int numberOfPoints, Point2D* curve);
54static float calligraphy_dist(float x1, float y1, float x2, float y2);
55int calligraphy_init(magic_api * api);
56Uint32 calligraphy_api_version(void);
57int calligraphy_get_tool_count(magic_api * api);
58SDL_Surface * calligraphy_get_icon(magic_api * api, int which);
59char * calligraphy_get_name(magic_api * api, int which);
60char * calligraphy_get_description(magic_api * api, int which, int mode);
61void calligraphy_drag(magic_api * api, int which, SDL_Surface * canvas,
62                   SDL_Surface * last, int ox, int oy, int x, int y,
63                       SDL_Rect * update_rect);
64void calligraphy_click(magic_api * api, int which, int mode,
65                    SDL_Surface * canvas, SDL_Surface * last,
66                    int x, int y, SDL_Rect * update_rect);
67void calligraphy_release(magic_api * api, int which,
68                    SDL_Surface * canvas, SDL_Surface * last,
69                    int x, int y, SDL_Rect * update_rect);
70void calligraphy_shutdown(magic_api * api);
71void calligraphy_set_color(magic_api * api, Uint8 r, Uint8 g, Uint8 b);
72int calligraphy_requires_colors(magic_api * api, int which);
73void calligraphy_switchin(magic_api * api, int which, int mode, SDL_Surface * canvas);
74void calligraphy_switchout(magic_api * api, int which, int mode, SDL_Surface * canvas);
75int calligraphy_modes(magic_api * api, int which);
76
77// No setup required:
78int calligraphy_init(magic_api * api)
79{
80  char fname[1024];
81
82  snprintf(fname, sizeof(fname), "%s/sounds/magic/calligraphy.ogg",
83           api->data_directory);
84
85  calligraphy_snd = Mix_LoadWAV(fname);
86
87  snprintf(fname, sizeof(fname), "%s/images/magic/calligraphy_brush.png",
88           api->data_directory);
89
90  calligraphy_brush = IMG_Load(fname);
91  calligraphy_colored_brush = NULL;
92
93  if (calligraphy_brush == NULL)
94    return(0);
95
96  calligraphy_last_time = 0;
97
98  /* (Force blit first time we get a color) */
99  calligraphy_r = -1;
100  calligraphy_g = -1;
101  calligraphy_b = -1;
102
103  return(1);
104}
105
106Uint32 calligraphy_api_version(void) { return(TP_MAGIC_API_VERSION); }
107
108// Only one tool:
109int calligraphy_get_tool_count(magic_api * api ATTRIBUTE_UNUSED)
110{
111  return(1);
112}
113
114// Load our icon:
115SDL_Surface * calligraphy_get_icon(magic_api * api, int which ATTRIBUTE_UNUSED)
116{
117  char fname[1024];
118
119  snprintf(fname, sizeof(fname), "%s/images/magic/calligraphy.png",
120           api->data_directory);
121  return(IMG_Load(fname));
122}
123
124// Return our name, localized:
125char * calligraphy_get_name(magic_api * api ATTRIBUTE_UNUSED, int which ATTRIBUTE_UNUSED)
126{
127  return(strdup(gettext_noop("Calligraphy")));
128}
129
130// Return our description, localized:
131char * calligraphy_get_description(magic_api * api ATTRIBUTE_UNUSED, int which ATTRIBUTE_UNUSED, int mode ATTRIBUTE_UNUSED)
132{
133  return(strdup(
134         gettext_noop("Click and move the mouse around to draw in calligraphy.")));
135}
136
137
138void calligraphy_drag(magic_api * api, int which ATTRIBUTE_UNUSED, SDL_Surface * canvas,
139                   SDL_Surface * last ATTRIBUTE_UNUSED, int ox, int oy, int x, int y,
140                   SDL_Rect * update_rect)
141{
142  Point2D * curve;
143  int i, n_points, thick, new_thick;
144  Uint32 colr;
145  SDL_Rect src, dest;
146
147//  if (SDL_GetTicks() < calligraphy_last_time + 5)
148//    return;
149 
150  calligraphy_control_points[0].x = calligraphy_control_points[1].x;
151  calligraphy_control_points[0].y = calligraphy_control_points[1].y;
152  calligraphy_control_points[1].x = calligraphy_control_points[2].x;
153  calligraphy_control_points[1].y = calligraphy_control_points[2].y;
154  calligraphy_control_points[2].x = calligraphy_control_points[3].x;
155  calligraphy_control_points[2].y = calligraphy_control_points[3].y;
156  calligraphy_control_points[3].x = x;
157  calligraphy_control_points[3].y = y;
158
159  calligraphy_last_time = SDL_GetTicks();
160
161
162/*
163  if ((calligraphy_control_points[0].x == calligraphy_control_points[1].x &&
164       calligraphy_control_points[0].y == calligraphy_control_points[1].y) ||
165      (calligraphy_control_points[1].x == calligraphy_control_points[2].x &&
166       calligraphy_control_points[1].y == calligraphy_control_points[2].y) ||
167      (calligraphy_control_points[2].x == calligraphy_control_points[3].x &&
168       calligraphy_control_points[2].y == calligraphy_control_points[3].y))
169    return; // No-op; not enough control points yet!
170*/
171
172  n_points = calligraphy_dist(calligraphy_control_points[0].x,
173                                calligraphy_control_points[0].y,
174                                calligraphy_control_points[1].x,
175                                calligraphy_control_points[1].y) +
176                calligraphy_dist(calligraphy_control_points[1].x,
177                                calligraphy_control_points[1].y,
178                                calligraphy_control_points[2].x,
179                                calligraphy_control_points[2].y) +
180                  calligraphy_dist(calligraphy_control_points[2].x,
181                                calligraphy_control_points[2].y,
182                                calligraphy_control_points[3].x,
183                                calligraphy_control_points[3].y);
184
185  if (n_points == 0)
186    return; // No-op; not any points to plot
187
188
189  curve = (Point2D *) malloc(sizeof(Point2D) * n_points);
190
191  calligraphy_ComputeBezier(calligraphy_control_points, n_points, curve);
192
193  colr = SDL_MapRGB(canvas->format, 
194                       calligraphy_r,
195                       calligraphy_g,
196                       calligraphy_b);
197
198  new_thick = 40 - min((n_points /* / 2 */), 32);
199
200  for (i = 0; i < n_points - 1; i++)
201  {
202    thick = ((new_thick * i) +
203             (calligraphy_old_thick * (n_points - i))) / n_points;
204
205
206    /* The new way, using an antialiased brush bitmap */
207
208    x = curve[i].x;
209    y = curve[i].y;
210
211    src.x = calligraphy_brush->w - thick / 2 - thick / 4;
212    src.w = thick / 2 + thick / 4;
213    src.y = 0;
214    src.h = thick / 4;
215
216    dest.x = x - thick / 4;
217    dest.y = y - thick / 4;
218
219    SDL_BlitSurface(calligraphy_colored_brush, &src, canvas, &dest);
220
221
222    src.x = 0;
223    src.w = thick / 2 + thick / 4;
224    src.y = calligraphy_brush->h - thick / 4;
225    src.h = thick / 4;
226
227    dest.x = x - thick / 2;
228    dest.y = y;
229
230    SDL_BlitSurface(calligraphy_colored_brush, &src, canvas, &dest);
231
232    /* Old way; using putpixel:
233    SDL_LockSurface(canvas);
234
235    for (j = -(thick / 2); j < (thick / 2) + 1; j++)
236    {
237      x = curve[i].x + j;
238      y = curve[i].y - (j / 2); // 30 degrees
239
240      api->putpixel(canvas, x, y, colr);
241      api->putpixel(canvas, x + 1, y, colr);
242      api->putpixel(canvas, x, y + 1, colr);
243      api->putpixel(canvas, x + 1, y + 1, colr);
244    }
245 
246    SDL_UnlockSurface(canvas);
247    */
248  }
249
250  calligraphy_old_thick = (calligraphy_old_thick + new_thick) / 2;
251
252  free(curve);
253
254
255
256  if (ox > x) { int tmp = ox; ox = x; x = tmp; }
257  if (oy > y) { int tmp = oy; oy = y; y = tmp; }
258
259  update_rect->x = ox - 16;
260  update_rect->y = oy - 16;
261  update_rect->w = (x + 16) - update_rect->x;
262  update_rect->h = (y + 16) - update_rect->h;
263
264  /* FIXME */
265
266  update_rect->x = 0;
267  update_rect->y = 0;
268  update_rect->w = canvas->w;
269  update_rect->h = canvas->h;
270
271  api->playsound(calligraphy_snd, (x * 255) / canvas->w, 255);
272}
273
274void calligraphy_click(magic_api * api ATTRIBUTE_UNUSED, int which ATTRIBUTE_UNUSED, int mode ATTRIBUTE_UNUSED,
275                    SDL_Surface * canvas ATTRIBUTE_UNUSED, SDL_Surface * last ATTRIBUTE_UNUSED,
276                    int x, int y, SDL_Rect * update_rect ATTRIBUTE_UNUSED)
277{
278  calligraphy_old_thick = 8;
279  calligraphy_last_time = 0;
280
281  calligraphy_control_points[0].x = x;
282  calligraphy_control_points[0].y = y;
283  calligraphy_control_points[1].x = x;
284  calligraphy_control_points[1].y = y;
285  calligraphy_control_points[2].x = x;
286  calligraphy_control_points[2].y = y;
287  calligraphy_control_points[3].x = x;
288  calligraphy_control_points[3].y = y;
289}
290
291
292void calligraphy_release(magic_api * api ATTRIBUTE_UNUSED, int which ATTRIBUTE_UNUSED,
293                    SDL_Surface * canvas ATTRIBUTE_UNUSED, SDL_Surface * last ATTRIBUTE_UNUSED, 
294                    int x ATTRIBUTE_UNUSED, int y ATTRIBUTE_UNUSED, SDL_Rect * update_rect ATTRIBUTE_UNUSED)
295{
296}
297
298
299void calligraphy_shutdown(magic_api * api ATTRIBUTE_UNUSED)
300{
301  if (calligraphy_snd != NULL)
302    Mix_FreeChunk(calligraphy_snd);
303  if (calligraphy_brush != NULL)
304    SDL_FreeSurface(calligraphy_brush);
305  if (calligraphy_colored_brush != NULL)
306    SDL_FreeSurface(calligraphy_colored_brush);
307}
308
309// We don't use colors
310void calligraphy_set_color(magic_api * api, Uint8 r, Uint8 g, Uint8 b)
311{
312  int x, y;
313  Uint8 a;
314  Uint32 amask;
315
316  if (calligraphy_r == r &&
317      calligraphy_g == g &&
318      calligraphy_b == b)
319    return;
320
321  calligraphy_r = r;
322  calligraphy_g = g;
323  calligraphy_b = b;
324
325  if (calligraphy_colored_brush != NULL)
326    SDL_FreeSurface(calligraphy_colored_brush);
327
328  amask = ~(calligraphy_brush->format->Rmask |
329            calligraphy_brush->format->Gmask |
330            calligraphy_brush->format->Bmask);
331
332  calligraphy_colored_brush =
333    SDL_CreateRGBSurface(SDL_SWSURFACE,
334                         calligraphy_brush->w,
335                         calligraphy_brush->h,
336                         calligraphy_brush->format->BitsPerPixel,
337                         calligraphy_brush->format->Rmask,
338                         calligraphy_brush->format->Gmask,
339                         calligraphy_brush->format->Bmask, amask);
340
341  if (calligraphy_colored_brush == NULL)
342    return; // FIXME: Error!
343
344  SDL_LockSurface(calligraphy_brush);
345  SDL_LockSurface(calligraphy_colored_brush);
346
347
348  for (y = 0; y < calligraphy_brush->h; y++)
349  {
350    for (x = 0; x < calligraphy_brush->w; x++)
351    {
352      SDL_GetRGBA(api->getpixel(calligraphy_brush, x, y),
353                  calligraphy_brush->format, &r, &g, &b, &a);
354
355      api->putpixel(calligraphy_colored_brush, x, y,
356                     SDL_MapRGBA(calligraphy_colored_brush->format,
357                                 calligraphy_r,
358                                 calligraphy_g,
359                                 calligraphy_b, a));
360    }
361  }
362
363  SDL_UnlockSurface(calligraphy_colored_brush);
364  SDL_UnlockSurface(calligraphy_brush);
365}
366
367// We don't use colors
368int calligraphy_requires_colors(magic_api * api ATTRIBUTE_UNUSED, int which ATTRIBUTE_UNUSED)
369{
370  return 1;
371}
372
373
374/*
375Code to generate a cubic Bezier curve
376*/
377
378/*
379cp is a 4 element array where:
380cp[0] is the starting point, or P0 in the above diagram
381cp[1] is the first control point, or P1 in the above diagram
382cp[2] is the second control point, or P2 in the above diagram
383cp[3] is the end point, or P3 in the above diagram
384t is the parameter value, 0 <= t <= 1
385*/
386
387static Point2D calligraphy_PointOnCubicBezier( Point2D* cp, float t )
388{
389    float   ax, bx, cx;
390    float   ay, by, cy;
391    float   tSquared, tCubed;
392    Point2D result;
393
394    /* calculate the polynomial coefficients */
395
396    cx = 3.0 * (cp[1].x - cp[0].x);
397    bx = 3.0 * (cp[2].x - cp[1].x) - cx;
398    ax = cp[3].x - cp[0].x - cx - bx;
399
400    cy = 3.0 * (cp[1].y - cp[0].y);
401    by = 3.0 * (cp[2].y - cp[1].y) - cy;
402    ay = cp[3].y - cp[0].y - cy - by;
403
404    /* calculate the curve point at parameter value t */
405
406    tSquared = t * t;
407    tCubed = tSquared * t;
408
409    result.x = (ax * tCubed) + (bx * tSquared) + (cx * t) + cp[0].x;
410    result.y = (ay * tCubed) + (by * tSquared) + (cy * t) + cp[0].y;
411
412    return result;
413}
414
415
416/*
417 ComputeBezier fills an array of Point2D structs with the curve
418 points generated from the control points cp. Caller must
419 allocate sufficient memory for the result, which is
420 <sizeof(Point2D) numberOfPoints>
421*/
422
423static void calligraphy_ComputeBezier(Point2D* cp, int numberOfPoints, Point2D* curve)
424{
425    float   dt;
426    int   i;
427
428    dt = 1.0 / ( numberOfPoints - 1 );
429
430    for( i = 0; i < numberOfPoints; i++)
431        curve[i] = calligraphy_PointOnCubicBezier( cp, i*dt );
432}
433
434static float calligraphy_dist(float x1, float y1, float x2, float y2)
435{
436  float d;
437  d = (sqrt((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1)));
438
439  return d;
440}
441
442void calligraphy_switchin(magic_api * api ATTRIBUTE_UNUSED, int which ATTRIBUTE_UNUSED, int mode ATTRIBUTE_UNUSED, SDL_Surface * canvas ATTRIBUTE_UNUSED)
443{
444}
445
446void calligraphy_switchout(magic_api * api ATTRIBUTE_UNUSED, int which ATTRIBUTE_UNUSED, int mode ATTRIBUTE_UNUSED, SDL_Surface * canvas ATTRIBUTE_UNUSED)
447{
448}
449
450int calligraphy_modes(magic_api * api ATTRIBUTE_UNUSED, int which ATTRIBUTE_UNUSED)
451{
452  return(MODE_PAINT);
453}
Note: See TracBrowser for help on using the repository browser.