/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ /* * art_rgba_svp.c: A slightly modified version of art_rgb_svp to render into rgba buffer * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public License * as published by the Free Software Foundation; either version 2 of * the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * Authors: * Raph Levien * Lauris Kaplinski * * Copyright (C) 1998 Raph Levien * */ #define SP_ART_RGBA_SVP_C /* Render a sorted vector path into an RGBA buffer. */ #include #include #include #include #include "art_rgba_svp.h" #include "unused.h" static void art_rgba_fill_run (art_u8 * linebuf, art_u8 r, art_u8 g, art_u8 b, int n); static void art_rgba_run_alpha (art_u8 * linebuf, art_u8 r, art_u8 g, art_u8 b, int alpha, int n); typedef struct _ArtRgbaSVPAlphaData ArtRgbaSVPAlphaData; struct _ArtRgbaSVPAlphaData { int alphatab[256]; art_u8 r, g, b, alpha; art_u8 *buf; int rowstride; int libart_x0, libart_x1; }; static void art_rgba_svp_alpha_callback (void *callback_data, int UNUSED(y), int start, ArtSVPRenderAAStep *steps, int n_steps) { ArtRgbaSVPAlphaData *data = callback_data; art_u8 *linebuf; int run_x0, run_x1; art_u32 running_sum = start; int libart_x0, libart_x1; int k; art_u8 r, g, b; int *alphatab; int alpha; linebuf = data->buf; libart_x0 = data->libart_x0; libart_x1 = data->libart_x1; r = data->r; g = data->g; b = data->b; alphatab = data->alphatab; if (n_steps > 0) { run_x1 = steps[0].x; if (run_x1 > libart_x0) { alpha = (running_sum >> 16) & 0xff; if (alpha) art_rgba_run_alpha (linebuf, r, g, b, alphatab[alpha], run_x1 - libart_x0); } /* render the steps into tmpbuf */ for (k = 0; k < n_steps - 1; k++) { running_sum += steps[k].delta; run_x0 = run_x1; run_x1 = steps[k + 1].x; if (run_x1 > run_x0) { alpha = (running_sum >> 16) & 0xff; if (alpha) art_rgba_run_alpha (linebuf + (run_x0 - libart_x0) * 4, r, g, b, alphatab[alpha], run_x1 - run_x0); } } running_sum += steps[k].delta; if (libart_x1 > run_x1) { alpha = (running_sum >> 16) & 0xff; if (alpha) art_rgba_run_alpha (linebuf + (run_x1 - libart_x0) * 4, r, g, b, alphatab[alpha], libart_x1 - run_x1); } } else { alpha = (running_sum >> 16) & 0xff; if (alpha) art_rgba_run_alpha (linebuf, r, g, b, alphatab[alpha], libart_x1 - libart_x0); } data->buf += data->rowstride; } static void art_rgba_svp_alpha_opaque_callback (void *callback_data, int UNUSED(y), int start, ArtSVPRenderAAStep *steps, int n_steps) { ArtRgbaSVPAlphaData *data = callback_data; art_u8 *linebuf; int run_x0, run_x1; art_u32 running_sum = start; int libart_x0, libart_x1; int k; art_u8 r, g, b; int *alphatab; int alpha; linebuf = data->buf; libart_x0 = data->libart_x0; libart_x1 = data->libart_x1; r = data->r; g = data->g; b = data->b; alphatab = data->alphatab; if (n_steps > 0) { run_x1 = steps[0].x; if (run_x1 > libart_x0) { alpha = running_sum >> 16; if (alpha) { if (alpha >= 255) art_rgba_fill_run (linebuf, r, g, b, run_x1 - libart_x0); else art_rgba_run_alpha (linebuf, r, g, b, alphatab[alpha], run_x1 - libart_x0); } } /* render the steps into tmpbuf */ for (k = 0; k < n_steps - 1; k++) { running_sum += steps[k].delta; run_x0 = run_x1; run_x1 = steps[k + 1].x; if (run_x1 > run_x0) { alpha = running_sum >> 16; if (alpha) { if (alpha >= 255) art_rgba_fill_run (linebuf + (run_x0 - libart_x0) * 4, r, g, b, run_x1 - run_x0); else art_rgba_run_alpha (linebuf + (run_x0 - libart_x0) * 4, r, g, b, alphatab[alpha], run_x1 - run_x0); } } } running_sum += steps[k].delta; if (libart_x1 > run_x1) { alpha = running_sum >> 16; if (alpha) { if (alpha >= 255) art_rgba_fill_run (linebuf + (run_x1 - libart_x0) * 4, r, g, b, libart_x1 - run_x1); else art_rgba_run_alpha (linebuf + (run_x1 - libart_x0) * 4, r, g, b, alphatab[alpha], libart_x1 - run_x1); } } } else { alpha = running_sum >> 16; if (alpha) { if (alpha >= 255) art_rgba_fill_run (linebuf, r, g, b, libart_x1 - libart_x0); else art_rgba_run_alpha (linebuf, r, g, b, alphatab[alpha], libart_x1 - libart_x0); } } data->buf += data->rowstride; } /** * gnome_print_art_rgba_svp_alpha: Alpha-composite sorted vector path over RGBA buffer. * @svp: The source sorted vector path. * @libart_x0: Left coordinate of destination rectangle. * @libart_y0: Top coordinate of destination rectangle. * @libart_x1: Right coordinate of destination rectangle. * @libart_y1: Bottom coordinate of destination rectangle. * @rgba: Color in 0xRRGGBBAA format. * @buf: Destination RGB buffer. * @rowstride: Rowstride of @buf buffer. * @alphagamma: #ArtAlphaGamma for gamma-correcting the compositing. * * Renders the shape specified with @svp over the @buf RGB buffer. * @libart_x1 - @x0 specifies the width, and @libart_y1 - @libart_y0 specifies the height, * of the rectangle rendered. The new pixels are stored starting at * the first byte of @buf. Thus, the @x0 and @libart_y0 parameters specify * an offset within @svp, and may be tweaked as a way of doing * integer-pixel translations without fiddling with @svp itself. * * The @rgba argument specifies the color for the rendering. Pixels of * entirely 0 winding number are left untouched. Pixels of entirely * 1 winding number have the color @rgba composited over them (ie, * are replaced by the red, green, blue components of @rgba if the alpha * component is 0xff). Pixels of intermediate coverage are interpolated * according to the rule in @alphagamma, or default to linear if * @alphagamma is NULL. **/ void gnome_print_art_rgba_svp_alpha (const ArtSVP *svp, int libart_x0, int libart_y0, int libart_x1, int libart_y1, art_u32 rgba, art_u8 *buf, int rowstride, ArtAlphaGamma UNUSED(*alphagamma)) { ArtRgbaSVPAlphaData data; int r, g, b, alpha; int i; int a, da; r = rgba >> 24; g = (rgba >> 16) & 0xff; b = (rgba >> 8) & 0xff; alpha = rgba & 0xff; data.r = r; data.g = g; data.b = b; data.alpha = alpha; a = 0x8000; da = (alpha * 66051 + 0x80) >> 8; /* 66051 equals 2 ^ 32 / (255 * 255) */ for (i = 0; i < 256; i++) { data.alphatab[i] = a >> 16; a += da; } data.buf = buf; data.rowstride = rowstride; data.libart_x0 = libart_x0; data.libart_x1 = libart_x1; if (alpha == 255) art_svp_render_aa (svp, libart_x0, libart_y0, libart_x1, libart_y1, art_rgba_svp_alpha_opaque_callback, &data); else art_svp_render_aa (svp, libart_x0, libart_y0, libart_x1, libart_y1, art_rgba_svp_alpha_callback, &data); } static void art_rgba_fill_run (art_u8 * buf, art_u8 r, art_u8 g, art_u8 b, int n) { int i; for (i = 0; i < n; i++) { * buf++ = r; * buf++ = g; * buf++ = b; * buf++ = 255; } } /* fixme: this */ static void art_rgba_run_alpha (art_u8 * buf, art_u8 r, art_u8 g, art_u8 b, int alpha, int n) { int i; int br, bg, bb, ba; int cr, cg, cb; for (i = 0; i < n; i++) { br = * (buf + 0); bg = * (buf + 1); bb = * (buf + 2); ba = * (buf + 3); cr = (br * ba + 0x80) >> 8; cg = (bg * ba + 0x80) >> 8; cb = (bb * ba + 0x80) >> 8; * buf++ = cr + (((r - cr) * alpha + 0x80) >> 8); * buf++ = cg + (((g - cg) * alpha + 0x80) >> 8); * buf++ = cb + (((b - cb) * alpha + 0x80) >> 8); * buf++ = ba + (((255 - ba) * alpha + 0x80) >> 8); } }