2 * art_render.c: Modular rendering architecture.
4 * Libart_LGPL - library of basic graphic primitives
5 * Copyright (C) 2000 Raph Levien
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Library General Public
9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Library General Public License for more details.
17 * You should have received a copy of the GNU Library General Public
18 * License along with this library; if not, write to the
19 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20 * Boston, MA 02111-1307, USA.
24 #include "art_render.h"
28 typedef struct _ArtRenderPriv ArtRenderPriv
;
30 struct _ArtRenderPriv
{
33 ArtImageSource
*image_source
;
36 ArtMaskSource
**mask_source
;
39 ArtRenderCallback
**callbacks
;
43 art_render_new (int x0
, int y0
, int x1
, int y1
,
44 art_u8
*pixels
, int rowstride
,
45 int n_chan
, int depth
, ArtAlphaType alpha_type
,
46 ArtAlphaGamma
*alphagamma
)
51 priv
= art_new (ArtRenderPriv
, 1);
52 result
= &priv
->super
;
54 if (n_chan
> ART_MAX_CHAN
)
56 art_warn ("art_render_new: n_chan = %d, exceeds %d max\n",
57 n_chan
, ART_MAX_CHAN
);
60 if (depth
> ART_MAX_DEPTH
)
62 art_warn ("art_render_new: depth = %d, exceeds %d max\n",
63 depth
, ART_MAX_DEPTH
);
68 art_warn ("art_render_new: x0 >= x1 (x0 = %d, x1 = %d)\n", x0
, x1
);
75 result
->pixels
= pixels
;
76 result
->rowstride
= rowstride
;
77 result
->n_chan
= n_chan
;
78 result
->depth
= depth
;
79 result
->alpha_type
= alpha_type
;
81 result
->clear
= ART_FALSE
;
82 result
->opacity
= 0x10000;
83 result
->compositing_mode
= ART_COMPOSITE_NORMAL
;
84 result
->alphagamma
= alphagamma
;
86 result
->alpha_buf
= NULL
;
87 result
->image_buf
= NULL
;
90 result
->span_x
= NULL
;
92 result
->need_span
= ART_FALSE
;
94 priv
->image_source
= NULL
;
96 priv
->n_mask_source
= 0;
97 priv
->mask_source
= NULL
;
102 /* todo on clear routines: I haven't really figured out what to do
103 with clearing the alpha channel. It _should_ be possible to clear
104 to an arbitrary RGBA color. */
107 * art_render_clear: Set clear color.
108 * @clear_color: Color with which to clear dest.
110 * Sets clear color, equivalent to actually clearing the destination
111 * buffer before rendering. This is the most general form.
114 art_render_clear (ArtRender
*render
, const ArtPixMaxDepth
*clear_color
)
117 int n_ch
= render
->n_chan
+ (render
->alpha_type
!= ART_ALPHA_NONE
);
119 render
->clear
= ART_TRUE
;
120 for (i
= 0; i
< n_ch
; i
++)
121 render
->clear_color
[i
] = clear_color
[i
];
125 * art_render_clear_rgb: Set clear color, given in RGB format.
126 * @clear_rgb: Clear color, in 0xRRGGBB format.
128 * Sets clear color, equivalent to actually clearing the destination
129 * buffer before rendering.
132 art_render_clear_rgb (ArtRender
*render
, art_u32 clear_rgb
)
134 if (render
->n_chan
!= 3)
135 art_warn ("art_render_clear_rgb: called on render with %d channels, only works with 3\n",
141 render
->clear
= ART_TRUE
;
143 g
= (clear_rgb
>> 8) & 0xff;
144 b
= clear_rgb
& 0xff;
145 render
->clear_color
[0] = ART_PIX_MAX_FROM_8(r
);
146 render
->clear_color
[1] = ART_PIX_MAX_FROM_8(g
);
147 render
->clear_color
[2] = ART_PIX_MAX_FROM_8(b
);
152 art_render_nop_done (ArtRenderCallback
*self
, ArtRender
*render
)
157 art_render_clear_render_rgb8 (ArtRenderCallback
*self
, ArtRender
*render
,
160 int width
= render
->x1
- render
->x0
;
162 ArtPixMaxDepth color_max
;
164 color_max
= render
->clear_color
[0];
165 r
= ART_PIX_8_FROM_MAX (color_max
);
166 color_max
= render
->clear_color
[1];
167 g
= ART_PIX_8_FROM_MAX (color_max
);
168 color_max
= render
->clear_color
[2];
169 b
= ART_PIX_8_FROM_MAX (color_max
);
171 art_rgb_fill_run (dest
, r
, g
, b
, width
);
175 art_render_clear_render_8 (ArtRenderCallback
*self
, ArtRender
*render
,
178 int width
= render
->x1
- render
->x0
;
180 int n_ch
= render
->n_chan
+ (render
->alpha_type
!= ART_ALPHA_NONE
);
182 art_u8 color
[ART_MAX_CHAN
+ 1];
184 for (j
= 0; j
< n_ch
; j
++)
186 ArtPixMaxDepth color_max
= render
->clear_color
[j
];
187 color
[j
] = ART_PIX_8_FROM_MAX (color_max
);
191 for (i
= 0; i
< width
; i
++)
192 for (j
= 0; j
< n_ch
; j
++)
193 dest
[ix
++] = color
[j
];
196 const ArtRenderCallback art_render_clear_rgb8_obj
=
198 art_render_clear_render_rgb8
,
202 const ArtRenderCallback art_render_clear_8_obj
=
204 art_render_clear_render_8
,
208 #if ART_MAX_DEPTH >= 16
211 art_render_clear_render_16 (ArtRenderCallback
*self
, ArtRender
*render
,
214 int width
= render
->x1
- render
->x0
;
216 int n_ch
= render
->n_chan
+ (render
->alpha_type
!= ART_ALPHA_NONE
);
218 art_u16
*dest_16
= (art_u16
*)dest
;
219 art_u8 color
[ART_MAX_CHAN
+ 1];
221 for (j
= 0; j
< n_ch
; j
++)
223 int color_16
= render
->clear_color
[j
];
228 for (i
= 0; i
< width
; i
++)
229 for (j
= 0; j
< n_ch
; j
++)
230 dest_16
[ix
++] = color
[j
];
233 const ArtRenderCallback art_render_clear_16_obj
=
235 art_render_clear_render_16
,
239 #endif /* ART_MAX_DEPTH >= 16 */
242 static ArtRenderCallback
*
243 art_render_choose_clear_callback (ArtRender
*render
)
245 ArtRenderCallback
*clear_callback
;
247 if (render
->depth
== 8)
249 if (render
->n_chan
== 3 &&
250 render
->alpha_type
== ART_ALPHA_NONE
)
251 clear_callback
= (ArtRenderCallback
*)&art_render_clear_rgb8_obj
;
253 clear_callback
= (ArtRenderCallback
*)&art_render_clear_8_obj
;
255 #if ART_MAX_DEPTH >= 16
256 else if (render
->depth
== 16)
257 clear_callback
= (ArtRenderCallback
*)&art_render_clear_16_obj
;
261 art_die ("art_render_choose_clear_callback: inconsistent render->depth = %d\n",
264 return clear_callback
;
268 /* todo: get around to writing this */
270 art_render_composite_render_noa_8_norm (ArtRenderCallback
*self
, ArtRender
*render
,
273 int width
= render
->x1
- render
->x0
;
278 /* This is the most general form of the function. It is slow but
279 (hopefully) correct. Actually, I'm still worried about roundoff
280 errors in the premul case - it seems to me that an off-by-one could
283 art_render_composite (ArtRenderCallback
*self
, ArtRender
*render
,
286 ArtRenderMaskRun
*run
= render
->run
;
287 art_u32 depth
= render
->depth
;
288 int n_run
= render
->n_run
;
292 art_u8
*alpha_buf
= render
->alpha_buf
;
293 art_u8
*image_buf
= render
->image_buf
;
299 art_u16 src
[ART_MAX_CHAN
+ 1];
300 art_u16 dst
[ART_MAX_CHAN
+ 1];
301 int n_chan
= render
->n_chan
;
302 ArtAlphaType alpha_type
= render
->alpha_type
;
303 int n_ch
= n_chan
+ (alpha_type
!= ART_ALPHA_NONE
);
304 int dst_pixstride
= n_ch
* (depth
>> 3);
305 int buf_depth
= render
->buf_depth
;
306 ArtAlphaType buf_alpha
= render
->buf_alpha
;
307 int buf_n_ch
= n_chan
+ (buf_alpha
!= ART_ALPHA_NONE
);
308 int buf_pixstride
= buf_n_ch
* (buf_depth
>> 3);
317 for (i
= 0; i
< n_run
- 1; i
++)
320 run_x1
= run
[i
+ 1].x
;
325 run_alpha
= (tmp
+ (tmp
>> 8) + (tmp
>> 16) - 0x8000) >> 8; /* range [0 .. 0x10000] */
326 bufptr
= image_buf
+ (run_x0
- x0
) * buf_pixstride
;
327 dstptr
= dest
+ (run_x0
- x0
) * dst_pixstride
;
328 for (x
= run_x0
; x
< run_x1
; x
++)
334 tmp
= run_alpha
* alpha_buf
[x
- x0
] + 0x80;
335 /* range 0x80 .. 0xff0080 */
336 alpha
= (tmp
+ (tmp
>> 8) + (tmp
>> 16)) >> 8;
338 else /* (depth == 16) */
340 tmp
= ((art_u16
*)alpha_buf
)[x
- x0
];
341 tmp
= (run_alpha
* tmp
+ 0x8000) >> 8;
342 /* range 0x80 .. 0xffff80 */
343 alpha
= (tmp
+ (tmp
>> 16)) >> 8;
348 /* alpha is run_alpha * alpha_buf[x], range 0 .. 0x10000 */
350 /* convert (src pixel * alpha) to premul alpha form,
351 store in src as 0..0xffff range */
352 if (buf_alpha
== ART_ALPHA_NONE
)
361 tmp
= alpha
* bufptr
[n_chan
] + 0x80;
362 /* range 0x80 .. 0xff0080 */
363 src_alpha
= (tmp
+ (tmp
>> 8) + (tmp
>> 16)) >> 8;
365 else /* (depth == 16) */
367 tmp
= ((art_u16
*)bufptr
)[n_chan
];
368 tmp
= (alpha
* tmp
+ 0x8000) >> 8;
369 /* range 0x80 .. 0xffff80 */
370 src_alpha
= (tmp
+ (tmp
>> 16)) >> 8;
372 if (buf_alpha
== ART_ALPHA_SEPARATE
)
374 else /* buf_alpha == (ART_ALPHA_PREMUL) */
377 /* src_alpha is the (alpha of the source pixel * alpha),
383 for (j
= 0; j
< n_chan
; j
++)
384 src
[j
] = (bufptr
[j
] * src_mul
+ 0x8000) >> 16;
386 else if (buf_depth
== 16)
388 for (j
= 0; j
< n_chan
; j
++)
389 src
[j
] = (((art_u16
*)bufptr
)[j
] * src_mul
+ 0x8000) >> 16;
391 bufptr
+= buf_pixstride
;
393 /* src[0..n_chan - 1] (range 0..0xffff) and src_alpha (range
394 0..0x10000) now contain the source pixel with
395 premultiplied alpha */
397 /* convert dst pixel to premul alpha form,
398 store in dst as 0..0xffff range */
399 if (alpha_type
== ART_ALPHA_NONE
)
408 tmp
= dstptr
[n_chan
];
410 dst_alpha
= (tmp
<< 8) + tmp
+ (tmp
>> 7);
412 else /* (depth == 16) */
414 tmp
= ((art_u16
*)dstptr
)[n_chan
];
415 dst_alpha
= (tmp
+ (tmp
>> 15));
417 if (alpha_type
== ART_ALPHA_SEPARATE
)
419 else /* (alpha_type == ART_ALPHA_PREMUL) */
422 /* dst_alpha is the alpha of the dest pixel,
428 for (j
= 0; j
< n_chan
; j
++)
429 dst
[j
] = (dstptr
[j
] * dst_mul
+ 0x8000) >> 16;
431 else if (buf_depth
== 16)
433 for (j
= 0; j
< n_chan
; j
++)
434 dst
[j
] = (((art_u16
*)dstptr
)[j
] * dst_mul
+ 0x8000) >> 16;
437 /* do the compositing, dst = (src over dst) */
438 for (j
= 0; j
< n_chan
; j
++)
445 tmp
= ((dstv
* (0x10000 - src_alpha
) + 0x8000) >> 16) + srcv
;
450 if (alpha_type
== ART_ALPHA_NONE
)
454 else /* (depth == 16) */
459 if (src_alpha
>= 0x10000)
462 dst_alpha
+= ((((0x10000 - dst_alpha
) * src_alpha
) >> 8) + 0x80) >> 8;
463 if (alpha_type
== ART_ALPHA_PREMUL
|| dst_alpha
== 0)
467 else /* (depth == 16) */
470 else /* (ALPHA_TYPE == ART_ALPHA_SEPARATE && dst_alpha != 0) */
473 dst_mul
= 0xff0000 / dst_alpha
;
474 else /* (depth == 16) */
475 dst_mul
= 0xffff0000 / dst_alpha
;
480 for (j
= 0; j
< n_chan
; j
++)
481 dstptr
[j
] = (dst
[j
] * dst_mul
+ 0x8000) >> 16;
482 if (alpha_type
!= ART_ALPHA_NONE
)
483 dstptr
[n_chan
] = (dst_alpha
* 0xff + 0x8000) >> 16;
485 else if (depth
== 16)
487 for (j
= 0; j
< n_chan
; j
++)
488 ((art_u16
*)dstptr
)[j
] = (dst
[j
] * dst_mul
+ 0x8000) >> 16;
489 if (alpha_type
!= ART_ALPHA_NONE
)
490 ((art_u16
*)dstptr
)[n_chan
] = (dst_alpha
* 0xffff + 0x8000) >> 16;
492 dstptr
+= dst_pixstride
;
497 const ArtRenderCallback art_render_composite_obj
=
499 art_render_composite
,
504 art_render_composite_8 (ArtRenderCallback
*self
, ArtRender
*render
,
507 ArtRenderMaskRun
*run
= render
->run
;
508 int n_run
= render
->n_run
;
512 art_u8
*alpha_buf
= render
->alpha_buf
;
513 art_u8
*image_buf
= render
->image_buf
;
519 int n_chan
= render
->n_chan
;
520 ArtAlphaType alpha_type
= render
->alpha_type
;
521 int n_ch
= n_chan
+ (alpha_type
!= ART_ALPHA_NONE
);
522 int dst_pixstride
= n_ch
;
523 ArtAlphaType buf_alpha
= render
->buf_alpha
;
524 int buf_n_ch
= n_chan
+ (buf_alpha
!= ART_ALPHA_NONE
);
525 int buf_pixstride
= buf_n_ch
;
531 art_u32 dst_mul
, dst_save_mul
;
534 for (i
= 0; i
< n_run
- 1; i
++)
537 run_x1
= run
[i
+ 1].x
;
542 run_alpha
= (tmp
+ (tmp
>> 8) + (tmp
>> 16) - 0x8000) >> 8; /* range [0 .. 0x10000] */
543 bufptr
= image_buf
+ (run_x0
- x0
) * buf_pixstride
;
544 dstptr
= dest
+ (run_x0
- x0
) * dst_pixstride
;
545 for (x
= run_x0
; x
< run_x1
; x
++)
549 tmp
= run_alpha
* alpha_buf
[x
- x0
] + 0x80;
550 /* range 0x80 .. 0xff0080 */
551 alpha
= (tmp
+ (tmp
>> 8) + (tmp
>> 16)) >> 8;
555 /* alpha is run_alpha * alpha_buf[x], range 0 .. 0x10000 */
557 /* convert (src pixel * alpha) to premul alpha form,
558 store in src as 0..0xffff range */
559 if (buf_alpha
== ART_ALPHA_NONE
)
566 tmp
= alpha
* bufptr
[n_chan
] + 0x80;
567 /* range 0x80 .. 0xff0080 */
568 src_alpha
= (tmp
+ (tmp
>> 8) + (tmp
>> 16)) >> 8;
570 if (buf_alpha
== ART_ALPHA_SEPARATE
)
572 else /* buf_alpha == (ART_ALPHA_PREMUL) */
575 /* src_alpha is the (alpha of the source pixel * alpha),
580 if (alpha_type
== ART_ALPHA_NONE
)
587 tmp
= dstptr
[n_chan
];
589 dst_alpha
= (tmp
<< 8) + tmp
+ (tmp
>> 7);
590 if (alpha_type
== ART_ALPHA_SEPARATE
)
592 else /* (alpha_type == ART_ALPHA_PREMUL) */
595 /* dst_alpha is the alpha of the dest pixel,
600 if (alpha_type
== ART_ALPHA_NONE
)
606 if (src_alpha
>= 0x10000)
609 dst_alpha
+= ((((0x10000 - dst_alpha
) * src_alpha
) >> 8) + 0x80) >> 8;
610 if (alpha_type
== ART_ALPHA_PREMUL
|| dst_alpha
== 0)
614 else /* (ALPHA_TYPE == ART_ALPHA_SEPARATE && dst_alpha != 0) */
616 dst_save_mul
= 0xff0000 / dst_alpha
;
620 for (j
= 0; j
< n_chan
; j
++)
625 src
= (bufptr
[j
] * src_mul
+ 0x8000) >> 16;
626 dst
= (dstptr
[j
] * dst_mul
+ 0x8000) >> 16;
627 tmp
= ((dst
* (0x10000 - src_alpha
) + 0x8000) >> 16) + src
;
629 dstptr
[j
] = (tmp
* dst_save_mul
+ 0x8000) >> 16;
631 if (alpha_type
!= ART_ALPHA_NONE
)
632 dstptr
[n_chan
] = (dst_alpha
* 0xff + 0x8000) >> 16;
634 bufptr
+= buf_pixstride
;
635 dstptr
+= dst_pixstride
;
640 const ArtRenderCallback art_render_composite_8_obj
=
642 art_render_composite_8
,
649 * buf_alpha = ART_ALPHA_NONE (source)
650 * alpha_type = ART_ALPHA_SEPARATE (dest)
654 art_render_composite_8_opt1 (ArtRenderCallback
*self
, ArtRender
*render
,
657 ArtRenderMaskRun
*run
= render
->run
;
658 int n_run
= render
->n_run
;
662 art_u8
*image_buf
= render
->image_buf
;
671 art_u32 dst_mul
, dst_save_mul
;
674 for (i
= 0; i
< n_run
- 1; i
++)
677 run_x1
= run
[i
+ 1].x
;
682 run_alpha
= (tmp
+ (tmp
>> 8) + (tmp
>> 16) - 0x8000) >> 8; /* range [0 .. 0x10000] */
683 bufptr
= image_buf
+ (run_x0
- x0
) * 3;
684 dstptr
= dest
+ (run_x0
- x0
) * 4;
685 if (run_alpha
== 0x10000)
687 for (x
= run_x0
; x
< run_x1
; x
++)
689 *dstptr
++ = *bufptr
++;
690 *dstptr
++ = *bufptr
++;
691 *dstptr
++ = *bufptr
++;
697 for (x
= run_x0
; x
< run_x1
; x
++)
699 src_mul
= run_alpha
* 0x101;
703 dst_alpha
= (tmp
<< 8) + tmp
+ (tmp
>> 7);
705 /* dst_alpha is the alpha of the dest pixel,
710 dst_alpha
+= ((((0x10000 - dst_alpha
) * run_alpha
) >> 8) + 0x80) >> 8;
713 else /* (dst_alpha != 0) */
714 dst_save_mul
= 0xff0000 / dst_alpha
;
716 for (j
= 0; j
< 3; j
++)
721 src
= (bufptr
[j
] * src_mul
+ 0x8000) >> 16;
722 dst
= (dstptr
[j
] * dst_mul
+ 0x8000) >> 16;
723 tmp
= ((dst
* (0x10000 - run_alpha
) + 0x8000) >> 16) + src
;
725 dstptr
[j
] = (tmp
* dst_save_mul
+ 0x8000) >> 16;
727 dstptr
[3] = (dst_alpha
* 0xff + 0x8000) >> 16;
737 const ArtRenderCallback art_render_composite_8_opt1_obj
=
739 art_render_composite_8_opt1
,
745 * buf_alpha = ART_ALPHA_PREMUL (source)
746 * alpha_type = ART_ALPHA_SEPARATE (dest)
750 art_render_composite_8_opt2 (ArtRenderCallback
*self
, ArtRender
*render
,
753 ArtRenderMaskRun
*run
= render
->run
;
754 int n_run
= render
->n_run
;
758 art_u8
*image_buf
= render
->image_buf
;
768 art_u32 dst_mul
, dst_save_mul
;
771 for (i
= 0; i
< n_run
- 1; i
++)
774 run_x1
= run
[i
+ 1].x
;
779 run_alpha
= (tmp
+ (tmp
>> 8) + (tmp
>> 16) - 0x8000) >> 8; /* range [0 .. 0x10000] */
780 bufptr
= image_buf
+ (run_x0
- x0
) * 4;
781 dstptr
= dest
+ (run_x0
- x0
) * 4;
782 if (run_alpha
== 0x10000)
784 for (x
= run_x0
; x
< run_x1
; x
++)
786 src_alpha
= (bufptr
[3] << 8) + bufptr
[3] + (bufptr
[3] >> 7);
787 /* src_alpha is the (alpha of the source pixel),
790 dst_alpha
= (dstptr
[3] << 8) + dstptr
[3] + (dstptr
[3] >> 7);
791 /* dst_alpha is the alpha of the dest pixel,
794 dst_mul
= dst_alpha
*0x101;
796 if (src_alpha
>= 0x10000)
799 dst_alpha
+= ((((0x10000 - dst_alpha
) * src_alpha
) >> 8) + 0x80) >> 8;
803 else /* dst_alpha != 0) */
804 dst_save_mul
= 0xff0000 / dst_alpha
;
806 for (j
= 0; j
< 3; j
++)
811 src
= (bufptr
[j
] << 8) | bufptr
[j
];
812 dst
= (dstptr
[j
] * dst_mul
+ 0x8000) >> 16;
813 tmp
= ((dst
* (0x10000 - src_alpha
) + 0x8000) >> 16) + src
;
815 dstptr
[j
] = (tmp
* dst_save_mul
+ 0x8000) >> 16;
817 dstptr
[3] = (dst_alpha
* 0xff + 0x8000) >> 16;
825 for (x
= run_x0
; x
< run_x1
; x
++)
827 tmp
= run_alpha
* bufptr
[3] + 0x80;
828 /* range 0x80 .. 0xff0080 */
829 src_alpha
= (tmp
+ (tmp
>> 8) + (tmp
>> 16)) >> 8;
830 /* src_alpha is the (alpha of the source pixel * alpha),
833 src_mul
= run_alpha
* 0x101;
837 dst_alpha
= (tmp
<< 8) + tmp
+ (tmp
>> 7);
839 /* dst_alpha is the alpha of the dest pixel,
844 if (src_alpha
>= 0x10000)
847 dst_alpha
+= ((((0x10000 - dst_alpha
) * src_alpha
) >> 8) + 0x80) >> 8;
853 else /* dst_alpha != 0) */
855 dst_save_mul
= 0xff0000 / dst_alpha
;
858 for (j
= 0; j
< 3; j
++)
863 src
= (bufptr
[j
] * src_mul
+ 0x8000) >> 16;
864 dst
= (dstptr
[j
] * dst_mul
+ 0x8000) >> 16;
865 tmp
= ((dst
* (0x10000 - src_alpha
) + 0x8000) >> 16) + src
;
867 dstptr
[j
] = (tmp
* dst_save_mul
+ 0x8000) >> 16;
869 dstptr
[3] = (dst_alpha
* 0xff + 0x8000) >> 16;
878 const ArtRenderCallback art_render_composite_8_opt2_obj
=
880 art_render_composite_8_opt2
,
886 static ArtRenderCallback
*
887 art_render_choose_compositing_callback (ArtRender
*render
)
889 if (render
->depth
== 8 && render
->buf_depth
== 8)
891 if (render
->n_chan
== 3 &&
892 render
->alpha_buf
== NULL
&&
893 render
->alpha_type
== ART_ALPHA_SEPARATE
)
895 if (render
->buf_alpha
== ART_ALPHA_NONE
)
896 return (ArtRenderCallback
*)&art_render_composite_8_opt1_obj
;
897 else if (render
->buf_alpha
== ART_ALPHA_PREMUL
)
898 return (ArtRenderCallback
*)&art_render_composite_8_opt2_obj
;
901 return (ArtRenderCallback
*)&art_render_composite_8_obj
;
903 return (ArtRenderCallback
*)&art_render_composite_obj
;
907 * art_render_invoke_callbacks: Invoke the callbacks in the render object.
908 * @render: The render object.
909 * @y: The current Y coordinate value.
911 * Invokes the callbacks of the render object in the appropriate
912 * order. Drivers should call this routine once per scanline.
914 * todo: should management of dest devolve to this routine? very
918 art_render_invoke_callbacks (ArtRender
*render
, art_u8
*dest
, int y
)
920 ArtRenderPriv
*priv
= (ArtRenderPriv
*)render
;
923 for (i
= 0; i
< priv
->n_callbacks
; i
++)
925 ArtRenderCallback
*callback
;
927 callback
= priv
->callbacks
[i
];
928 callback
->render (callback
, render
, dest
, y
);
933 * art_render_invoke: Perform the requested rendering task.
934 * @render: The render object.
936 * Invokes the renderer and all sources associated with it, to perform
937 * the requested rendering task.
940 art_render_invoke (ArtRender
*render
)
942 ArtRenderPriv
*priv
= (ArtRenderPriv
*)render
;
944 int best_driver
, best_score
;
946 int n_callbacks
, n_callbacks_max
;
947 ArtImageSource
*image_source
;
950 ArtAlphaType buf_alpha
;
951 art_boolean first
= ART_TRUE
;
955 art_warn ("art_render_invoke: called with render == NULL\n");
958 if (priv
->image_source
== NULL
)
960 art_warn ("art_render_invoke: no image source given\n");
964 width
= render
->x1
- render
->x0
;
966 render
->run
= art_new (ArtRenderMaskRun
, width
+ 1);
968 /* Elect a mask source as driver. */
971 for (i
= 0; i
< priv
->n_mask_source
; i
++)
974 ArtMaskSource
*mask_source
;
976 mask_source
= priv
->mask_source
[i
];
977 score
= mask_source
->can_drive (mask_source
, render
);
978 if (score
> best_score
)
985 /* Allocate alpha buffer if needed. */
986 if (priv
->n_mask_source
> 1 ||
987 (priv
->n_mask_source
== 1 && best_driver
< 0))
989 render
->alpha_buf
= art_new (art_u8
, (width
* render
->depth
) >> 3);
992 /* Negotiate image rendering and compositing. */
993 image_source
= priv
->image_source
;
994 image_source
->negotiate (image_source
, render
, &image_flags
, &buf_depth
,
997 /* Build callback list. */
998 n_callbacks_max
= priv
->n_mask_source
+ 3;
999 priv
->callbacks
= art_new (ArtRenderCallback
*, n_callbacks_max
);
1001 for (i
= 0; i
< priv
->n_mask_source
; i
++)
1002 if (i
!= best_driver
)
1004 ArtMaskSource
*mask_source
= priv
->mask_source
[i
];
1006 mask_source
->prepare (mask_source
, render
, first
);
1008 priv
->callbacks
[n_callbacks
++] = &mask_source
->super
;
1011 if (render
->clear
&& !(image_flags
& ART_IMAGE_SOURCE_CAN_CLEAR
))
1012 priv
->callbacks
[n_callbacks
++] =
1013 art_render_choose_clear_callback (render
);
1015 priv
->callbacks
[n_callbacks
++] = &image_source
->super
;
1017 /* Allocate image buffer and add compositing callback if needed. */
1018 if (!(image_flags
& ART_IMAGE_SOURCE_CAN_COMPOSITE
))
1020 int bytespp
= ((render
->n_chan
+ (buf_alpha
!= ART_ALPHA_NONE
)) *
1022 render
->buf_depth
= buf_depth
;
1023 render
->buf_alpha
= buf_alpha
;
1024 render
->image_buf
= art_new (art_u8
, width
* bytespp
);
1025 priv
->callbacks
[n_callbacks
++] =
1026 art_render_choose_compositing_callback (render
);
1029 priv
->n_callbacks
= n_callbacks
;
1031 if (render
->need_span
)
1032 render
->span_x
= art_new (int, width
+ 1);
1034 /* Invoke the driver */
1035 if (best_driver
>= 0)
1037 ArtMaskSource
*driver
;
1039 driver
= priv
->mask_source
[best_driver
];
1040 driver
->invoke_driver (driver
, render
);
1044 art_u8
*dest_ptr
= render
->pixels
;
1049 render
->run
[0].x
= render
->x0
;
1050 render
->run
[0].alpha
= 0x8000 + 0xff * render
->opacity
;
1051 render
->run
[1].x
= render
->x1
;
1052 render
->run
[1].alpha
= 0x8000;
1053 if (render
->need_span
)
1056 render
->span_x
[0] = render
->x0
;
1057 render
->span_x
[1] = render
->x1
;
1059 for (y
= render
->y0
; y
< render
->y1
; y
++)
1061 art_render_invoke_callbacks (render
, dest_ptr
, y
);
1062 dest_ptr
+= render
->rowstride
;
1066 if (priv
->mask_source
!= NULL
)
1067 art_free (priv
->mask_source
);
1069 /* clean up callbacks */
1070 for (i
= 0; i
< priv
->n_callbacks
; i
++)
1072 ArtRenderCallback
*callback
;
1074 callback
= priv
->callbacks
[i
];
1075 callback
->done (callback
, render
);
1078 /* Tear down object */
1079 if (render
->alpha_buf
!= NULL
)
1080 art_free (render
->alpha_buf
);
1081 if (render
->image_buf
!= NULL
)
1082 art_free (render
->image_buf
);
1083 art_free (render
->run
);
1084 if (render
->span_x
!= NULL
)
1085 art_free (render
->span_x
);
1086 art_free (priv
->callbacks
);
1091 * art_render_mask_solid: Add a solid translucent mask.
1092 * @render: The render object.
1093 * @opacity: Opacity in [0..0x10000] form.
1095 * Adds a translucent mask to the rendering object.
1098 art_render_mask_solid (ArtRender
*render
, int opacity
)
1100 art_u32 old_opacity
= render
->opacity
;
1101 art_u32 new_opacity_tmp
;
1103 if (opacity
== 0x10000)
1104 /* avoid potential overflow */
1106 new_opacity_tmp
= old_opacity
* (art_u32
)opacity
+ 0x8000;
1107 render
->opacity
= new_opacity_tmp
>> 16;
1111 * art_render_add_mask_source: Add a mask source to the render object.
1112 * @render: Render object.
1113 * @mask_source: Mask source to add.
1115 * This routine adds a mask source to the render object. In general,
1116 * client api's for adding mask sources should just take a render object,
1117 * then the mask source creation function should call this function.
1118 * Clients should never have to call this function directly, unless of
1119 * course they're creating custom mask sources.
1122 art_render_add_mask_source (ArtRender
*render
, ArtMaskSource
*mask_source
)
1124 ArtRenderPriv
*priv
= (ArtRenderPriv
*)render
;
1125 int n_mask_source
= priv
->n_mask_source
++;
1127 if (n_mask_source
== 0)
1128 priv
->mask_source
= art_new (ArtMaskSource
*, 1);
1129 /* This predicate is true iff n_mask_source is a power of two */
1130 else if (!(n_mask_source
& (n_mask_source
- 1)))
1131 priv
->mask_source
= art_renew (priv
->mask_source
, ArtMaskSource
*,
1132 n_mask_source
<< 1);
1134 priv
->mask_source
[n_mask_source
] = mask_source
;
1138 * art_render_add_image_source: Add a mask source to the render object.
1139 * @render: Render object.
1140 * @image_source: Image source to add.
1142 * This routine adds an image source to the render object. In general,
1143 * client api's for adding image sources should just take a render
1144 * object, then the mask source creation function should call this
1145 * function. Clients should never have to call this function
1146 * directly, unless of course they're creating custom image sources.
1149 art_render_add_image_source (ArtRender
*render
, ArtImageSource
*image_source
)
1151 ArtRenderPriv
*priv
= (ArtRenderPriv
*)render
;
1153 if (priv
->image_source
!= NULL
)
1155 art_warn ("art_render_add_image_source: image source already present.\n");
1158 priv
->image_source
= image_source
;
1161 /* Solid image source object and methods. Perhaps this should go into a
1164 typedef struct _ArtImageSourceSolid ArtImageSourceSolid
;
1166 struct _ArtImageSourceSolid
{
1167 ArtImageSource super
;
1168 ArtPixMaxDepth color
[ART_MAX_CHAN
];
1174 art_render_image_solid_done (ArtRenderCallback
*self
, ArtRender
*render
)
1176 ArtImageSourceSolid
*z
= (ArtImageSourceSolid
*)self
;
1178 if (z
->rgbtab
!= NULL
)
1179 art_free (z
->rgbtab
);
1184 art_render_image_solid_rgb8_opaq_init (ArtImageSourceSolid
*self
, ArtRender
*render
)
1186 ArtImageSourceSolid
*z
= (ArtImageSourceSolid
*)self
;
1187 ArtPixMaxDepth color_max
;
1188 int r_fg
, g_fg
, b_fg
;
1189 int r_bg
, g_bg
, b_bg
;
1196 rgbtab
= art_new (art_u32
, 256);
1199 color_max
= self
->color
[0];
1200 r_fg
= ART_PIX_8_FROM_MAX (color_max
);
1201 color_max
= self
->color
[1];
1202 g_fg
= ART_PIX_8_FROM_MAX (color_max
);
1203 color_max
= self
->color
[2];
1204 b_fg
= ART_PIX_8_FROM_MAX (color_max
);
1206 color_max
= render
->clear_color
[0];
1207 r_bg
= ART_PIX_8_FROM_MAX (color_max
);
1208 color_max
= render
->clear_color
[1];
1209 g_bg
= ART_PIX_8_FROM_MAX (color_max
);
1210 color_max
= render
->clear_color
[2];
1211 b_bg
= ART_PIX_8_FROM_MAX (color_max
);
1213 r
= (r_bg
<< 16) + 0x8000;
1214 g
= (g_bg
<< 16) + 0x8000;
1215 b
= (b_bg
<< 16) + 0x8000;
1216 tmp
= ((r_fg
- r_bg
) << 16) + 0x80;
1217 dr
= (tmp
+ (tmp
>> 8)) >> 8;
1218 tmp
= ((g_fg
- g_bg
) << 16) + 0x80;
1219 dg
= (tmp
+ (tmp
>> 8)) >> 8;
1220 tmp
= ((b_fg
- b_bg
) << 16) + 0x80;
1221 db
= (tmp
+ (tmp
>> 8)) >> 8;
1223 for (i
= 0; i
< 256; i
++)
1225 rgbtab
[i
] = (r
& 0xff0000) | ((g
& 0xff0000) >> 8) | (b
>> 16);
1233 art_render_image_solid_rgb8_opaq (ArtRenderCallback
*self
, ArtRender
*render
,
1234 art_u8
*dest
, int y
)
1236 ArtImageSourceSolid
*z
= (ArtImageSourceSolid
*)self
;
1237 ArtRenderMaskRun
*run
= render
->run
;
1238 int n_run
= render
->n_run
;
1239 art_u32
*rgbtab
= z
->rgbtab
;
1241 int x0
= render
->x0
;
1242 int x1
= render
->x1
;
1253 art_rgb_fill_run (dest
,
1254 rgb
>> 16, (rgb
>> 8) & 0xff, rgb
& 0xff,
1257 for (i
= 0; i
< n_run
- 1; i
++)
1260 run_x1
= run
[i
+ 1].x
;
1261 rgb
= rgbtab
[(run
[i
].alpha
>> 16) & 0xff];
1262 ix
= (run_x0
- x0
) * 3;
1263 #define OPTIMIZE_LEN_1
1264 #ifdef OPTIMIZE_LEN_1
1265 if (run_x1
- run_x0
== 1)
1267 dest
[ix
] = rgb
>> 16;
1268 dest
[ix
+ 1] = (rgb
>> 8) & 0xff;
1269 dest
[ix
+ 2] = rgb
& 0xff;
1273 art_rgb_fill_run (dest
+ ix
,
1274 rgb
>> 16, (rgb
>> 8) & 0xff, rgb
& 0xff,
1278 art_rgb_fill_run (dest
+ ix
,
1279 rgb
>> 16, (rgb
>> 8) & 0xff, rgb
& 0xff,
1291 art_rgb_fill_run (dest
+ (run_x1
- x0
) * 3,
1292 rgb
>> 16, (rgb
>> 8) & 0xff, rgb
& 0xff,
1298 art_render_image_solid_rgb8 (ArtRenderCallback
*self
, ArtRender
*render
,
1299 art_u8
*dest
, int y
)
1301 ArtImageSourceSolid
*z
= (ArtImageSourceSolid
*)self
;
1302 int width
= render
->x1
- render
->x0
;
1304 ArtPixMaxDepth color_max
;
1306 /* todo: replace this simple test with real sparseness */
1311 color_max
= z
->color
[0];
1312 r
= ART_PIX_8_FROM_MAX (color_max
);
1313 color_max
= z
->color
[1];
1314 g
= ART_PIX_8_FROM_MAX (color_max
);
1315 color_max
= z
->color
[2];
1316 b
= ART_PIX_8_FROM_MAX (color_max
);
1318 art_rgb_fill_run (render
->image_buf
, r
, g
, b
, width
);
1322 art_render_image_solid_negotiate (ArtImageSource
*self
, ArtRender
*render
,
1324 int *p_buf_depth
, ArtAlphaType
*p_alpha
)
1326 ArtImageSourceSolid
*z
= (ArtImageSourceSolid
*)self
;
1328 static void (*render_cbk
) (ArtRenderCallback
*self
, ArtRender
*render
,
1329 art_u8
*dest
, int y
);
1333 if (render
->depth
== 8 && render
->n_chan
== 3 &&
1334 render
->alpha_type
== ART_ALPHA_NONE
)
1338 render_cbk
= art_render_image_solid_rgb8_opaq
;
1339 flags
|= ART_IMAGE_SOURCE_CAN_CLEAR
| ART_IMAGE_SOURCE_CAN_COMPOSITE
;
1340 art_render_image_solid_rgb8_opaq_init (z
, render
);
1343 if (render_cbk
== NULL
)
1345 if (render
->depth
== 8)
1347 render_cbk
= art_render_image_solid_rgb8
;
1349 *p_alpha
= ART_ALPHA_NONE
; /* todo */
1352 /* todo: general case */
1353 self
->super
.render
= render_cbk
;
1358 * art_render_image_solid: Add a solid color image source.
1359 * @render: The render object.
1362 * Adds an image source with the solid color given by @color. The
1363 * color need not be retained in memory after this call.
1366 art_render_image_solid (ArtRender
*render
, ArtPixMaxDepth
*color
)
1368 ArtImageSourceSolid
*image_source
;
1371 image_source
= art_new (ArtImageSourceSolid
, 1);
1372 image_source
->super
.super
.render
= NULL
;
1373 image_source
->super
.super
.done
= art_render_image_solid_done
;
1374 image_source
->super
.negotiate
= art_render_image_solid_negotiate
;
1376 for (i
= 0; i
< render
->n_chan
; i
++)
1377 image_source
->color
[i
] = color
[i
];
1379 image_source
->rgbtab
= NULL
;
1380 image_source
->init
= ART_FALSE
;
1382 art_render_add_image_source (render
, &image_source
->super
);