new function list_deep_free
[swftools.git] / lib / art / art_rgb_svp.c
1 /* Libart_LGPL - library of basic graphic primitives
2  * Copyright (C) 1998 Raph Levien
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */
19
20 /* Render a sorted vector path into an RGB buffer. */
21
22 #include "config.h"
23 #include "art_rgb_svp.h"
24
25 #include "art_svp.h"
26 #include "art_svp_render_aa.h"
27 #include "art_rgb.h"
28
29 typedef struct _ArtRgbSVPData ArtRgbSVPData;
30 typedef struct _ArtRgbSVPAlphaData ArtRgbSVPAlphaData;
31
32 struct _ArtRgbSVPData {
33   art_u32 rgbtab[256];
34   art_u8 *buf;
35   int rowstride;
36   int x0, x1;
37 };
38
39 struct _ArtRgbSVPAlphaData {
40   int alphatab[256];
41   art_u8 r, g, b, alpha;
42   art_u8 *buf;
43   int rowstride;
44   int x0, x1;
45 };
46
47 static void
48 art_rgb_svp_callback (void *callback_data, int y,
49                       int start, ArtSVPRenderAAStep *steps, int n_steps)
50 {
51   ArtRgbSVPData *data = (ArtRgbSVPData *)callback_data;
52   art_u8 *linebuf;
53   int run_x0, run_x1;
54   art_u32 running_sum = start;
55   art_u32 rgb;
56   int x0, x1;
57   int k;
58
59   linebuf = data->buf;
60   x0 = data->x0;
61   x1 = data->x1;
62
63   if (n_steps > 0)
64     {
65       run_x1 = steps[0].x;
66       if (run_x1 > x0)
67         {
68           rgb = data->rgbtab[(running_sum >> 16) & 0xff];
69           art_rgb_fill_run (linebuf,
70                             rgb >> 16, (rgb >> 8) & 0xff, rgb & 0xff,
71                             run_x1 - x0);
72         }
73
74       for (k = 0; k < n_steps - 1; k++)
75         {
76           running_sum += steps[k].delta;
77           run_x0 = run_x1;
78           run_x1 = steps[k + 1].x;
79           if (run_x1 > run_x0)
80             {
81               rgb = data->rgbtab[(running_sum >> 16) & 0xff];
82               art_rgb_fill_run (linebuf + (run_x0 - x0) * 3,
83                                 rgb >> 16, (rgb >> 8) & 0xff, rgb & 0xff,
84                                 run_x1 - run_x0);
85             }
86         }
87       running_sum += steps[k].delta;
88       if (x1 > run_x1)
89         {
90           rgb = data->rgbtab[(running_sum >> 16) & 0xff];
91           art_rgb_fill_run (linebuf + (run_x1 - x0) * 3,
92                             rgb >> 16, (rgb >> 8) & 0xff, rgb & 0xff,
93                             x1 - run_x1);
94         }
95     }
96   else
97     {
98       rgb = data->rgbtab[(running_sum >> 16) & 0xff];
99       art_rgb_fill_run (linebuf,
100                         rgb >> 16, (rgb >> 8) & 0xff, rgb & 0xff,
101                         x1 - x0);
102     }
103
104   data->buf += data->rowstride;
105 }
106
107 /* Render the vector path into the RGB buffer. */
108
109 /**
110  * art_rgb_svp_aa: Render sorted vector path into RGB buffer.
111  * @svp: The source sorted vector path.
112  * @x0: Left coordinate of destination rectangle.
113  * @y0: Top coordinate of destination rectangle.
114  * @x1: Right coordinate of destination rectangle.
115  * @y1: Bottom coordinate of destination rectangle.
116  * @fg_color: Foreground color in 0xRRGGBB format.
117  * @bg_color: Background color in 0xRRGGBB format.
118  * @buf: Destination RGB buffer.
119  * @rowstride: Rowstride of @buf buffer.
120  * @alphagamma: #ArtAlphaGamma for gamma-correcting the rendering.
121  *
122  * Renders the shape specified with @svp into the @buf RGB buffer.
123  * @x1 - @x0 specifies the width, and @y1 - @y0 specifies the height,
124  * of the rectangle rendered. The new pixels are stored starting at
125  * the first byte of @buf. Thus, the @x0 and @y0 parameters specify
126  * an offset within @svp, and may be tweaked as a way of doing
127  * integer-pixel translations without fiddling with @svp itself.
128  *
129  * The @fg_color and @bg_color arguments specify the opaque colors to
130  * be used for rendering. For pixels of entirely 0 winding-number,
131  * @bg_color is used. For pixels of entirely 1 winding number,
132  * @fg_color is used. In between, the color is interpolated based on
133  * the fraction of the pixel with a winding number of 1. If
134  * @alphagamma is NULL, then linear interpolation (in pixel counts) is
135  * the default. Otherwise, the interpolation is as specified by
136  * @alphagamma.
137  **/
138 void
139 art_rgb_svp_aa (const ArtSVP *svp,
140                 int x0, int y0, int x1, int y1,
141                 art_u32 fg_color, art_u32 bg_color,
142                 art_u8 *buf, int rowstride,
143                 ArtAlphaGamma *alphagamma)
144 {
145   ArtRgbSVPData data;
146
147   int r_fg, g_fg, b_fg;
148   int r_bg, g_bg, b_bg;
149   int r, g, b;
150   int dr, dg, db;
151   int i;
152
153   if (alphagamma == NULL)
154     {
155       r_fg = fg_color >> 16;
156       g_fg = (fg_color >> 8) & 0xff;
157       b_fg = fg_color & 0xff;
158
159       r_bg = bg_color >> 16;
160       g_bg = (bg_color >> 8) & 0xff;
161       b_bg = bg_color & 0xff;
162
163       r = (r_bg << 16) + 0x8000;
164       g = (g_bg << 16) + 0x8000;
165       b = (b_bg << 16) + 0x8000;
166       dr = ((r_fg - r_bg) << 16) / 255;
167       dg = ((g_fg - g_bg) << 16) / 255;
168       db = ((b_fg - b_bg) << 16) / 255;
169
170       for (i = 0; i < 256; i++)
171         {
172           data.rgbtab[i] = (r & 0xff0000) | ((g & 0xff0000) >> 8) | (b >> 16);
173           r += dr;
174           g += dg;
175           b += db;
176         }
177     }
178   else
179     {
180       int *table;
181       art_u8 *invtab;
182
183       table = alphagamma->table;
184
185       r_fg = table[fg_color >> 16];
186       g_fg = table[(fg_color >> 8) & 0xff];
187       b_fg = table[fg_color & 0xff];
188
189       r_bg = table[bg_color >> 16];
190       g_bg = table[(bg_color >> 8) & 0xff];
191       b_bg = table[bg_color & 0xff];
192
193       r = (r_bg << 16) + 0x8000;
194       g = (g_bg << 16) + 0x8000;
195       b = (b_bg << 16) + 0x8000;
196       dr = ((r_fg - r_bg) << 16) / 255;
197       dg = ((g_fg - g_bg) << 16) / 255;
198       db = ((b_fg - b_bg) << 16) / 255;
199
200       invtab = alphagamma->invtable;
201       for (i = 0; i < 256; i++)
202         {
203           data.rgbtab[i] = (invtab[r >> 16] << 16) |
204             (invtab[g >> 16] << 8) |
205             invtab[b >> 16];
206           r += dr;
207           g += dg;
208           b += db;
209         }
210     }
211   data.buf = buf;
212   data.rowstride = rowstride;
213   data.x0 = x0;
214   data.x1 = x1;
215   art_svp_render_aa (svp, x0, y0, x1, y1, art_rgb_svp_callback, &data);
216 }
217
218 static void
219 art_rgb_svp_alpha_callback (void *callback_data, int y,
220                             int start, ArtSVPRenderAAStep *steps, int n_steps)
221 {
222   ArtRgbSVPAlphaData *data = (ArtRgbSVPAlphaData *)callback_data;
223   art_u8 *linebuf;
224   int run_x0, run_x1;
225   art_u32 running_sum = start;
226   int x0, x1;
227   int k;
228   art_u8 r, g, b;
229   int *alphatab;
230   int alpha;
231
232   linebuf = data->buf;
233   x0 = data->x0;
234   x1 = data->x1;
235
236   r = data->r;
237   g = data->g;
238   b = data->b;
239   alphatab = data->alphatab;
240
241   if (n_steps > 0)
242     {
243       run_x1 = steps[0].x;
244       if (run_x1 > x0)
245         {
246           alpha = (running_sum >> 16) & 0xff;
247           if (alpha)
248             art_rgb_run_alpha (linebuf,
249                                r, g, b, alphatab[alpha],
250                                run_x1 - x0);
251         }
252
253       for (k = 0; k < n_steps - 1; k++)
254         {
255           running_sum += steps[k].delta;
256           run_x0 = run_x1;
257           run_x1 = steps[k + 1].x;
258           if (run_x1 > run_x0)
259             {
260               alpha = (running_sum >> 16) & 0xff;
261               if (alpha)
262                 art_rgb_run_alpha (linebuf + (run_x0 - x0) * 3,
263                                    r, g, b, alphatab[alpha],
264                                    run_x1 - run_x0);
265             }
266         }
267       running_sum += steps[k].delta;
268       if (x1 > run_x1)
269         {
270           alpha = (running_sum >> 16) & 0xff;
271           if (alpha)
272             art_rgb_run_alpha (linebuf + (run_x1 - x0) * 3,
273                                r, g, b, alphatab[alpha],
274                                x1 - run_x1);
275         }
276     }
277   else
278     {
279       alpha = (running_sum >> 16) & 0xff;
280       if (alpha)
281         art_rgb_run_alpha (linebuf,
282                            r, g, b, alphatab[alpha],
283                            x1 - x0);
284     }
285
286   data->buf += data->rowstride;
287 }
288
289 static void
290 art_rgb_svp_alpha_opaque_callback (void *callback_data, int y,
291                                    int start,
292                                    ArtSVPRenderAAStep *steps, int n_steps)
293 {
294   ArtRgbSVPAlphaData *data = (ArtRgbSVPAlphaData *)callback_data;
295   art_u8 *linebuf;
296   int run_x0, run_x1;
297   art_u32 running_sum = start;
298   int x0, x1;
299   int k;
300   art_u8 r, g, b;
301   int *alphatab;
302   int alpha;
303
304   linebuf = data->buf;
305   x0 = data->x0;
306   x1 = data->x1;
307
308   r = data->r;
309   g = data->g;
310   b = data->b;
311   alphatab = data->alphatab;
312
313   if (n_steps > 0)
314     {
315       run_x1 = steps[0].x;
316       if (run_x1 > x0)
317         {
318           alpha = running_sum >> 16;
319           if (alpha)
320             {
321               if (alpha >= 255)
322                 art_rgb_fill_run (linebuf,
323                                   r, g, b,
324                                   run_x1 - x0);
325               else
326                 art_rgb_run_alpha (linebuf,
327                                    r, g, b, alphatab[alpha],
328                                    run_x1 - x0);
329             }
330         }
331
332       for (k = 0; k < n_steps - 1; k++)
333         {
334           running_sum += steps[k].delta;
335           run_x0 = run_x1;
336           run_x1 = steps[k + 1].x;
337           if (run_x1 > run_x0)
338             {
339               alpha = running_sum >> 16;
340               if (alpha)
341                 {
342                   if (alpha >= 255)
343                     art_rgb_fill_run (linebuf + (run_x0 - x0) * 3,
344                                       r, g, b,
345                                       run_x1 - run_x0);
346                   else
347                     art_rgb_run_alpha (linebuf + (run_x0 - x0) * 3,
348                                        r, g, b, alphatab[alpha],
349                                        run_x1 - run_x0);
350                 }
351             }
352         }
353       running_sum += steps[k].delta;
354       if (x1 > run_x1)
355         {
356           alpha = running_sum >> 16;
357           if (alpha)
358             {
359               if (alpha >= 255)
360                 art_rgb_fill_run (linebuf + (run_x1 - x0) * 3,
361                                   r, g, b,
362                                   x1 - run_x1);
363               else
364                 art_rgb_run_alpha (linebuf + (run_x1 - x0) * 3,
365                                    r, g, b, alphatab[alpha],
366                                    x1 - run_x1);
367             }
368         }
369     }
370   else
371     {
372       alpha = running_sum >> 16;
373       if (alpha)
374         {
375           if (alpha >= 255)
376             art_rgb_fill_run (linebuf,
377                               r, g, b,
378                               x1 - x0);
379           else
380             art_rgb_run_alpha (linebuf,
381                                r, g, b, alphatab[alpha],
382                                x1 - x0);
383         }
384     }
385
386   data->buf += data->rowstride;
387 }
388
389 /**
390  * art_rgb_svp_alpha: Alpha-composite sorted vector path over RGB buffer.
391  * @svp: The source sorted vector path.
392  * @x0: Left coordinate of destination rectangle.
393  * @y0: Top coordinate of destination rectangle.
394  * @x1: Right coordinate of destination rectangle.
395  * @y1: Bottom coordinate of destination rectangle.
396  * @rgba: Color in 0xRRGGBBAA format.
397  * @buf: Destination RGB buffer.
398  * @rowstride: Rowstride of @buf buffer.
399  * @alphagamma: #ArtAlphaGamma for gamma-correcting the compositing.
400  *
401  * Renders the shape specified with @svp over the @buf RGB buffer.
402  * @x1 - @x0 specifies the width, and @y1 - @y0 specifies the height,
403  * of the rectangle rendered. The new pixels are stored starting at
404  * the first byte of @buf. Thus, the @x0 and @y0 parameters specify
405  * an offset within @svp, and may be tweaked as a way of doing
406  * integer-pixel translations without fiddling with @svp itself.
407  *
408  * The @rgba argument specifies the color for the rendering. Pixels of
409  * entirely 0 winding number are left untouched. Pixels of entirely
410  * 1 winding number have the color @rgba composited over them (ie,
411  * are replaced by the red, green, blue components of @rgba if the alpha
412  * component is 0xff). Pixels of intermediate coverage are interpolated
413  * according to the rule in @alphagamma, or default to linear if
414  * @alphagamma is NULL.
415  **/
416 void
417 art_rgb_svp_alpha (const ArtSVP *svp,
418                    int x0, int y0, int x1, int y1,
419                    art_u32 rgba,
420                    art_u8 *buf, int rowstride,
421                    ArtAlphaGamma *alphagamma)
422 {
423   ArtRgbSVPAlphaData data;
424   int r, g, b, alpha;
425   int i;
426   int a, da;
427
428   r = rgba >> 24;
429   g = (rgba >> 16) & 0xff;
430   b = (rgba >> 8) & 0xff;
431   alpha = rgba & 0xff;
432
433   data.r = r;
434   data.g = g;
435   data.b = b;
436   data.alpha = alpha;
437
438   a = 0x8000;
439   da = (alpha * 66051 + 0x80) >> 8; /* 66051 equals 2 ^ 32 / (255 * 255) */
440
441   for (i = 0; i < 256; i++)
442     {
443       data.alphatab[i] = a >> 16;
444       a += da;
445     }
446
447   data.buf = buf;
448   data.rowstride = rowstride;
449   data.x0 = x0;
450   data.x1 = x1;
451   if (alpha == 255)
452     art_svp_render_aa (svp, x0, y0, x1, y1, art_rgb_svp_alpha_opaque_callback,
453                        &data);
454   else
455     art_svp_render_aa (svp, x0, y0, x1, y1, art_rgb_svp_alpha_callback, &data);
456 }
457