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 			    rgb >> 16, (rgb >> 8) & 0xff, 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 				rgb >> 16, (rgb >> 8) & 0xff, 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 			    rgb >> 16, (rgb >> 8) & 0xff, 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 			rgb >> 16, (rgb >> 8) & 0xff, 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