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 */
27 #define SP_ART_RGBA_SVP_C
29 /* Render a sorted vector path into an RGBA buffer. */
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>
36 #include "art_rgba_svp.h"
37 #include "unused.h"
39 static void art_rgba_fill_run (art_u8 * linebuf, art_u8 r, art_u8 g, art_u8 b, int n);
40 static void art_rgba_run_alpha (art_u8 * linebuf, art_u8 r, art_u8 g, art_u8 b, int alpha, int n);
42 typedef struct _ArtRgbaSVPAlphaData ArtRgbaSVPAlphaData;
44 struct _ArtRgbaSVPAlphaData {
45 int alphatab[256];
46 art_u8 r, g, b, alpha;
47 art_u8 *buf;
48 int rowstride;
49 int libart_x0, libart_x1;
50 };
52 static void
53 art_rgba_svp_alpha_callback (void *callback_data, int UNUSED(y),
54 int start, ArtSVPRenderAAStep *steps, int n_steps)
55 {
56 ArtRgbaSVPAlphaData *data = callback_data;
57 art_u8 *linebuf;
58 int run_x0, run_x1;
59 art_u32 running_sum = start;
60 int libart_x0, libart_x1;
61 int k;
62 art_u8 r, g, b;
63 int *alphatab;
64 int alpha;
66 linebuf = data->buf;
67 libart_x0 = data->libart_x0;
68 libart_x1 = data->libart_x1;
70 r = data->r;
71 g = data->g;
72 b = data->b;
73 alphatab = data->alphatab;
75 if (n_steps > 0)
76 {
77 run_x1 = steps[0].x;
78 if (run_x1 > libart_x0)
79 {
80 alpha = (running_sum >> 16) & 0xff;
81 if (alpha)
82 art_rgba_run_alpha (linebuf,
83 r, g, b, alphatab[alpha],
84 run_x1 - libart_x0);
85 }
87 /* render the steps into tmpbuf */
88 for (k = 0; k < n_steps - 1; k++)
89 {
90 running_sum += steps[k].delta;
91 run_x0 = run_x1;
92 run_x1 = steps[k + 1].x;
93 if (run_x1 > run_x0)
94 {
95 alpha = (running_sum >> 16) & 0xff;
96 if (alpha)
97 art_rgba_run_alpha (linebuf + (run_x0 - libart_x0) * 4,
98 r, g, b, alphatab[alpha],
99 run_x1 - run_x0);
100 }
101 }
102 running_sum += steps[k].delta;
103 if (libart_x1 > run_x1)
104 {
105 alpha = (running_sum >> 16) & 0xff;
106 if (alpha)
107 art_rgba_run_alpha (linebuf + (run_x1 - libart_x0) * 4,
108 r, g, b, alphatab[alpha],
109 libart_x1 - run_x1);
110 }
111 }
112 else
113 {
114 alpha = (running_sum >> 16) & 0xff;
115 if (alpha)
116 art_rgba_run_alpha (linebuf,
117 r, g, b, alphatab[alpha],
118 libart_x1 - libart_x0);
119 }
121 data->buf += data->rowstride;
122 }
124 static void
125 art_rgba_svp_alpha_opaque_callback (void *callback_data, int UNUSED(y),
126 int start,
127 ArtSVPRenderAAStep *steps, int n_steps)
128 {
129 ArtRgbaSVPAlphaData *data = callback_data;
130 art_u8 *linebuf;
131 int run_x0, run_x1;
132 art_u32 running_sum = start;
133 int libart_x0, libart_x1;
134 int k;
135 art_u8 r, g, b;
136 int *alphatab;
137 int alpha;
139 linebuf = data->buf;
140 libart_x0 = data->libart_x0;
141 libart_x1 = data->libart_x1;
143 r = data->r;
144 g = data->g;
145 b = data->b;
146 alphatab = data->alphatab;
148 if (n_steps > 0)
149 {
150 run_x1 = steps[0].x;
151 if (run_x1 > libart_x0)
152 {
153 alpha = running_sum >> 16;
154 if (alpha)
155 {
156 if (alpha >= 255)
157 art_rgba_fill_run (linebuf,
158 r, g, b,
159 run_x1 - libart_x0);
160 else
161 art_rgba_run_alpha (linebuf,
162 r, g, b, alphatab[alpha],
163 run_x1 - libart_x0);
164 }
165 }
167 /* render the steps into tmpbuf */
168 for (k = 0; k < n_steps - 1; k++)
169 {
170 running_sum += steps[k].delta;
171 run_x0 = run_x1;
172 run_x1 = steps[k + 1].x;
173 if (run_x1 > run_x0)
174 {
175 alpha = running_sum >> 16;
176 if (alpha)
177 {
178 if (alpha >= 255)
179 art_rgba_fill_run (linebuf + (run_x0 - libart_x0) * 4,
180 r, g, b,
181 run_x1 - run_x0);
182 else
183 art_rgba_run_alpha (linebuf + (run_x0 - libart_x0) * 4,
184 r, g, b, alphatab[alpha],
185 run_x1 - run_x0);
186 }
187 }
188 }
189 running_sum += steps[k].delta;
190 if (libart_x1 > run_x1)
191 {
192 alpha = running_sum >> 16;
193 if (alpha)
194 {
195 if (alpha >= 255)
196 art_rgba_fill_run (linebuf + (run_x1 - libart_x0) * 4,
197 r, g, b,
198 libart_x1 - run_x1);
199 else
200 art_rgba_run_alpha (linebuf + (run_x1 - libart_x0) * 4,
201 r, g, b, alphatab[alpha],
202 libart_x1 - run_x1);
203 }
204 }
205 }
206 else
207 {
208 alpha = running_sum >> 16;
209 if (alpha)
210 {
211 if (alpha >= 255)
212 art_rgba_fill_run (linebuf,
213 r, g, b,
214 libart_x1 - libart_x0);
215 else
216 art_rgba_run_alpha (linebuf,
217 r, g, b, alphatab[alpha],
218 libart_x1 - libart_x0);
219 }
220 }
222 data->buf += data->rowstride;
223 }
225 /**
226 * gnome_print_art_rgba_svp_alpha: Alpha-composite sorted vector path over RGBA buffer.
227 * @svp: The source sorted vector path.
228 * @libart_x0: Left coordinate of destination rectangle.
229 * @libart_y0: Top coordinate of destination rectangle.
230 * @libart_x1: Right coordinate of destination rectangle.
231 * @libart_y1: Bottom coordinate of destination rectangle.
232 * @rgba: Color in 0xRRGGBBAA format.
233 * @buf: Destination RGB buffer.
234 * @rowstride: Rowstride of @buf buffer.
235 * @alphagamma: #ArtAlphaGamma for gamma-correcting the compositing.
236 *
237 * Renders the shape specified with @svp over the @buf RGB buffer.
238 * @libart_x1 - @x0 specifies the width, and @libart_y1 - @libart_y0 specifies the height,
239 * of the rectangle rendered. The new pixels are stored starting at
240 * the first byte of @buf. Thus, the @x0 and @libart_y0 parameters specify
241 * an offset within @svp, and may be tweaked as a way of doing
242 * integer-pixel translations without fiddling with @svp itself.
243 *
244 * The @rgba argument specifies the color for the rendering. Pixels of
245 * entirely 0 winding number are left untouched. Pixels of entirely
246 * 1 winding number have the color @rgba composited over them (ie,
247 * are replaced by the red, green, blue components of @rgba if the alpha
248 * component is 0xff). Pixels of intermediate coverage are interpolated
249 * according to the rule in @alphagamma, or default to linear if
250 * @alphagamma is NULL.
251 **/
252 void
253 gnome_print_art_rgba_svp_alpha (const ArtSVP *svp,
254 int libart_x0, int libart_y0, int libart_x1, int libart_y1,
255 art_u32 rgba,
256 art_u8 *buf, int rowstride,
257 ArtAlphaGamma UNUSED(*alphagamma))
258 {
259 ArtRgbaSVPAlphaData data;
260 int r, g, b, alpha;
261 int i;
262 int a, da;
264 r = rgba >> 24;
265 g = (rgba >> 16) & 0xff;
266 b = (rgba >> 8) & 0xff;
267 alpha = rgba & 0xff;
269 data.r = r;
270 data.g = g;
271 data.b = b;
272 data.alpha = alpha;
274 a = 0x8000;
275 da = (alpha * 66051 + 0x80) >> 8; /* 66051 equals 2 ^ 32 / (255 * 255) */
277 for (i = 0; i < 256; i++)
278 {
279 data.alphatab[i] = a >> 16;
280 a += da;
281 }
283 data.buf = buf;
284 data.rowstride = rowstride;
285 data.libart_x0 = libart_x0;
286 data.libart_x1 = libart_x1;
287 if (alpha == 255)
288 art_svp_render_aa (svp, libart_x0, libart_y0, libart_x1, libart_y1, art_rgba_svp_alpha_opaque_callback,
289 &data);
290 else
291 art_svp_render_aa (svp, libart_x0, libart_y0, libart_x1, libart_y1, art_rgba_svp_alpha_callback, &data);
292 }
294 static void
295 art_rgba_fill_run (art_u8 * buf, art_u8 r, art_u8 g, art_u8 b, int n)
296 {
297 int i;
299 for (i = 0; i < n; i++) {
300 * buf++ = r;
301 * buf++ = g;
302 * buf++ = b;
303 * buf++ = 255;
304 }
305 }
307 /* fixme: this */
309 static void
310 art_rgba_run_alpha (art_u8 * buf, art_u8 r, art_u8 g, art_u8 b, int alpha, int n)
311 {
312 int i;
313 int br, bg, bb, ba;
314 int cr, cg, cb;
316 for (i = 0; i < n; i++) {
317 br = * (buf + 0);
318 bg = * (buf + 1);
319 bb = * (buf + 2);
320 ba = * (buf + 3);
322 cr = (br * ba + 0x80) >> 8;
323 cg = (bg * ba + 0x80) >> 8;
324 cb = (bb * ba + 0x80) >> 8;
326 * buf++ = cr + (((r - cr) * alpha + 0x80) >> 8);
327 * buf++ = cg + (((g - cg) * alpha + 0x80) >> 8);
328 * buf++ = cb + (((b - cb) * alpha + 0x80) >> 8);
329 * buf++ = ba + (((255 - ba) * alpha + 0x80) >> 8);
330 }
331 }