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
art_rgb_svp_callback(void * callback_data,int y,int start,ArtSVPRenderAAStep * steps,int n_steps)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 (art_u8)(rgb >> 16), (art_u8)((rgb >> 8) & 0xff), (art_u8)(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 (art_u8)(rgb >> 16), (art_u8)((rgb >> 8) & 0xff), (art_u8)(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 (art_u8)(rgb >> 16), (art_u8)((rgb >> 8) & 0xff), (art_u8)(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 (art_u8)(rgb >> 16), (art_u8)((rgb >> 8) & 0xff), (art_u8)(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
art_rgb_svp_aa(const ArtSVP * svp,int x0,int y0,int x1,int y1,art_u32 fg_color,art_u32 bg_color,art_u8 * buf,int rowstride,ArtAlphaGamma * alphagamma)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
art_rgb_svp_alpha_callback(void * callback_data,int y,int start,ArtSVPRenderAAStep * steps,int n_steps)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
art_rgb_svp_alpha_opaque_callback(void * callback_data,int y,int start,ArtSVPRenderAAStep * steps,int n_steps)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
art_rgb_svp_alpha(const ArtSVP * svp,int x0,int y0,int x1,int y1,art_u32 rgba,art_u8 * buf,int rowstride,ArtAlphaGamma * alphagamma)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
458