* we are now creating true RGBA pngs
[rrdtool.git] / src / art_rgba_svp.c
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /*
3  *  art_rgba_svp.c: A slightly modified version of art_rgb_svp to render into rgba buffer
4  *
5  *  This program is free software; you can redistribute it and/or
6  *  modify it under the terms of the GNU Library General Public License
7  *  as published by the Free Software Foundation; either version 2 of
8  *  the License, or (at your option) any later version.
9  *
10  *  This program is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  *  GNU Library General Public License for more details.
14  *
15  *  You should have received a copy of the GNU Library General Public
16  *  License along with this program; if not, write to the Free Software
17  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18  *
19  *  Authors:
20  *    Raph Levien <raph@acm.org>
21  *    Lauris Kaplinski <lauris@ariman.ee>
22  *
23  *  Copyright (C) 1998 Raph Levien
24  *
25  */
26
27 #define SP_ART_RGBA_SVP_C
28
29 /* Render a sorted vector path into an RGBA buffer. */
30
31 #include <libart_lgpl/art_misc.h>
32 #include <libart_lgpl/art_svp.h>
33 #include <libart_lgpl/art_svp_render_aa.h>
34 #include <libart_lgpl/art_rgb.h>
35
36 #include "art_rgba_svp.h"
37
38 static void art_rgba_fill_run (art_u8 * linebuf, art_u8 r, art_u8 g, art_u8 b, int n);
39 static void art_rgba_run_alpha (art_u8 * linebuf, art_u8 r, art_u8 g, art_u8 b, int alpha, int n);
40
41 typedef struct _ArtRgbaSVPAlphaData ArtRgbaSVPAlphaData;
42
43 struct _ArtRgbaSVPAlphaData {
44   int alphatab[256];
45   art_u8 r, g, b, alpha;
46   art_u8 *buf;
47   int rowstride;
48   int x0, x1;
49 };
50
51 static void
52 art_rgba_svp_alpha_callback (void *callback_data, int y,
53                             int start, ArtSVPRenderAAStep *steps, int n_steps)
54 {
55   ArtRgbaSVPAlphaData *data = callback_data;
56   art_u8 *linebuf;
57   int run_x0, run_x1;
58   art_u32 running_sum = start;
59   int x0, x1;
60   int k;
61   art_u8 r, g, b;
62   int *alphatab;
63   int alpha;
64
65   linebuf = data->buf;
66   x0 = data->x0;
67   x1 = data->x1;
68
69   r = data->r;
70   g = data->g;
71   b = data->b;
72   alphatab = data->alphatab;
73
74   if (n_steps > 0)
75     {
76       run_x1 = steps[0].x;
77       if (run_x1 > x0)
78         {
79           alpha = (running_sum >> 16) & 0xff;
80           if (alpha)
81             art_rgba_run_alpha (linebuf,
82                                r, g, b, alphatab[alpha],
83                                run_x1 - x0);
84         }
85
86       /* render the steps into tmpbuf */
87       for (k = 0; k < n_steps - 1; k++)
88         {
89           running_sum += steps[k].delta;
90           run_x0 = run_x1;
91           run_x1 = steps[k + 1].x;
92           if (run_x1 > run_x0)
93             {
94               alpha = (running_sum >> 16) & 0xff;
95               if (alpha)
96                 art_rgba_run_alpha (linebuf + (run_x0 - x0) * 4,
97                                    r, g, b, alphatab[alpha],
98                                    run_x1 - run_x0);
99             }
100         }
101       running_sum += steps[k].delta;
102       if (x1 > run_x1)
103         {
104           alpha = (running_sum >> 16) & 0xff;
105           if (alpha)
106             art_rgba_run_alpha (linebuf + (run_x1 - x0) * 4,
107                                r, g, b, alphatab[alpha],
108                                x1 - run_x1);
109         }
110     }
111   else
112     {
113       alpha = (running_sum >> 16) & 0xff;
114       if (alpha)
115         art_rgba_run_alpha (linebuf,
116                            r, g, b, alphatab[alpha],
117                            x1 - x0);
118     }
119
120   data->buf += data->rowstride;
121 }
122
123 static void
124 art_rgba_svp_alpha_opaque_callback (void *callback_data, int y,
125                                    int start,
126                                    ArtSVPRenderAAStep *steps, int n_steps)
127 {
128   ArtRgbaSVPAlphaData *data = callback_data;
129   art_u8 *linebuf;
130   int run_x0, run_x1;
131   art_u32 running_sum = start;
132   int x0, x1;
133   int k;
134   art_u8 r, g, b;
135   int *alphatab;
136   int alpha;
137
138   linebuf = data->buf;
139   x0 = data->x0;
140   x1 = data->x1;
141
142   r = data->r;
143   g = data->g;
144   b = data->b;
145   alphatab = data->alphatab;
146
147   if (n_steps > 0)
148     {
149       run_x1 = steps[0].x;
150       if (run_x1 > x0)
151         {
152           alpha = running_sum >> 16;
153           if (alpha)
154             {
155               if (alpha >= 255)
156                 art_rgba_fill_run (linebuf,
157                                   r, g, b,
158                                   run_x1 - x0);
159               else
160                 art_rgba_run_alpha (linebuf,
161                                    r, g, b, alphatab[alpha],
162                                    run_x1 - x0);
163             }
164         }
165
166       /* render the steps into tmpbuf */
167       for (k = 0; k < n_steps - 1; k++)
168         {
169           running_sum += steps[k].delta;
170           run_x0 = run_x1;
171           run_x1 = steps[k + 1].x;
172           if (run_x1 > run_x0)
173             {
174               alpha = running_sum >> 16;
175               if (alpha)
176                 {
177                   if (alpha >= 255)
178                     art_rgba_fill_run (linebuf + (run_x0 - x0) * 4,
179                                       r, g, b,
180                                       run_x1 - run_x0);
181                   else
182                     art_rgba_run_alpha (linebuf + (run_x0 - x0) * 4,
183                                        r, g, b, alphatab[alpha],
184                                        run_x1 - run_x0);
185                 }
186             }
187         }
188       running_sum += steps[k].delta;
189       if (x1 > run_x1)
190         {
191           alpha = running_sum >> 16;
192           if (alpha)
193             {
194               if (alpha >= 255)
195                 art_rgba_fill_run (linebuf + (run_x1 - x0) * 4,
196                                   r, g, b,
197                                   x1 - run_x1);
198               else
199                 art_rgba_run_alpha (linebuf + (run_x1 - x0) * 4,
200                                    r, g, b, alphatab[alpha],
201                                    x1 - run_x1);
202             }
203         }
204     }
205   else
206     {
207       alpha = running_sum >> 16;
208       if (alpha)
209         {
210           if (alpha >= 255)
211             art_rgba_fill_run (linebuf,
212                               r, g, b,
213                               x1 - x0);
214           else
215             art_rgba_run_alpha (linebuf,
216                                r, g, b, alphatab[alpha],
217                                x1 - x0);
218         }
219     }
220
221   data->buf += data->rowstride;
222 }
223
224 /**
225  * gnome_print_art_rgba_svp_alpha: Alpha-composite sorted vector path over RGBA buffer.
226  * @svp: The source sorted vector path.
227  * @x0: Left coordinate of destination rectangle.
228  * @y0: Top coordinate of destination rectangle.
229  * @x1: Right coordinate of destination rectangle.
230  * @y1: Bottom coordinate of destination rectangle.
231  * @rgba: Color in 0xRRGGBBAA format.
232  * @buf: Destination RGB buffer.
233  * @rowstride: Rowstride of @buf buffer.
234  * @alphagamma: #ArtAlphaGamma for gamma-correcting the compositing.
235  *
236  * Renders the shape specified with @svp over the @buf RGB buffer.
237  * @x1 - @x0 specifies the width, and @y1 - @y0 specifies the height,
238  * of the rectangle rendered. The new pixels are stored starting at
239  * the first byte of @buf. Thus, the @x0 and @y0 parameters specify
240  * an offset within @svp, and may be tweaked as a way of doing
241  * integer-pixel translations without fiddling with @svp itself.
242  *
243  * The @rgba argument specifies the color for the rendering. Pixels of
244  * entirely 0 winding number are left untouched. Pixels of entirely
245  * 1 winding number have the color @rgba composited over them (ie,
246  * are replaced by the red, green, blue components of @rgba if the alpha
247  * component is 0xff). Pixels of intermediate coverage are interpolated
248  * according to the rule in @alphagamma, or default to linear if
249  * @alphagamma is NULL.
250  **/
251 void
252 gnome_print_art_rgba_svp_alpha (const ArtSVP *svp,
253                                 int x0, int y0, int x1, int y1,
254                                 art_u32 rgba,
255                                 art_u8 *buf, int rowstride,
256                                 ArtAlphaGamma *alphagamma)
257 {
258   ArtRgbaSVPAlphaData data;
259   int r, g, b, alpha;
260   int i;
261   int a, da;
262
263   r = rgba >> 24;
264   g = (rgba >> 16) & 0xff;
265   b = (rgba >> 8) & 0xff;
266   alpha = rgba & 0xff;
267
268   data.r = r;
269   data.g = g;
270   data.b = b;
271   data.alpha = alpha;
272
273   a = 0x8000;
274   da = (alpha * 66051 + 0x80) >> 8; /* 66051 equals 2 ^ 32 / (255 * 255) */
275
276   for (i = 0; i < 256; i++)
277     {
278       data.alphatab[i] = a >> 16;
279       a += da;
280     }
281
282   data.buf = buf;
283   data.rowstride = rowstride;
284   data.x0 = x0;
285   data.x1 = x1;
286   if (alpha == 255)
287     art_svp_render_aa (svp, x0, y0, x1, y1, art_rgba_svp_alpha_opaque_callback,
288                        &data);
289   else
290     art_svp_render_aa (svp, x0, y0, x1, y1, art_rgba_svp_alpha_callback, &data);
291 }
292
293 static void
294 art_rgba_fill_run (art_u8 * buf, art_u8 r, art_u8 g, art_u8 b, int n)
295 {
296         int i;
297
298         for (i = 0; i < n; i++) {
299                 * buf++ = r;
300                 * buf++ = g;
301                 * buf++ = b;
302                 * buf++ = 255;
303         }
304 }
305
306 /* fixme: this */
307
308 static void
309 art_rgba_run_alpha (art_u8 * buf, art_u8 r, art_u8 g, art_u8 b, int alpha, int n)
310 {
311         int i;
312         int br, bg, bb, ba;
313         int cr, cg, cb;
314
315         for (i = 0; i < n; i++) {
316                 br = * (buf + 0);
317                 bg = * (buf + 1);
318                 bb = * (buf + 2);
319                 ba = * (buf + 3);
320
321                 cr = (br * ba + 0x80) >> 8;
322                 cg = (bg * ba + 0x80) >> 8;
323                 cb = (bb * ba + 0x80) >> 8;
324
325                 * buf++ = cr + (((r - cr) * alpha + 0x80) >> 8);
326                 * buf++ = cg + (((g - cg) * alpha + 0x80) >> 8);
327                 * buf++ = cb + (((b - cb) * alpha + 0x80) >> 8);
328                 * buf++ = ba + (((255 - ba) * alpha + 0x80) >> 8);
329         }
330 }
331
332