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"
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);
41 typedef struct _ArtRgbaSVPAlphaData ArtRgbaSVPAlphaData;
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 };
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;
65 linebuf = data->buf;
66 x0 = data->x0;
67 x1 = data->x1;
69 r = data->r;
70 g = data->g;
71 b = data->b;
72 alphatab = data->alphatab;
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 }
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 }
120 data->buf += data->rowstride;
121 }
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;
138 linebuf = data->buf;
139 x0 = data->x0;
140 x1 = data->x1;
142 r = data->r;
143 g = data->g;
144 b = data->b;
145 alphatab = data->alphatab;
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 }
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 }
221 data->buf += data->rowstride;
222 }
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;
263 r = rgba >> 24;
264 g = (rgba >> 16) & 0xff;
265 b = (rgba >> 8) & 0xff;
266 alpha = rgba & 0xff;
268 data.r = r;
269 data.g = g;
270 data.b = b;
271 data.alpha = alpha;
273 a = 0x8000;
274 da = (alpha * 66051 + 0x80) >> 8; /* 66051 equals 2 ^ 32 / (255 * 255) */
276 for (i = 0; i < 256; i++)
277 {
278 data.alphatab[i] = a >> 16;
279 a += da;
280 }
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 }
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;
298 for (i = 0; i < n; i++) {
299 * buf++ = r;
300 * buf++ = g;
301 * buf++ = b;
302 * buf++ = 255;
303 }
304 }
306 /* fixme: this */
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;
315 for (i = 0; i < n; i++) {
316 br = * (buf + 0);
317 bg = * (buf + 1);
318 bb = * (buf + 2);
319 ba = * (buf + 3);
321 cr = (br * ba + 0x80) >> 8;
322 cg = (bg * ba + 0x80) >> 8;
323 cb = (bb * ba + 0x80) >> 8;
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 }