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